diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0962526 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +sudo: required +language: go +go: +- "1.10" + +# This moves Kubernetes specific config files. +env: +- CHANGE_MINIKUBE_NONE_USER=true + +# All deps are vendored and checked in. +install: true + +before_script: +# Download kubectl, which is a requirement for using minikube. +- curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/ +# Download minikube. +- curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ +# Start Kubernetes with apiserver configured to use local test Vault for authentication. +- sudo minikube start --vm-driver=none --bootstrapper=localkube --kubernetes-version=v1.10.0 --extra-config apiserver.Authentication.WebHook.ConfigFile=$(pwd)/testing/webhook-authn.yaml --extra-config apiserver.Authentication.WebHook.CacheTTL=0s +# Fix the kubectl context, as it's often stale. +- minikube update-context +# Wait for Kubernetes to be up and ready. +- JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; until kubectl get nodes -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1; done + +script: + - CGO_ENABLED=0 go build -o bin/kubernetes-credential-provider-vault ./cmd/kubernetes-credential-provider-vault + - KUBE_ADDR=https://$(minikube ip):8443 go test -v ./... diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..cb8146b --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,794 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "cloud.google.com/go" + packages = ["civil"] + revision = "0fd7230b2a7505833d5f69b75cbd6c9582401479" + version = "v0.23.0" + +[[projects]] + name = "github.com/Jeffail/gabs" + packages = ["."] + revision = "7a0fed31069aba77993a518cc2f37b28ee7aa883" + version = "1.1" + +[[projects]] + name = "github.com/NYTimes/gziphandler" + packages = ["."] + revision = "2600fb119af974220d3916a5916d6e31176aac1b" + version = "v1.0.1" + +[[projects]] + name = "github.com/SAP/go-hdb" + packages = [ + "driver", + "driver/sqltrace", + "internal/bufio", + "internal/protocol", + "internal/unicode", + "internal/unicode/cesu8" + ] + revision = "4e1c5bf7d81c4a7cd2c64f4eec5bc64068500b5a" + version = "v0.12.0" + +[[projects]] + name = "github.com/SermoDigital/jose" + packages = [ + ".", + "crypto", + "jws", + "jwt" + ] + revision = "f6df55f235c24f236d11dbcf665249a59ac2021f" + version = "1.1" + +[[projects]] + branch = "master" + name = "github.com/armon/go-metrics" + packages = ["."] + revision = "783273d703149aaeb9897cf58613d5af48861c25" + +[[projects]] + branch = "master" + name = "github.com/armon/go-radix" + packages = ["."] + revision = "1fca145dffbcaa8fe914309b1ec0cfc67500fe61" + +[[projects]] + name = "github.com/bgentry/speakeasy" + packages = ["."] + revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" + version = "v0.1.0" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/denisenkom/go-mssqldb" + packages = [ + ".", + "internal/cp" + ] + revision = "c12642a8f7884ab01719704032c36ff300ff52c6" + +[[projects]] + branch = "master" + name = "github.com/duosecurity/duo_api_golang" + packages = [ + ".", + "authapi" + ] + revision = "d0530c80e49a86b1c3f5525daa5a324bfb795ef3" + +[[projects]] + name = "github.com/elazarl/go-bindata-assetfs" + packages = ["."] + revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43" + version = "v1.0.0" + +[[projects]] + name = "github.com/fatih/color" + packages = ["."] + revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" + version = "v1.7.0" + +[[projects]] + name = "github.com/ghodss/yaml" + packages = ["."] + revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" + version = "v1.0.0" + +[[projects]] + name = "github.com/go-errors/errors" + packages = ["."] + revision = "a6af135bd4e28680facf08a3d206b454abc877a4" + version = "v1.0.1" + +[[projects]] + name = "github.com/go-sql-driver/mysql" + packages = ["."] + revision = "d523deb1b23d913de5bdada721a6071e71283618" + version = "v1.4.0" + +[[projects]] + branch = "master" + name = "github.com/gocql/gocql" + packages = [ + ".", + "internal/lru", + "internal/murmur", + "internal/streams" + ] + revision = "651d6b1f343c6e168e45d119dcfe8f71e5bafb32" + +[[projects]] + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys" + ] + revision = "1adfc126b41513cc696b209667c8656ea7aac67c" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "github.com/golang/glog" + packages = ["."] + revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" + +[[projects]] + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp" + ] + revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/golang/snappy" + packages = ["."] + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + branch = "master" + name = "github.com/google/gofuzz" + packages = ["."] + revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" + +[[projects]] + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions" + ] + revision = "7c663266750e7d82587642f65e60bc4083f1f84e" + version = "v0.2.0" + +[[projects]] + branch = "master" + name = "github.com/hailocab/go-hostpool" + packages = ["."] + revision = "e80d13ce29ede4452c43dea11e79b9bc8a15b478" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/errwrap" + packages = ["."] + revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-cleanhttp" + packages = ["."] + revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-hclog" + packages = ["."] + revision = "69ff559dc25f3b435631604f573a5fa1efdb6433" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-immutable-radix" + packages = ["."] + revision = "7f3cd4390caab3250a57f30efdb2a65dd7649ecf" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-memdb" + packages = ["."] + revision = "1289e7fffe71d8fd4d4d491ba9a412c50f244c44" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-multierror" + packages = ["."] + revision = "b7773ae218740a7be65057fc60b366a49b538a44" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-plugin" + packages = ["."] + revision = "e8d22c780116115ae5624720c9af0c97afe4f551" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-retryablehttp" + packages = ["."] + revision = "3b087ef2d313afe6c55b2f511d20db04ca767075" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-rootcerts" + packages = ["."] + revision = "6bb64b370b90e7ef1fa532be9e591a81c3493e00" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-sockaddr" + packages = ["."] + revision = "6d291a969b86c4b633730bfc6b8b9d64c3aafed9" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-uuid" + packages = ["."] + revision = "27454136f0364f2d44b1276c552d69105cf8c498" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-version" + packages = ["."] + revision = "23480c0665776210b5fbbac6eaaee40e3e6a96b7" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/golang-lru" + packages = [ + ".", + "simplelru" + ] + revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" + +[[projects]] + name = "github.com/hashicorp/vault" + packages = [ + "api", + "audit", + "builtin/credential/userpass", + "builtin/logical/database/dbplugin", + "command/config", + "command/token", + "helper/builtinplugins", + "helper/certutil", + "helper/cidrutil", + "helper/compressutil", + "helper/consts", + "helper/dbtxn", + "helper/errutil", + "helper/forwarding", + "helper/identity", + "helper/jsonutil", + "helper/kdf", + "helper/keysutil", + "helper/locksutil", + "helper/logging", + "helper/mfa", + "helper/mfa/duo", + "helper/mlock", + "helper/parseutil", + "helper/password", + "helper/pathmanager", + "helper/pgpkeys", + "helper/pluginutil", + "helper/policyutil", + "helper/reload", + "helper/salt", + "helper/storagepacker", + "helper/strutil", + "helper/tlsutil", + "helper/wrapping", + "helper/xor", + "http", + "logical", + "logical/framework", + "logical/plugin", + "logical/plugin/pb", + "physical", + "physical/inmem", + "plugins", + "plugins/database/cassandra", + "plugins/database/hana", + "plugins/database/mongodb", + "plugins/database/mssql", + "plugins/database/mysql", + "plugins/database/postgresql", + "plugins/helper/database/connutil", + "plugins/helper/database/credsutil", + "plugins/helper/database/dbutil", + "shamir", + "vault", + "version" + ] + revision = "3ee0802ed08cb7f4046c2151ec4671a076b76166" + version = "v0.10.2" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/yamux" + packages = ["."] + revision = "3520598351bb3500a49ae9563f5539666ae0a27c" + +[[projects]] + branch = "master" + name = "github.com/howeyc/gopass" + packages = ["."] + revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8" + +[[projects]] + name = "github.com/imdario/mergo" + packages = ["."] + revision = "9d5f1277e9a8ed20c3684bda8fde67c05628518c" + version = "v0.3.4" + +[[projects]] + branch = "master" + name = "github.com/jefferai/jsonx" + packages = ["."] + revision = "9cc31c3135eef39b8e72585f37efa92b6ca314d0" + +[[projects]] + name = "github.com/json-iterator/go" + packages = ["."] + revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4" + version = "1.1.3" + +[[projects]] + branch = "master" + name = "github.com/keybase/go-crypto" + packages = [ + "brainpool", + "cast5", + "curve25519", + "ed25519", + "ed25519/internal/edwards25519", + "openpgp", + "openpgp/armor", + "openpgp/ecdh", + "openpgp/elgamal", + "openpgp/errors", + "openpgp/packet", + "openpgp/s2k", + "rsa" + ] + revision = "d11a37f123888ff060339f516e392032dfcb98ff" + +[[projects]] + branch = "master" + name = "github.com/lib/pq" + packages = [ + ".", + "oid" + ] + revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8" + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/cli" + packages = ["."] + revision = "c48282d14eba4b0817ddef3f832ff8d13851aefd" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/copystructure" + packages = ["."] + revision = "d23ffcb85de31694d6ccaa23ccb4a03e55c1303f" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/go-testing-interface" + packages = ["."] + revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/reflectwalk" + packages = ["."] + revision = "63d60e9d0dbc60cf9164e6510889b0db6683d98c" + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + name = "github.com/modern-go/reflect2" + packages = ["."] + revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f" + version = "1.0.0" + +[[projects]] + name = "github.com/oklog/run" + packages = ["."] + revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39" + version = "v1.0.0" + +[[projects]] + name = "github.com/patrickmn/go-cache" + packages = ["."] + revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0" + version = "v2.1.0" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/posener/complete" + packages = [ + ".", + "cmd", + "cmd/install", + "match" + ] + revision = "98eb9847f27ba2008d380a32c98be474dea55bdf" + version = "v1.1.1" + +[[projects]] + name = "github.com/ryanuber/go-glob" + packages = ["."] + revision = "572520ed46dbddaed19ea3d9541bdd0494163693" + version = "v0.1" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "bcrypt", + "blowfish", + "chacha20poly1305", + "curve25519", + "ed25519", + "ed25519/internal/edwards25519", + "hkdf", + "internal/chacha20", + "md4", + "poly1305", + "ssh", + "ssh/terminal" + ] + revision = "b47b1587369238182299fe4dad77d05b8b461e06" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "trace" + ] + revision = "1e491301e022f8f977054da4c2d852decd59571f" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = [ + "cpu", + "unix", + "windows" + ] + revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + name = "golang.org/x/time" + packages = ["rate"] + revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" + +[[projects]] + name = "google.golang.org/appengine" + packages = ["cloudsql"] + revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + revision = "81158efcc9f219c511e4d3c0d61a0e6e49c01a24" + +[[projects]] + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "channelz", + "codes", + "connectivity", + "credentials", + "encoding", + "encoding/proto", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "health", + "health/grpc_health_v1", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport" + ] + revision = "22a49e732a507a11ac524e4ea5fd1a3e384b6fb8" + version = "v1.12.1" + +[[projects]] + name = "gopkg.in/inf.v0" + packages = ["."] + revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" + version = "v0.9.1" + +[[projects]] + branch = "v2" + name = "gopkg.in/mgo.v2" + packages = [ + ".", + "bson", + "internal/json", + "internal/sasl", + "internal/scram" + ] + revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[[projects]] + name = "k8s.io/api" + packages = [ + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1" + ] + revision = "8b7507fac302640dd5f1efbf9643199952cc58db" + +[[projects]] + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1beta1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/clock", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/net", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/wait", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/reflect" + ] + revision = "17529ec7eadb8de8e7dc835201455f53571f655a" + +[[projects]] + name = "k8s.io/client-go" + packages = [ + "discovery", + "kubernetes", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/core/v1", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/networking/v1", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1beta1", + "pkg/apis/clientauthentication", + "pkg/apis/clientauthentication/v1alpha1", + "pkg/version", + "plugin/pkg/client/auth/exec", + "rest", + "rest/watch", + "tools/auth", + "tools/clientcmd", + "tools/clientcmd/api", + "tools/clientcmd/api/latest", + "tools/clientcmd/api/v1", + "tools/metrics", + "tools/reference", + "transport", + "util/cert", + "util/flowcontrol", + "util/homedir", + "util/integer" + ] + revision = "23781f4d6632d88e869066eaebb743857aa1ef9b" + version = "v7.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "b4ba5e62e6879ebb95e2ba25c384af7cf1e198001fad1d36439482340af4abd3" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..3eab4a5 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,66 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/go-errors/errors" + version = "1.0.1" + +[[constraint]] + branch = "master" + name = "github.com/hashicorp/go-uuid" + +[[constraint]] + name = "github.com/hashicorp/vault" + version = "0.10.2" + +[[constraint]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.0" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.1" + +[[constraint]] + revision = "8b7507fac302640dd5f1efbf9643199952cc58db" + name = "k8s.io/api" + +[[constraint]] + revision = "17529ec7eadb8de8e7dc835201455f53571f655a" + name = "k8s.io/apimachinery" + +[[constraint]] + name = "k8s.io/client-go" + version = "7.0.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/README.md b/README.md index 78b40c5..1fc2080 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # vault-plugin-secrets-kubernetes A Vault secrets plugin for issuing and verifying Kubernetes webhook-mode authentication tokens. + +# TODO: Documentation of plugin and client. diff --git a/cmd/kubernetes-credential-provider-vault/main.go b/cmd/kubernetes-credential-provider-vault/main.go new file mode 100644 index 0000000..f02565b --- /dev/null +++ b/cmd/kubernetes-credential-provider-vault/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "github.com/paxos-bankchain/vault-plugin-secrets-kubernetes/pkg/client" + "os" +) + +func main() { + err := client.Run() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/vault-plugin-secrets-kubernetes/main.go b/cmd/vault-plugin-secrets-kubernetes/main.go new file mode 100644 index 0000000..2e4e4dc --- /dev/null +++ b/cmd/vault-plugin-secrets-kubernetes/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + "os" + + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical/plugin" + "github.com/paxos-bankchain/vault-plugin-secrets-kubernetes/pkg/backend" +) + +func main() { + apiClientMeta := &pluginutil.APIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := pluginutil.VaultPluginTLSProvider(tlsConfig) + + if err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }); err != nil { + log.Fatal(err) + } +} diff --git a/pkg/backend/backend.go b/pkg/backend/backend.go new file mode 100644 index 0000000..94ea501 --- /dev/null +++ b/pkg/backend/backend.go @@ -0,0 +1,63 @@ +package backend + +import ( + "context" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "sync" +) + +func Factory(ctx context.Context, c *logical.BackendConfig) (logical.Backend, error) { + b := Backend(c) + if err := b.Setup(ctx, c); err != nil { + return nil, err + } + return b, nil +} + +type backend struct { + *framework.Backend + + storage logical.Storage + salt *salt.Salt + // TODO: Do we need to support invalidation + salt replacement? + initSalt sync.Once +} + +func Backend(c *logical.BackendConfig) *backend { + b := &backend{ + storage: c.StorageView, + } + + b.Backend = &framework.Backend{ + BackendType: logical.TypeLogical, + PathsSpecial: &logical.Paths{ + Unauthenticated: []string{"tokenreviews"}, + }, + Paths: []*framework.Path{ + pathRoles(), + pathListRoles(), + pathToken(b), + pathReview(b), + }, + Secrets: []*framework.Secret{ + secretToken(b), + }, + // TODO: Invalidate, Clean. + } + + return b +} + +func (b *backend) Salt(ctx context.Context) (*salt.Salt, error) { + var err error + // Initialize the salt if needed. + b.initSalt.Do(func() { + b.salt, err = salt.NewSalt(ctx, b.storage, &salt.Config{ + HashFunc: salt.SHA256Hash, + Location: salt.DefaultLocation, + }) + }) + return b.salt, err +} diff --git a/pkg/backend/path_roles.go b/pkg/backend/path_roles.go new file mode 100644 index 0000000..7fa72d1 --- /dev/null +++ b/pkg/backend/path_roles.go @@ -0,0 +1,145 @@ +package backend + +import ( + "context" + "encoding/json" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "github.com/mitchellh/mapstructure" + "time" +) + +func pathListRoles() *framework.Path { + + handler := func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "roles/") + if err != nil { + return nil, err + } + return logical.ListResponse(entries), nil + } + + return &framework.Path{ + Pattern: "roles/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: handler, + }, + + HelpSynopsis: pathListRolesHelpSyn, + HelpDescription: pathListRolesHelpDesc, + } +} + +func pathRoles() *framework.Path { + return &framework.Path{ + Pattern: "roles/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeString, + Description: "Name of the role", + }, + "groups": { + Type: framework.TypeCommaStringSlice, + Description: "Names of the Kubernetes groups users authenticated via this role should be part of", + }, + "extra": { + Type: framework.TypeMap, + Description: "Extra fields to include in the UserInfo object returned to Kubernetes: A map of strings => list of strings", + }, + "default_ttl": { + Type: framework.TypeDurationSecond, + Description: "Default ttl for role.", + }, + + "max_ttl": { + Type: framework.TypeDurationSecond, + Description: "Maximum time a credential is valid for", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.DeleteOperation: pathRolesDelete, + logical.ReadOperation: pathRolesRead, + logical.UpdateOperation: pathRolesWrite, + }, + + HelpSynopsis: pathRolesHelpSyn, + HelpDescription: pathRolesHelpDesc, + } +} + +type Extra map[string][]string + +type roleEntry struct { + Groups []string `json:"groups"` + Extra Extra `json:"extra"` + DefaultTTL time.Duration `json:"default_ttl"` + MaxTTL time.Duration `json:"max_ttl"` +} + +func pathRolesDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "roles/"+d.Get("name").(string)) + if err != nil { + return nil, err + } + + return nil, nil +} + +func getRole(ctx context.Context, s logical.Storage, name string) (*roleEntry, error) { + storageEntry, err := s.Get(ctx, "roles/"+name) + if storageEntry == nil || err != nil { + return nil, err + } + var role roleEntry + err = json.Unmarshal(storageEntry.Value, &role) + return &role, err +} + +func pathRolesRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + role, err := getRole(ctx, req.Storage, d.Get("name").(string)) + if role == nil || err != nil { + return nil, err + } + return &logical.Response{ + Data: map[string]interface{}{ + "groups": role.Groups, + "extra": role.Extra, + "default_ttl": role.DefaultTTL.Seconds(), + "max_ttl": role.MaxTTL.Seconds(), + }, + }, nil +} + +func pathRolesWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + e := make(Extra) + err := mapstructure.Decode(d.Get("extra"), &e) + if err != nil { + return logical.ErrorResponse("extra must be a map: string -> list of strings"), nil + } + role := &roleEntry{ + Groups: d.Get("groups").([]string), + Extra: e, + DefaultTTL: time.Duration(d.Get("default_ttl").(int)) * time.Second, + MaxTTL: time.Duration(d.Get("max_ttl").(int)) * time.Second, + } + storageEntry, err := logical.StorageEntryJSON( + "roles/"+d.Get("name").(string), role) + if err != nil { + return nil, err + } + return nil, req.Storage.Put(ctx, storageEntry) +} + +const pathListRolesHelpSyn = `List the existing roles in this backend.` + +const pathListRolesHelpDesc = `Roles will be listed by the role name.` + +const pathRolesHelpSyn = ` +Read, write and update roles controlling Kubernetes group membership and user extra fields. +` + +const pathRolesHelpDesc = ` +TODO +` diff --git a/pkg/backend/path_token.go b/pkg/backend/path_token.go new file mode 100644 index 0000000..fb9c19e --- /dev/null +++ b/pkg/backend/path_token.go @@ -0,0 +1,134 @@ +package backend + +import ( + "context" + "fmt" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "time" +) + +func pathToken(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "token/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeString, + Description: "Name of the role", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathTokenRead, + }, + + HelpSynopsis: pathTokenReadHelpSyn, + HelpDescription: pathTokenReadHelpDesc, + } +} + +type tokenEntry struct { + Role string `json:"role"` + ExpirationTime time.Time `json:"expiration_time"` + Username string `json:"username"` + UID string `json:"uid"` + Groups []string `json:"groups"` + Extra Extra `json:"extra"` +} + +func (b *backend) pathTokenRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + roleName := d.Get("name").(string) + role, err := getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + if role == nil { + return logical.ErrorResponse(fmt.Sprintf("Unknown role: %s", roleName)), nil + } + + var username, uid string + if req.EntityID != "" { + // Use available entity information if we can. + entity, err := b.System().EntityInfo(req.EntityID) + if err != nil { + return nil, err + } + uid = entity.ID + if len(entity.Aliases) > 0 { + // Take the first alias available for the username. + alias := entity.Aliases[0] + username = fmt.Sprintf("%s_%s", alias.Name, alias.MountAccessor) + } else { + // If no aliases, use the display name, role name, and entity ID. + username = fmt.Sprintf("v_%s_%s_%s", req.DisplayName, roleName, uid) + } + } else { + // If no entity, use the display name, role name, and a UUID. + uid, err = uuid.GenerateUUID() + if err != nil { + return nil, err + } + username = fmt.Sprintf("v_%s_%s_%s", req.DisplayName, roleName, uid) + } + + secret, err := uuid.GenerateUUID() + if err != nil { + return nil, err + } + + // TODO: Explicit TTLs in requests? + ttl, _, err := framework.CalculateTTL(b.System(), 0, role.DefaultTTL, 0, role.MaxTTL, 0, time.Time{}) + if err != nil { + return nil, err + } + expiration := time.Now().Add(ttl + tokenExpireBuffer) + + entry := &tokenEntry{ + Role: roleName, + ExpirationTime: expiration, + Username: username, + UID: uid, + Groups: role.Groups, + Extra: role.Extra, + } + tokenPath, err := b.tokenPath(ctx, secret) + if err != nil { + return nil, err + } + storageEntry, err := logical.StorageEntryJSON(tokenPath, entry) + if err := req.Storage.Put(ctx, storageEntry); err != nil { + return nil, err + } + + token := secret + resp := b.Secret(SecretTokenType).Response(map[string]interface{}{ + "token": token, + }, map[string]interface{}{ + "token_path": tokenPath, + "role": roleName, + }) + resp.Secret.TTL = role.DefaultTTL + resp.Secret.MaxTTL = role.MaxTTL + return resp, nil +} + +func (b *backend) tokenPath(ctx context.Context, secret string) (string, error) { + s, err := b.Salt(ctx) + if err != nil { + return "", err + } + tokenIndex := s.SaltID(secret) + return fmt.Sprintf("token/%s", tokenIndex), nil +} + +const pathTokenReadHelpSyn = ` +Request Kubernetes bearer token for a role. +` + +const pathTokenReadHelpDesc = ` +This path creates a Kubernetes bearer token for a certain role. The token will +expire at the end of its lease. Note that Kubernetes caches token validity for +a configurable amount of time (apiserver --authentication-token-webhook-cache-ttl, +default 2 minutes). +` diff --git a/pkg/backend/path_tokenreviews.go b/pkg/backend/path_tokenreviews.go new file mode 100644 index 0000000..2a53d6d --- /dev/null +++ b/pkg/backend/path_tokenreviews.go @@ -0,0 +1,132 @@ +package backend + +import ( + "context" + "encoding/json" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "net/http" + "time" +) + +func pathReview(b *backend) *framework.Path { + + return &framework.Path{ + Pattern: "tokenreviews", + HelpSynopsis: "tokenreviews should be called by the Kubernetes webhook token authenticator to authenticate tokens", + Fields: map[string]*framework.FieldSchema{ + "apiVersion": { + Type: framework.TypeString, + Description: "Kubernetes API version string", + }, + "kind": { + Type: framework.TypeString, + Description: "Kubernetes object kind (must be TokenReview)", + }, + "spec": { + Type: framework.TypeMap, + Description: "Kubernetes TokenReview object spec", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathTokenReviewsUpdate, + }, + } +} + +func (b *backend) pathTokenReviewsUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + spec := d.Get("spec").(map[string]interface{}) + tokenRaw, ok := spec["token"] + if !ok { + return reviewResponseErr( + http.StatusBadRequest, "no token in TokenReview request spec") + } + token, ok := tokenRaw.(string) + if !ok { + return reviewResponseErr( + http.StatusBadRequest, "illegal non-string token in TokenReview request spec") + } + secret := token + tokenPath, err := b.tokenPath(ctx, secret) + if err != nil { + return nil, err + } + + rawEntry, err := req.Storage.Get(ctx, tokenPath) + if err != nil { + return nil, err + } + if rawEntry == nil { + return reviewResponseDeny("token not found") + } + var entry tokenEntry + if err := json.Unmarshal(rawEntry.Value, &entry); err != nil { + return nil, err + } + if time.Now().After(entry.ExpirationTime) { + return reviewResponseDeny("token expired") + } + // Allow - this is a valid, non-expired token. + // CREATED matches k8s status code for non-error reviews. + return reviewResponse(http.StatusCreated, map[string]interface{}{ + "authenticated": true, + "user": map[string]interface{}{ + "username": entry.Username, + "uid": entry.UID, + "groups": entry.Groups, + "extra": entry.Extra, + }, + }, auditData{"authenticated": true}) +} + +// In order to have more helpful audit logs on token reviews, we add extra data +// to our responses alongside the raw data sent to the client. +type auditData map[string]interface{} + +// reviewResponseErr packages an error response for Kubernetes. +func reviewResponseErr(code int, err string) (*logical.Response, error) { + return reviewResponse(code, map[string]interface{}{ + "authenticated": false, + "error": err, + }, auditData{ + "authenticated": false, + "error": err, + }) +} + +// reviewResponseDeny packages a deny response for Kubernetes. +func reviewResponseDeny(reason string) (*logical.Response, error) { + // Deny. HTTP code is OK, because we're not actually denying the review request - + // just saying that the apiserver should deny the client. + return reviewResponse(http.StatusCreated, map[string]interface{}{ + "authenticated": false, + }, auditData{ + "authenticated": false, + "deny_reason": reason, + }) +} + +// reviewResponse packages responses as expected by Kubernetes (including errors). +func reviewResponse(code int, status interface{}, auditData auditData) (*logical.Response, error) { + response := map[string]interface{}{ + // TODO: Send back v1beta1 if that was in the request? + "apiVersion": "authentication.k8s.io/v1", + "kind": "TokenReview", + "status": status, + } + rawResponse, err := json.Marshal(response) + if err != nil { + return nil, err + } + data := map[string]interface{}{ + logical.HTTPContentType: "application/json", + logical.HTTPStatusCode: code, + logical.HTTPRawBody: rawResponse, + } + for k, v := range auditData { + data[k] = v + } + return &logical.Response{ + Data: data, + }, nil +} diff --git a/pkg/backend/secret_token.go b/pkg/backend/secret_token.go new file mode 100644 index 0000000..ba13faa --- /dev/null +++ b/pkg/backend/secret_token.go @@ -0,0 +1,106 @@ +package backend + +import ( + "context" + "fmt" + + "encoding/json" + "github.com/go-errors/errors" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "time" +) + +const ( + // SecretTokenType is the secret type for Kubernetes bearer tokens issued by this backend. + SecretTokenType = "kubernetes-token" + // We add a small buffer to token expirations to ensure they do not expire before their + // associated leases. + tokenExpireBuffer = 1 * time.Second +) + +func secretToken(b *backend) *framework.Secret { + return &framework.Secret{ + Type: SecretTokenType, + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Bearer token for Kubernetes webhook authentication", + }, + }, + + Renew: b.secretTokenRenew, + Revoke: b.secretTokenRevoke, + } +} + +func (b *backend) secretTokenRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // Get the lease information + roleRaw, ok := req.Secret.InternalData["role"] + if !ok { + return nil, errors.New("secret is missing role internal data") + } + roleName, ok := roleRaw.(string) + if !ok { + return nil, errors.New("error converting role internal data to string") + } + tokenPathRaw, ok := req.Secret.InternalData["token_path"] + if !ok { + return nil, errors.New("secret is missing token_path internal data") + } + tokenPath, ok := tokenPathRaw.(string) + if !ok { + return nil, errors.New("error converting token_path internal data to string") + } + + // Determine the new TTL. + role, err := getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + if role == nil { + return nil, errors.New("role not found: " + roleName) + } + ttl, _, err := framework.CalculateTTL(b.System(), req.Secret.Increment, role.DefaultTTL, 0, role.MaxTTL, 0, req.Secret.IssueTime) + if err != nil { + return nil, err + } + // TODO: Check if ttl > 0? + + // Read the token storage entry, update its ttl, and write it back. + storageEntry, err := req.Storage.Get(ctx, tokenPath) + if err != nil { + return nil, err + } + if storageEntry == nil { + return nil, errors.New("token not found") + } + var token tokenEntry + err = json.Unmarshal(storageEntry.Value, &token) + if err != nil { + return nil, err + } + token.ExpirationTime = time.Now().Add(ttl + tokenExpireBuffer) + storageEntry, err = logical.StorageEntryJSON(tokenPath, token) + if err := req.Storage.Put(ctx, storageEntry); err != nil { + return nil, err + } + + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = ttl + resp.Secret.MaxTTL = role.MaxTTL + return resp, nil +} + +func (b *backend) secretTokenRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // Get the lease information + tokenPathRaw, ok := req.Secret.InternalData["token_path"] + if !ok { + return nil, fmt.Errorf("secret is missing token_path internal data") + } + tokenPath, ok := tokenPathRaw.(string) + if !ok { + return nil, fmt.Errorf("error converting token_path internal data to string") + } + return nil, req.Storage.Delete(ctx, tokenPath) +} diff --git a/pkg/client/cache.go b/pkg/client/cache.go new file mode 100644 index 0000000..ab5dfb6 --- /dev/null +++ b/pkg/client/cache.go @@ -0,0 +1,102 @@ +package client + +import ( + "encoding/json" + "fmt" + "io" + "k8s.io/client-go/tools/clientcmd" + "os" + "path" + "time" +) + +var ( + defaultCacheFile = path.Join(clientcmd.RecommendedConfigDir, "vault-plugin-tokens") +) + +// tokenCache is a simple JSON-file-backed cache of Kubernetes credentials. +type tokenCache struct { + entries []*cacheEntry + file string +} + +type cacheEntry struct { + // The "key" fields. + Addr string `json:"addr"` + Path string `json:"path"` + Role string `json:"role"` + + Token string `json:"token"` + Expiration time.Time `json:"expiration"` + Lease string `json:"lease"` + Renewable bool `json:"renewable"` +} + +func loadCache(file string) (*tokenCache, error) { + if file == "" { + file = defaultCacheFile + } + c := &tokenCache{file: file} + r, err := os.Open(file) + if err != nil { + if os.IsNotExist(err) { + return c, nil + } + return nil, err + } + defer r.Close() + + err = json.NewDecoder(r).Decode(&c.entries) + // Allow EOF errors so /dev/null is a valid cache file. + if err != nil && err != io.EOF { + return nil, err + } + return c, nil +} + +func (_ tokenCache) keysEqual(a, b *cacheEntry) bool { + return a.Addr == b.Addr && a.Path == b.Path && a.Role == b.Role +} + +func (c *tokenCache) Get(addr, path, role string) *cacheEntry { + key := &cacheEntry{Addr: addr, Path: path, Role: role} + for _, e := range c.entries { + if c.keysEqual(key, e) { + return e + } + } + return nil +} + +func (c *tokenCache) Put(u *cacheEntry) { + for i, e := range c.entries { + if c.keysEqual(u, e) { + c.entries[i] = u + return + } + } + c.entries = append(c.entries, u) +} + +func (c *tokenCache) Delete(u *cacheEntry) { + for i, e := range c.entries { + if c.keysEqual(u, e) { + c.entries = append(c.entries[:i], c.entries[i+1:]...) + return + } + } +} + +func (c *tokenCache) WriteOut() error { + w, err := os.OpenFile(c.file, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.FileMode(0600)) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("parent does not exist for %s file %s", cacheEnv, c.file) + } + return err + } + defer w.Close() + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + return enc.Encode(&c.entries) +} diff --git a/pkg/client/cache_test.go b/pkg/client/cache_test.go new file mode 100644 index 0000000..9b1560b --- /dev/null +++ b/pkg/client/cache_test.go @@ -0,0 +1,79 @@ +package client + +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "path" + "testing" + "time" +) + +func TestCache(t *testing.T) { + dir, err := ioutil.TempDir("", "") + defer os.RemoveAll(dir) + require.NoError(t, err) + file := path.Join(dir, "token-cache") + c, err := loadCache(file) + require.NoError(t, err) + ret := c.Get("http://localhost:8200", "kubernetes", "role1") + assert.Nil(t, ret, "no entry should be found initially") + require.NoError(t, err) + e := &cacheEntry{ + Addr: "http://localhost:8200", + Path: "kubernetes", + Role: "role1", + Token: "mytoken", + Lease: "mylease", + // Round(0) strips the monotonic clock reading (so we can compare). + // Manually specified location ensures comparisons with == work. + Expiration: time.Now().Add(5 * time.Minute).Round(0).In(time.UTC), + } + c.Put(e) + ret = c.Get("http://localhost:8200", "kubernetes", "role1") + assert.Equal(t, e, ret, "entry should be found after put") + + err = c.WriteOut() + assert.NoError(t, err, "write out should succeed") + + c, err = loadCache(file) + require.NoError(t, err) + ret = c.Get("http://localhost:8200", "kubernetes", "role1") + assert.Equal(t, e, ret, "entry should be found after put and reload") + + c.Delete(e) + ret = c.Get("http://localhost:8200", "kubernetes", "role1") + assert.Nil(t, ret, "no entry should be found after delete") + + err = c.WriteOut() + assert.NoError(t, err, "write out should succeed") + + c, err = loadCache(file) + require.NoError(t, err) + ret = c.Get("http://localhost:8200", "kubernetes", "role1") + assert.Nil(t, ret, "no entry should be found after delete and reload") +} + +func TestCache_DevNull(t *testing.T) { + c, err := loadCache(os.DevNull) + require.NoError(t, err, "a /dev/null configured cache should load") + assert.Empty(t, c.entries, "a /dev/null configured cache should be empty") + e := &cacheEntry{ + Addr: "http://localhost:8200", + Path: "kubernetes", + Role: "role1", + Token: "mytoken", + Lease: "mylease", + // Round(0) strips the monotonic clock reading (so we can compare). + Expiration: time.Now().Add(5 * time.Minute).Round(0), + } + c.Put(e) + + err = c.WriteOut() + assert.NoError(t, err, "write out to /dev/null should succeed") + + c, err = loadCache(os.DevNull) + require.NoError(t, err, "a /dev/null configured cache should load") + assert.Empty(t, c.entries, "a /dev/null configured cache should be empty") +} diff --git a/pkg/client/client.go b/pkg/client/client.go new file mode 100644 index 0000000..b87c462 --- /dev/null +++ b/pkg/client/client.go @@ -0,0 +1,199 @@ +// Package client implements a Kubernetes client-go auth plugin using Vault. +package client + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/command/config" + "github.com/pkg/errors" + "io" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientauthv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" + "net/http" + "os" + "time" +) + +const ( + reqEnv = "KUBERNETES_EXEC_INFO" + pathEnv = "KUBE_VAULT_PATH" + roleEnv = "KUBE_VAULT_ROLE" + cacheEnv = "KUBE_VAULT_CACHE" + pathDefault = "kubernetes" + expireBuffer = 1 * time.Second + v1alpha1 = "client.authentication.k8s.io/v1alpha1" +) + +// env holds all the inputs and outputs of the Kubernetes client-go exec auth plugin. +type env struct { + Getenv func(string) string + Stderr io.Writer + Stdout io.Writer + Stdin io.Reader + // For testing, a manually-specified Vault client. + vaultClient *api.Client +} + +// Run runs the auth plugin, using the process environment for input and output. +func Run() error { + return runEnv(env{ + Getenv: os.Getenv, + Stderr: os.Stderr, + Stdout: os.Stdout, + Stdin: os.Stdin, + }) +} + +// runEnv runs the auth plugin usnig the configured inputs and outputs (useful for testing). +func runEnv(e env) error { + var req clientauthv1.ExecCredential + rawReq := e.Getenv(reqEnv) + err := json.Unmarshal([]byte(rawReq), &req) + if err != nil { + return errors.Wrap(err, "invalid exec credential input") + } + if req.APIVersion != v1alpha1 { + return fmt.Errorf("unknown exec credential API version: %s", req.APIVersion) + } + + path := e.Getenv(pathEnv) + if path == "" { + if req.Spec.Interactive { + fmt.Fprintf(e.Stderr, "%s not set - prompting for Kubernetes backend mount path\n", pathEnv) + fmt.Fprintf(e.Stderr, "path (empty for '%s'): ", pathDefault) + fmt.Fscanln(e.Stdin, &path) + } + if path == "" { + path = pathDefault + } + } + + role := e.Getenv(roleEnv) + if role == "" { + if req.Spec.Interactive { + fmt.Fprintf(e.Stderr, "%s not set - prompting for Kubernetes backend role name\n", roleEnv) + fmt.Fprint(e.Stderr, "role: ") + fmt.Fscanln(e.Stdin, &role) + } + if role == "" { + return fmt.Errorf("role name required - set %s or enter interactively", roleEnv) + } + } + + client := e.vaultClient + if client == nil { + if client, err = createClient(); err != nil { + return errors.Wrap(err, "failed to create vault client") + } + } + + cache, err := loadCache(e.Getenv(cacheEnv)) + if err != nil { + return errors.Wrap(err, "error loading token cache") + } + // TODO: Support lease renewals. + entry := cache.Get(client.Address(), path, role) + if req.Spec.Response != nil && req.Spec.Response.Code == http.StatusUnauthorized { + // The previous returned credential was unauthorized. Clear it from the cache. + cache.Delete(entry) + if err := cache.WriteOut(); err != nil { + return err + } + entry = nil + } + if entry != nil && time.Now().Before(entry.Expiration) { + return writeResponse(e.Stdout, entry) + } + entry, err = fetchToken(client, path, role) + if err != nil { + return err + } + cache.Put(entry) + if err := cache.WriteOut(); err != nil { + return err + } + return writeResponse(e.Stdout, entry) +} + +func fetchToken(client *api.Client, path, role string) (*cacheEntry, error) { + if client.Token() == "" { + return nil, errors.New("no Vault token found - do you need to `vault login`?") + } + tokenPath := fmt.Sprintf("%s/token/%s", path, role) + secret, err := client.Logical().Read(tokenPath) + if err != nil { + return nil, errors.Wrap(err, "failed to get Kubernetes token from Vault") + } + if secret == nil { + return nil, fmt.Errorf( + "no Vault value at %s - the Kubernetes backend may not be mounted at %s", + tokenPath, path) + } + + token, ok := secret.Data["token"].(string) + if !ok { + return nil, errors.New("could not parse Kubernetes token string from Vault response") + } + expiration := time.Now().Add(time.Duration(secret.LeaseDuration) * time.Second).Add(-expireBuffer) + return &cacheEntry{ + Addr: client.Address(), + Path: path, + Role: role, + Token: token, + Expiration: expiration, + Lease: secret.LeaseID, + Renewable: secret.Renewable, + }, nil +} + +func writeResponse(w io.Writer, entry *cacheEntry) error { + resp := &clientauthv1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + Kind: "ExecCredential", + APIVersion: v1alpha1, + }, + Status: &clientauthv1.ExecCredentialStatus{ + ExpirationTimestamp: &metav1.Time{Time: entry.Expiration}, + Token: entry.Token, + }, + } + enc := json.NewEncoder(w) + if err := enc.Encode(resp); err != nil { + return errors.Wrap(err, "error writing response") + } + return nil +} + +// TODO: Replace this: https://github.com/hashicorp/vault/issues/4688. +func createClient() (*api.Client, error) { + cfg := api.DefaultConfig() + if err := cfg.ReadEnvironment(); err != nil { + return nil, errors.Wrap(err, "failed to read environment") + } + // Build the client + client, err := api.NewClient(cfg) + if err != nil { + return nil, errors.Wrap(err, "failed to create client") + } + // Get the token if it came in from the environment + token := client.Token() + + // If we don't have a token, check the token helper + if token == "" { + helper, err := config.DefaultTokenHelper() + if err != nil { + return nil, errors.Wrap(err, "failed to get token helper") + } + token, err = helper.Get() + if err != nil { + return nil, errors.Wrap(err, "failed to get token from token helper") + } + } + + // Set the token + if token != "" { + client.SetToken(token) + } + return client, nil +} diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go new file mode 100644 index 0000000..044f7b7 --- /dev/null +++ b/pkg/client/client_test.go @@ -0,0 +1,298 @@ +package client + +import ( + "bytes" + "encoding/json" + "github.com/davecgh/go-spew/spew" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + vaulthttp "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" + "github.com/paxos-bankchain/vault-plugin-secrets-kubernetes/pkg/backend" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "io/ioutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientauthv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" + "net/http" + "os" + "path" + "strings" + "testing" + "time" +) + +func envFunc(m map[string]string) func(string) string { + return func(k string) string { + return m[k] + } +} + +const ( + noneToken = "magical string indicating test case should strip Vault token" +) + +func getCluster(t *testing.T) *vault.TestCluster { + coreConfig := &vault.CoreConfig{ + LogicalBackends: map[string]logical.Factory{ + "kubernetes": backend.Factory, + }, + // Quiet down the Vault cluster logs. + Logger: hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + }), + } + cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ + HandlerFunc: vaulthttp.Handler, + }) + cluster.Start() + client := cluster.Cores[0].Client + err := client.Sys().Mount("kubernetes", &api.MountInput{ + Type: "kubernetes", + Config: api.MountConfigInput{ + DefaultLeaseTTL: "16h", + MaxLeaseTTL: "32h", + }, + }) + require.NoError(t, err) + return cluster +} + +type testCase struct { + // path is the value of KUBE_VAULT_PATH during execution. + path string + // role is the value of KUBE_VAULT_ROLE during execution. + role string + // interactive is whether this is an interactive execution. + interactive bool + // stdin is the line-by-line input for interactive execution. + stdin []string + // cache is the contents of the cache before execution. + cache []*cacheEntry + // vaultToken overrides the token used by the provided Vault client. + vaultToken string + // afterDenial indicates this execution follows a denial of earlier credentials. + afterDenial bool + // errLike is a regexp indicating execution should fail with a matching error. + errLike string +} + +func (c testCase) run(t *testing.T, vaultClient *api.Client) { + cacheDir, err := ioutil.TempDir("", "") + defer os.RemoveAll(cacheDir) + cacheFile := path.Join(cacheDir, "token-cache") + + // Pre-load the cache with any specified state. + if len(c.cache) != 0 { + assert.NoError(t, (&tokenCache{file: cacheFile, entries: c.cache}).WriteOut()) + } + + if c.vaultToken != "" { + vaultClient, err = vaultClient.Clone() + require.NoError(t, err) + if c.vaultToken == noneToken { + vaultClient.ClearToken() + } else { + vaultClient.SetToken(c.vaultToken) + } + } + + req := &clientauthv1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + Kind: "ExecCredential", + APIVersion: v1alpha1, + }, + Spec: clientauthv1.ExecCredentialSpec{ + Interactive: c.interactive, + }, + } + if c.afterDenial { + req.Spec.Response = &clientauthv1.Response{ + Code: http.StatusUnauthorized, + } + } + reqBytes, err := json.Marshal(req) + require.NoError(t, err) + + e := env{ + Getenv: envFunc(map[string]string{ + pathEnv: c.path, + roleEnv: c.role, + reqEnv: string(reqBytes), + cacheEnv: cacheFile, + }), + Stderr: &bytes.Buffer{}, + Stdout: &bytes.Buffer{}, + Stdin: strings.NewReader(strings.Join(c.stdin, "\n")), + vaultClient: vaultClient, + } + err = runEnv(e) + if c.errLike != "" { + if assert.Error(t, err) { + assert.Regexp(t, c.errLike, err.Error()) + } + _, err := loadCache(cacheFile) + require.NoError(t, err, "errors should not corrupt token cache") + return + } + require.NoError(t, err) + var resp clientauthv1.ExecCredential + err = json.Unmarshal(e.Stdout.(*bytes.Buffer).Bytes(), &resp) + assert.NoError(t, err, "plugin response should parse") + if assert.NotNil(t, resp.TypeMeta, "plugin response should have meta") { + assert.Equal(t, "ExecCredential", resp.TypeMeta.Kind, "plugin response should have kind") + assert.Equal(t, v1alpha1, resp.TypeMeta.APIVersion, "plugin response should have API version") + } + if assert.NotNil(t, resp.Status, "plugin response should have status") { + assert.NotEmpty(t, resp.Status.Token, "plugin response should have token") + assert.NotNil(t, resp.Status.ExpirationTimestamp, "plugin response should have expiration") + c.assertMatchingEntry(t, resp.Status, cacheFile, vaultClient.Address()) + } +} + +func (c testCase) assertMatchingEntry(t *testing.T, respStatus *clientauthv1.ExecCredentialStatus, cacheFile, addr string) { + cache, err := loadCache(cacheFile) + if assert.NoError(t, err, "cache should not be corrupted") { + for _, e := range cache.entries { + if e.Addr == addr && + (e.Path == c.path || c.path == "") && + (e.Role == c.role || c.role == "") && + e.Token == respStatus.Token && + e.Expiration.Truncate(time.Second).Equal(respStatus.ExpirationTimestamp.Time) { + return + } + } + entries := spew.Sdump(cache.entries) + expected := spew.Sdump(&cacheEntry{ + Addr: addr, + Path: c.path, + Role: c.role, + Token: respStatus.Token, + Expiration: respStatus.ExpirationTimestamp.Time}) + assert.Fail(t, "no matching entry found", + "expected %s to contain entry matching %s", + entries, expected) + } +} + +func TestRun(t *testing.T) { + cluster := getCluster(t) + defer cluster.Cleanup() + + vaultClient := cluster.Cores[0].Client + _, err := vaultClient.Logical().Write( + "kubernetes/roles/role1", map[string]interface{}{}) + require.NoError(t, err) + + cases := map[string]testCase{ + "ErrNoRole": { + errLike: "role name required", + }, + "ErrNoRoleInteractive": { + interactive: true, + stdin: []string{"", ""}, + errLike: "role name required", + }, + "ErrBadPath": { + path: "notmounted", + role: "role1", + errLike: "no Vault value at notmounted/token/role1", + }, + "ErrBadRole": { + role: "notarole", + errLike: "failed to get Kubernetes token", + }, + "ErrNoToken": { + role: "role1", + errLike: "no Vault token found", + vaultToken: noneToken, + }, + "ErrForbidden": { + role: "role1", + errLike: "failed to get Kubernetes token", + vaultToken: "invalid-token", + }, + "NonInteractive": { + path: "kubernetes", + role: "role1", + }, + "NonInteractive_PathDefault": { + role: "role1", + }, + "Interactive_PathEnvRoleEnv": { + interactive: true, + path: "kubernetes", + role: "role1", + }, + "Interactive_PathEnvRoleInteractive": { + interactive: true, + path: "kubernetes", + stdin: []string{"role1"}, + }, + "Interactive_PathDefaultRoleInteractive": { + interactive: true, + stdin: []string{"", "role1"}, + }, + "Cached": { + role: "role1", + vaultToken: noneToken, + cache: []*cacheEntry{ + { + Addr: vaultClient.Address(), + Path: "kubernetes", + Role: "role1", + Token: "kube-auth-token", + Expiration: time.Now().Add(5 * time.Minute).Truncate(time.Second), + }, + }, + }, + "ErrCachedExpired": { + role: "role1", + vaultToken: noneToken, + cache: []*cacheEntry{ + { + Addr: vaultClient.Address(), + Path: "kubernetes", + Role: "role1", + Token: "kube-auth-token", + Expiration: time.Now().Add(-5 * time.Minute).Truncate(time.Second), + }, + }, + errLike: "no Vault token found", + }, + "CachedExpired": { + role: "role1", + cache: []*cacheEntry{ + { + Addr: vaultClient.Address(), + Path: "kubernetes", + Role: "role1", + Token: "kube-auth-token", + Expiration: time.Now().Add(-5 * time.Minute).Truncate(time.Second), + }, + }, + }, + "ErrCachedRevoked": { + role: "role1", + vaultToken: "forbidden-token", + afterDenial: true, + cache: []*cacheEntry{ + { + Addr: vaultClient.Address(), + Path: "kubernetes", + Role: "role1", + Token: "kube-auth-token", + Expiration: time.Now().Add(5 * time.Minute).Truncate(time.Second), + }, + }, + errLike: "failed to get Kubernetes token", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + c.run(t, vaultClient) + }) + } +} diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go new file mode 100644 index 0000000..b74afe1 --- /dev/null +++ b/pkg/integration/integration_test.go @@ -0,0 +1,538 @@ +// Package integration_test does end-to-end testing of Kubernetes auth flows. +package integration_test + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/json" + "fmt" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/credential/userpass" + vaulthttp "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" + "github.com/mitchellh/mapstructure" + "github.com/paxos-bankchain/vault-plugin-secrets-kubernetes/pkg/backend" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "io/ioutil" + authv1 "k8s.io/api/authentication/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + kubeApi "k8s.io/client-go/tools/clientcmd/api" + "net" + "net/http" + "net/http/httputil" + "net/url" + "os" + "path" + "path/filepath" + "testing" + "time" +) + +const ( + kubeAddrEnv = "KUBE_ADDR" + kubeContextEnv = "KUBE_CONTEXT" + kubeAuthVersionEnv = "KUBE_AUTH_VERSION" + kubeTargetPortEnv = "KUBE_TARGET_PORT" +) + +var ( + insecureTransport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } +) + +func apiVersion(t *testing.T) string { + v := os.Getenv(kubeAuthVersionEnv) + switch v { + case "", "v1": + return "v1" + case "v1beta1": + return "v1beta1" + default: + t.Fatalf( + "Unrecognized Kubernetes authentication.k8s.io API version in %s: %s", + kubeAuthVersionEnv, v) + panic("unreachable") + } +} + +// reviewer sends token review requests either to Vault or to Kubernetes. +// We make use of the "tokenreviews" endpoint exposed by Kubernetes to perform +// end-to-end checks of authentication decisions using vault-issued webhook tokens +// and the user information passed to Kubernetes on successful authentication. +// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#create-597 +// Conveniently, this endpoint accepts the same input as the "tokenreviews" +// endpoint we must expose from Vault, meaning we can play the same requests +// against both for verification. +type reviewer interface { + assertAllowed(t *testing.T, token string, expect expectedAllow) *authv1.UserInfo + assertDenied(t *testing.T, token string) + awaitDenied(t *testing.T, token string, expectedTime time.Time) +} + +// reviewToken posts the given token for review to the given Vault or Kubernetes URL. +func reviewToken(t *testing.T, url, token, bearer string) (int, authv1.TokenReviewStatus, error) { + buf, err := json.Marshal( + &authv1.TokenReview{ + TypeMeta: metav1.TypeMeta{ + Kind: "TokenReview", + APIVersion: "authentication.k8s.io/" + apiVersion(t), + }, + Spec: authv1.TokenReviewSpec{ + Token: token, + }, + }) + require.NoError(t, err, "err encoding json") + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(buf)) + require.NoError(t, err, "err creating http request") + req.Header.Add("Content-Type", "application/json") + if bearer != "" { + req.Header.Add("Authorization", "Bearer "+bearer) + } + // For test simplicity, we don't enforce TLS checks. + client := &http.Client{Transport: insecureTransport} + resp, err := client.Do(req) + + require.NoError(t, err, "err making http request") + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + var respReview authv1.TokenReview + decodeErr := json.Unmarshal(body, &respReview) + return resp.StatusCode, respReview.Status, decodeErr +} + +func awaitDenied(t *testing.T, isDenied func() bool, expectedTime time.Time, tolerance time.Duration) { + stopTime := expectedTime.Add(tolerance) + for { + now := time.Now() + if isDenied() { + if now.Before(expectedTime) { + t.Errorf("token denied %s before expected time %s", expectedTime.Sub(now), expectedTime) + } else { + t.Logf("token denied %s after expected time %s (tolerance %s)", now.Sub(expectedTime), expectedTime, tolerance) + } + return + } + if time.Now().After(stopTime) { + t.Errorf("token was not denied at time %s (tolerance %s)", expectedTime, tolerance) + return + } + time.Sleep(1 * time.Second) + } +} + +// kubeReviewer posts TokenReview requests to Kubernetes. +type kubeReviewer struct{} + +func (r kubeReviewer) url(t *testing.T) string { + kubeAddr := os.Getenv(kubeAddrEnv) + if kubeAddr == "" { + t.Skipf("%s must be set for integration tests", kubeAddrEnv) + } + return fmt.Sprintf("%s/apis/authentication.k8s.io/%s/tokenreviews", + kubeAddr, apiVersion(t)) +} + +func (r kubeReviewer) assertAllowed(t *testing.T, token string, expect expectedAllow) *authv1.UserInfo { + // Kubernetes adds the "system:authenticated" group to all authenticated users. + expect.groups = append(expect.groups, "system:authenticated") + code, status, decodeErr := reviewToken(t, r.url(t), token, token) + expect.Assert(t, code, status, decodeErr) + return &status.User +} + +func (r kubeReviewer) assertDenied(t *testing.T, token string) { + code, status, decodeErr := reviewToken(t, r.url(t), token, token) + assert.Equal(t, http.StatusUnauthorized, code, "resp should have http status code UNAUTHORIZED") + assert.Error(t, decodeErr, "resp should not parse to TokenReviewStatus") + assert.Equal(t, authv1.TokenReviewStatus{}, status, "TokenReviewStatus should be empty") +} + +func (r kubeReviewer) awaitDenied(t *testing.T, token string, expectedTime time.Time) { + isDenied := func() bool { + code, _, _ := reviewToken(t, r.url(t), token, token) + return code == http.StatusUnauthorized + } + awaitDenied(t, isDenied, expectedTime, 15*time.Second) +} + +// vaultReviewer posts TokenReview requests to Vault. +type vaultReviewer struct { + url string +} + +func (r vaultReviewer) assertAllowed(t *testing.T, token string, expect expectedAllow) *authv1.UserInfo { + code, status, decodeErr := reviewToken(t, r.url, token, token) + expect.Assert(t, code, status, decodeErr) + return &status.User +} + +func (r vaultReviewer) assertDenied(t *testing.T, token string) { + code, status, decodeErr := reviewToken(t, r.url, token, "") + assert.Equal(t, http.StatusCreated, code, "resp should have http status code CREATED") + require.NoError(t, decodeErr, "resp should parse into TokenReviewStatus") + assert.Equal(t, false, status.Authenticated, "user should not be authenticated") + assert.Equal(t, authv1.UserInfo{}, status.User, "userinfo should be empty") +} + +func (r vaultReviewer) awaitDenied(t *testing.T, token string, expectedTime time.Time) { + isDenied := func() bool { + _, status, _ := reviewToken(t, r.url, token, "") + return !status.Authenticated + } + awaitDenied(t, isDenied, expectedTime, 1*time.Second) +} + +type expectedAllow struct { + uid string + usernameLike string + groups []string + extra backend.Extra +} + +func (e *expectedAllow) Assert(t *testing.T, code int, status authv1.TokenReviewStatus, decodeErr error) { + assert.NoError(t, decodeErr) + assert.Equal(t, true, status.Authenticated, "user should be authenticated") + assert.Equal(t, http.StatusCreated, code, "resp should have http status code CREATED") + if e.uid == "" { + assert.NotEmpty(t, status.User.UID, "user should have uid") + } else { + assert.Equal(t, e.uid, status.User.UID, "user should have uid") + } + assert.Regexp(t, e.usernameLike, status.User.Username, "user should have username") + assert.Equal(t, e.groups, status.User.Groups, "user should have groups") + if e.extra == nil { + assert.Empty(t, status.User.Extra, "user should not have extra") + } else { + actualExtra := make(backend.Extra) + mapstructure.Decode(status.User.Extra, &actualExtra) + assert.Equal(t, e.extra, actualExtra, "user should have extra") + } +} + +func getCluster(t *testing.T) *vault.TestCluster { + coreConfig := &vault.CoreConfig{ + LogicalBackends: map[string]logical.Factory{ + "kubernetes": backend.Factory, + }, + CredentialBackends: map[string]logical.Factory{ + "userpass": userpass.Factory, + }, + // Quiet down the Vault cluster logs. + Logger: hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + }), + } + cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ + HandlerFunc: vaulthttp.Handler, + }) + cluster.Start() + client := cluster.Cores[0].Client + err := client.Sys().Mount("kubernetes", &api.MountInput{ + Type: "kubernetes", + Config: api.MountConfigInput{ + DefaultLeaseTTL: "16h", + MaxLeaseTTL: "32h", + }, + }) + err = client.Sys().EnableAuthWithOptions("userpass-mnt", &api.EnableAuthOptions{ + Type: "userpass", + }) + require.NoError(t, err) + return cluster +} + +func TestIntegration_Vault(t *testing.T) { + t.Parallel() + cluster := getCluster(t) + defer func() { + cluster.Cleanup() + }() + r := vaultReviewer{ + url: cluster.Cores[0].Client.Address() + "/v1/kubernetes/tokenreviews", + } + runBackendTests(t, cluster, r) +} + +func getKubeTargetPort() string { + port := os.Getenv(kubeTargetPortEnv) + if port == "" { + return "8200" + } + return port +} + +func TestIntegration_Kubernetes(t *testing.T) { + t.Parallel() + cluster := getCluster(t) + defer cluster.Cleanup() + // To provide an HTTP target on a pre-arranged port (much simpler for + // configuring the test Kubernetes cluster), run an HTTP reverse proxy + // to the test Vault cluster. + clusterUrl, err := url.Parse(cluster.Cores[0].Client.Address()) + require.NoError(t, err, "parsing cluster url") + proxy := httputil.NewSingleHostReverseProxy(clusterUrl) + proxy.Transport = insecureTransport + port := os.Getenv(kubeTargetPortEnv) + if port == "" { + port = "8200" + } + lis, err := net.Listen("tcp", "0.0.0.0:"+getKubeTargetPort()) + require.NoError(t, err, "listening on Kubernetes target port") + srv := &http.Server{Handler: proxy} + go func() { + assert.Equal(t, http.ErrServerClosed, srv.Serve(lis), "proxy shutdown error") + }() + defer func() { + assert.NoError(t, srv.Shutdown(context.Background()), "shutting down proxy") + }() + runBackendTests(t, cluster, kubeReviewer{}) + + t.Run("ClientPlugin", func(t *testing.T) { + testKubernetesClientPlugin(t, cluster.Cores[0].Client) + }) +} + +func runBackendTests(t *testing.T, cluster *vault.TestCluster, r reviewer) { + type tc func(*testing.T, *api.Client, reviewer) + cases := map[string]tc{ + "UnknownTokenDenied": testUnknownTokenDenied, + "TokenWithGroupsAndExtras": testTokenWithGroupsAndExtras, + "TokenAllowedUntilExpired": testTokenAllowedUntilExpired, + "TokenAllowedUntilRevoked": testTokenAllowedUntilRevoked, + "TokenAllowedAfterRenewed": testTokenAllowedAfterRenewed, + "TokenWithIdentity": testTokenWithIdentity, + } + // Group the subtests so they can be run in parallel. + t.Run("TokenReviews", func(t *testing.T) { + for name, c := range cases { + t.Run(name, func(t *testing.T) { + t.Parallel() + c(t, cluster.Cores[0].Client, r) + }) + } + }) +} + +func testUnknownTokenDenied(t *testing.T, c *api.Client, r reviewer) { + r.assertDenied(t, "notavalidtoken") +} + +func testTokenWithGroupsAndExtras(t *testing.T, c *api.Client, r reviewer) { + _, err := c.Logical().Write("kubernetes/roles/groups-and-extras", map[string]interface{}{ + "groups": []string{ + "group1", + "group2", + }, + "extra": backend.Extra{ + "a": []string{"a1", "a2"}, + "b": []string{"a1"}, + "c": []string{}, + }, + }) + require.NoError(t, err) + tokenResp, err := c.Logical().Read("kubernetes/token/groups-and-extras") + require.NoError(t, err) + token := tokenResp.Data["token"].(string) + r.assertAllowed(t, token, expectedAllow{ + usernameLike: "v_root_groups-and-extras_.*", + groups: []string{"group1", "group2"}, + extra: backend.Extra{ + "a": []string{"a1", "a2"}, + "b": []string{"a1"}, + "c": []string{}, + }, + }) +} + +func testTokenAllowedUntilExpired(t *testing.T, c *api.Client, r reviewer) { + _, err := c.Logical().Write("kubernetes/roles/expire-fast", map[string]interface{}{ + "groups": []string{"group1"}, + "default_ttl": "3s", + }) + require.NoError(t, err) + + expireTime := time.Now().Add(3 * time.Second) + tokenResp, err := c.Logical().Read("kubernetes/token/expire-fast") + require.NoError(t, err) + assert.Equal(t, 3, tokenResp.LeaseDuration) + + r.awaitDenied(t, tokenResp.Data["token"].(string), expireTime) +} + +func testTokenAllowedUntilRevoked(t *testing.T, c *api.Client, r reviewer) { + _, err := c.Logical().Write("kubernetes/roles/will-revoke", map[string]interface{}{ + "groups": []string{"group1"}, + "default_ttl": "1h", + }) + require.NoError(t, err) + tokenResp, err := c.Logical().Read("kubernetes/token/will-revoke") + require.NoError(t, err) + assert.Equal(t, 1*60*60, tokenResp.LeaseDuration) + token := tokenResp.Data["token"].(string) + + r.assertAllowed(t, token, expectedAllow{ + usernameLike: "v_root_will-revoke_.*", + groups: []string{"group1"}, + }) + + err = c.Sys().Revoke(tokenResp.LeaseID) + require.NoError(t, err) + + r.awaitDenied(t, tokenResp.Data["token"].(string), time.Now()) +} + +func testTokenAllowedAfterRenewed(t *testing.T, c *api.Client, r reviewer) { + _, err := c.Logical().Write("kubernetes/roles/will-renew", map[string]interface{}{ + "groups": []string{"group1"}, + "default_ttl": "3s", + }) + require.NoError(t, err) + tokenResp, err := c.Logical().Read("kubernetes/token/will-renew") + require.NoError(t, err) + assert.Equal(t, 3, tokenResp.LeaseDuration) + assert.True(t, tokenResp.Renewable) + token := tokenResp.Data["token"].(string) + + renewResp, err := c.Sys().Renew(tokenResp.LeaseID, 10) + require.NoError(t, err) + assert.Equal(t, 10, renewResp.LeaseDuration) + time.Sleep(5 * time.Second) + + r.assertAllowed(t, token, expectedAllow{ + usernameLike: "v_root_will-renew_.*", + groups: []string{"group1"}, + }) +} + +func testTokenWithIdentity(t *testing.T, c *api.Client, r reviewer) { + // Set up a userpass-auth user who can read from the Kubernetes token endpoint. + _, err := c.Logical().Write("auth/userpass-mnt/users/testuser", map[string]interface{}{ + "password": "testpass", + "policies": "eng-policy", + }) + require.NoError(t, err) + err = c.Sys().PutPolicy("eng-policy", ` +path "kubernetes/token/eng" { + capabilities = ["read"] +} +`) + require.NoError(t, err) + _, err = c.Logical().Write("kubernetes/roles/eng", map[string]interface{}{ + "groups": []string{"eng"}, + "default_ttl": "3s", + }) + require.NoError(t, err) + + // Log in as the test user. + uc, err := c.Clone() + require.NoError(t, err) + uc.ClearToken() + resp, err := uc.Logical().Write("auth/userpass-mnt/login/testuser", map[string]interface{}{ + "password": "testpass", + }) + require.NoError(t, err) + uc.SetToken(resp.Auth.ClientToken) + + // Get a Kubernetes token as the user. + tokenResp, err := uc.Logical().Read("kubernetes/token/eng") + require.NoError(t, err) + token := tokenResp.Data["token"].(string) + r.assertAllowed(t, token, expectedAllow{ + usernameLike: "testuser_auth_userpass_.*", + groups: []string{"eng"}, + }) +} + +// testKubernetesClientPlugin is an end-to-end test of the Kubernetes client plugin. +func testKubernetesClientPlugin(t *testing.T, vaultClient *api.Client) { + cacheDir, err := ioutil.TempDir("", "") + defer os.RemoveAll(cacheDir) + cacheFile := path.Join(cacheDir, "token-cache") + + _, err = vaultClient.Logical().Write("kubernetes/roles/cluster-admin", map[string]interface{}{ + "groups": []string{ + "cluster-admin", + }, + }) + require.NoError(t, err) + + kubeConfig, err := clientcmd.NewDefaultClientConfigLoadingRules().Load() + require.NoError(t, err) + if kubeContext := os.Getenv(kubeContextEnv); kubeContext != "" { + kubeConfig.CurrentContext = kubeContext + } + + pluginCmd, err := filepath.Abs("../../bin/kubernetes-credential-provider-vault") + require.NoError(t, err) + + // Create a child token so we can revoke it to test revocation. + s, err := vaultClient.Logical().Write("auth/token/create", map[string]interface{}{}) + require.NoError(t, err) + childToken := s.Auth.ClientToken + require.NotEmpty(t, childToken) + + configOverrides := &clientcmd.ConfigOverrides{ + AuthInfo: kubeApi.AuthInfo{ + Exec: &kubeApi.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + Command: pluginCmd, + Env: []kubeApi.ExecEnvVar{ + {"KUBE_VAULT_PATH", "kubernetes"}, + {"KUBE_VAULT_ROLE", "cluster-admin"}, + {"KUBE_VAULT_CACHE", cacheFile}, + {"VAULT_TOKEN", childToken}, + {"VAULT_ADDR", "http://localhost:" + getKubeTargetPort()}, + }, + }, + }, + } + + restClientConfig, err := clientcmd.NewDefaultClientConfig(*kubeConfig, configOverrides).ClientConfig() + require.NoError(t, err) + // Make sure TLS client keys don't sneak in to authentication flow. + restClientConfig.TLSClientConfig.CertFile = "" + restClientConfig.TLSClientConfig.KeyFile = "" + kubeClient, err := kubernetes.NewForConfig(restClientConfig) + require.NoError(t, err) + + // The client plugin should fetch and use Kubernetes credentials from Vault. + namespaces, err := kubeClient.CoreV1().Namespaces().List(metav1.ListOptions{}) + assert.NoError(t, err, "kubernetes request should be allowed") + assert.NotEmpty(t, namespaces.Items) + assertCacheSize(t, cacheFile, 1) + + // To check that auth was actually happening via Vault creds, revoke the creds and + // wait for a denial. + _, err = vaultClient.Logical().Write("/auth/token/revoke", map[string]interface{}{ + "token": childToken, + }) + require.NoError(t, err) + isDenied := func() bool { + _, err := kubeClient.CoreV1().Namespaces().List(metav1.ListOptions{}) + if err != nil { + assert.True(t, errors.IsUnauthorized(err), "Kubernetes error should be UNAUTHORIZED") + return true + } + return false + } + awaitDenied(t, isDenied, time.Now(), 20*time.Second) + // After the revocation, the entry should be cleared from the cache. + assertCacheSize(t, cacheFile, 0) +} + +func assertCacheSize(t *testing.T, file string, expectedSize int) { + if r, err := os.Open(file); assert.NoError(t, err) { + defer r.Close() + var entries []interface{} + assert.NoError(t, json.NewDecoder(r).Decode(&entries)) + assert.Equal(t, expectedSize, len(entries), "cache file should have entries") + } +} diff --git a/testing/webhook-authn.yaml b/testing/webhook-authn.yaml new file mode 100644 index 0000000..91b2db7 --- /dev/null +++ b/testing/webhook-authn.yaml @@ -0,0 +1,22 @@ +# The webhook server. +clusters: + - name: vault + cluster: + # In a real configuration, this would be HTTPS with trust configured for + # the Vault CA. + server: http://127.0.0.1:8200/v1/kubernetes/tokenreviews + + +# The webhook client (the api server) +users: + - name: api-server + user: + token: unused + +current-context: webhook +contexts: +- context: + cluster: vault + user: api-server + name: webhook + diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS new file mode 100644 index 0000000..c364af1 --- /dev/null +++ b/vendor/cloud.google.com/go/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of cloud authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Filippo Valsorda +Google Inc. +Ingo Oeser +Palm Stone Games, Inc. +Paweł Knap +Péter Szilágyi +Tyler Treat diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS new file mode 100644 index 0000000..3b3cbed --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTORS @@ -0,0 +1,40 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +# Keep the list alphabetically sorted. + +Alexis Hunt +Andreas Litt +Andrew Gerrand +Brad Fitzpatrick +Burcu Dogan +Dave Day +David Sansome +David Symonds +Filippo Valsorda +Glenn Lewis +Ingo Oeser +James Hall +Johan Euphrosine +Jonathan Amsterdam +Kunpei Sakai +Luna Duclos +Magnus Hiie +Mario Castro +Michael McGreevy +Omar Jarjur +Paweł Knap +Péter Szilágyi +Sarah Adams +Thanatat Tamtan +Toby Burress +Tuo Shan +Tyler Treat diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/vendor/cloud.google.com/go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/civil/civil.go b/vendor/cloud.google.com/go/civil/civil.go new file mode 100644 index 0000000..1cb2675 --- /dev/null +++ b/vendor/cloud.google.com/go/civil/civil.go @@ -0,0 +1,277 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package civil implements types for civil time, a time-zone-independent +// representation of time that follows the rules of the proleptic +// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second +// minutes. +// +// Because they lack location information, these types do not represent unique +// moments or intervals of time. Use time.Time for that purpose. +package civil + +import ( + "fmt" + "time" +) + +// A Date represents a date (year, month, day). +// +// This type does not include location information, and therefore does not +// describe a unique 24-hour timespan. +type Date struct { + Year int // Year (e.g., 2014). + Month time.Month // Month of the year (January = 1, ...). + Day int // Day of the month, starting at 1. +} + +// DateOf returns the Date in which a time occurs in that time's location. +func DateOf(t time.Time) Date { + var d Date + d.Year, d.Month, d.Day = t.Date() + return d +} + +// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents. +func ParseDate(s string) (Date, error) { + t, err := time.Parse("2006-01-02", s) + if err != nil { + return Date{}, err + } + return DateOf(t), nil +} + +// String returns the date in RFC3339 full-date format. +func (d Date) String() string { + return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) +} + +// IsValid reports whether the date is valid. +func (d Date) IsValid() bool { + return DateOf(d.In(time.UTC)) == d +} + +// In returns the time corresponding to time 00:00:00 of the date in the location. +// +// In is always consistent with time.Date, even when time.Date returns a time +// on a different day. For example, if loc is America/Indiana/Vincennes, then both +// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc) +// and +// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc) +// return 23:00:00 on April 30, 1955. +// +// In panics if loc is nil. +func (d Date) In(loc *time.Location) time.Time { + return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc) +} + +// AddDays returns the date that is n days in the future. +// n can also be negative to go into the past. +func (d Date) AddDays(n int) Date { + return DateOf(d.In(time.UTC).AddDate(0, 0, n)) +} + +// DaysSince returns the signed number of days between the date and s, not including the end day. +// This is the inverse operation to AddDays. +func (d Date) DaysSince(s Date) (days int) { + // We convert to Unix time so we do not have to worry about leap seconds: + // Unix time increases by exactly 86400 seconds per day. + deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix() + return int(deltaUnix / 86400) +} + +// Before reports whether d1 occurs before d2. +func (d1 Date) Before(d2 Date) bool { + if d1.Year != d2.Year { + return d1.Year < d2.Year + } + if d1.Month != d2.Month { + return d1.Month < d2.Month + } + return d1.Day < d2.Day +} + +// After reports whether d1 occurs after d2. +func (d1 Date) After(d2 Date) bool { + return d2.Before(d1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of d.String(). +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The date is expected to be a string in a format accepted by ParseDate. +func (d *Date) UnmarshalText(data []byte) error { + var err error + *d, err = ParseDate(string(data)) + return err +} + +// A Time represents a time with nanosecond precision. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +// +// This type exists to represent the TIME type in storage-based APIs like BigQuery. +// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type. +type Time struct { + Hour int // The hour of the day in 24-hour format; range [0-23] + Minute int // The minute of the hour; range [0-59] + Second int // The second of the minute; range [0-59] + Nanosecond int // The nanosecond of the second; range [0-999999999] +} + +// TimeOf returns the Time representing the time of day in which a time occurs +// in that time's location. It ignores the date. +func TimeOf(t time.Time) Time { + var tm Time + tm.Hour, tm.Minute, tm.Second = t.Clock() + tm.Nanosecond = t.Nanosecond() + return tm +} + +// ParseTime parses a string and returns the time value it represents. +// ParseTime accepts an extended form of the RFC3339 partial-time format. After +// the HH:MM:SS part of the string, an optional fractional part may appear, +// consisting of a decimal point followed by one to nine decimal digits. +// (RFC3339 admits only one digit after the decimal point). +func ParseTime(s string) (Time, error) { + t, err := time.Parse("15:04:05.999999999", s) + if err != nil { + return Time{}, err + } + return TimeOf(t), nil +} + +// String returns the date in the format described in ParseTime. If Nanoseconds +// is zero, no fractional part will be generated. Otherwise, the result will +// end with a fractional part consisting of a decimal point and nine digits. +func (t Time) String() string { + s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second) + if t.Nanosecond == 0 { + return s + } + return s + fmt.Sprintf(".%09d", t.Nanosecond) +} + +// IsValid reports whether the time is valid. +func (t Time) IsValid() bool { + // Construct a non-zero time. + tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC) + return TimeOf(tm) == t +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of t.String(). +func (t Time) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The time is expected to be a string in a format accepted by ParseTime. +func (t *Time) UnmarshalText(data []byte) error { + var err error + *t, err = ParseTime(string(data)) + return err +} + +// A DateTime represents a date and time. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +type DateTime struct { + Date Date + Time Time +} + +// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub. + +// DateTimeOf returns the DateTime in which a time occurs in that time's location. +func DateTimeOf(t time.Time) DateTime { + return DateTime{ + Date: DateOf(t), + Time: TimeOf(t), + } +} + +// ParseDateTime parses a string and returns the DateTime it represents. +// ParseDateTime accepts a variant of the RFC3339 date-time format that omits +// the time offset but includes an optional fractional time, as described in +// ParseTime. Informally, the accepted format is +// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF] +// where the 'T' may be a lower-case 't'. +func ParseDateTime(s string) (DateTime, error) { + t, err := time.Parse("2006-01-02T15:04:05.999999999", s) + if err != nil { + t, err = time.Parse("2006-01-02t15:04:05.999999999", s) + if err != nil { + return DateTime{}, err + } + } + return DateTimeOf(t), nil +} + +// String returns the date in the format described in ParseDate. +func (dt DateTime) String() string { + return dt.Date.String() + "T" + dt.Time.String() +} + +// IsValid reports whether the datetime is valid. +func (dt DateTime) IsValid() bool { + return dt.Date.IsValid() && dt.Time.IsValid() +} + +// In returns the time corresponding to the DateTime in the given location. +// +// If the time is missing or ambigous at the location, In returns the same +// result as time.Date. For example, if loc is America/Indiana/Vincennes, then +// both +// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc) +// and +// civil.DateTime{ +// civil.Date{Year: 1955, Month: time.May, Day: 1}}, +// civil.Time{Minute: 30}}.In(loc) +// return 23:30:00 on April 30, 1955. +// +// In panics if loc is nil. +func (dt DateTime) In(loc *time.Location) time.Time { + return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc) +} + +// Before reports whether dt1 occurs before dt2. +func (dt1 DateTime) Before(dt2 DateTime) bool { + return dt1.In(time.UTC).Before(dt2.In(time.UTC)) +} + +// After reports whether dt1 occurs after dt2. +func (dt1 DateTime) After(dt2 DateTime) bool { + return dt2.Before(dt1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of dt.String(). +func (dt DateTime) MarshalText() ([]byte, error) { + return []byte(dt.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The datetime is expected to be a string in a format accepted by ParseDateTime +func (dt *DateTime) UnmarshalText(data []byte) error { + var err error + *dt, err = ParseDateTime(string(data)) + return err +} diff --git a/vendor/github.com/Jeffail/gabs/LICENSE b/vendor/github.com/Jeffail/gabs/LICENSE new file mode 100644 index 0000000..99a62c6 --- /dev/null +++ b/vendor/github.com/Jeffail/gabs/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Ashley Jeffs + +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/vendor/github.com/Jeffail/gabs/README.md b/vendor/github.com/Jeffail/gabs/README.md new file mode 100644 index 0000000..a58193f --- /dev/null +++ b/vendor/github.com/Jeffail/gabs/README.md @@ -0,0 +1,315 @@ +![Gabs](gabs_logo.png "Gabs") + +Gabs is a small utility for dealing with dynamic or unknown JSON structures in +golang. It's pretty much just a helpful wrapper around the golang +`json.Marshal/json.Unmarshal` behaviour and `map[string]interface{}` objects. +It does nothing spectacular except for being fabulous. + +https://godoc.org/github.com/Jeffail/gabs + +## How to install: + +``` bash +go get github.com/Jeffail/gabs +``` + +## How to use + +### Parsing and searching JSON + +``` go +... + +import "github.com/Jeffail/gabs" + +jsonParsed, err := gabs.ParseJSON([]byte(`{ + "outter":{ + "inner":{ + "value1":10, + "value2":22 + }, + "alsoInner":{ + "value1":20 + } + } +}`)) + +var value float64 +var ok bool + +value, ok = jsonParsed.Path("outter.inner.value1").Data().(float64) +// value == 10.0, ok == true + +value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64) +// value == 10.0, ok == true + +value, ok = jsonParsed.Path("does.not.exist").Data().(float64) +// value == 0.0, ok == false + +exists := jsonParsed.Exists("outter", "inner", "value1") +// exists == true + +exists := jsonParsed.Exists("does", "not", "exist") +// exists == false + +exists := jsonParsed.ExistsP("does.not.exist") +// exists == false + +... +``` + +### Iterating objects + +``` go +... + +jsonParsed, _ := gabs.ParseJSON([]byte(`{"object":{ "first": 1, "second": 2, "third": 3 }}`)) + +// S is shorthand for Search +children, _ := jsonParsed.S("object").ChildrenMap() +for key, child := range children { + fmt.Printf("key: %v, value: %v\n", key, child.Data().(string)) +} + +... +``` + +### Iterating arrays + +``` go +... + +jsonParsed, _ := gabs.ParseJSON([]byte(`{"array":[ "first", "second", "third" ]}`)) + +// S is shorthand for Search +children, _ := jsonParsed.S("array").Children() +for _, child := range children { + fmt.Println(child.Data().(string)) +} + +... +``` + +Will print: + +``` +first +second +third +``` + +Children() will return all children of an array in order. This also works on +objects, however, the children will be returned in a random order. + +### Searching through arrays + +If your JSON structure contains arrays you can still search the fields of the +objects within the array, this returns a JSON array containing the results for +each element. + +``` go +... + +jsonParsed, _ := gabs.ParseJSON([]byte(`{"array":[ {"value":1}, {"value":2}, {"value":3} ]}`)) +fmt.Println(jsonParsed.Path("array.value").String()) + +... +``` + +Will print: + +``` +[1,2,3] +``` + +### Generating JSON + +``` go +... + +jsonObj := gabs.New() +// or gabs.Consume(jsonObject) to work on an existing map[string]interface{} + +jsonObj.Set(10, "outter", "inner", "value") +jsonObj.SetP(20, "outter.inner.value2") +jsonObj.Set(30, "outter", "inner2", "value3") + +fmt.Println(jsonObj.String()) + +... +``` + +Will print: + +``` +{"outter":{"inner":{"value":10,"value2":20},"inner2":{"value3":30}}} +``` + +To pretty-print: + +``` go +... + +fmt.Println(jsonObj.StringIndent("", " ")) + +... +``` + +Will print: + +``` +{ + "outter": { + "inner": { + "value": 10, + "value2": 20 + }, + "inner2": { + "value3": 30 + } + } +} +``` + +### Generating Arrays + +``` go +... + +jsonObj := gabs.New() + +jsonObj.Array("foo", "array") +// Or .ArrayP("foo.array") + +jsonObj.ArrayAppend(10, "foo", "array") +jsonObj.ArrayAppend(20, "foo", "array") +jsonObj.ArrayAppend(30, "foo", "array") + +fmt.Println(jsonObj.String()) + +... +``` + +Will print: + +``` +{"foo":{"array":[10,20,30]}} +``` + +Working with arrays by index: + +``` go +... + +jsonObj := gabs.New() + +// Create an array with the length of 3 +jsonObj.ArrayOfSize(3, "foo") + +jsonObj.S("foo").SetIndex("test1", 0) +jsonObj.S("foo").SetIndex("test2", 1) + +// Create an embedded array with the length of 3 +jsonObj.S("foo").ArrayOfSizeI(3, 2) + +jsonObj.S("foo").Index(2).SetIndex(1, 0) +jsonObj.S("foo").Index(2).SetIndex(2, 1) +jsonObj.S("foo").Index(2).SetIndex(3, 2) + +fmt.Println(jsonObj.String()) + +... +``` + +Will print: + +``` +{"foo":["test1","test2",[1,2,3]]} +``` + +### Converting back to JSON + +This is the easiest part: + +``` go +... + +jsonParsedObj, _ := gabs.ParseJSON([]byte(`{ + "outter":{ + "values":{ + "first":10, + "second":11 + } + }, + "outter2":"hello world" +}`)) + +jsonOutput := jsonParsedObj.String() +// Becomes `{"outter":{"values":{"first":10,"second":11}},"outter2":"hello world"}` + +... +``` + +And to serialize a specific segment is as simple as: + +``` go +... + +jsonParsedObj := gabs.ParseJSON([]byte(`{ + "outter":{ + "values":{ + "first":10, + "second":11 + } + }, + "outter2":"hello world" +}`)) + +jsonOutput := jsonParsedObj.Search("outter").String() +// Becomes `{"values":{"first":10,"second":11}}` + +... +``` + +### Merge two containers + +You can merge a JSON structure into an existing one, where collisions will be +converted into a JSON array. + +``` go +jsonParsed1, _ := ParseJSON([]byte(`{"outter": {"value1": "one"}}`)) +jsonParsed2, _ := ParseJSON([]byte(`{"outter": {"inner": {"value3": "three"}}, "outter2": {"value2": "two"}}`)) + +jsonParsed1.Merge(jsonParsed2) +// Becomes `{"outter":{"inner":{"value3":"three"},"value1":"one"},"outter2":{"value2":"two"}}` +``` + +Arrays are merged: + +``` go +jsonParsed1, _ := ParseJSON([]byte(`{"array": ["one"]}`)) +jsonParsed2, _ := ParseJSON([]byte(`{"array": ["two"]}`)) + +jsonParsed1.Merge(jsonParsed2) +// Becomes `{"array":["one", "two"]}` +``` + +### Parsing Numbers + +Gabs uses the `json` package under the bonnet, which by default will parse all +number values into `float64`. If you need to parse `Int` values then you should +use a `json.Decoder` (https://golang.org/pkg/encoding/json/#Decoder): + +``` go +sample := []byte(`{"test":{"int":10, "float":6.66}}`) +dec := json.NewDecoder(bytes.NewReader(sample)) +dec.UseNumber() + +val, err := gabs.ParseJSONDecoder(dec) +if err != nil { + t.Errorf("Failed to parse: %v", err) + return +} + +intValue, err := val.Path("test.int").Data().(json.Number).Int64() +``` diff --git a/vendor/github.com/Jeffail/gabs/gabs.go b/vendor/github.com/Jeffail/gabs/gabs.go new file mode 100644 index 0000000..a27a711 --- /dev/null +++ b/vendor/github.com/Jeffail/gabs/gabs.go @@ -0,0 +1,579 @@ +/* +Copyright (c) 2014 Ashley Jeffs + +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. +*/ + +// Package gabs implements a simplified wrapper around creating and parsing JSON. +package gabs + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "strings" +) + +//-------------------------------------------------------------------------------------------------- + +var ( + // ErrOutOfBounds - Index out of bounds. + ErrOutOfBounds = errors.New("out of bounds") + + // ErrNotObjOrArray - The target is not an object or array type. + ErrNotObjOrArray = errors.New("not an object or array") + + // ErrNotObj - The target is not an object type. + ErrNotObj = errors.New("not an object") + + // ErrNotArray - The target is not an array type. + ErrNotArray = errors.New("not an array") + + // ErrPathCollision - Creating a path failed because an element collided with an existing value. + ErrPathCollision = errors.New("encountered value collision whilst building path") + + // ErrInvalidInputObj - The input value was not a map[string]interface{}. + ErrInvalidInputObj = errors.New("invalid input object") + + // ErrInvalidInputText - The input data could not be parsed. + ErrInvalidInputText = errors.New("input text could not be parsed") + + // ErrInvalidPath - The filepath was not valid. + ErrInvalidPath = errors.New("invalid file path") + + // ErrInvalidBuffer - The input buffer contained an invalid JSON string + ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") +) + +//-------------------------------------------------------------------------------------------------- + +// Container - an internal structure that holds a reference to the core interface map of the parsed +// json. Use this container to move context. +type Container struct { + object interface{} +} + +// Data - Return the contained data as an interface{}. +func (g *Container) Data() interface{} { + if g == nil { + return nil + } + return g.object +} + +//-------------------------------------------------------------------------------------------------- + +// Path - Search for a value using dot notation. +func (g *Container) Path(path string) *Container { + return g.Search(strings.Split(path, ".")...) +} + +// Search - Attempt to find and return an object within the JSON structure by specifying the +// hierarchy of field names to locate the target. If the search encounters an array and has not +// reached the end target then it will iterate each object of the array for the target and return +// all of the results in a JSON array. +func (g *Container) Search(hierarchy ...string) *Container { + var object interface{} + + object = g.Data() + for target := 0; target < len(hierarchy); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + object, ok = mmap[hierarchy[target]] + if !ok { + return nil + } + } else if marray, ok := object.([]interface{}); ok { + tmpArray := []interface{}{} + for _, val := range marray { + tmpGabs := &Container{val} + res := tmpGabs.Search(hierarchy[target:]...) + if res != nil { + tmpArray = append(tmpArray, res.Data()) + } + } + if len(tmpArray) == 0 { + return nil + } + return &Container{tmpArray} + } else { + return nil + } + } + return &Container{object} +} + +// S - Shorthand method, does the same thing as Search. +func (g *Container) S(hierarchy ...string) *Container { + return g.Search(hierarchy...) +} + +// Exists - Checks whether a path exists. +func (g *Container) Exists(hierarchy ...string) bool { + return g.Search(hierarchy...) != nil +} + +// ExistsP - Checks whether a dot notation path exists. +func (g *Container) ExistsP(path string) bool { + return g.Exists(strings.Split(path, ".")...) +} + +// Index - Attempt to find and return an object within a JSON array by index. +func (g *Container) Index(index int) *Container { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil} + } + return &Container{array[index]} + } + return &Container{nil} +} + +// Children - Return a slice of all the children of the array. This also works for objects, however, +// the children returned for an object will NOT be in order and you lose the names of the returned +// objects this way. +func (g *Container) Children() ([]*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + children := make([]*Container, len(array)) + for i := 0; i < len(array); i++ { + children[i] = &Container{array[i]} + } + return children, nil + } + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := []*Container{} + for _, obj := range mmap { + children = append(children, &Container{obj}) + } + return children, nil + } + return nil, ErrNotObjOrArray +} + +// ChildrenMap - Return a map of all the children of an object. +func (g *Container) ChildrenMap() (map[string]*Container, error) { + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := map[string]*Container{} + for name, obj := range mmap { + children[name] = &Container{obj} + } + return children, nil + } + return nil, ErrNotObj +} + +//-------------------------------------------------------------------------------------------------- + +// Set - Set the value of a field at a JSON path, any parts of the path that do not exist will be +// constructed, and if a collision occurs with a non object type whilst iterating the path an error +// is returned. +func (g *Container) Set(value interface{}, path ...string) (*Container, error) { + if len(path) == 0 { + g.object = value + return g, nil + } + var object interface{} + if g.object == nil { + g.object = map[string]interface{}{} + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + mmap[path[target]] = value + } else if mmap[path[target]] == nil { + mmap[path[target]] = map[string]interface{}{} + } + object = mmap[path[target]] + } else { + return &Container{nil}, ErrPathCollision + } + } + return &Container{object}, nil +} + +// SetP - Does the same as Set, but using a dot notation JSON path. +func (g *Container) SetP(value interface{}, path string) (*Container, error) { + return g.Set(value, strings.Split(path, ".")...) +} + +// SetIndex - Set a value of an array element based on the index. +func (g *Container) SetIndex(value interface{}, index int) (*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil}, ErrOutOfBounds + } + array[index] = value + return &Container{array[index]}, nil + } + return &Container{nil}, ErrNotArray +} + +// Object - Create a new JSON object at a path. Returns an error if the path contains a collision +// with a non object type. +func (g *Container) Object(path ...string) (*Container, error) { + return g.Set(map[string]interface{}{}, path...) +} + +// ObjectP - Does the same as Object, but using a dot notation JSON path. +func (g *Container) ObjectP(path string) (*Container, error) { + return g.Object(strings.Split(path, ".")...) +} + +// ObjectI - Create a new JSON object at an array index. Returns an error if the object is not an +// array or the index is out of bounds. +func (g *Container) ObjectI(index int) (*Container, error) { + return g.SetIndex(map[string]interface{}{}, index) +} + +// Array - Create a new JSON array at a path. Returns an error if the path contains a collision with +// a non object type. +func (g *Container) Array(path ...string) (*Container, error) { + return g.Set([]interface{}{}, path...) +} + +// ArrayP - Does the same as Array, but using a dot notation JSON path. +func (g *Container) ArrayP(path string) (*Container, error) { + return g.Array(strings.Split(path, ".")...) +} + +// ArrayI - Create a new JSON array at an array index. Returns an error if the object is not an +// array or the index is out of bounds. +func (g *Container) ArrayI(index int) (*Container, error) { + return g.SetIndex([]interface{}{}, index) +} + +// ArrayOfSize - Create a new JSON array of a particular size at a path. Returns an error if the +// path contains a collision with a non object type. +func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) { + a := make([]interface{}, size) + return g.Set(a, path...) +} + +// ArrayOfSizeP - Does the same as ArrayOfSize, but using a dot notation JSON path. +func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) { + return g.ArrayOfSize(size, strings.Split(path, ".")...) +} + +// ArrayOfSizeI - Create a new JSON array of a particular size at an array index. Returns an error +// if the object is not an array or the index is out of bounds. +func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) { + a := make([]interface{}, size) + return g.SetIndex(a, index) +} + +// Delete - Delete an element at a JSON path, an error is returned if the element does not exist. +func (g *Container) Delete(path ...string) error { + var object interface{} + + if g.object == nil { + return ErrNotObj + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + if _, ok := mmap[path[target]]; ok { + delete(mmap, path[target]) + } else { + return ErrNotObj + } + } + object = mmap[path[target]] + } else { + return ErrNotObj + } + } + return nil +} + +// DeleteP - Does the same as Delete, but using a dot notation JSON path. +func (g *Container) DeleteP(path string) error { + return g.Delete(strings.Split(path, ".")...) +} + +// Merge - Merges two gabs-containers +func (g *Container) Merge(toMerge *Container) error { + var recursiveFnc func(map[string]interface{}, []string) error + recursiveFnc = func(mmap map[string]interface{}, path []string) error { + for key, value := range mmap { + newPath := append(path, key) + if g.Exists(newPath...) { + target := g.Search(newPath...) + switch t := value.(type) { + case map[string]interface{}: + switch targetV := target.Data().(type) { + case map[string]interface{}: + if err := recursiveFnc(t, newPath); err != nil { + return err + } + case []interface{}: + g.Set(append(targetV, t), newPath...) + default: + newSlice := append([]interface{}{}, targetV) + g.Set(append(newSlice, t), newPath...) + } + case []interface{}: + for _, valueOfSlice := range t { + if err := g.ArrayAppend(valueOfSlice, newPath...); err != nil { + return err + } + } + default: + switch targetV := target.Data().(type) { + case []interface{}: + g.Set(append(targetV, t), newPath...) + default: + newSlice := append([]interface{}{}, targetV) + g.Set(append(newSlice, t), newPath...) + } + } + } else { + // path doesn't exist. So set the value + if _, err := g.Set(value, newPath...); err != nil { + return err + } + } + } + return nil + } + if mmap, ok := toMerge.Data().(map[string]interface{}); ok { + return recursiveFnc(mmap, []string{}) + } + return nil +} + +//-------------------------------------------------------------------------------------------------- + +/* +Array modification/search - Keeping these options simple right now, no need for anything more +complicated since you can just cast to []interface{}, modify and then reassign with Set. +*/ + +// ArrayAppend - Append a value onto a JSON array. If the target is not a JSON array then it will be +// converted into one, with its contents as the first element of the array. +func (g *Container) ArrayAppend(value interface{}, path ...string) error { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + array = append(array, value) + _, err := g.Set(array, path...) + return err + } + + newArray := []interface{}{} + newArray = append(newArray, g.Search(path...).Data()) + newArray = append(newArray, value) + + _, err := g.Set(newArray, path...) + return err +} + +// ArrayAppendP - Append a value onto a JSON array using a dot notation JSON path. +func (g *Container) ArrayAppendP(value interface{}, path string) error { + return g.ArrayAppend(value, strings.Split(path, ".")...) +} + +// ArrayRemove - Remove an element from a JSON array. +func (g *Container) ArrayRemove(index int, path ...string) error { + if index < 0 { + return ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return ErrNotArray + } + if index < len(array) { + array = append(array[:index], array[index+1:]...) + } else { + return ErrOutOfBounds + } + _, err := g.Set(array, path...) + return err +} + +// ArrayRemoveP - Remove an element from a JSON array using a dot notation JSON path. +func (g *Container) ArrayRemoveP(index int, path string) error { + return g.ArrayRemove(index, strings.Split(path, ".")...) +} + +// ArrayElement - Access an element from a JSON array. +func (g *Container) ArrayElement(index int, path ...string) (*Container, error) { + if index < 0 { + return &Container{nil}, ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return &Container{nil}, ErrNotArray + } + if index < len(array) { + return &Container{array[index]}, nil + } + return &Container{nil}, ErrOutOfBounds +} + +// ArrayElementP - Access an element from a JSON array using a dot notation JSON path. +func (g *Container) ArrayElementP(index int, path string) (*Container, error) { + return g.ArrayElement(index, strings.Split(path, ".")...) +} + +// ArrayCount - Count the number of elements in a JSON array. +func (g *Container) ArrayCount(path ...string) (int, error) { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + return len(array), nil + } + return 0, ErrNotArray +} + +// ArrayCountP - Count the number of elements in a JSON array using a dot notation JSON path. +func (g *Container) ArrayCountP(path string) (int, error) { + return g.ArrayCount(strings.Split(path, ".")...) +} + +//-------------------------------------------------------------------------------------------------- + +// Bytes - Converts the contained object back to a JSON []byte blob. +func (g *Container) Bytes() []byte { + if g.Data() != nil { + if bytes, err := json.Marshal(g.object); err == nil { + return bytes + } + } + return []byte("{}") +} + +// BytesIndent - Converts the contained object to a JSON []byte blob formatted with prefix, indent. +func (g *Container) BytesIndent(prefix string, indent string) []byte { + if g.object != nil { + if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil { + return bytes + } + } + return []byte("{}") +} + +// String - Converts the contained object to a JSON formatted string. +func (g *Container) String() string { + return string(g.Bytes()) +} + +// StringIndent - Converts the contained object back to a JSON formatted string with prefix, indent. +func (g *Container) StringIndent(prefix string, indent string) string { + return string(g.BytesIndent(prefix, indent)) +} + +// EncodeOpt is a functional option for the EncodeJSON method. +type EncodeOpt func(e *json.Encoder) + +// EncodeOptHTMLEscape sets the encoder to escape the JSON for html. +func EncodeOptHTMLEscape(doEscape bool) EncodeOpt { + return func(e *json.Encoder) { + e.SetEscapeHTML(doEscape) + } +} + +// EncodeOptIndent sets the encoder to indent the JSON output. +func EncodeOptIndent(prefix string, indent string) EncodeOpt { + return func(e *json.Encoder) { + e.SetIndent(prefix, indent) + } +} + +// EncodeJSON - Encodes the contained object back to a JSON formatted []byte +// using a variant list of modifier functions for the encoder being used. +// Functions for modifying the output are prefixed with EncodeOpt, e.g. +// EncodeOptHTMLEscape. +func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte { + var b bytes.Buffer + encoder := json.NewEncoder(&b) + encoder.SetEscapeHTML(false) // Do not escape by default. + for _, opt := range encodeOpts { + opt(encoder) + } + if err := encoder.Encode(g.object); err != nil { + return []byte("{}") + } + result := b.Bytes() + if len(result) > 0 { + result = result[:len(result)-1] + } + return result +} + +// New - Create a new gabs JSON object. +func New() *Container { + return &Container{map[string]interface{}{}} +} + +// Consume - Gobble up an already converted JSON object, or a fresh map[string]interface{} object. +func Consume(root interface{}) (*Container, error) { + return &Container{root}, nil +} + +// ParseJSON - Convert a string into a representation of the parsed JSON. +func ParseJSON(sample []byte) (*Container, error) { + var gabs Container + + if err := json.Unmarshal(sample, &gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +// ParseJSONDecoder - Convert a json.Decoder into a representation of the parsed JSON. +func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) { + var gabs Container + + if err := decoder.Decode(&gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +// ParseJSONFile - Read a file and convert into a representation of the parsed JSON. +func ParseJSONFile(path string) (*Container, error) { + if len(path) > 0 { + cBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + container, err := ParseJSON(cBytes) + if err != nil { + return nil, err + } + + return container, nil + } + return nil, ErrInvalidPath +} + +// ParseJSONBuffer - Read the contents of a buffer into a representation of the parsed JSON. +func ParseJSONBuffer(buffer io.Reader) (*Container, error) { + var gabs Container + jsonDecoder := json.NewDecoder(buffer) + if err := jsonDecoder.Decode(&gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +//-------------------------------------------------------------------------------------------------- diff --git a/vendor/github.com/Jeffail/gabs/gabs_logo.png b/vendor/github.com/Jeffail/gabs/gabs_logo.png new file mode 100644 index 0000000..b6c1fad Binary files /dev/null and b/vendor/github.com/Jeffail/gabs/gabs_logo.png differ diff --git a/vendor/github.com/NYTimes/gziphandler/.gitignore b/vendor/github.com/NYTimes/gziphandler/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/vendor/github.com/NYTimes/gziphandler/.travis.yml b/vendor/github.com/NYTimes/gziphandler/.travis.yml new file mode 100644 index 0000000..d2b67f6 --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.7 + - 1.8 + - tip diff --git a/vendor/github.com/NYTimes/gziphandler/CODE_OF_CONDUCT.md b/vendor/github.com/NYTimes/gziphandler/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cdbca19 --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +--- +layout: code-of-conduct +version: v1.0 +--- + +This code of conduct outlines our expectations for participants within the **NYTimes/gziphandler** community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. + +Our open source community strives to: + +* **Be friendly and patient.** +* **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. +* **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. +* **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. +* **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. +* **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. + +## Definitions + +Harassment includes, but is not limited to: + +- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation +- Unwelcome comments regarding a person’s lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment +- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle +- Physical contact and simulated physical contact (eg, textual descriptions like “*hug*” or “*backrub*”) without consent or after a request to stop +- Threats of violence, both physical and psychological +- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm +- Deliberate intimidation +- Stalking or following +- Harassing photography or recording, including logging online activity for harassment purposes +- Sustained disruption of discussion +- Unwelcome sexual attention, including gratuitous or off-topic sexual images or behaviour +- Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others +- Continued one-on-one communication after requests to cease +- Deliberate “outing” of any aspect of a person’s identity without their consent except as necessary to protect others from intentional abuse +- Publication of non-harassing private communication + +Our open source community prioritizes marginalized people’s safety over privileged people’s comfort. We will not act on complaints regarding: + +- ‘Reverse’ -isms, including ‘reverse racism,’ ‘reverse sexism,’ and ‘cisphobia’ +- Reasonable communication of boundaries, such as “leave me alone,” “go away,” or “I’m not discussing this with you” +- Refusal to explain or debate social justice concepts +- Communicating in a ‘tone’ you don’t find congenial +- Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions + + +### Diversity Statement + +We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. + +Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected +characteristics above, including participants with disabilities. + +### Reporting Issues + +If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via **code@nytimes.com**. All reports will be handled with discretion. In your report please include: + +- Your contact information. +- Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please +include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. +- Any additional information that may be helpful. + +After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse. + +### Attribution & Acknowledgements + +We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration: + +* [Django](https://www.djangoproject.com/conduct/reporting/) +* [Python](https://www.python.org/community/diversity/) +* [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct) +* [Contributor Covenant](http://contributor-covenant.org/) +* [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/) +* [Citizen Code of Conduct](http://citizencodeofconduct.org/) + +This Code of Conduct was based on https://github.com/todogroup/opencodeofconduct diff --git a/vendor/github.com/NYTimes/gziphandler/CONTRIBUTING.md b/vendor/github.com/NYTimes/gziphandler/CONTRIBUTING.md new file mode 100644 index 0000000..b89a9eb --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing to NYTimes/gziphandler + +This is an open source project started by handful of developers at The New York Times and open to the entire Go community. + +We really appreciate your help! + +## Filing issues + +When filing an issue, make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +## Contributing code + +Before submitting changes, please follow these guidelines: + +1. Check the open issues and pull requests for existing discussions. +2. Open an issue to discuss a new feature. +3. Write tests. +4. Make sure code follows the ['Go Code Review Comments'](https://github.com/golang/go/wiki/CodeReviewComments). +5. Make sure your changes pass `go test`. +6. Make sure the entire test suite passes locally and on Travis CI. +7. Open a Pull Request. +8. [Squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) after receiving feedback and add a [great commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +Unless otherwise noted, the gziphandler source files are distributed under the Apache 2.0-style license found in the LICENSE.md file. diff --git a/vendor/github.com/NYTimes/gziphandler/LICENSE b/vendor/github.com/NYTimes/gziphandler/LICENSE new file mode 100644 index 0000000..df6192d --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2017 The New York Times Company + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/NYTimes/gziphandler/README.md b/vendor/github.com/NYTimes/gziphandler/README.md new file mode 100644 index 0000000..6d72460 --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/README.md @@ -0,0 +1,52 @@ +Gzip Handler +============ + +This is a tiny Go package which wraps HTTP handlers to transparently gzip the +response body, for clients which support it. Although it's usually simpler to +leave that to a reverse proxy (like nginx or Varnish), this package is useful +when that's undesirable. + + +## Usage + +Call `GzipHandler` with any handler (an object which implements the +`http.Handler` interface), and it'll return a new handler which gzips the +response. For example: + +```go +package main + +import ( + "io" + "net/http" + "github.com/NYTimes/gziphandler" +) + +func main() { + withoutGz := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + io.WriteString(w, "Hello, World") + }) + + withGz := gziphandler.GzipHandler(withoutGz) + + http.Handle("/", withGz) + http.ListenAndServe("0.0.0.0:8000", nil) +} +``` + + +## Documentation + +The docs can be found at [godoc.org][docs], as usual. + + +## License + +[Apache 2.0][license]. + + + + +[docs]: https://godoc.org/github.com/nytimes/gziphandler +[license]: https://github.com/nytimes/gziphandler/blob/master/LICENSE.md diff --git a/vendor/github.com/NYTimes/gziphandler/gzip.go b/vendor/github.com/NYTimes/gziphandler/gzip.go new file mode 100644 index 0000000..f91dcfa --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/gzip.go @@ -0,0 +1,429 @@ +package gziphandler + +import ( + "bufio" + "compress/gzip" + "fmt" + "io" + "net" + "net/http" + "strconv" + "strings" + "sync" +) + +const ( + vary = "Vary" + acceptEncoding = "Accept-Encoding" + contentEncoding = "Content-Encoding" + contentType = "Content-Type" + contentLength = "Content-Length" +) + +type codings map[string]float64 + +const ( + // DefaultQValue is the default qvalue to assign to an encoding if no explicit qvalue is set. + // This is actually kind of ambiguous in RFC 2616, so hopefully it's correct. + // The examples seem to indicate that it is. + DefaultQValue = 1.0 + + // 1500 bytes is the MTU size for the internet since that is the largest size allowed at the network layer. + // If you take a file that is 1300 bytes and compress it to 800 bytes, it’s still transmitted in that same 1500 byte packet regardless, so you’ve gained nothing. + // That being the case, you should restrict the gzip compression to files with a size greater than a single packet, 1400 bytes (1.4KB) is a safe value. + DefaultMinSize = 1400 +) + +// gzipWriterPools stores a sync.Pool for each compression level for reuse of +// gzip.Writers. Use poolIndex to covert a compression level to an index into +// gzipWriterPools. +var gzipWriterPools [gzip.BestCompression - gzip.BestSpeed + 2]*sync.Pool + +func init() { + for i := gzip.BestSpeed; i <= gzip.BestCompression; i++ { + addLevelPool(i) + } + addLevelPool(gzip.DefaultCompression) +} + +// poolIndex maps a compression level to its index into gzipWriterPools. It +// assumes that level is a valid gzip compression level. +func poolIndex(level int) int { + // gzip.DefaultCompression == -1, so we need to treat it special. + if level == gzip.DefaultCompression { + return gzip.BestCompression - gzip.BestSpeed + 1 + } + return level - gzip.BestSpeed +} + +func addLevelPool(level int) { + gzipWriterPools[poolIndex(level)] = &sync.Pool{ + New: func() interface{} { + // NewWriterLevel only returns error on a bad level, we are guaranteeing + // that this will be a valid level so it is okay to ignore the returned + // error. + w, _ := gzip.NewWriterLevel(nil, level) + return w + }, + } +} + +// GzipResponseWriter provides an http.ResponseWriter interface, which gzips +// bytes before writing them to the underlying response. This doesn't close the +// writers, so don't forget to do that. +// It can be configured to skip response smaller than minSize. +type GzipResponseWriter struct { + http.ResponseWriter + index int // Index for gzipWriterPools. + gw *gzip.Writer + + code int // Saves the WriteHeader value. + + minSize int // Specifed the minimum response size to gzip. If the response length is bigger than this value, it is compressed. + buf []byte // Holds the first part of the write before reaching the minSize or the end of the write. + + contentTypes []string // Only compress if the response is one of these content-types. All are accepted if empty. +} + +type GzipResponseWriterWithCloseNotify struct { + *GzipResponseWriter +} + +func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool { + return w.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +// Write appends data to the gzip writer. +func (w *GzipResponseWriter) Write(b []byte) (int, error) { + // If content type is not set. + if _, ok := w.Header()[contentType]; !ok { + // It infer it from the uncompressed body. + w.Header().Set(contentType, http.DetectContentType(b)) + } + + // GZIP responseWriter is initialized. Use the GZIP responseWriter. + if w.gw != nil { + n, err := w.gw.Write(b) + return n, err + } + + // Save the write into a buffer for later use in GZIP responseWriter (if content is long enough) or at close with regular responseWriter. + // On the first write, w.buf changes from nil to a valid slice + w.buf = append(w.buf, b...) + + // If the global writes are bigger than the minSize and we're about to write + // a response containing a content type we want to handle, enable + // compression. + if len(w.buf) >= w.minSize && handleContentType(w.contentTypes, w) && w.Header().Get(contentEncoding) == "" { + err := w.startGzip() + if err != nil { + return 0, err + } + } + + return len(b), nil +} + +// startGzip initialize any GZIP specific informations. +func (w *GzipResponseWriter) startGzip() error { + + // Set the GZIP header. + w.Header().Set(contentEncoding, "gzip") + + // if the Content-Length is already set, then calls to Write on gzip + // will fail to set the Content-Length header since its already set + // See: https://github.com/golang/go/issues/14975. + w.Header().Del(contentLength) + + // Write the header to gzip response. + if w.code != 0 { + w.ResponseWriter.WriteHeader(w.code) + } + + // Initialize the GZIP response. + w.init() + + // Flush the buffer into the gzip response. + n, err := w.gw.Write(w.buf) + + // This should never happen (per io.Writer docs), but if the write didn't + // accept the entire buffer but returned no specific error, we have no clue + // what's going on, so abort just to be safe. + if err == nil && n < len(w.buf) { + return io.ErrShortWrite + } + + w.buf = nil + return err +} + +// WriteHeader just saves the response code until close or GZIP effective writes. +func (w *GzipResponseWriter) WriteHeader(code int) { + if w.code == 0 { + w.code = code + } +} + +// init graps a new gzip writer from the gzipWriterPool and writes the correct +// content encoding header. +func (w *GzipResponseWriter) init() { + // Bytes written during ServeHTTP are redirected to this gzip writer + // before being written to the underlying response. + gzw := gzipWriterPools[w.index].Get().(*gzip.Writer) + gzw.Reset(w.ResponseWriter) + w.gw = gzw +} + +// Close will close the gzip.Writer and will put it back in the gzipWriterPool. +func (w *GzipResponseWriter) Close() error { + if w.gw == nil { + // Gzip not trigged yet, write out regular response. + if w.code != 0 { + w.ResponseWriter.WriteHeader(w.code) + } + if w.buf != nil { + _, writeErr := w.ResponseWriter.Write(w.buf) + // Returns the error if any at write. + if writeErr != nil { + return fmt.Errorf("gziphandler: write to regular responseWriter at close gets error: %q", writeErr.Error()) + } + } + return nil + } + + err := w.gw.Close() + gzipWriterPools[w.index].Put(w.gw) + w.gw = nil + return err +} + +// Flush flushes the underlying *gzip.Writer and then the underlying +// http.ResponseWriter if it is an http.Flusher. This makes GzipResponseWriter +// an http.Flusher. +func (w *GzipResponseWriter) Flush() { + if w.gw == nil { + // Only flush once startGzip has been called. + // + // Flush is thus a no-op until the written body + // exceeds minSize. + return + } + + w.gw.Flush() + + if fw, ok := w.ResponseWriter.(http.Flusher); ok { + fw.Flush() + } +} + +// Hijack implements http.Hijacker. If the underlying ResponseWriter is a +// Hijacker, its Hijack method is returned. Otherwise an error is returned. +func (w *GzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + if hj, ok := w.ResponseWriter.(http.Hijacker); ok { + return hj.Hijack() + } + return nil, nil, fmt.Errorf("http.Hijacker interface is not supported") +} + +// verify Hijacker interface implementation +var _ http.Hijacker = &GzipResponseWriter{} + +// MustNewGzipLevelHandler behaves just like NewGzipLevelHandler except that in +// an error case it panics rather than returning an error. +func MustNewGzipLevelHandler(level int) func(http.Handler) http.Handler { + wrap, err := NewGzipLevelHandler(level) + if err != nil { + panic(err) + } + return wrap +} + +// NewGzipLevelHandler returns a wrapper function (often known as middleware) +// which can be used to wrap an HTTP handler to transparently gzip the response +// body if the client supports it (via the Accept-Encoding header). Responses will +// be encoded at the given gzip compression level. An error will be returned only +// if an invalid gzip compression level is given, so if one can ensure the level +// is valid, the returned error can be safely ignored. +func NewGzipLevelHandler(level int) (func(http.Handler) http.Handler, error) { + return NewGzipLevelAndMinSize(level, DefaultMinSize) +} + +// NewGzipLevelAndMinSize behave as NewGzipLevelHandler except it let the caller +// specify the minimum size before compression. +func NewGzipLevelAndMinSize(level, minSize int) (func(http.Handler) http.Handler, error) { + return GzipHandlerWithOpts(CompressionLevel(level), MinSize(minSize)) +} + +func GzipHandlerWithOpts(opts ...option) (func(http.Handler) http.Handler, error) { + c := &config{ + level: gzip.DefaultCompression, + minSize: DefaultMinSize, + } + + for _, o := range opts { + o(c) + } + + if err := c.validate(); err != nil { + return nil, err + } + + return func(h http.Handler) http.Handler { + index := poolIndex(c.level) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add(vary, acceptEncoding) + if acceptsGzip(r) { + gw := &GzipResponseWriter{ + ResponseWriter: w, + index: index, + minSize: c.minSize, + contentTypes: c.contentTypes, + } + defer gw.Close() + + if _, ok := w.(http.CloseNotifier); ok { + gwcn := GzipResponseWriterWithCloseNotify{gw} + h.ServeHTTP(gwcn, r) + } else { + h.ServeHTTP(gw, r) + } + + } else { + h.ServeHTTP(w, r) + } + }) + }, nil +} + +// Used for functional configuration. +type config struct { + minSize int + level int + contentTypes []string +} + +func (c *config) validate() error { + if c.level != gzip.DefaultCompression && (c.level < gzip.BestSpeed || c.level > gzip.BestCompression) { + return fmt.Errorf("invalid compression level requested: %d", c.level) + } + + if c.minSize < 0 { + return fmt.Errorf("minimum size must be more than zero") + } + + return nil +} + +type option func(c *config) + +func MinSize(size int) option { + return func(c *config) { + c.minSize = size + } +} + +func CompressionLevel(level int) option { + return func(c *config) { + c.level = level + } +} + +func ContentTypes(types []string) option { + return func(c *config) { + c.contentTypes = []string{} + for _, v := range types { + c.contentTypes = append(c.contentTypes, strings.ToLower(v)) + } + } +} + +// GzipHandler wraps an HTTP handler, to transparently gzip the response body if +// the client supports it (via the Accept-Encoding header). This will compress at +// the default compression level. +func GzipHandler(h http.Handler) http.Handler { + wrapper, _ := NewGzipLevelHandler(gzip.DefaultCompression) + return wrapper(h) +} + +// acceptsGzip returns true if the given HTTP request indicates that it will +// accept a gzipped response. +func acceptsGzip(r *http.Request) bool { + acceptedEncodings, _ := parseEncodings(r.Header.Get(acceptEncoding)) + return acceptedEncodings["gzip"] > 0.0 +} + +// returns true if we've been configured to compress the specific content type. +func handleContentType(contentTypes []string, w http.ResponseWriter) bool { + // If contentTypes is empty we handle all content types. + if len(contentTypes) == 0 { + return true + } + + ct := strings.ToLower(w.Header().Get(contentType)) + for _, c := range contentTypes { + if c == ct { + return true + } + } + + return false +} + +// parseEncodings attempts to parse a list of codings, per RFC 2616, as might +// appear in an Accept-Encoding header. It returns a map of content-codings to +// quality values, and an error containing the errors encountered. It's probably +// safe to ignore those, because silently ignoring errors is how the internet +// works. +// +// See: http://tools.ietf.org/html/rfc2616#section-14.3. +func parseEncodings(s string) (codings, error) { + c := make(codings) + var e []string + + for _, ss := range strings.Split(s, ",") { + coding, qvalue, err := parseCoding(ss) + + if err != nil { + e = append(e, err.Error()) + } else { + c[coding] = qvalue + } + } + + // TODO (adammck): Use a proper multi-error struct, so the individual errors + // can be extracted if anyone cares. + if len(e) > 0 { + return c, fmt.Errorf("errors while parsing encodings: %s", strings.Join(e, ", ")) + } + + return c, nil +} + +// parseCoding parses a single conding (content-coding with an optional qvalue), +// as might appear in an Accept-Encoding header. It attempts to forgive minor +// formatting errors. +func parseCoding(s string) (coding string, qvalue float64, err error) { + for n, part := range strings.Split(s, ";") { + part = strings.TrimSpace(part) + qvalue = DefaultQValue + + if n == 0 { + coding = strings.ToLower(part) + } else if strings.HasPrefix(part, "q=") { + qvalue, err = strconv.ParseFloat(strings.TrimPrefix(part, "q="), 64) + + if qvalue < 0.0 { + qvalue = 0.0 + } else if qvalue > 1.0 { + qvalue = 1.0 + } + } + } + + if coding == "" { + err = fmt.Errorf("empty content-coding") + } + + return +} diff --git a/vendor/github.com/NYTimes/gziphandler/gzip_go18.go b/vendor/github.com/NYTimes/gziphandler/gzip_go18.go new file mode 100644 index 0000000..fa9665b --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/gzip_go18.go @@ -0,0 +1,43 @@ +// +build go1.8 + +package gziphandler + +import "net/http" + +// Push initiates an HTTP/2 server push. +// Push returns ErrNotSupported if the client has disabled push or if push +// is not supported on the underlying connection. +func (w *GzipResponseWriter) Push(target string, opts *http.PushOptions) error { + pusher, ok := w.ResponseWriter.(http.Pusher) + if ok && pusher != nil { + return pusher.Push(target, setAcceptEncodingForPushOptions(opts)) + } + return http.ErrNotSupported +} + +// setAcceptEncodingForPushOptions sets "Accept-Encoding" : "gzip" for PushOptions without overriding existing headers. +func setAcceptEncodingForPushOptions(opts *http.PushOptions) *http.PushOptions { + + if opts == nil { + opts = &http.PushOptions{ + Header: http.Header{ + acceptEncoding: []string{"gzip"}, + }, + } + return opts + } + + if opts.Header == nil { + opts.Header = http.Header{ + acceptEncoding: []string{"gzip"}, + } + return opts + } + + if encoding := opts.Header.Get(acceptEncoding); encoding == "" { + opts.Header.Add(acceptEncoding, "gzip") + return opts + } + + return opts +} diff --git a/vendor/github.com/SAP/go-hdb/LICENSE b/vendor/github.com/SAP/go-hdb/LICENSE new file mode 100644 index 0000000..ad410e1 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/SAP/go-hdb/NOTICE b/vendor/github.com/SAP/go-hdb/NOTICE new file mode 100644 index 0000000..de5f2ea --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/NOTICE @@ -0,0 +1,5 @@ +SAP HANA Database driver for the Go Programming Language +Copyright 2014 SAP SE + +This product includes software developed at +SAP SE (http://www.sap.com). \ No newline at end of file diff --git a/vendor/github.com/SAP/go-hdb/driver/bytes.go b/vendor/github.com/SAP/go-hdb/driver/bytes.go new file mode 100644 index 0000000..1bb77bf --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/bytes.go @@ -0,0 +1,43 @@ +/* +Copyright 2017 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "database/sql/driver" +) + +// NullBytes represents an []byte that may be null. +// NullBytes implements the Scanner interface so +// it can be used as a scan destination, similar to NullString. +type NullBytes struct { + Bytes []byte + Valid bool // Valid is true if Bytes is not NULL +} + +// Scan implements the Scanner interface. +func (n *NullBytes) Scan(value interface{}) error { + n.Bytes, n.Valid = value.([]byte) + return nil +} + +// Value implements the driver Valuer interface. +func (n NullBytes) Value() (driver.Value, error) { + if !n.Valid { + return nil, nil + } + return n.Bytes, nil +} diff --git a/vendor/github.com/SAP/go-hdb/driver/connector.go b/vendor/github.com/SAP/go-hdb/driver/connector.go new file mode 100644 index 0000000..9e4b939 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/connector.go @@ -0,0 +1,287 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "context" + "crypto/tls" + "crypto/x509" + "database/sql/driver" + "fmt" + "io/ioutil" + "net/url" + "strconv" + "sync" +) + +/* +A Connector represents a hdb driver in a fixed configuration. +A Connector can be passed to sql.OpenDB (starting from go 1.10) allowing users to bypass a string based data source name. +*/ +type Connector struct { + mu sync.RWMutex + host, username, password string + locale string + bufferSize, fetchSize, timeout int + tlsConfig *tls.Config +} + +func newConnector() *Connector { + return &Connector{ + fetchSize: DefaultFetchSize, + timeout: DefaultTimeout, + } +} + +// NewBasicAuthConnector creates a connector for basic authentication. +func NewBasicAuthConnector(host, username, password string) *Connector { + c := newConnector() + c.host = host + c.username = username + c.password = password + return c +} + +// NewDSNConnector creates a connector from a data source name. +func NewDSNConnector(dsn string) (*Connector, error) { + c := newConnector() + + url, err := url.Parse(dsn) + if err != nil { + return nil, err + } + + c.host = url.Host + + if url.User != nil { + c.username = url.User.Username() + c.password, _ = url.User.Password() + } + + var certPool *x509.CertPool + + for k, v := range url.Query() { + switch k { + + default: + return nil, fmt.Errorf("URL parameter %s is not supported", k) + + case DSNFetchSize: + if len(v) == 0 { + continue + } + fetchSize, err := strconv.Atoi(v[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse fetchSize: %s", v[0]) + } + if fetchSize < minFetchSize { + c.fetchSize = minFetchSize + } else { + c.fetchSize = fetchSize + } + + case DSNTimeout: + if len(v) == 0 { + continue + } + timeout, err := strconv.Atoi(v[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse timeout: %s", v[0]) + } + if timeout < minTimeout { + c.timeout = minTimeout + } else { + c.timeout = timeout + } + + case DSNLocale: + if len(v) == 0 { + continue + } + c.locale = v[0] + + case DSNTLSServerName: + if len(v) == 0 { + continue + } + if c.tlsConfig == nil { + c.tlsConfig = &tls.Config{} + } + c.tlsConfig.ServerName = v[0] + + case DSNTLSInsecureSkipVerify: + if len(v) == 0 { + continue + } + var err error + b := true + if v[0] != "" { + b, err = strconv.ParseBool(v[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse InsecureSkipVerify (bool): %s", v[0]) + } + } + if c.tlsConfig == nil { + c.tlsConfig = &tls.Config{} + } + c.tlsConfig.InsecureSkipVerify = b + + case DSNTLSRootCAFile: + for _, fn := range v { + rootPEM, err := ioutil.ReadFile(fn) + if err != nil { + return nil, err + } + if certPool == nil { + certPool = x509.NewCertPool() + } + if ok := certPool.AppendCertsFromPEM(rootPEM); !ok { + return nil, fmt.Errorf("failed to parse root certificate - filename: %s", fn) + } + } + if certPool != nil { + if c.tlsConfig == nil { + c.tlsConfig = &tls.Config{} + } + c.tlsConfig.RootCAs = certPool + } + } + } + return c, nil +} + +// Host returns the host of the connector. +func (c *Connector) Host() string { + return c.host +} + +// Username returns the username of the connector. +func (c *Connector) Username() string { + return c.username +} + +// Password returns the password of the connector. +func (c *Connector) Password() string { + return c.password +} + +// Locale returns the locale of the connector. +func (c *Connector) Locale() string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.locale +} + +/* +SetLocale sets the locale of the connector. + +For more information please see DSNLocale. +*/ +func (c *Connector) SetLocale(locale string) { + c.mu.Lock() + c.locale = locale + c.mu.Unlock() +} + +// FetchSize returns the fetchSize of the connector. +func (c *Connector) FetchSize() int { + c.mu.RLock() + defer c.mu.RUnlock() + return c.fetchSize +} + +/* +SetFetchSize sets the fetchSize of the connector. + +For more information please see DSNFetchSize. +*/ +func (c *Connector) SetFetchSize(fetchSize int) error { + c.mu.Lock() + defer c.mu.Unlock() + if fetchSize < minFetchSize { + fetchSize = minFetchSize + } + c.fetchSize = fetchSize + return nil +} + +// Timeout returns the timeout of the connector. +func (c *Connector) Timeout() int { + c.mu.RLock() + defer c.mu.RUnlock() + return c.timeout +} + +/* +SetTimeout sets the timeout of the connector. + +For more information please see DSNTimeout. +*/ +func (c *Connector) SetTimeout(timeout int) error { + c.mu.Lock() + defer c.mu.Unlock() + if timeout < minTimeout { + timeout = minTimeout + } + c.timeout = timeout + return nil +} + +// TLSConfig returns the TLS configuration of the connector. +func (c *Connector) TLSConfig() *tls.Config { + c.mu.RLock() + defer c.mu.RUnlock() + return c.tlsConfig +} + +// SetTLSConfig sets the TLS configuration of the connector. +func (c *Connector) SetTLSConfig(tlsConfig *tls.Config) error { + c.mu.Lock() + defer c.mu.Unlock() + c.tlsConfig = tlsConfig + return nil +} + +// BasicAuthDSN return the connector DSN for basic authentication. +func (c *Connector) BasicAuthDSN() string { + values := url.Values{} + if c.locale != "" { + values.Set(DSNLocale, c.locale) + } + if c.fetchSize != 0 { + values.Set(DSNFetchSize, fmt.Sprintf("%d", c.fetchSize)) + } + if c.timeout != 0 { + values.Set(DSNTimeout, fmt.Sprintf("%d", c.timeout)) + } + return (&url.URL{ + Scheme: DriverName, + User: url.UserPassword(c.username, c.password), + Host: c.host, + RawQuery: values.Encode(), + }).String() +} + +// Connect implements the database/sql/driver/Connector interface. +func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { + return newConn(ctx, c) +} + +// Driver implements the database/sql/driver/Connector interface. +func (c *Connector) Driver() driver.Driver { + return drv +} diff --git a/vendor/github.com/SAP/go-hdb/driver/converter.go b/vendor/github.com/SAP/go-hdb/driver/converter.go new file mode 100644 index 0000000..c181cc0 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/converter.go @@ -0,0 +1,363 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "database/sql/driver" + "errors" + "fmt" + "math" + "reflect" + "time" + + p "github.com/SAP/go-hdb/internal/protocol" +) + +const ( + minTinyint = 0 + maxTinyint = math.MaxUint8 + minSmallint = math.MinInt16 + maxSmallint = math.MaxInt16 + minInteger = math.MinInt32 + maxInteger = math.MaxInt32 + minBigint = math.MinInt64 + maxBigint = math.MaxInt64 + maxReal = math.MaxFloat32 + maxDouble = math.MaxFloat64 +) + +// ErrIntegerOutOfRange means that an integer exceeds the size of the hdb integer field. +var ErrIntegerOutOfRange = errors.New("integer out of range error") + +// ErrFloatOutOfRange means that a float exceeds the size of the hdb float field. +var ErrFloatOutOfRange = errors.New("float out of range error") + +var typeOfTime = reflect.TypeOf((*time.Time)(nil)).Elem() +var typeOfBytes = reflect.TypeOf((*[]byte)(nil)).Elem() + +func checkNamedValue(prmFieldSet *p.ParameterFieldSet, nv *driver.NamedValue) error { + idx := nv.Ordinal - 1 + + if idx >= prmFieldSet.NumInputField() { + return nil + } + + f := prmFieldSet.Field(idx) + dt := f.TypeCode().DataType() + + value, err := convertNamedValue(idx, f, dt, nv.Value) + + if err != nil { + return err + } + + nv.Value = value + return nil +} + +func convertNamedValue(idx int, f *p.ParameterField, dt p.DataType, v driver.Value) (driver.Value, error) { + var err error + + // let fields with own Value converter convert themselves first (e.g. NullInt64, ...) + if _, ok := v.(driver.Valuer); ok { + if v, err = driver.DefaultParameterConverter.ConvertValue(v); err != nil { + return nil, err + } + } + + switch dt { + + default: + return nil, fmt.Errorf("convert named value datatype error: %[1]d - %[1]s", dt) + + case p.DtTinyint: + return convertNvInteger(v, minTinyint, maxTinyint) + + case p.DtSmallint: + return convertNvInteger(v, minSmallint, maxSmallint) + + case p.DtInteger: + return convertNvInteger(v, minInteger, maxInteger) + + case p.DtBigint: + return convertNvInteger(v, minBigint, maxBigint) + + case p.DtReal: + return convertNvFloat(v, maxReal) + + case p.DtDouble: + return convertNvFloat(v, maxDouble) + + case p.DtTime: + return convertNvTime(v) + + case p.DtDecimal: + return convertNvDecimal(v) + + case p.DtString: + return convertNvString(v) + + case p.DtBytes: + return convertNvBytes(v) + + case p.DtLob: + return convertNvLob(idx, f, v) + + } +} + +// integer types +func convertNvInteger(v interface{}, min, max int64) (driver.Value, error) { + + if v == nil { + return v, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + + // bool is represented in HDB as tinyint + case reflect.Bool: + return rv.Bool(), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i64 := rv.Int() + if i64 > max || i64 < min { + return nil, ErrIntegerOutOfRange + } + return i64, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u64 := rv.Uint() + if u64 > uint64(max) { + return nil, ErrIntegerOutOfRange + } + return int64(u64), nil + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } + return convertNvInteger(rv.Elem().Interface(), min, max) + } + + return nil, fmt.Errorf("unsupported integer conversion type error %[1]T %[1]v", v) +} + +// float types +func convertNvFloat(v interface{}, max float64) (driver.Value, error) { + + if v == nil { + return v, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + + case reflect.Float32, reflect.Float64: + f64 := rv.Float() + if math.Abs(f64) > max { + return nil, ErrFloatOutOfRange + } + return f64, nil + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } + return convertNvFloat(rv.Elem().Interface(), max) + } + + return nil, fmt.Errorf("unsupported float conversion type error %[1]T %[1]v", v) +} + +// time +func convertNvTime(v interface{}) (driver.Value, error) { + + if v == nil { + return nil, nil + } + + switch v := v.(type) { + + case time.Time: + return v, nil + } + + rv := reflect.ValueOf(v) + + switch rv.Kind() { + + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } + return convertNvTime(rv.Elem().Interface()) + } + + if rv.Type().ConvertibleTo(typeOfTime) { + tv := rv.Convert(typeOfTime) + return tv.Interface().(time.Time), nil + } + + return nil, fmt.Errorf("unsupported time conversion type error %[1]T %[1]v", v) +} + +// decimal +func convertNvDecimal(v interface{}) (driver.Value, error) { + + if v == nil { + return nil, nil + } + + if v, ok := v.([]byte); ok { + return v, nil + } + + return nil, fmt.Errorf("unsupported decimal conversion type error %[1]T %[1]v", v) +} + +// string +func convertNvString(v interface{}) (driver.Value, error) { + + if v == nil { + return v, nil + } + + switch v := v.(type) { + + case string, []byte: + return v, nil + } + + rv := reflect.ValueOf(v) + + switch rv.Kind() { + + case reflect.String: + return rv.String(), nil + + case reflect.Slice: + if rv.Type() == typeOfBytes { + return rv.Bytes(), nil + } + + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } + return convertNvString(rv.Elem().Interface()) + } + + if rv.Type().ConvertibleTo(typeOfBytes) { + bv := rv.Convert(typeOfBytes) + return bv.Interface().([]byte), nil + } + + return nil, fmt.Errorf("unsupported character conversion type error %[1]T %[1]v", v) +} + +// bytes +func convertNvBytes(v interface{}) (driver.Value, error) { + + if v == nil { + return v, nil + } + + if v, ok := v.([]byte); ok { + return v, nil + } + + rv := reflect.ValueOf(v) + + switch rv.Kind() { + + case reflect.Slice: + if rv.Type() == typeOfBytes { + return rv.Bytes(), nil + } + + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } + return convertNvBytes(rv.Elem().Interface()) + } + + if rv.Type().ConvertibleTo(typeOfBytes) { + bv := rv.Convert(typeOfBytes) + return bv.Interface().([]byte), nil + } + + return nil, fmt.Errorf("unsupported bytes conversion type error %[1]T %[1]v", v) +} + +// Lob +func convertNvLob(idx int, f *p.ParameterField, v interface{}) (driver.Value, error) { + + if v == nil { + return v, nil + } + + switch v := v.(type) { + case Lob: + if v.rd == nil { + return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v) + } + f.SetLobReader(v.rd) + return fmt.Sprintf(" src/pkg/math/big/arith.go) +const ( + // Compute the size _S of a Word in bytes. + _m = ^big.Word(0) + _logS = _m>>8&1 + _m>>16&1 + _m>>32&1 + _S = 1 << _logS +) + +const ( + // http://en.wikipedia.org/wiki/Decimal128_floating-point_format + dec128Digits = 34 + dec128Bias = 6176 + dec128MinExp = -6176 + dec128MaxExp = 6111 +) + +const ( + decimalSize = 16 //number of bytes +) + +var natZero = big.NewInt(0) +var natOne = big.NewInt(1) +var natTen = big.NewInt(10) + +var nat = []*big.Int{ + natOne, //10^0 + natTen, //10^1 + big.NewInt(100), //10^2 + big.NewInt(1000), //10^3 + big.NewInt(10000), //10^4 + big.NewInt(100000), //10^5 + big.NewInt(1000000), //10^6 + big.NewInt(10000000), //10^7 + big.NewInt(100000000), //10^8 + big.NewInt(1000000000), //10^9 + big.NewInt(10000000000), //10^10 +} + +const lg10 = math.Ln10 / math.Ln2 // ~log2(10) + +var maxDecimal = new(big.Int).SetBytes([]byte{0x01, 0xED, 0x09, 0xBE, 0xAD, 0x87, 0xC0, 0x37, 0x8D, 0x8E, 0x63, 0xFF, 0xFF, 0xFF, 0xFF}) + +type decFlags byte + +const ( + dfNotExact decFlags = 1 << iota + dfOverflow + dfUnderflow +) + +// ErrDecimalOutOfRange means that a big.Rat exceeds the size of hdb decimal fields. +var ErrDecimalOutOfRange = errors.New("decimal out of range error") + +// big.Int free list +var bigIntFree = sync.Pool{ + New: func() interface{} { return new(big.Int) }, +} + +// big.Rat free list +var bigRatFree = sync.Pool{ + New: func() interface{} { return new(big.Rat) }, +} + +// A Decimal is the driver representation of a database decimal field value as big.Rat. +type Decimal big.Rat + +// Scan implements the database/sql/Scanner interface. +func (d *Decimal) Scan(src interface{}) error { + + b, ok := src.([]byte) + if !ok { + return fmt.Errorf("decimal: invalid data type %T", src) + } + + if len(b) != decimalSize { + return fmt.Errorf("decimal: invalid size %d of %v - %d expected", len(b), b, decimalSize) + } + + if (b[15] & 0x60) == 0x60 { + return fmt.Errorf("decimal: format (infinity, nan, ...) not supported : %v", b) + } + + v := (*big.Rat)(d) + p := v.Num() + q := v.Denom() + + neg, exp := decodeDecimal(b, p) + + switch { + case exp < 0: + q.Set(exp10(exp * -1)) + case exp == 0: + q.Set(natOne) + case exp > 0: + p.Mul(p, exp10(exp)) + q.Set(natOne) + } + + if neg { + v.Neg(v) + } + return nil +} + +// Value implements the database/sql/Valuer interface. +func (d Decimal) Value() (driver.Value, error) { + m := bigIntFree.Get().(*big.Int) + neg, exp, df := convertRatToDecimal((*big.Rat)(&d), m, dec128Digits, dec128MinExp, dec128MaxExp) + + var v driver.Value + var err error + + switch { + default: + v, err = encodeDecimal(m, neg, exp) + case df&dfUnderflow != 0: // set to zero + m.Set(natZero) + v, err = encodeDecimal(m, false, 0) + case df&dfOverflow != 0: + err = ErrDecimalOutOfRange + } + + // performance (avoid expensive defer) + bigIntFree.Put(m) + + return v, err +} + +func convertRatToDecimal(x *big.Rat, m *big.Int, digits, minExp, maxExp int) (bool, int, decFlags) { + + neg := x.Sign() < 0 //store sign + + if x.Num().Cmp(natZero) == 0 { // zero + m.Set(natZero) + return neg, 0, 0 + } + + c := bigRatFree.Get().(*big.Rat).Abs(x) // copy && abs + a := c.Num() + b := c.Denom() + + exp, shift := 0, 0 + + if c.IsInt() { + exp = digits10(a) - 1 + } else { + shift = digits10(a) - digits10(b) + switch { + case shift < 0: + a.Mul(a, exp10(shift*-1)) + case shift > 0: + b.Mul(b, exp10(shift)) + } + if a.Cmp(b) == -1 { + exp = shift - 1 + } else { + exp = shift + } + } + + var df decFlags + + switch { + default: + exp = max(exp-digits+1, minExp) + case exp < minExp: + df |= dfUnderflow + exp = exp - digits + 1 + } + + if exp > maxExp { + df |= dfOverflow + } + + shift = exp - shift + switch { + case shift < 0: + a.Mul(a, exp10(shift*-1)) + case exp > 0: + b.Mul(b, exp10(shift)) + } + + m.QuoRem(a, b, a) // reuse a as rest + if a.Cmp(natZero) != 0 { + // round (business >= 0.5 up) + df |= dfNotExact + if a.Add(a, a).Cmp(b) >= 0 { + m.Add(m, natOne) + if m.Cmp(exp10(digits)) == 0 { + shift := min(digits, maxExp-exp) + if shift < 1 { // overflow -> shift one at minimum + df |= dfOverflow + shift = 1 + } + m.Set(exp10(digits - shift)) + exp += shift + } + } + } + + // norm + for exp < maxExp { + a.QuoRem(m, natTen, b) // reuse a, b + if b.Cmp(natZero) != 0 { + break + } + m.Set(a) + exp++ + } + + // performance (avoid expensive defer) + bigRatFree.Put(c) + + return neg, exp, df +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +// performance: tested with reference work variable +// - but int.Set is expensive, so let's live with big.Int creation for n >= len(nat) +func exp10(n int) *big.Int { + if n < len(nat) { + return nat[n] + } + r := big.NewInt(int64(n)) + return r.Exp(natTen, r, nil) +} + +func digits10(p *big.Int) int { + k := p.BitLen() // 2^k <= p < 2^(k+1) - 1 + //i := int(float64(k) / lg10) //minimal digits base 10 + //i := int(float64(k) / lg10) //minimal digits base 10 + i := k * 100 / 332 + if i < 1 { + i = 1 + } + + for ; ; i++ { + if p.Cmp(exp10(i)) < 0 { + return i + } + } +} + +func decodeDecimal(b []byte, m *big.Int) (bool, int) { + + neg := (b[15] & 0x80) != 0 + exp := int((((uint16(b[15])<<8)|uint16(b[14]))<<1)>>2) - dec128Bias + + b14 := b[14] // save b[14] + b[14] &= 0x01 // keep the mantissa bit (rest: sign and exp) + + //most significand byte + msb := 14 + for msb > 0 { + if b[msb] != 0 { + break + } + msb-- + } + + //calc number of words + numWords := (msb / _S) + 1 + w := make([]big.Word, numWords) + + k := numWords - 1 + d := big.Word(0) + for i := msb; i >= 0; i-- { + d |= big.Word(b[i]) + if k*_S == i { + w[k] = d + k-- + d = 0 + } + d <<= 8 + } + b[14] = b14 // restore b[14] + m.SetBits(w) + return neg, exp +} + +func encodeDecimal(m *big.Int, neg bool, exp int) (driver.Value, error) { + + b := make([]byte, decimalSize) + + // little endian bigint words (significand) -> little endian db decimal format + j := 0 + for _, d := range m.Bits() { + for i := 0; i < 8; i++ { + b[j] = byte(d) + d >>= 8 + j++ + } + } + + exp += dec128Bias + b[14] |= (byte(exp) << 1) + b[15] = byte(uint16(exp) >> 7) + + if neg { + b[15] |= 0x80 + } + + return b, nil +} + +// NullDecimal represents an Decimal that may be null. +// NullDecimal implements the Scanner interface so +// it can be used as a scan destination, similar to NullString. +type NullDecimal struct { + Decimal *Decimal + Valid bool // Valid is true if Decimal is not NULL +} + +// Scan implements the Scanner interface. +func (n *NullDecimal) Scan(value interface{}) error { + var b []byte + + b, n.Valid = value.([]byte) + if !n.Valid { + return nil + } + if n.Decimal == nil { + return fmt.Errorf("invalid decimal value %v", n.Decimal) + } + return n.Decimal.Scan(b) +} + +// Value implements the driver Valuer interface. +func (n NullDecimal) Value() (driver.Value, error) { + if !n.Valid { + return nil, nil + } + if n.Decimal == nil { + return nil, fmt.Errorf("invalid decimal value %v", n.Decimal) + } + return n.Decimal.Value() +} diff --git a/vendor/github.com/SAP/go-hdb/driver/doc.go b/vendor/github.com/SAP/go-hdb/driver/doc.go new file mode 100644 index 0000000..d61bb5a --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package driver is a native Go SAP HANA driver implementation for the database/sql package. +package driver diff --git a/vendor/github.com/SAP/go-hdb/driver/driver.go b/vendor/github.com/SAP/go-hdb/driver/driver.go new file mode 100644 index 0000000..4ebc747 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/driver.go @@ -0,0 +1,542 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "io" + "reflect" + "time" + + "github.com/SAP/go-hdb/driver/sqltrace" + + p "github.com/SAP/go-hdb/internal/protocol" +) + +// DriverVersion is the version number of the hdb driver. +const DriverVersion = "0.12.0" + +// DriverName is the driver name to use with sql.Open for hdb databases. +const DriverName = "hdb" + +// Transaction isolation levels supported by hdb. +const ( + LevelReadCommitted = "READ COMMITTED" + LevelRepeatableRead = "REPEATABLE READ" + LevelSerializable = "SERIALIZABLE" +) + +// Access modes supported by hdb. +const ( + modeReadOnly = "READ ONLY" + modeReadWrite = "READ WRITE" +) + +// map sql isolation level to hdb isolation level. +var isolationLevel = map[driver.IsolationLevel]string{ + driver.IsolationLevel(sql.LevelDefault): LevelReadCommitted, + driver.IsolationLevel(sql.LevelReadCommitted): LevelReadCommitted, + driver.IsolationLevel(sql.LevelRepeatableRead): LevelRepeatableRead, + driver.IsolationLevel(sql.LevelSerializable): LevelSerializable, +} + +// map sql read only flag to hdb access mode. +var readOnly = map[bool]string{ + true: modeReadOnly, + false: modeReadWrite, +} + +// ErrUnsupportedIsolationLevel is the error raised if a transaction is started with a not supported isolation level. +var ErrUnsupportedIsolationLevel = errors.New("Unsupported isolation level") + +// ErrNestedTransaction is the error raised if a tranasction is created within a transaction as this is not supported by hdb. +var ErrNestedTransaction = errors.New("Nested transactions are not supported") + +// needed for testing +const driverDataFormatVersion = 1 + +// queries +const ( + pingQuery = "select 1 from dummy" + isolationLevelStmt = "set transaction isolation level %s" + accessModeStmt = "set transaction %s" +) + +// bulk statement +const noFlush = "$nf" + +// NoFlush is to be used as parameter in bulk inserts. +var NoFlush = sql.Named(noFlush, nil) + +var drv = &hdbDrv{} + +func init() { + sql.Register(DriverName, drv) +} + +// driver + +// check if driver implements all required interfaces +var ( + _ driver.Driver = (*hdbDrv)(nil) +) + +type hdbDrv struct{} + +func (d *hdbDrv) Open(dsn string) (driver.Conn, error) { + connector, err := NewDSNConnector(dsn) + if err != nil { + return nil, err + } + return connector.Connect(context.Background()) +} + +// database connection + +// check if conn implements all required interfaces +var ( + _ driver.Conn = (*conn)(nil) + _ driver.ConnPrepareContext = (*conn)(nil) + _ driver.Pinger = (*conn)(nil) + _ driver.ConnBeginTx = (*conn)(nil) + _ driver.ExecerContext = (*conn)(nil) + //go 1.9 issue (ExecerContext is only called if Execer is implemented) + _ driver.Execer = (*conn)(nil) + _ driver.QueryerContext = (*conn)(nil) + //go 1.9 issue (QueryerContext is only called if Queryer is implemented) + // QueryContext is needed for stored procedures with table output parameters. + _ driver.Queryer = (*conn)(nil) + _ driver.NamedValueChecker = (*conn)(nil) +) + +type conn struct { + session *p.Session +} + +func newConn(ctx context.Context, c *Connector) (driver.Conn, error) { + session, err := p.NewSession(ctx, c) + if err != nil { + return nil, err + } + return &conn{session: session}, nil +} + +func (c *conn) Prepare(query string) (driver.Stmt, error) { + panic("deprecated") +} + +func (c *conn) Close() error { + c.session.Close() + return nil +} + +func (c *conn) Begin() (driver.Tx, error) { + panic("deprecated") +} + +func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (tx driver.Tx, err error) { + + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + if c.session.InTx() { + return nil, ErrNestedTransaction + } + + level, ok := isolationLevel[opts.Isolation] + if !ok { + return nil, ErrUnsupportedIsolationLevel + } + + done := make(chan struct{}) + go func() { + // set isolation level + if _, err = c.ExecContext(ctx, fmt.Sprintf(isolationLevelStmt, level), nil); err != nil { + goto done + } + // set access mode + if _, err = c.ExecContext(ctx, fmt.Sprintf(accessModeStmt, readOnly[opts.ReadOnly]), nil); err != nil { + goto done + } + c.session.SetInTx(true) + tx = newTx(c.session) + done: + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return tx, err + } +} + +// Exec implements the database/sql/driver/Execer interface. +// delete after go 1.9 compatibility is given up. +func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { + panic("deprecated") +} + +// ExecContext implements the database/sql/driver/ExecerContext interface. +func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (r driver.Result, err error) { + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + if len(args) != 0 { + return nil, driver.ErrSkip //fast path not possible (prepare needed) + } + + sqltrace.Traceln(query) + + done := make(chan struct{}) + go func() { + r, err = c.session.ExecDirect(query) + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return r, err + } +} + +// Queryer implements the database/sql/driver/Queryer interface. +// delete after go 1.9 compatibility is given up. +func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { + panic("deprecated") +} + +func (c *conn) Ping(ctx context.Context) (err error) { + if c.session.IsBad() { + return driver.ErrBadConn + } + + done := make(chan struct{}) + go func() { + _, err = c.QueryContext(ctx, pingQuery, nil) + close(done) + }() + + select { + case <-ctx.Done(): + return ctx.Err() + case <-done: + return err + } +} + +// CheckNamedValue implements NamedValueChecker interface. +// implemented for conn: +// if querier or execer is called, sql checks parameters before in case of +// parameters the method can be 'skipped' and force the prepare path +// --> guarantee that a valid driver value is returned +// --> if not implemented, Lob need to have a pseudo Value method to return a valid driver value +func (c *conn) CheckNamedValue(nv *driver.NamedValue) error { + switch nv.Value.(type) { + case Lob, *Lob: + nv.Value = nil + } + return nil +} + +//transaction + +// check if tx implements all required interfaces +var ( + _ driver.Tx = (*tx)(nil) +) + +type tx struct { + session *p.Session +} + +func newTx(session *p.Session) *tx { + return &tx{ + session: session, + } +} + +func (t *tx) Commit() error { + if t.session.IsBad() { + return driver.ErrBadConn + } + + return t.session.Commit() +} + +func (t *tx) Rollback() error { + if t.session.IsBad() { + return driver.ErrBadConn + } + + return t.session.Rollback() +} + +//statement + +// check if stmt implements all required interfaces +var ( + _ driver.Stmt = (*stmt)(nil) + _ driver.StmtExecContext = (*stmt)(nil) + _ driver.StmtQueryContext = (*stmt)(nil) + _ driver.NamedValueChecker = (*stmt)(nil) +) + +type stmt struct { + qt p.QueryType + session *p.Session + query string + id uint64 + prmFieldSet *p.ParameterFieldSet + resultFieldSet *p.ResultFieldSet +} + +func newStmt(qt p.QueryType, session *p.Session, query string, id uint64, prmFieldSet *p.ParameterFieldSet, resultFieldSet *p.ResultFieldSet) (*stmt, error) { + return &stmt{qt: qt, session: session, query: query, id: id, prmFieldSet: prmFieldSet, resultFieldSet: resultFieldSet}, nil +} + +func (s *stmt) Close() error { + return s.session.DropStatementID(s.id) +} + +func (s *stmt) NumInput() int { + return s.prmFieldSet.NumInputField() +} + +func (s *stmt) Exec(args []driver.Value) (driver.Result, error) { + panic("deprecated") +} + +func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (r driver.Result, err error) { + if s.session.IsBad() { + return nil, driver.ErrBadConn + } + + numField := s.prmFieldSet.NumInputField() + if len(args) != numField { + return nil, fmt.Errorf("invalid number of arguments %d - %d expected", len(args), numField) + } + + sqltrace.Tracef("%s %v", s.query, args) + + done := make(chan struct{}) + go func() { + r, err = s.session.Exec(s.id, s.prmFieldSet, args) + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return r, err + } +} + +func (s *stmt) Query(args []driver.Value) (rows driver.Rows, err error) { + panic("deprecated") +} + +// Deprecated: see NamedValueChecker. +//func (s *stmt) ColumnConverter(idx int) driver.ValueConverter { +//} + +// CheckNamedValue implements NamedValueChecker interface. +func (s *stmt) CheckNamedValue(nv *driver.NamedValue) error { + if nv.Name == noFlush { + //... + + print("remove variable") + + return driver.ErrRemoveArgument + } + return checkNamedValue(s.prmFieldSet, nv) +} + +// driver.Rows drop-in replacement if driver Query or QueryRow is used for statements that doesn't return rows +var noColumns = []string{} +var noResult = new(noResultType) + +// check if noResultType implements all required interfaces +var ( + _ driver.Rows = (*noResultType)(nil) +) + +type noResultType struct{} + +func (r *noResultType) Columns() []string { return noColumns } +func (r *noResultType) Close() error { return nil } +func (r *noResultType) Next(dest []driver.Value) error { return io.EOF } + +// rows +type rows struct { +} + +// query result + +// check if queryResult implements all required interfaces +var ( + _ driver.Rows = (*queryResult)(nil) + _ driver.RowsColumnTypeDatabaseTypeName = (*queryResult)(nil) // go 1.8 + _ driver.RowsColumnTypeLength = (*queryResult)(nil) // go 1.8 + _ driver.RowsColumnTypeNullable = (*queryResult)(nil) // go 1.8 + _ driver.RowsColumnTypePrecisionScale = (*queryResult)(nil) // go 1.8 + _ driver.RowsColumnTypeScanType = (*queryResult)(nil) // go 1.8 +) + +type queryResult struct { + session *p.Session + id uint64 + resultFieldSet *p.ResultFieldSet + fieldValues *p.FieldValues + pos int + attrs p.PartAttributes + columns []string + lastErr error +} + +func newQueryResult(session *p.Session, id uint64, resultFieldSet *p.ResultFieldSet, fieldValues *p.FieldValues, attrs p.PartAttributes) (driver.Rows, error) { + columns := make([]string, resultFieldSet.NumField()) + for i := 0; i < len(columns); i++ { + columns[i] = resultFieldSet.Field(i).Name() + } + + return &queryResult{ + session: session, + id: id, + resultFieldSet: resultFieldSet, + fieldValues: fieldValues, + attrs: attrs, + columns: columns, + }, nil +} + +func (r *queryResult) Columns() []string { + return r.columns +} + +func (r *queryResult) Close() error { + // if lastError is set, attrs are nil + if r.lastErr != nil { + return r.lastErr + } + + if !r.attrs.ResultsetClosed() { + return r.session.CloseResultsetID(r.id) + } + return nil +} + +func (r *queryResult) Next(dest []driver.Value) error { + if r.session.IsBad() { + return driver.ErrBadConn + } + + if r.pos >= r.fieldValues.NumRow() { + if r.attrs.LastPacket() { + return io.EOF + } + + var err error + + if r.attrs, err = r.session.FetchNext(r.id, r.resultFieldSet, r.fieldValues); err != nil { + r.lastErr = err //fieldValues and attrs are nil + return err + } + + if r.attrs.NoRows() { + return io.EOF + } + + r.pos = 0 + + } + + r.fieldValues.Row(r.pos, dest) + r.pos++ + + return nil +} + +func (r *queryResult) ColumnTypeDatabaseTypeName(idx int) string { + return r.resultFieldSet.Field(idx).TypeCode().TypeName() +} + +func (r *queryResult) ColumnTypeLength(idx int) (int64, bool) { + return r.resultFieldSet.Field(idx).TypeLength() +} + +func (r *queryResult) ColumnTypePrecisionScale(idx int) (int64, int64, bool) { + return r.resultFieldSet.Field(idx).TypePrecisionScale() +} + +func (r *queryResult) ColumnTypeNullable(idx int) (bool, bool) { + return r.resultFieldSet.Field(idx).Nullable(), true +} + +var ( + scanTypeUnknown = reflect.TypeOf(new(interface{})).Elem() + scanTypeTinyint = reflect.TypeOf(uint8(0)) + scanTypeSmallint = reflect.TypeOf(int16(0)) + scanTypeInteger = reflect.TypeOf(int32(0)) + scanTypeBigint = reflect.TypeOf(int64(0)) + scanTypeReal = reflect.TypeOf(float32(0.0)) + scanTypeDouble = reflect.TypeOf(float64(0.0)) + scanTypeTime = reflect.TypeOf(time.Time{}) + scanTypeString = reflect.TypeOf(string("")) + scanTypeBytes = reflect.TypeOf([]byte{}) + scanTypeDecimal = reflect.TypeOf(Decimal{}) + scanTypeLob = reflect.TypeOf(Lob{}) +) + +func (r *queryResult) ColumnTypeScanType(idx int) reflect.Type { + switch r.resultFieldSet.Field(idx).TypeCode().DataType() { + default: + return scanTypeUnknown + case p.DtTinyint: + return scanTypeTinyint + case p.DtSmallint: + return scanTypeSmallint + case p.DtInteger: + return scanTypeInteger + case p.DtBigint: + return scanTypeBigint + case p.DtReal: + return scanTypeReal + case p.DtDouble: + return scanTypeDouble + case p.DtTime: + return scanTypeTime + case p.DtDecimal: + return scanTypeDecimal + case p.DtString: + return scanTypeString + case p.DtBytes: + return scanTypeBytes + case p.DtLob: + return scanTypeLob + } +} diff --git a/vendor/github.com/SAP/go-hdb/driver/driver_future.go b/vendor/github.com/SAP/go-hdb/driver/driver_future.go new file mode 100644 index 0000000..8ffd91a --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/driver_future.go @@ -0,0 +1,162 @@ +// +build future + +/* +Copyright 2018 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "context" + //"database/sql" + "database/sql/driver" + + "github.com/SAP/go-hdb/driver/sqltrace" + + p "github.com/SAP/go-hdb/internal/protocol" +) + +// database connection + +func (c *conn) PrepareContext(ctx context.Context, query string) (stmt driver.Stmt, err error) { + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + done := make(chan struct{}) + go func() { + var ( + qt p.QueryType + id uint64 + prmFieldSet *p.ParameterFieldSet + resultFieldSet *p.ResultFieldSet + ) + qt, id, prmFieldSet, resultFieldSet, err = c.session.Prepare(query) + if err != nil { + goto done + } + select { + default: + case <-ctx.Done(): + return + } + stmt, err = newStmt(qt, c.session, query, id, prmFieldSet, resultFieldSet) + done: + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return stmt, err + } +} + +// QueryContext implements the database/sql/driver/QueryerContext interface. +func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (rows driver.Rows, err error) { + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + if len(args) != 0 { + return nil, driver.ErrSkip //fast path not possible (prepare needed) + } + + // direct execution of call procedure + // - returns no parameter metadata (sps 82) but only field values + // --> let's take the 'prepare way' for stored procedures + // if checkCallProcedure(query) { + // return nil, driver.ErrSkip + // } + + sqltrace.Traceln(query) + + done := make(chan struct{}) + go func() { + var ( + id uint64 + resultFieldSet *p.ResultFieldSet + fieldValues *p.FieldValues + attributes p.PartAttributes + ) + id, resultFieldSet, fieldValues, attributes, err = c.session.QueryDirect(query) + if err != nil { + goto done + } + select { + default: + case <-ctx.Done(): + return + } + if id == 0 { // non select query + rows = noResult + } else { + rows, err = newQueryResult(c.session, id, resultFieldSet, fieldValues, attributes) + } + done: + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return rows, err + } +} + +//statement + +func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (rows driver.Rows, err error) { + + if s.session.IsBad() { + return nil, driver.ErrBadConn + } + + done := make(chan struct{}) + go func() { + rows, err = s.defaultQuery(ctx, args) + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return rows, err + } +} + +func (s *stmt) defaultQuery(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + + sqltrace.Tracef("%s %v", s.query, args) + + rid, values, attributes, err := s.session.Query(s.id, s.prmFieldSet, s.resultFieldSet, args) + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() + } + + if rid == 0 { // non select query + return noResult, nil + } + return newQueryResult(s.session, rid, s.resultFieldSet, values, attributes) +} diff --git a/vendor/github.com/SAP/go-hdb/driver/driver_go1.10.go b/vendor/github.com/SAP/go-hdb/driver/driver_go1.10.go new file mode 100644 index 0000000..b58113d --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/driver_go1.10.go @@ -0,0 +1,32 @@ +// +build go1.10 + +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "database/sql/driver" +) + +// driver + +// check if driver implements all required interfaces +var _ driver.DriverContext = (*hdbDrv)(nil) + +func (d *hdbDrv) OpenConnector(dsn string) (driver.Connector, error) { + return NewDSNConnector(dsn) +} diff --git a/vendor/github.com/SAP/go-hdb/driver/driver_legacy.go b/vendor/github.com/SAP/go-hdb/driver/driver_legacy.go new file mode 100644 index 0000000..3a8df4c --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/driver_legacy.go @@ -0,0 +1,507 @@ +// +build !future + +/* +Copyright 2018 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "context" + "database/sql/driver" + "encoding/binary" + "fmt" + "io" + "regexp" + "sync" + + "github.com/SAP/go-hdb/driver/sqltrace" + + p "github.com/SAP/go-hdb/internal/protocol" +) + +var reBulk = regexp.MustCompile("(?i)^(\\s)*(bulk +)(.*)") + +func checkBulkInsert(sql string) (string, bool) { + if reBulk.MatchString(sql) { + return reBulk.ReplaceAllString(sql, "${3}"), true + } + return sql, false +} + +var reCall = regexp.MustCompile("(?i)^(\\s)*(call +)(.*)") + +func checkCallProcedure(sql string) bool { + return reCall.MatchString(sql) +} + +// database connection + +func (c *conn) PrepareContext(ctx context.Context, query string) (stmt driver.Stmt, err error) { + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + done := make(chan struct{}) + go func() { + prepareQuery, bulkInsert := checkBulkInsert(query) + var ( + qt p.QueryType + id uint64 + prmFieldSet *p.ParameterFieldSet + resultFieldSet *p.ResultFieldSet + ) + qt, id, prmFieldSet, resultFieldSet, err = c.session.Prepare(prepareQuery) + if err != nil { + goto done + } + select { + default: + case <-ctx.Done(): + return + } + if bulkInsert { + stmt, err = newBulkInsertStmt(c.session, prepareQuery, id, prmFieldSet) + } else { + stmt, err = newStmt(qt, c.session, prepareQuery, id, prmFieldSet, resultFieldSet) + } + done: + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return stmt, err + } +} + +// QueryContext implements the database/sql/driver/QueryerContext interface. +func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (rows driver.Rows, err error) { + if c.session.IsBad() { + return nil, driver.ErrBadConn + } + + if len(args) != 0 { + return nil, driver.ErrSkip //fast path not possible (prepare needed) + } + + // direct execution of call procedure + // - returns no parameter metadata (sps 82) but only field values + // --> let's take the 'prepare way' for stored procedures + if checkCallProcedure(query) { + return nil, driver.ErrSkip + } + + sqltrace.Traceln(query) + + id, idx, ok := decodeTableQuery(query) + if ok { + r := procedureCallResultStore.get(id) + if r == nil { + return nil, fmt.Errorf("invalid procedure table query %s", query) + } + return r.tableRows(int(idx)) + } + + done := make(chan struct{}) + go func() { + var ( + id uint64 + resultFieldSet *p.ResultFieldSet + fieldValues *p.FieldValues + attributes p.PartAttributes + ) + id, resultFieldSet, fieldValues, attributes, err = c.session.QueryDirect(query) + if err != nil { + goto done + } + select { + default: + case <-ctx.Done(): + return + } + if id == 0 { // non select query + rows = noResult + } else { + rows, err = newQueryResult(c.session, id, resultFieldSet, fieldValues, attributes) + } + done: + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return rows, err + } +} + +//statement + +func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (rows driver.Rows, err error) { + + if s.session.IsBad() { + return nil, driver.ErrBadConn + } + + done := make(chan struct{}) + go func() { + switch s.qt { + default: + rows, err = s.defaultQuery(ctx, args) + case p.QtProcedureCall: + rows, err = s.procedureCall(ctx, args) + } + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return rows, err + } +} + +func (s *stmt) defaultQuery(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + + sqltrace.Tracef("%s %v", s.query, args) + + rid, values, attributes, err := s.session.Query(s.id, s.prmFieldSet, s.resultFieldSet, args) + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() + } + + if rid == 0 { // non select query + return noResult, nil + } + return newQueryResult(s.session, rid, s.resultFieldSet, values, attributes) +} + +func (s *stmt) procedureCall(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + + sqltrace.Tracef("%s %v", s.query, args) + + fieldValues, tableResults, err := s.session.Call(s.id, s.prmFieldSet, args) + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() + } + + return newProcedureCallResult(s.session, s.prmFieldSet, fieldValues, tableResults) +} + +// bulk insert statement + +// check if bulkInsertStmt implements all required interfaces +var ( + _ driver.Stmt = (*bulkInsertStmt)(nil) + _ driver.StmtExecContext = (*bulkInsertStmt)(nil) + _ driver.StmtQueryContext = (*bulkInsertStmt)(nil) + _ driver.NamedValueChecker = (*bulkInsertStmt)(nil) +) + +type bulkInsertStmt struct { + session *p.Session + query string + id uint64 + prmFieldSet *p.ParameterFieldSet + numArg int + args []driver.NamedValue +} + +func newBulkInsertStmt(session *p.Session, query string, id uint64, prmFieldSet *p.ParameterFieldSet) (*bulkInsertStmt, error) { + return &bulkInsertStmt{session: session, query: query, id: id, prmFieldSet: prmFieldSet, args: make([]driver.NamedValue, 0)}, nil +} + +func (s *bulkInsertStmt) Close() error { + return s.session.DropStatementID(s.id) +} + +func (s *bulkInsertStmt) NumInput() int { + return -1 +} + +func (s *bulkInsertStmt) Exec(args []driver.Value) (driver.Result, error) { + panic("deprecated") +} + +func (s *bulkInsertStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (r driver.Result, err error) { + + if s.session.IsBad() { + return nil, driver.ErrBadConn + } + + sqltrace.Tracef("%s %v", s.query, args) + + done := make(chan struct{}) + go func() { + if args == nil || len(args) == 0 { + r, err = s.execFlush() + } else { + r, err = s.execBuffer(args) + } + close(done) + }() + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return r, err + } +} + +func (s *bulkInsertStmt) execFlush() (driver.Result, error) { + + if s.numArg == 0 { + return driver.ResultNoRows, nil + } + + sqltrace.Traceln("execFlush") + + result, err := s.session.Exec(s.id, s.prmFieldSet, s.args) + s.args = s.args[:0] + s.numArg = 0 + return result, err +} + +func (s *bulkInsertStmt) execBuffer(args []driver.NamedValue) (driver.Result, error) { + + numField := s.prmFieldSet.NumInputField() + if len(args) != numField { + return nil, fmt.Errorf("invalid number of arguments %d - %d expected", len(args), numField) + } + + var result driver.Result = driver.ResultNoRows + var err error + + if s.numArg == maxSmallint { // TODO: check why bigArgument count does not work + result, err = s.execFlush() + } + + s.args = append(s.args, args...) + s.numArg++ + + return result, err +} + +func (s *bulkInsertStmt) Query(args []driver.Value) (driver.Rows, error) { + panic("deprecated") +} + +func (s *bulkInsertStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + return nil, fmt.Errorf("query not allowed in context of bulk insert statement %s", s.query) +} + +// Deprecated: see NamedValueChecker. +//func (s *bulkInsertStmt) ColumnConverter(idx int) driver.ValueConverter { +//} + +// CheckNamedValue implements NamedValueChecker interface. +func (s *bulkInsertStmt) CheckNamedValue(nv *driver.NamedValue) error { + return checkNamedValue(s.prmFieldSet, nv) +} + +//call result store +type callResultStore struct { + mu sync.RWMutex + store map[uint64]*procedureCallResult + cnt uint64 + free []uint64 +} + +func (s *callResultStore) get(k uint64) *procedureCallResult { + s.mu.RLock() + defer s.mu.RUnlock() + + if r, ok := s.store[k]; ok { + return r + } + return nil +} + +func (s *callResultStore) add(v *procedureCallResult) uint64 { + s.mu.Lock() + defer s.mu.Unlock() + + var k uint64 + + if s.free == nil || len(s.free) == 0 { + s.cnt++ + k = s.cnt + } else { + size := len(s.free) + k = s.free[size-1] + s.free = s.free[:size-1] + } + + if s.store == nil { + s.store = make(map[uint64]*procedureCallResult) + } + + s.store[k] = v + + return k +} + +func (s *callResultStore) del(k uint64) { + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.store, k) + + if s.free == nil { + s.free = []uint64{k} + } else { + s.free = append(s.free, k) + } +} + +var procedureCallResultStore = new(callResultStore) + +//procedure call result + +// check if procedureCallResult implements all required interfaces +var _ driver.Rows = (*procedureCallResult)(nil) + +type procedureCallResult struct { + id uint64 + session *p.Session + prmFieldSet *p.ParameterFieldSet + fieldValues *p.FieldValues + _tableRows []driver.Rows + columns []string + eof error +} + +func newProcedureCallResult(session *p.Session, prmFieldSet *p.ParameterFieldSet, fieldValues *p.FieldValues, tableResults []*p.TableResult) (driver.Rows, error) { + + fieldIdx := prmFieldSet.NumOutputField() + columns := make([]string, fieldIdx+len(tableResults)) + + for i := 0; i < fieldIdx; i++ { + columns[i] = prmFieldSet.OutputField(i).Name() + } + + tableRows := make([]driver.Rows, len(tableResults)) + for i, tableResult := range tableResults { + var err error + + if tableRows[i], err = newQueryResult(session, tableResult.ID(), tableResult.FieldSet(), tableResult.FieldValues(), tableResult.Attrs()); err != nil { + return nil, err + } + + columns[fieldIdx] = fmt.Sprintf("table %d", i) + + fieldIdx++ + + } + + result := &procedureCallResult{ + session: session, + prmFieldSet: prmFieldSet, + fieldValues: fieldValues, + _tableRows: tableRows, + columns: columns, + } + id := procedureCallResultStore.add(result) + result.id = id + return result, nil +} + +func (r *procedureCallResult) Columns() []string { + return r.columns +} + +func (r *procedureCallResult) Close() error { + procedureCallResultStore.del(r.id) + return nil +} + +func (r *procedureCallResult) Next(dest []driver.Value) error { + if r.session.IsBad() { + return driver.ErrBadConn + } + + if r.eof != nil { + return r.eof + } + + if r.fieldValues.NumRow() == 0 && len(r._tableRows) == 0 { + r.eof = io.EOF + return r.eof + } + + if r.fieldValues.NumRow() != 0 { + r.fieldValues.Row(0, dest) + } + + i := r.prmFieldSet.NumOutputField() + for j := range r._tableRows { + dest[i] = encodeTableQuery(r.id, uint64(j)) + i++ + } + + r.eof = io.EOF + return nil +} + +func (r *procedureCallResult) tableRows(idx int) (driver.Rows, error) { + if idx >= len(r._tableRows) { + return nil, fmt.Errorf("table row index %d exceeds maximun %d", idx, len(r._tableRows)-1) + } + return r._tableRows[idx], nil +} + +// helper +const tableQueryPrefix = "@tq" + +func encodeTableQuery(id, idx uint64) string { + start := len(tableQueryPrefix) + b := make([]byte, start+8+8) + copy(b, tableQueryPrefix) + binary.LittleEndian.PutUint64(b[start:start+8], id) + binary.LittleEndian.PutUint64(b[start+8:start+8+8], idx) + return string(b) +} + +func decodeTableQuery(query string) (uint64, uint64, bool) { + size := len(query) + start := len(tableQueryPrefix) + if size != start+8+8 { + return 0, 0, false + } + if query[:start] != tableQueryPrefix { + return 0, 0, false + } + id := binary.LittleEndian.Uint64([]byte(query[start : start+8])) + idx := binary.LittleEndian.Uint64([]byte(query[start+8 : start+8+8])) + return id, idx, true +} diff --git a/vendor/github.com/SAP/go-hdb/driver/dsn.go b/vendor/github.com/SAP/go-hdb/driver/dsn.go new file mode 100644 index 0000000..28518f8 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/dsn.go @@ -0,0 +1,64 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +// DSN parameters. For parameter client locale see http://help.sap.com/hana/SAP_HANA_SQL_Command_Network_Protocol_Reference_en.pdf. +const ( + DSNLocale = "locale" // Client locale as described in the protocol reference. + DSNTimeout = "timeout" // Driver side connection timeout in seconds. + DSNFetchSize = "fetchSize" // Maximum number of fetched records from database by database/sql/driver/Rows.Next(). +) + +/* +DSN TLS parameters. +For more information please see https://golang.org/pkg/crypto/tls/#Config. +For more flexibility in TLS configuration please see driver.Connector. +*/ +const ( + DSNTLSRootCAFile = "TLSRootCAFile" // Path,- filename to root certificate(s). + DSNTLSServerName = "TLSServerName" // ServerName to verify the hostname. + DSNTLSInsecureSkipVerify = "TLSInsecureSkipVerify" // Controls whether a client verifies the server's certificate chain and host name. +) + +// DSN default values. +const ( + DefaultTimeout = 300 // Default value connection timeout (300 seconds = 5 minutes). + DefaultFetchSize = 128 // Default value fetchSize. +) + +// DSN minimal values. +const ( + minTimeout = 0 // Minimal timeout value. + minFetchSize = 1 // Minimal fetchSize value. +) + +/* +DSN is here for the purposes of documentation only. A DSN string is an URL string with the following format + + "hdb://:@:" + +and optional query parameters (see DSN query parameters and DSN query default values). + +Example: + "hdb://myuser:mypassword@localhost:30015?timeout=60" + +Examples TLS connection: + "hdb://myuser:mypassword@localhost:39013?TLSRootCAFile=trust.pem" + "hdb://myuser:mypassword@localhost:39013?TLSRootCAFile=trust.pem&TLSServerName=hostname" + "hdb://myuser:mypassword@localhost:39013?TLSInsecureSkipVerify" +*/ +type DSN string diff --git a/vendor/github.com/SAP/go-hdb/driver/error.go b/vendor/github.com/SAP/go-hdb/driver/error.go new file mode 100644 index 0000000..4399a8b --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/error.go @@ -0,0 +1,39 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +// HDB error levels. +const ( + HdbWarning = 0 + HdbError = 1 + HdbFatalError = 2 +) + +// Error represents errors send by the database server. +type Error interface { + Error() string // Implements the golang error interface. + NumError() int // NumError returns the number of errors. + SetIdx(idx int) // Sets the error index in case number of errors are greater 1 in the range of 0 <= index < NumError(). + StmtNo() int // Returns the statement number of the error in multi statement contexts (e.g. bulk insert). + Code() int // Code return the database error code. + Position() int // Position returns the start position of erroneous sql statements sent to the database server. + Level() int // Level return one of the database server predefined error levels. + Text() string // Text return the error description sent from database server. + IsWarning() bool // IsWarning returns true if the HDB error level equals 0. + IsError() bool // IsError returns true if the HDB error level equals 1. + IsFatal() bool // IsFatal returns true if the HDB error level equals 2. +} diff --git a/vendor/github.com/SAP/go-hdb/driver/identifier.go b/vendor/github.com/SAP/go-hdb/driver/identifier.go new file mode 100644 index 0000000..3ea663b --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/identifier.go @@ -0,0 +1,49 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "crypto/rand" + "fmt" + "io" + "regexp" + "strconv" +) + +var reSimple = regexp.MustCompile("^[_A-Z][_#$A-Z0-9]*$") + +// Identifier in hdb SQL statements like schema or table name. +type Identifier string + +// RandomIdentifier returns a random Identifier prefixed by the prefix parameter. +// This function is used to generate database objects with random names for test and example code. +func RandomIdentifier(prefix string) Identifier { + b := make([]byte, 16) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + panic(err.Error()) // rand should never fail + } + return Identifier(fmt.Sprintf("%s%x", prefix, b)) +} + +// String implements Stringer interface. +func (i Identifier) String() string { + s := string(i) + if reSimple.MatchString(s) { + return s + } + return strconv.Quote(s) +} diff --git a/vendor/github.com/SAP/go-hdb/driver/lob.go b/vendor/github.com/SAP/go-hdb/driver/lob.go new file mode 100644 index 0000000..5a6fc48 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/lob.go @@ -0,0 +1,94 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "fmt" + "io" +) + +// A Lob is the driver representation of a database large object field. +// A Lob object uses an io.Reader object as source for writing content to a database lob field. +// A Lob object uses an io.Writer object as destination for reading content from a database lob field. +// A Lob can be created by contructor method NewLob with io.Reader and io.Writer as parameters or +// created by new, setting io.Reader and io.Writer by SetReader and SetWriter methods. +type Lob struct { + rd io.Reader + wr io.Writer +} + +// NewLob creates a new Lob instance with the io.Reader and io.Writer given as parameters. +func NewLob(rd io.Reader, wr io.Writer) *Lob { + return &Lob{rd: rd, wr: wr} +} + +// SetReader sets the io.Reader source for a lob field to be written to database +// and return *Lob, to enable simple call chaining. +func (l *Lob) SetReader(rd io.Reader) *Lob { + l.rd = rd + return l +} + +// SetWriter sets the io.Writer destination for a lob field to be read from database +// and return *Lob, to enable simple call chaining. +func (l *Lob) SetWriter(wr io.Writer) *Lob { + l.wr = wr + return l +} + +type writerSetter interface { + SetWriter(w io.Writer) error +} + +// Scan implements the database/sql/Scanner interface. +func (l *Lob) Scan(src interface{}) error { + + if l.wr == nil { + return fmt.Errorf("lob error: initial reader %[1]T %[1]v", l) + } + + ws, ok := src.(writerSetter) + if !ok { + return fmt.Errorf("lob: invalid scan type %T", src) + } + + if err := ws.SetWriter(l.wr); err != nil { + return err + } + return nil +} + +// NullLob represents an Lob that may be null. +// NullLob implements the Scanner interface so +// it can be used as a scan destination, similar to NullString. +type NullLob struct { + Lob *Lob + Valid bool // Valid is true if Lob is not NULL +} + +// Scan implements the database/sql/Scanner interface. +func (l *NullLob) Scan(src interface{}) error { + if src == nil { + l.Valid = false + return nil + } + if err := l.Lob.Scan(src); err != nil { + return err + } + l.Valid = true + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/driver/sqltrace/doc.go b/vendor/github.com/SAP/go-hdb/driver/sqltrace/doc.go new file mode 100644 index 0000000..ac23bbc --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/sqltrace/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package sqltrace implements driver sql trace functions. +package sqltrace diff --git a/vendor/github.com/SAP/go-hdb/driver/sqltrace/sqltrace.go b/vendor/github.com/SAP/go-hdb/driver/sqltrace/sqltrace.go new file mode 100644 index 0000000..50a2807 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/sqltrace/sqltrace.go @@ -0,0 +1,78 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sqltrace + +import ( + "flag" + "log" + "os" + "sync" +) + +type sqlTrace struct { + mu sync.RWMutex //protects field on + on bool + *log.Logger +} + +func newSQLTrace() *sqlTrace { + return &sqlTrace{ + Logger: log.New(os.Stdout, "hdb ", log.Ldate|log.Ltime|log.Lshortfile), + } +} + +var tracer = newSQLTrace() + +func init() { + flag.BoolVar(&tracer.on, "hdb.sqlTrace", false, "enabling hdb sql trace") +} + +// On returns if tracing methods output is active. +func On() bool { + tracer.mu.RLock() + on := tracer.on + tracer.mu.RUnlock() + return on +} + +// SetOn sets tracing methods output active or inactive. +func SetOn(on bool) { + tracer.mu.Lock() + tracer.on = on + tracer.mu.Unlock() +} + +// Trace calls trace logger Print method to print to the trace logger. +func Trace(v ...interface{}) { + if On() { + tracer.Print(v...) + } +} + +// Tracef calls trace logger Printf method to print to the trace logger. +func Tracef(format string, v ...interface{}) { + if On() { + tracer.Printf(format, v...) + } +} + +// Traceln calls trace logger Println method to print to the trace logger. +func Traceln(v ...interface{}) { + if On() { + tracer.Println(v...) + } +} diff --git a/vendor/github.com/SAP/go-hdb/driver/time.go b/vendor/github.com/SAP/go-hdb/driver/time.go new file mode 100644 index 0000000..3b3d8ac --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/driver/time.go @@ -0,0 +1,44 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "database/sql/driver" + "time" +) + +// NullTime represents an time.Time that may be null. +// NullTime implements the Scanner interface so +// it can be used as a scan destination, similar to NullString. +type NullTime struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL +} + +// Scan implements the Scanner interface. +func (n *NullTime) Scan(value interface{}) error { + n.Time, n.Valid = value.(time.Time) + return nil +} + +// Value implements the driver Valuer interface. +func (n NullTime) Value() (driver.Value, error) { + if !n.Valid { + return nil, nil + } + return n.Time, nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/bufio/bufio.go b/vendor/github.com/SAP/go-hdb/internal/bufio/bufio.go new file mode 100644 index 0000000..65026c9 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/bufio/bufio.go @@ -0,0 +1,414 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package bufio implements buffered I/O for database read and writes on basis of the standard Go bufio package. +package bufio + +import ( + "bufio" + "encoding/binary" + "io" + "math" + + "github.com/SAP/go-hdb/internal/unicode" + "golang.org/x/text/transform" +) + +// Reader is a bufio.Reader extended by methods needed for hdb protocol. +type Reader struct { + rd *bufio.Reader + err error + b [8]byte // scratch buffer (8 Bytes) + tr transform.Transformer +} + +// NewReader creates a new Reader instance. +func NewReader(r io.Reader) *Reader { + return &Reader{ + rd: bufio.NewReader(r), + tr: unicode.Cesu8ToUtf8Transformer, + } +} + +// NewReaderSize creates a new Reader instance with given size for bufio.Reader. +func NewReaderSize(r io.Reader, size int) *Reader { + return &Reader{ + rd: bufio.NewReaderSize(r, size), + tr: unicode.Cesu8ToUtf8Transformer, + } +} + +// GetError returns reader error +func (r *Reader) GetError() error { + err := r.err + r.err = nil + return err +} + +// Skip skips cnt bytes from reading. +func (r *Reader) Skip(cnt int) { + if r.err != nil { + return + } + _, r.err = r.rd.Discard(cnt) +} + +// ReadB reads and returns a byte. +func (r *Reader) ReadB() byte { // ReadB as sig differs from ReadByte (vet issues) + if r.err != nil { + return 0 + } + var b byte + b, r.err = r.rd.ReadByte() + return b +} + +// ReadFull implements io.ReadFull on Reader. +func (r *Reader) ReadFull(p []byte) { + if r.err != nil { + return + } + _, r.err = io.ReadFull(r.rd, p) +} + +// ReadBool reads and returns a boolean. +func (r *Reader) ReadBool() bool { + if r.err != nil { + return false + } + return !(r.ReadB() == 0) +} + +// ReadInt8 reads and returns an int8. +func (r *Reader) ReadInt8() int8 { + return int8(r.ReadB()) +} + +// ReadInt16 reads and returns an int16. +func (r *Reader) ReadInt16() int16 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:2]); r.err != nil { + return 0 + } + return int16(binary.LittleEndian.Uint16(r.b[:2])) +} + +// ReadUint16 reads and returns an uint16. +func (r *Reader) ReadUint16() uint16 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:2]); r.err != nil { + return 0 + } + return binary.LittleEndian.Uint16(r.b[:2]) +} + +// ReadInt32 reads and returns an int32. +func (r *Reader) ReadInt32() int32 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:4]); r.err != nil { + return 0 + } + return int32(binary.LittleEndian.Uint32(r.b[:4])) +} + +// ReadUint32 reads and returns an uint32. +func (r *Reader) ReadUint32() uint32 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:4]); r.err != nil { + return 0 + } + return binary.LittleEndian.Uint32(r.b[:4]) +} + +// ReadInt64 reads and returns an int64. +func (r *Reader) ReadInt64() int64 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:8]); r.err != nil { + return 0 + } + return int64(binary.LittleEndian.Uint64(r.b[:8])) +} + +// ReadUint64 reads and returns an uint64. +func (r *Reader) ReadUint64() uint64 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:8]); r.err != nil { + return 0 + } + return binary.LittleEndian.Uint64(r.b[:8]) +} + +// ReadFloat32 reads and returns a float32. +func (r *Reader) ReadFloat32() float32 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:4]); r.err != nil { + return 0 + } + bits := binary.LittleEndian.Uint32(r.b[:4]) + return math.Float32frombits(bits) +} + +// ReadFloat64 reads and returns a float64. +func (r *Reader) ReadFloat64() float64 { + if r.err != nil { + return 0 + } + if _, r.err = io.ReadFull(r.rd, r.b[:8]); r.err != nil { + return 0 + } + bits := binary.LittleEndian.Uint64(r.b[:8]) + return math.Float64frombits(bits) +} + +// ReadCesu8 reads a size CESU-8 encoded byte sequence and returns an UTF-8 byte slice. +func (r *Reader) ReadCesu8(size int) []byte { + if r.err != nil { + return nil + } + p := make([]byte, size) + if _, r.err = io.ReadFull(r.rd, p); r.err != nil { + return nil + } + r.tr.Reset() + var n int + if n, _, r.err = r.tr.Transform(p, p, true); r.err != nil { // inplace transformation + return nil + } + return p[:n] +} + +const writerBufferSize = 4096 + +// Writer is a bufio.Writer extended by methods needed for hdb protocol. +type Writer struct { + wr *bufio.Writer + err error + b []byte // scratch buffer (min 8 Bytes) + tr transform.Transformer +} + +// NewWriter creates a new Writer instance. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + wr: bufio.NewWriter(w), + b: make([]byte, writerBufferSize), + tr: unicode.Utf8ToCesu8Transformer, + } +} + +// NewWriterSize creates a new Writer instance with given size for bufio.Writer. +func NewWriterSize(w io.Writer, size int) *Writer { + return &Writer{ + wr: bufio.NewWriterSize(w, size), + b: make([]byte, writerBufferSize), + tr: unicode.Utf8ToCesu8Transformer, + } +} + +// Flush writes any buffered data to the underlying io.Writer. +func (w *Writer) Flush() error { + if w.err != nil { + return w.err + } + return w.wr.Flush() +} + +// WriteZeroes writes cnt zero byte values. +func (w *Writer) WriteZeroes(cnt int) { + if w.err != nil { + return + } + + // zero out scratch area + l := cnt + if l > len(w.b) { + l = len(w.b) + } + for i := 0; i < l; i++ { + w.b[i] = 0 + } + + for i := 0; i < cnt; { + j := cnt - i + if j > len(w.b) { + j = len(w.b) + } + n, _ := w.wr.Write(w.b[:j]) + i += n + } +} + +// Write writes the contents of p. +func (w *Writer) Write(p []byte) { + if w.err != nil { + return + } + w.wr.Write(p) +} + +// WriteB writes a byte. +func (w *Writer) WriteB(b byte) { // WriteB as sig differs from WriteByte (vet issues) + if w.err != nil { + return + } + w.wr.WriteByte(b) +} + +// WriteBool writes a boolean. +func (w *Writer) WriteBool(v bool) { + if w.err != nil { + return + } + if v { + w.wr.WriteByte(1) + } else { + w.wr.WriteByte(0) + } +} + +// WriteInt8 writes an int8. +func (w *Writer) WriteInt8(i int8) { + if w.err != nil { + return + } + w.wr.WriteByte(byte(i)) +} + +// WriteInt16 writes an int16. +func (w *Writer) WriteInt16(i int16) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint16(w.b[:2], uint16(i)) + w.wr.Write(w.b[:2]) +} + +// WriteUint16 writes an uint16. +func (w *Writer) WriteUint16(i uint16) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint16(w.b[:2], i) + w.wr.Write(w.b[:2]) +} + +// WriteInt32 writes an int32. +func (w *Writer) WriteInt32(i int32) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint32(w.b[:4], uint32(i)) + w.wr.Write(w.b[:4]) +} + +// WriteUint32 writes an uint32. +func (w *Writer) WriteUint32(i uint32) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint32(w.b[:4], i) + w.wr.Write(w.b[:4]) +} + +// WriteInt64 writes an int64. +func (w *Writer) WriteInt64(i int64) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint64(w.b[:8], uint64(i)) + w.wr.Write(w.b[:8]) +} + +// WriteUint64 writes an uint64. +func (w *Writer) WriteUint64(i uint64) { + if w.err != nil { + return + } + binary.LittleEndian.PutUint64(w.b[:8], i) + w.wr.Write(w.b[:8]) +} + +// WriteFloat32 writes a float32. +func (w *Writer) WriteFloat32(f float32) { + if w.err != nil { + return + } + bits := math.Float32bits(f) + binary.LittleEndian.PutUint32(w.b[:4], bits) + w.wr.Write(w.b[:4]) +} + +// WriteFloat64 writes a float64. +func (w *Writer) WriteFloat64(f float64) { + if w.err != nil { + return + } + bits := math.Float64bits(f) + binary.LittleEndian.PutUint64(w.b[:8], bits) + w.wr.Write(w.b[:8]) +} + +// WriteString writes a string. +func (w *Writer) WriteString(s string) { + if w.err != nil { + return + } + w.wr.WriteString(s) +} + +// WriteCesu8 writes an UTF-8 byte slice as CESU-8 and returns the CESU-8 bytes written. +func (w *Writer) WriteCesu8(p []byte) int { + if w.err != nil { + return 0 + } + w.tr.Reset() + cnt := 0 + i := 0 + for i < len(p) { + m, n, err := w.tr.Transform(w.b, p[i:], true) + if err != nil && err != transform.ErrShortDst { + w.err = err + return cnt + } + if m == 0 { + w.err = transform.ErrShortDst + return cnt + } + o, _ := w.wr.Write(w.b[:m]) + cnt += o + i += n + } + return cnt +} + +// WriteStringCesu8 is like WriteCesu8 with an UTF-8 string as parameter. +func (w *Writer) WriteStringCesu8(s string) int { + return w.WriteCesu8([]byte(s)) +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/clientid.go b/vendor/github.com/SAP/go-hdb/internal/protocol/clientid.go new file mode 100644 index 0000000..e3d5636 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/clientid.go @@ -0,0 +1,55 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "os" + "strconv" + "strings" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type clientID []byte + +func newClientID() clientID { + if h, err := os.Hostname(); err == nil { + return clientID(strings.Join([]string{strconv.Itoa(os.Getpid()), h}, "@")) + } + return clientID(strconv.Itoa(os.Getpid())) +} + +func (id clientID) kind() partKind { + return partKind(pkClientID) +} + +func (id clientID) size() (int, error) { + return len(id), nil +} + +func (id clientID) numArg() int { + return 1 +} + +func (id clientID) write(wr *bufio.Writer) error { + wr.Write(id) + + if trace { + outLogger.Printf("client id: %s", id) + } + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/command.go b/vendor/github.com/SAP/go-hdb/internal/protocol/command.go new file mode 100644 index 0000000..d96c161 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/command.go @@ -0,0 +1,47 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "github.com/SAP/go-hdb/internal/bufio" + "github.com/SAP/go-hdb/internal/unicode/cesu8" +) + +// cesu8 command +type command []byte + +func (c command) kind() partKind { + return pkCommand +} + +func (c command) size() (int, error) { + return cesu8.Size(c), nil +} + +func (c command) numArg() int { + return 1 +} + +func (c command) write(wr *bufio.Writer) error { + wr.WriteCesu8(c) + + if trace { + outLogger.Printf("command: %s", c) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption.go b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption.go new file mode 100644 index 0000000..f1c33fd --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption.go @@ -0,0 +1,57 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=connectOption + +type connectOption int8 + +const ( + coConnectionID connectOption = 1 + coCompleteArrayExecution connectOption = 2 + coClientLocale connectOption = 3 + coSupportsLargeBulkOperations connectOption = 4 + // duplicate in docu: coDataFormatVersion2 connectOption = 5 + // 6-9 reserved: do not use + coLargeNumberOfParameterSupport connectOption = 10 + coSystemID connectOption = 11 + // 12 reserved: do not use + coAbapVarcharMode connectOption = 13 + coSelectForUpdateSupported connectOption = 14 + coClientDistributionMode connectOption = 15 + coEngineDataFormatVersion connectOption = 16 + coDistributionProtocolVersion connectOption = 17 + coSplitBatchCommands connectOption = 18 + coUseTransactionFlagsOnly connectOption = 19 + //coRowAndColumnOptimizedFormat connectOption = 20 reserved: do not use + coIgnoreUnknownParts connectOption = 21 + coTableOutputParameter connectOption = 22 + coDataFormatVersion2 connectOption = 23 + coItabParameter connectOption = 24 + coDescribeTableOutputParameter connectOption = 25 + coColumnarResultset connectOption = 26 + coScrollablResultSet connectOption = 27 + coClientInfoNullValueSupported connectOption = 28 + coAssociatedConnectionID connectOption = 29 + coNoTransactionalPrepare connectOption = 30 + coFDAEnabled connectOption = 31 + coOSUser connectOption = 32 + coRowslotImageResult connectOption = 33 + coEndianess connectOption = 34 + // 35, 36 reserved: do not use + coImplicitLobStreaming connectOption = 37 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption_string.go new file mode 100644 index 0000000..27c7818 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoption_string.go @@ -0,0 +1,41 @@ +// Code generated by "stringer -type=connectOption"; DO NOT EDIT. + +package protocol + +import "strconv" + +const ( + _connectOption_name_0 = "coConnectionIDcoCompleteArrayExecutioncoClientLocalecoSupportsLargeBulkOperations" + _connectOption_name_1 = "coLargeNumberOfParameterSupportcoSystemID" + _connectOption_name_2 = "coAbapVarcharModecoSelectForUpdateSupportedcoClientDistributionModecoEngineDataFormatVersioncoDistributionProtocolVersioncoSplitBatchCommandscoUseTransactionFlagsOnly" + _connectOption_name_3 = "coIgnoreUnknownPartscoTableOutputParametercoDataFormatVersion2coItabParametercoDescribeTableOutputParametercoColumnarResultsetcoScrollablResultSetcoClientInfoNullValueSupportedcoAssociatedConnectionIDcoNoTransactionalPreparecoFDAEnabledcoOSUsercoRowslotImageResultcoEndianess" + _connectOption_name_4 = "coImplicitLobStreaming" +) + +var ( + _connectOption_index_0 = [...]uint8{0, 14, 38, 52, 81} + _connectOption_index_1 = [...]uint8{0, 31, 41} + _connectOption_index_2 = [...]uint8{0, 17, 43, 67, 92, 121, 141, 166} + _connectOption_index_3 = [...]uint16{0, 20, 42, 62, 77, 107, 126, 146, 176, 200, 224, 236, 244, 264, 275} +) + +func (i connectOption) String() string { + switch { + case 1 <= i && i <= 4: + i -= 1 + return _connectOption_name_0[_connectOption_index_0[i]:_connectOption_index_0[i+1]] + case 10 <= i && i <= 11: + i -= 10 + return _connectOption_name_1[_connectOption_index_1[i]:_connectOption_index_1[i+1]] + case 13 <= i && i <= 19: + i -= 13 + return _connectOption_name_2[_connectOption_index_2[i]:_connectOption_index_2[i+1]] + case 21 <= i && i <= 34: + i -= 21 + return _connectOption_name_3[_connectOption_index_3[i]:_connectOption_index_3[i+1]] + case i == 37: + return _connectOption_name_4 + default: + return "connectOption(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/connectoptions.go b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoptions.go new file mode 100644 index 0000000..32e959c --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/connectoptions.go @@ -0,0 +1,109 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +// data format version +const ( + dfvBaseline intType = 1 + dfvDoNotUse intType = 3 + dfvSPS06 intType = 4 //see docu + dfvBINTEXT intType = 6 +) + +// client distribution mode +const ( + cdmOff intType = 0 + cdmConnection = 1 + cdmStatement = 2 + cdmConnectionStatement = 3 +) + +// distribution protocol version +const ( + dpvBaseline = 0 + dpvClientHandlesStatementSequence = 1 +) + +type connectOptions struct { + po plainOptions + _numArg int +} + +func newConnectOptions() *connectOptions { + return &connectOptions{ + po: plainOptions{}, + } +} + +func (o *connectOptions) String() string { + m := make(map[connectOption]interface{}) + for k, v := range o.po { + m[connectOption(k)] = v + } + return fmt.Sprintf("%s", m) +} + +func (o *connectOptions) kind() partKind { + return pkConnectOptions +} + +func (o *connectOptions) size() (int, error) { + return o.po.size(), nil +} + +func (o *connectOptions) numArg() int { + return len(o.po) +} + +func (o *connectOptions) setNumArg(numArg int) { + o._numArg = numArg +} + +func (o *connectOptions) set(k connectOption, v interface{}) { + o.po[int8(k)] = v +} + +func (o *connectOptions) get(k connectOption) (interface{}, bool) { + v, ok := o.po[int8(k)] + return v, ok +} + +func (o *connectOptions) read(rd *bufio.Reader) error { + o.po.read(rd, o._numArg) + + if trace { + outLogger.Printf("connect options: %v", o) + } + + return rd.GetError() +} + +func (o *connectOptions) write(wr *bufio.Writer) error { + o.po.write(wr) + + if trace { + outLogger.Printf("connect options: %v", o) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/datatype.go b/vendor/github.com/SAP/go-hdb/internal/protocol/datatype.go new file mode 100644 index 0000000..4ae793f --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/datatype.go @@ -0,0 +1,38 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=DataType + +// DataType is the type definition for data types supported by this package. +type DataType byte + +// Data type constants. +const ( + DtUnknown DataType = iota // unknown data type + DtTinyint + DtSmallint + DtInteger + DtBigint + DtReal + DtDouble + DtDecimal + DtTime + DtString + DtBytes + DtLob +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/datatype_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/datatype_string.go new file mode 100644 index 0000000..0b356d3 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/datatype_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=DataType"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _DataType_name = "DtUnknownDtTinyintDtSmallintDtIntegerDtBigintDtRealDtDoubleDtDecimalDtTimeDtStringDtBytesDtLob" + +var _DataType_index = [...]uint8{0, 9, 18, 28, 37, 45, 51, 59, 68, 74, 82, 89, 94} + +func (i DataType) String() string { + if i >= DataType(len(_DataType_index)-1) { + return "DataType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _DataType_name[_DataType_index[i]:_DataType_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/doc.go b/vendor/github.com/SAP/go-hdb/internal/protocol/doc.go new file mode 100644 index 0000000..f23fe24 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package protocol implements the hdb command network protocol. +// +// http://help.sap.com/hana/SAP_HANA_SQL_Command_Network_Protocol_Reference_en.pdf +package protocol diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/endianess.go b/vendor/github.com/SAP/go-hdb/internal/protocol/endianess.go new file mode 100644 index 0000000..579c2a7 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/endianess.go @@ -0,0 +1,26 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=endianess + +type endianess int8 + +const ( + bigEndian endianess = 0 + littleEndian endianess = 1 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/endianess_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/endianess_string.go new file mode 100644 index 0000000..5f5c0c8 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/endianess_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=endianess"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _endianess_name = "bigEndianlittleEndian" + +var _endianess_index = [...]uint8{0, 9, 21} + +func (i endianess) String() string { + if i < 0 || i >= endianess(len(_endianess_index)-1) { + return "endianess(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _endianess_name[_endianess_index[i]:_endianess_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/error.go b/vendor/github.com/SAP/go-hdb/internal/protocol/error.go new file mode 100644 index 0000000..8f58e95 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/error.go @@ -0,0 +1,204 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + sqlStateSize = 5 + //bytes of fix length fields mod 8 + // - errorCode = 4, errorPosition = 4, errortextLength = 4, errorLevel = 1, sqlState = 5 => 18 bytes + // - 18 mod 8 = 2 + fixLength = 2 +) + +type sqlState [sqlStateSize]byte + +type hdbError struct { + errorCode int32 + errorPosition int32 + errorTextLength int32 + errorLevel errorLevel + sqlState sqlState + stmtNo int + errorText []byte +} + +// String implements the Stringer interface. +func (e *hdbError) String() string { + return fmt.Sprintf("errorCode %d, errorPosition %d, errorTextLength % d errorLevel %s, sqlState %s stmtNo %d errorText %s", + e.errorCode, + e.errorPosition, + e.errorTextLength, + e.errorLevel, + e.sqlState, + e.stmtNo, + e.errorText, + ) +} + +// Error implements the Error interface. +func (e *hdbError) Error() string { + if e.stmtNo != -1 { + return fmt.Sprintf("SQL %s %d - %s (statement no: %d)", e.errorLevel, e.errorCode, e.errorText, e.stmtNo) + } + return fmt.Sprintf("SQL %s %d - %s", e.errorLevel, e.errorCode, e.errorText) +} + +type hdbErrors struct { + errors []*hdbError + numArg int + idx int +} + +// String implements the Stringer interface. +func (e *hdbErrors) String() string { + return e.errors[e.idx].String() +} + +// Error implements the golang error interface. +func (e *hdbErrors) Error() string { + return e.errors[e.idx].Error() +} + +// NumError implements the driver.Error interface. +func (e *hdbErrors) NumError() int { + return e.numArg +} + +// SetIdx implements the driver.Error interface. +func (e *hdbErrors) SetIdx(idx int) { + switch { + case idx < 0: + e.idx = 0 + case idx >= e.numArg: + e.idx = e.numArg - 1 + default: + e.idx = idx + } +} + +// StmtNo implements the driver.Error interface. +func (e *hdbErrors) StmtNo() int { + return e.errors[e.idx].stmtNo +} + +// Code implements the driver.Error interface. +func (e *hdbErrors) Code() int { + return int(e.errors[e.idx].errorCode) +} + +// Position implements the driver.Error interface. +func (e *hdbErrors) Position() int { + return int(e.errors[e.idx].errorPosition) +} + +// Level implements the driver.Error interface. +func (e *hdbErrors) Level() int { + return int(e.errors[e.idx].errorLevel) +} + +// Text implements the driver.Error interface. +func (e *hdbErrors) Text() string { + return string(e.errors[e.idx].errorText) +} + +// IsWarning implements the driver.Error interface. +func (e *hdbErrors) IsWarning() bool { + return e.errors[e.idx].errorLevel == errorLevelWarning +} + +// IsError implements the driver.Error interface. +func (e *hdbErrors) IsError() bool { + return e.errors[e.idx].errorLevel == errorLevelError +} + +// IsFatal implements the driver.Error interface. +func (e *hdbErrors) IsFatal() bool { + return e.errors[e.idx].errorLevel == errorLevelFatalError +} + +func (e *hdbErrors) setStmtNo(idx, no int) { + if idx >= 0 && idx < e.numArg { + e.errors[idx].stmtNo = no + } +} + +func (e *hdbErrors) isWarnings() bool { + for _, _error := range e.errors { + if _error.errorLevel != errorLevelWarning { + return false + } + } + return true +} + +func (e *hdbErrors) kind() partKind { + return pkError +} + +func (e *hdbErrors) setNumArg(numArg int) { + e.numArg = numArg +} + +func (e *hdbErrors) read(rd *bufio.Reader) error { + e.idx = 0 // init error index + + if e.errors == nil || e.numArg > cap(e.errors) { + e.errors = make([]*hdbError, e.numArg) + } else { + e.errors = e.errors[:e.numArg] + } + + for i := 0; i < e.numArg; i++ { + _error := e.errors[i] + if _error == nil { + _error = new(hdbError) + e.errors[i] = _error + } + + _error.stmtNo = -1 + _error.errorCode = rd.ReadInt32() + _error.errorPosition = rd.ReadInt32() + _error.errorTextLength = rd.ReadInt32() + _error.errorLevel = errorLevel(rd.ReadInt8()) + rd.ReadFull(_error.sqlState[:]) + + // read error text as ASCII data as some errors return invalid CESU-8 characters + // e.g: SQL HdbError 7 - feature not supported: invalid character encoding: + // if e.errorText, err = rd.ReadCesu8(int(e.errorTextLength)); err != nil { + // return err + // } + _error.errorText = make([]byte, int(_error.errorTextLength)) + rd.ReadFull(_error.errorText) + + if trace { + outLogger.Printf("error %d: %s", i, _error) + } + + pad := padBytes(int(fixLength + _error.errorTextLength)) + if pad != 0 { + rd.Skip(pad) + } + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/errorlevel.go b/vendor/github.com/SAP/go-hdb/internal/protocol/errorlevel.go new file mode 100644 index 0000000..9abe620 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/errorlevel.go @@ -0,0 +1,40 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +// ErrorLevel send from database server. +type errorLevel int8 + +func (e errorLevel) String() string { + switch e { + case 0: + return "Warning" + case 1: + return "Error" + case 2: + return "Fatal Error" + default: + return "" + } +} + +// HDB error level constants. +const ( + errorLevelWarning errorLevel = 0 + errorLevelError errorLevel = 1 + errorLevelFatalError errorLevel = 2 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/fetchsize.go b/vendor/github.com/SAP/go-hdb/internal/protocol/fetchsize.go new file mode 100644 index 0000000..aa91e02 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/fetchsize.go @@ -0,0 +1,46 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "github.com/SAP/go-hdb/internal/bufio" +) + +//fetch size +type fetchsize int32 + +func (s fetchsize) kind() partKind { + return pkFetchSize +} + +func (s fetchsize) size() (int, error) { + return 4, nil +} + +func (s fetchsize) numArg() int { + return 1 +} + +func (s fetchsize) write(wr *bufio.Writer) error { + wr.WriteInt32(int32(s)) + + if trace { + outLogger.Printf("fetchsize: %d", s) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/field.go b/vendor/github.com/SAP/go-hdb/internal/protocol/field.go new file mode 100644 index 0000000..297a2d9 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/field.go @@ -0,0 +1,774 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "database/sql/driver" + "fmt" + "math" + "sort" + "time" + + "github.com/SAP/go-hdb/internal/bufio" + "github.com/SAP/go-hdb/internal/unicode/cesu8" +) + +var test uint32 + +const ( + realNullValue uint32 = ^uint32(0) + doubleNullValue uint64 = ^uint64(0) +) + +const noFieldName uint32 = 0xFFFFFFFF + +type uint32Slice []uint32 + +func (p uint32Slice) Len() int { return len(p) } +func (p uint32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p uint32Slice) sort() { sort.Sort(p) } + +type fieldNames map[uint32]string + +func newFieldNames() fieldNames { + return make(map[uint32]string) +} + +func (f fieldNames) addOffset(offset uint32) { + if offset != noFieldName { + f[offset] = "" + } +} + +func (f fieldNames) name(offset uint32) string { + if name, ok := f[offset]; ok { + return name + } + return "" +} + +func (f fieldNames) setName(offset uint32, name string) { + f[offset] = name +} + +func (f fieldNames) sortOffsets() []uint32 { + offsets := make([]uint32, 0, len(f)) + for k := range f { + offsets = append(offsets, k) + } + uint32Slice(offsets).sort() + return offsets +} + +// FieldValues contains rows read from database. +type FieldValues struct { + rows int + cols int + values []driver.Value +} + +func newFieldValues() *FieldValues { + return &FieldValues{} +} + +func (f *FieldValues) String() string { + return fmt.Sprintf("rows %d columns %d", f.rows, f.cols) +} + +func (f *FieldValues) resize(rows, cols int) { + f.rows, f.cols = rows, cols + f.values = make([]driver.Value, rows*cols) +} + +// NumRow returns the number of rows available in FieldValues. +func (f *FieldValues) NumRow() int { + return f.rows +} + +// Row fills the dest value slice with row data at index idx. +func (f *FieldValues) Row(idx int, dest []driver.Value) { + copy(dest, f.values[idx*f.cols:(idx+1)*f.cols]) +} + +const ( + tinyintFieldSize = 1 + smallintFieldSize = 2 + intFieldSize = 4 + bigintFieldSize = 8 + realFieldSize = 4 + doubleFieldSize = 8 + dateFieldSize = 4 + timeFieldSize = 4 + timestampFieldSize = dateFieldSize + timeFieldSize + longdateFieldSize = 8 + seconddateFieldSize = 8 + daydateFieldSize = 4 + secondtimeFieldSize = 4 + decimalFieldSize = 16 + lobInputDescriptorSize = 9 +) + +func fieldSize(tc TypeCode, arg driver.NamedValue) (int, error) { + v := arg.Value + + if v == nil { //HDB bug: secondtime null value --> see writeField + return 0, nil + } + + switch tc { + case tcTinyint: + return tinyintFieldSize, nil + case tcSmallint: + return smallintFieldSize, nil + case tcInteger: + return intFieldSize, nil + case tcBigint: + return bigintFieldSize, nil + case tcReal: + return realFieldSize, nil + case tcDouble: + return doubleFieldSize, nil + case tcDate: + return dateFieldSize, nil + case tcTime: + return timeFieldSize, nil + case tcTimestamp: + return timestampFieldSize, nil + case tcLongdate: + return longdateFieldSize, nil + case tcSeconddate: + return seconddateFieldSize, nil + case tcDaydate: + return daydateFieldSize, nil + case tcSecondtime: + return secondtimeFieldSize, nil + case tcDecimal: + return decimalFieldSize, nil + case tcChar, tcVarchar, tcString: + switch v := v.(type) { + case []byte: + return bytesSize(len(v)) + case string: + return bytesSize(len(v)) + default: + outLogger.Fatalf("data type %s mismatch %T", tc, v) + } + case tcNchar, tcNvarchar, tcNstring: + switch v := v.(type) { + case []byte: + return bytesSize(cesu8.Size(v)) + case string: + return bytesSize(cesu8.StringSize(v)) + default: + outLogger.Fatalf("data type %s mismatch %T", tc, v) + } + case tcBinary, tcVarbinary: + v, ok := v.([]byte) + if !ok { + outLogger.Fatalf("data type %s mismatch %T", tc, v) + } + return bytesSize(len(v)) + case tcBlob, tcClob, tcNclob: + return lobInputDescriptorSize, nil + } + outLogger.Fatalf("data type %s not implemented", tc) + return 0, nil +} + +func readField(session *Session, rd *bufio.Reader, tc TypeCode) (interface{}, error) { + + switch tc { + + case tcTinyint, tcSmallint, tcInteger, tcBigint: + + if !rd.ReadBool() { //null value + return nil, nil + } + + switch tc { + case tcTinyint: + return int64(rd.ReadB()), nil + case tcSmallint: + return int64(rd.ReadInt16()), nil + case tcInteger: + return int64(rd.ReadInt32()), nil + case tcBigint: + return rd.ReadInt64(), nil + } + + case tcReal: + v := rd.ReadUint32() + if v == realNullValue { + return nil, nil + } + return float64(math.Float32frombits(v)), nil + + case tcDouble: + v := rd.ReadUint64() + if v == doubleNullValue { + return nil, nil + } + return math.Float64frombits(v), nil + + case tcDate: + year, month, day, null := readDate(rd) + if null { + return nil, nil + } + return time.Date(year, month, day, 0, 0, 0, 0, time.UTC), nil + + // time read gives only seconds (cut), no milliseconds + case tcTime: + hour, minute, nanosecs, null := readTime(rd) + if null { + return nil, nil + } + return time.Date(1, 1, 1, hour, minute, 0, nanosecs, time.UTC), nil + + case tcTimestamp: + year, month, day, dateNull := readDate(rd) + hour, minute, nanosecs, timeNull := readTime(rd) + if dateNull || timeNull { + return nil, nil + } + return time.Date(year, month, day, hour, minute, 0, nanosecs, time.UTC), nil + + case tcLongdate: + time, null := readLongdate(rd) + if null { + return nil, nil + } + return time, nil + + case tcSeconddate: + time, null := readSeconddate(rd) + if null { + return nil, nil + } + return time, nil + + case tcDaydate: + time, null := readDaydate(rd) + if null { + return nil, nil + } + return time, nil + + case tcSecondtime: + time, null := readSecondtime(rd) + if null { + return nil, nil + } + return time, nil + + case tcDecimal: + b, null := readDecimal(rd) + if null { + return nil, nil + } + return b, nil + + case tcChar, tcVarchar: + value, null := readBytes(rd) + if null { + return nil, nil + } + return value, nil + + case tcNchar, tcNvarchar: + value, null := readUtf8(rd) + if null { + return nil, nil + } + return value, nil + + case tcBinary, tcVarbinary: + value, null := readBytes(rd) + if null { + return nil, nil + } + return value, nil + + case tcBlob, tcClob, tcNclob: + null, writer, err := readLob(session, rd, tc) + if null { + return nil, nil + } + return writer, err + } + + outLogger.Fatalf("read field: type code %s not implemented", tc) + return nil, nil +} + +func writeField(wr *bufio.Writer, tc TypeCode, arg driver.NamedValue) error { + v := arg.Value + //HDB bug: secondtime null value cannot be set by setting high byte + // trying so, gives + // SQL HdbError 1033 - error while parsing protocol: no such data type: type_code=192, index=2 + + // null value + //if v == nil && tc != tcSecondtime + if v == nil { + wr.WriteB(byte(tc) | 0x80) //set high bit + return nil + } + + // type code + wr.WriteB(byte(tc)) + + switch tc { + + default: + outLogger.Fatalf("write field: type code %s not implemented", tc) + + case tcTinyint, tcSmallint, tcInteger, tcBigint: + var i64 int64 + + switch v := v.(type) { + default: + return fmt.Errorf("invalid argument type %T", v) + + case bool: + if v { + i64 = 1 + } else { + i64 = 0 + } + case int64: + i64 = v + } + + switch tc { + case tcTinyint: + wr.WriteB(byte(i64)) + case tcSmallint: + wr.WriteInt16(int16(i64)) + case tcInteger: + wr.WriteInt32(int32(i64)) + case tcBigint: + wr.WriteInt64(i64) + } + + case tcReal: + + f64, ok := v.(float64) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + wr.WriteFloat32(float32(f64)) + + case tcDouble: + + f64, ok := v.(float64) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + wr.WriteFloat64(f64) + + case tcDate: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeDate(wr, t) + + case tcTime: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeTime(wr, t) + + case tcTimestamp: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeDate(wr, t) + writeTime(wr, t) + + case tcLongdate: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeLongdate(wr, t) + + case tcSeconddate: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeSeconddate(wr, t) + + case tcDaydate: + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeDaydate(wr, t) + + case tcSecondtime: + // HDB bug: write null value explicite + if v == nil { + wr.WriteInt32(86401) + return nil + } + t, ok := v.(time.Time) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeSecondtime(wr, t) + + case tcDecimal: + b, ok := v.([]byte) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + if len(b) != 16 { + return fmt.Errorf("invalid argument length %d of type %T - expected %d", len(b), v, 16) + } + wr.Write(b) + + case tcChar, tcVarchar, tcString: + switch v := v.(type) { + case []byte: + writeBytes(wr, v) + case string: + writeString(wr, v) + default: + return fmt.Errorf("invalid argument type %T", v) + } + + case tcNchar, tcNvarchar, tcNstring: + switch v := v.(type) { + case []byte: + writeUtf8Bytes(wr, v) + case string: + writeUtf8String(wr, v) + default: + return fmt.Errorf("invalid argument type %T", v) + } + + case tcBinary, tcVarbinary: + v, ok := v.([]byte) + if !ok { + return fmt.Errorf("invalid argument type %T", v) + } + writeBytes(wr, v) + + case tcBlob, tcClob, tcNclob: + writeLob(wr) + } + + return nil +} + +// null values: most sig bit unset +// year: unset second most sig bit (subtract 2^15) +// --> read year as unsigned +// month is 0-based +// day is 1 byte +func readDate(rd *bufio.Reader) (int, time.Month, int, bool) { + year := rd.ReadUint16() + null := ((year & 0x8000) == 0) //null value + year &= 0x3fff + month := rd.ReadInt8() + month++ + day := rd.ReadInt8() + return int(year), time.Month(month), int(day), null +} + +// year: set most sig bit +// month 0 based +func writeDate(wr *bufio.Writer, t time.Time) { + //store in utc + utc := t.In(time.UTC) + + year, month, day := utc.Date() + + wr.WriteUint16(uint16(year) | 0x8000) + wr.WriteInt8(int8(month) - 1) + wr.WriteInt8(int8(day)) +} + +func readTime(rd *bufio.Reader) (int, int, int, bool) { + hour := rd.ReadB() + null := (hour & 0x80) == 0 //null value + hour &= 0x7f + minute := rd.ReadInt8() + millisecs := rd.ReadUint16() + nanosecs := int(millisecs) * 1000000 + return int(hour), int(minute), nanosecs, null +} + +func writeTime(wr *bufio.Writer, t time.Time) { + //store in utc + utc := t.UTC() + + wr.WriteB(byte(utc.Hour()) | 0x80) + wr.WriteInt8(int8(utc.Minute())) + millisecs := utc.Second()*1000 + utc.Round(time.Millisecond).Nanosecond()/1000000 + wr.WriteUint16(uint16(millisecs)) +} + +var zeroTime = time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC) + +func readLongdate(rd *bufio.Reader) (time.Time, bool) { + longdate := rd.ReadInt64() + if longdate == 3155380704000000001 { // null value + return zeroTime, true + } + return convertLongdateToTime(longdate), false +} + +func writeLongdate(wr *bufio.Writer, t time.Time) { + wr.WriteInt64(convertTimeToLongdate(t)) +} + +func readSeconddate(rd *bufio.Reader) (time.Time, bool) { + seconddate := rd.ReadInt64() + if seconddate == 315538070401 { // null value + return zeroTime, true + } + return convertSeconddateToTime(seconddate), false +} + +func writeSeconddate(wr *bufio.Writer, t time.Time) { + wr.WriteInt64(convertTimeToSeconddate(t)) +} + +func readDaydate(rd *bufio.Reader) (time.Time, bool) { + daydate := rd.ReadInt32() + if daydate == 3652062 { // null value + return zeroTime, true + } + return convertDaydateToTime(int64(daydate)), false +} + +func writeDaydate(wr *bufio.Writer, t time.Time) { + wr.WriteInt32(int32(convertTimeToDayDate(t))) +} + +func readSecondtime(rd *bufio.Reader) (time.Time, bool) { + secondtime := rd.ReadInt32() + if secondtime == 86401 { // null value + return zeroTime, true + } + return convertSecondtimeToTime(int(secondtime)), false +} + +func writeSecondtime(wr *bufio.Writer, t time.Time) { + wr.WriteInt32(int32(convertTimeToSecondtime(t))) +} + +// nanosecond: HDB - 7 digits precision (not 9 digits) +func convertTimeToLongdate(t time.Time) int64 { + t = t.UTC() + return (((((((int64(convertTimeToDayDate(t))-1)*24)+int64(t.Hour()))*60)+int64(t.Minute()))*60)+int64(t.Second()))*10000000 + int64(t.Nanosecond()/100) + 1 +} + +func convertLongdateToTime(longdate int64) time.Time { + const dayfactor = 10000000 * 24 * 60 * 60 + longdate-- + d := (longdate % dayfactor) * 100 + t := convertDaydateToTime((longdate / dayfactor) + 1) + return t.Add(time.Duration(d)) +} + +func convertTimeToSeconddate(t time.Time) int64 { + t = t.UTC() + return (((((int64(convertTimeToDayDate(t))-1)*24)+int64(t.Hour()))*60)+int64(t.Minute()))*60 + int64(t.Second()) + 1 +} + +func convertSeconddateToTime(seconddate int64) time.Time { + const dayfactor = 24 * 60 * 60 + seconddate-- + d := (seconddate % dayfactor) * 1000000000 + t := convertDaydateToTime((seconddate / dayfactor) + 1) + return t.Add(time.Duration(d)) +} + +const julianHdb = 1721423 // 1 January 0001 00:00:00 (1721424) - 1 + +func convertTimeToDayDate(t time.Time) int64 { + return int64(timeToJulianDay(t) - julianHdb) +} + +func convertDaydateToTime(daydate int64) time.Time { + return julianDayToTime(int(daydate) + julianHdb) +} + +func convertTimeToSecondtime(t time.Time) int { + t = t.UTC() + return (t.Hour()*60+t.Minute())*60 + t.Second() + 1 +} + +func convertSecondtimeToTime(secondtime int) time.Time { + return time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(int64(secondtime-1) * 1000000000)) +} + +func readDecimal(rd *bufio.Reader) ([]byte, bool) { + b := make([]byte, 16) + rd.ReadFull(b) + if (b[15] & 0x70) == 0x70 { //null value (bit 4,5,6 set) + return nil, true + } + return b, false +} + +// string / binary length indicators +const ( + bytesLenIndNullValue byte = 255 + bytesLenIndSmall byte = 245 + bytesLenIndMedium byte = 246 + bytesLenIndBig byte = 247 +) + +func bytesSize(size int) (int, error) { //size + length indicator + switch { + default: + return 0, fmt.Errorf("max string length %d exceeded %d", math.MaxInt32, size) + case size <= int(bytesLenIndSmall): + return size + 1, nil + case size <= math.MaxInt16: + return size + 3, nil + case size <= math.MaxInt32: + return size + 5, nil + } +} + +func readBytesSize(rd *bufio.Reader) (int, bool) { + + ind := rd.ReadB() //length indicator + + switch { + + default: + return 0, false + + case ind == bytesLenIndNullValue: + return 0, true + + case ind <= bytesLenIndSmall: + return int(ind), false + + case ind == bytesLenIndMedium: + return int(rd.ReadInt16()), false + + case ind == bytesLenIndBig: + return int(rd.ReadInt32()), false + + } +} + +func writeBytesSize(wr *bufio.Writer, size int) error { + switch { + + default: + return fmt.Errorf("max argument length %d of string exceeded", size) + + case size <= int(bytesLenIndSmall): + wr.WriteB(byte(size)) + case size <= math.MaxInt16: + wr.WriteB(bytesLenIndMedium) + wr.WriteInt16(int16(size)) + case size <= math.MaxInt32: + wr.WriteB(bytesLenIndBig) + wr.WriteInt32(int32(size)) + } + return nil +} + +func readBytes(rd *bufio.Reader) ([]byte, bool) { + size, null := readBytesSize(rd) + if null { + return nil, true + } + b := make([]byte, size) + rd.ReadFull(b) + return b, false +} + +func readUtf8(rd *bufio.Reader) ([]byte, bool) { + size, null := readBytesSize(rd) + if null { + return nil, true + } + b := rd.ReadCesu8(size) + return b, false +} + +// strings with one byte length +func readShortUtf8(rd *bufio.Reader) ([]byte, int) { + size := rd.ReadB() + b := rd.ReadCesu8(int(size)) + return b, int(size) +} + +func writeBytes(wr *bufio.Writer, b []byte) { + writeBytesSize(wr, len(b)) + wr.Write(b) +} + +func writeString(wr *bufio.Writer, s string) { + writeBytesSize(wr, len(s)) + wr.WriteString(s) +} + +func writeUtf8Bytes(wr *bufio.Writer, b []byte) { + size := cesu8.Size(b) + writeBytesSize(wr, size) + wr.WriteCesu8(b) +} + +func writeUtf8String(wr *bufio.Writer, s string) { + size := cesu8.StringSize(s) + writeBytesSize(wr, size) + wr.WriteStringCesu8(s) +} + +func readLob(s *Session, rd *bufio.Reader, tc TypeCode) (bool, lobChunkWriter, error) { + rd.ReadInt8() // type code (is int here) + opt := rd.ReadInt8() + null := (lobOptions(opt) & loNullindicator) != 0 + if null { + return true, nil, nil + } + eof := (lobOptions(opt) & loLastdata) != 0 + rd.Skip(2) + + charLen := rd.ReadInt64() + byteLen := rd.ReadInt64() + id := rd.ReadUint64() + chunkLen := rd.ReadInt32() + + lobChunkWriter := newLobChunkWriter(tc.isCharBased(), s, locatorID(id), charLen, byteLen) + if err := lobChunkWriter.write(rd, int(chunkLen), eof); err != nil { + return null, lobChunkWriter, err + } + return null, lobChunkWriter, nil +} + +// TODO: first write: add content? - actually no data transferred +func writeLob(wr *bufio.Writer) { + wr.WriteB(0) + wr.WriteInt32(0) + wr.WriteInt32(0) +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode.go b/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode.go new file mode 100644 index 0000000..87d7658 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode.go @@ -0,0 +1,60 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=functionCode + +type functionCode int16 + +const ( + fcNil functionCode = 0 + fcDDL functionCode = 1 + fcInsert functionCode = 2 + fcUpdate functionCode = 3 + fcDelete functionCode = 4 + fcSelect functionCode = 5 + fcSelectForUpdate functionCode = 6 + fcExplain functionCode = 7 + fcDBProcedureCall functionCode = 8 + fcDBProcedureCallWithResult functionCode = 9 + fcFetch functionCode = 10 + fcCommit functionCode = 11 + fcRollback functionCode = 12 + fcSavepoint functionCode = 13 + fcConnect functionCode = 14 + fcWriteLob functionCode = 15 + fcReadLob functionCode = 16 + fcPing functionCode = 17 //reserved: do not use + fcDisconnect functionCode = 18 + fcCloseCursor functionCode = 19 + fcFindLob functionCode = 20 + fcAbapStream functionCode = 21 + fcXAStart functionCode = 22 + fcXAJoin functionCode = 23 +) + +func (k functionCode) queryType() QueryType { + + switch k { + default: + return QtNone + case fcSelect, fcSelectForUpdate: + return QtSelect + case fcDBProcedureCall: + return QtProcedureCall + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode_string.go new file mode 100644 index 0000000..a089630 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/functioncode_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=functionCode"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _functionCode_name = "fcNilfcDDLfcInsertfcUpdatefcDeletefcSelectfcSelectForUpdatefcExplainfcDBProcedureCallfcDBProcedureCallWithResultfcFetchfcCommitfcRollbackfcSavepointfcConnectfcWriteLobfcReadLobfcPingfcDisconnectfcCloseCursorfcFindLobfcAbapStreamfcXAStartfcXAJoin" + +var _functionCode_index = [...]uint8{0, 5, 10, 18, 26, 34, 42, 59, 68, 85, 112, 119, 127, 137, 148, 157, 167, 176, 182, 194, 207, 216, 228, 237, 245} + +func (i functionCode) String() string { + if i < 0 || i >= functionCode(len(_functionCode_index)-1) { + return "functionCode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _functionCode_name[_functionCode_index[i]:_functionCode_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/init.go b/vendor/github.com/SAP/go-hdb/internal/protocol/init.go new file mode 100644 index 0000000..434fb97 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/init.go @@ -0,0 +1,198 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + okEndianess int8 = 1 +) + +const ( + initRequestFillerSize = 4 +) + +var initRequestFiller uint32 = 0xffffffff + +type productVersion struct { + major int8 + minor int16 +} + +func (v *productVersion) String() string { + return fmt.Sprintf("%d.%d", v.major, v.minor) +} + +type protocolVersion struct { + major int8 + minor int16 +} + +func (v *protocolVersion) String() string { + return fmt.Sprintf("%d.%d", v.major, v.minor) +} + +type version struct { + major int8 + minor int16 +} + +func (v *version) String() string { + return fmt.Sprintf("%d.%d", v.major, v.minor) +} + +type initRequest struct { + product *version + protocol *version + numOptions int8 + endianess endianess +} + +func newInitRequest() *initRequest { + return &initRequest{ + product: new(version), + protocol: new(version), + } +} + +func (r *initRequest) String() string { + switch r.numOptions { + default: + return fmt.Sprintf("init request: product version %s protocol version %s", r.product, r.protocol) + case 1: + return fmt.Sprintf("init request: product version %s protocol version %s endianess %s", r.product, r.protocol, r.endianess) + } +} + +func (r *initRequest) read(rd *bufio.Reader) error { + rd.Skip(initRequestFillerSize) //filler + r.product.major = rd.ReadInt8() + r.product.minor = rd.ReadInt16() + r.protocol.major = rd.ReadInt8() + r.protocol.minor = rd.ReadInt16() + rd.Skip(1) //reserved filler + r.numOptions = rd.ReadInt8() + + switch r.numOptions { + default: + outLogger.Fatalf("invalid number of options %d", r.numOptions) + + case 0: + rd.Skip(2) + + case 1: + cnt := rd.ReadInt8() + if cnt != 1 { + outLogger.Fatalf("endianess %d - 1 expected", cnt) + } + r.endianess = endianess(rd.ReadInt8()) + } + + if trace { + outLogger.Printf("read %s", r) + } + + return rd.GetError() +} + +func (r *initRequest) write(wr *bufio.Writer) error { + wr.WriteUint32(initRequestFiller) + wr.WriteInt8(r.product.major) + wr.WriteInt16(r.product.minor) + wr.WriteInt8(r.protocol.major) + wr.WriteInt16(r.protocol.minor) + + switch r.numOptions { + default: + outLogger.Fatalf("invalid number of options %d", r.numOptions) + + case 0: + wr.WriteZeroes(4) + + case 1: + // reserved + wr.WriteZeroes(1) + wr.WriteInt8(r.numOptions) + wr.WriteInt8(int8(okEndianess)) + wr.WriteInt8(int8(r.endianess)) + + } + + // flush + if err := wr.Flush(); err != nil { + return err + } + + if trace { + outLogger.Printf("write %s", r) + } + + return nil +} + +type initReply struct { + product *version + protocol *version +} + +func newInitReply() *initReply { + return &initReply{ + product: new(version), + protocol: new(version), + } +} + +func (r *initReply) String() string { + return fmt.Sprintf("init reply: product version %s protocol version %s", r.product, r.protocol) +} + +func (r *initReply) read(rd *bufio.Reader) error { + r.product.major = rd.ReadInt8() + r.product.minor = rd.ReadInt16() + r.protocol.major = rd.ReadInt8() + r.protocol.minor = rd.ReadInt16() + rd.Skip(2) //commitInitReplySize + + if trace { + outLogger.Printf("read %s", r) + } + + return rd.GetError() +} + +func (r *initReply) write(wr *bufio.Writer) error { + wr.WriteInt8(r.product.major) + wr.WriteInt16(r.product.minor) + wr.WriteInt8(r.product.major) + wr.WriteInt16(r.protocol.minor) + wr.WriteZeroes(2) // commitInitReplySize + + // flush + if err := wr.Flush(); err != nil { + return err + } + + if trace { + outLogger.Printf("write %s", r) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/littleendian.go b/vendor/github.com/SAP/go-hdb/internal/protocol/littleendian.go new file mode 100644 index 0000000..27a8ed8 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/littleendian.go @@ -0,0 +1,23 @@ +// +build amd64 386 arm arm64 ppc64le mipsle mips64le + +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//amd64, 386 architectures: little endian +//arm, arm64: go supports little endian only +var archEndian = littleEndian diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/lob.go b/vendor/github.com/SAP/go-hdb/internal/protocol/lob.go new file mode 100644 index 0000000..dc2e0c7 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/lob.go @@ -0,0 +1,507 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + "io" + "math" + "unicode/utf8" + + "golang.org/x/text/transform" + + "github.com/SAP/go-hdb/internal/bufio" + "github.com/SAP/go-hdb/internal/unicode" + "github.com/SAP/go-hdb/internal/unicode/cesu8" +) + +const ( + locatorIDSize = 8 + writeLobRequestHeaderSize = 21 + readLobRequestSize = 24 +) + +// variable (unit testing) +//var lobChunkSize = 1 << 14 //TODO: check size +var lobChunkSize int32 = 4096 //TODO: check size + +//lob options +type lobOptions int8 + +const ( + loNullindicator lobOptions = 0x01 + loDataincluded lobOptions = 0x02 + loLastdata lobOptions = 0x04 +) + +var lobOptionsText = map[lobOptions]string{ + loNullindicator: "null indicator", + loDataincluded: "data included", + loLastdata: "last data", +} + +func (k lobOptions) String() string { + t := make([]string, 0, len(lobOptionsText)) + + for option, text := range lobOptionsText { + if (k & option) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +type locatorID uint64 // byte[locatorIdSize] + +// write lob reply +type writeLobReply struct { + ids []locatorID + numArg int +} + +func (r *writeLobReply) String() string { + return fmt.Sprintf("write lob reply: %v", r.ids) +} + +func (r *writeLobReply) kind() partKind { + return pkWriteLobReply +} + +func (r *writeLobReply) setNumArg(numArg int) { + r.numArg = numArg +} + +func (r *writeLobReply) read(rd *bufio.Reader) error { + + //resize ids + if r.ids == nil || cap(r.ids) < r.numArg { + r.ids = make([]locatorID, r.numArg) + } else { + r.ids = r.ids[:r.numArg] + } + + for i := 0; i < r.numArg; i++ { + r.ids[i] = locatorID(rd.ReadUint64()) + } + + return rd.GetError() +} + +//write lob request +type writeLobRequest struct { + lobPrmFields []*ParameterField +} + +func (r *writeLobRequest) kind() partKind { + return pkWriteLobRequest +} + +func (r *writeLobRequest) size() (int, error) { + + // TODO: check size limit + + size := 0 + for _, prmField := range r.lobPrmFields { + cr := prmField.chunkReader + if cr.done() { + continue + } + + if err := cr.fill(); err != nil { + return 0, err + } + size += writeLobRequestHeaderSize + size += cr.size() + } + return size, nil +} + +func (r *writeLobRequest) numArg() int { + n := 0 + for _, prmField := range r.lobPrmFields { + cr := prmField.chunkReader + if !cr.done() { + n++ + } + } + return n +} + +func (r *writeLobRequest) write(wr *bufio.Writer) error { + for _, prmField := range r.lobPrmFields { + cr := prmField.chunkReader + if !cr.done() { + + wr.WriteUint64(uint64(prmField.lobLocatorID)) + + opt := int8(0x02) // data included + if cr.eof() { + opt |= 0x04 // last data + } + + wr.WriteInt8(opt) + wr.WriteInt64(-1) //offset (-1 := append) + wr.WriteInt32(int32(cr.size())) // size + wr.Write(cr.bytes()) + } + } + return nil +} + +//read lob request +type readLobRequest struct { + w lobChunkWriter +} + +func (r *readLobRequest) kind() partKind { + return pkReadLobRequest +} + +func (r *readLobRequest) size() (int, error) { + return readLobRequestSize, nil +} + +func (r *readLobRequest) numArg() int { + return 1 +} + +func (r *readLobRequest) write(wr *bufio.Writer) error { + wr.WriteUint64(uint64(r.w.id())) + + readOfs, readLen := r.w.readOfsLen() + + wr.WriteInt64(readOfs + 1) //1-based + wr.WriteInt32(readLen) + wr.WriteZeroes(4) + + return nil +} + +// read lob reply +// - seems like readLobreply gives only an result for one lob - even if more then one is requested +// --> read single lobs +type readLobReply struct { + w lobChunkWriter +} + +func (r *readLobReply) kind() partKind { + return pkReadLobReply +} + +func (r *readLobReply) setNumArg(numArg int) { + if numArg != 1 { + panic("numArg == 1 expected") + } +} + +func (r *readLobReply) read(rd *bufio.Reader) error { + id := rd.ReadUint64() + + if r.w.id() != locatorID(id) { + return fmt.Errorf("internal error: invalid lob locator %d - expected %d", id, r.w.id()) + } + + opt := rd.ReadInt8() + chunkLen := rd.ReadInt32() + rd.Skip(3) + eof := (lobOptions(opt) & loLastdata) != 0 + + if err := r.w.write(rd, int(chunkLen), eof); err != nil { + return err + } + + return rd.GetError() +} + +// lobChunkReader reads lob field io.Reader in chunks for writing to db. +type lobChunkReader interface { + fill() error + size() int + bytes() []byte + eof() bool + done() bool +} + +func newLobChunkReader(isCharBased bool, r io.Reader) lobChunkReader { + if isCharBased { + return &charLobChunkReader{r: r} + } + return &binaryLobChunkReader{r: r} +} + +// binaryLobChunkReader (byte based chunks). +type binaryLobChunkReader struct { + r io.Reader + _size int + _eof bool + _done bool + b []byte +} + +func (l *binaryLobChunkReader) eof() bool { return l._eof } +func (l *binaryLobChunkReader) done() bool { return l._done } +func (l *binaryLobChunkReader) size() int { return l._size } + +func (l *binaryLobChunkReader) bytes() []byte { + l._done = l._eof + return l.b[:l._size] +} + +func (l *binaryLobChunkReader) fill() error { + if l._eof { + return io.EOF + } + + var err error + + l.b = resizeBuffer(l.b, int(lobChunkSize)) + l._size, err = l.r.Read(l.b) + if err != nil && err != io.EOF { + return err + } + l._eof = err == io.EOF + return nil +} + +// charLobChunkReader (cesu8 character based chunks). +type charLobChunkReader struct { + r io.Reader + _size int + _eof bool + _done bool + b []byte + c []byte + ofs int +} + +func (l *charLobChunkReader) eof() bool { return l._eof } +func (l *charLobChunkReader) done() bool { return l._done } +func (l *charLobChunkReader) size() int { return l._size } + +func (l *charLobChunkReader) bytes() []byte { + l._done = l._eof + return l.b[:l._size] +} + +func (l *charLobChunkReader) fill() error { + if l._eof { + return io.EOF + } + + l.c = resizeBuffer(l.c, int(lobChunkSize)+l.ofs) + n, err := l.r.Read(l.c[l.ofs:]) + size := n + l.ofs + + if err != nil && err != io.EOF { + return err + } + l._eof = err == io.EOF + if l._eof && size == 0 { + l._size = 0 + return nil + } + + l.b = resizeBuffer(l.b, cesu8.Size(l.c[:size])) // last rune might be incomplete, so size is one greater than needed + nDst, nSrc, err := unicode.Utf8ToCesu8Transformer.Transform(l.b, l.c[:size], l._eof) + if err != nil && err != transform.ErrShortSrc { + return err + } + + if l._eof && err == transform.ErrShortSrc { + return unicode.ErrInvalidUtf8 + } + + l._size = nDst + l.ofs = size - nSrc + + if l.ofs > 0 { + copy(l.c, l.c[nSrc:size]) // copy rest to buffer beginn + } + return nil +} + +// lobChunkWriter reads db lob chunks and writes them into lob field io.Writer. +type lobChunkWriter interface { + SetWriter(w io.Writer) error // gets called by driver.Lob.Scan + + id() locatorID + write(rd *bufio.Reader, size int, eof bool) error + readOfsLen() (int64, int32) + eof() bool +} + +func newLobChunkWriter(isCharBased bool, s *Session, id locatorID, charLen, byteLen int64) lobChunkWriter { + if isCharBased { + return &charLobChunkWriter{s: s, _id: id, charLen: charLen, byteLen: byteLen} + } + return &binaryLobChunkWriter{s: s, _id: id, charLen: charLen, byteLen: byteLen} +} + +// binaryLobChunkWriter (byte based lobs). +type binaryLobChunkWriter struct { + s *Session + + _id locatorID + charLen int64 + byteLen int64 + + readOfs int64 + _eof bool + + ofs int + + wr io.Writer + + b []byte +} + +func (l *binaryLobChunkWriter) id() locatorID { return l._id } +func (l *binaryLobChunkWriter) eof() bool { return l._eof } + +func (l *binaryLobChunkWriter) SetWriter(wr io.Writer) error { + l.wr = wr + if err := l.flush(); err != nil { + return err + } + return l.s.readLobStream(l) +} + +func (l *binaryLobChunkWriter) write(rd *bufio.Reader, size int, eof bool) error { + l._eof = eof // store eof + + if size == 0 { + return nil + } + + l.b = resizeBuffer(l.b, size+l.ofs) + rd.ReadFull(l.b[l.ofs:]) + if l.wr != nil { + return l.flush() + } + return nil +} + +func (l *binaryLobChunkWriter) readOfsLen() (int64, int32) { + readLen := l.charLen - l.readOfs + if readLen > int64(math.MaxInt32) || readLen > int64(lobChunkSize) { + return l.readOfs, lobChunkSize + } + return l.readOfs, int32(readLen) +} + +func (l *binaryLobChunkWriter) flush() error { + if _, err := l.wr.Write(l.b); err != nil { + return err + } + l.readOfs += int64(len(l.b)) + return nil +} + +type charLobChunkWriter struct { + s *Session + + _id locatorID + charLen int64 + byteLen int64 + + readOfs int64 + _eof bool + + ofs int + + wr io.Writer + + b []byte +} + +func (l *charLobChunkWriter) id() locatorID { return l._id } +func (l *charLobChunkWriter) eof() bool { return l._eof } + +func (l *charLobChunkWriter) SetWriter(wr io.Writer) error { + l.wr = wr + if err := l.flush(); err != nil { + return err + } + return l.s.readLobStream(l) +} + +func (l *charLobChunkWriter) write(rd *bufio.Reader, size int, eof bool) error { + l._eof = eof // store eof + + if size == 0 { + return nil + } + + l.b = resizeBuffer(l.b, size+l.ofs) + rd.ReadFull(l.b[l.ofs:]) + if l.wr != nil { + return l.flush() + } + return nil +} + +func (l *charLobChunkWriter) readOfsLen() (int64, int32) { + readLen := l.charLen - l.readOfs + if readLen > int64(math.MaxInt32) || readLen > int64(lobChunkSize) { + return l.readOfs, lobChunkSize + } + return l.readOfs, int32(readLen) +} + +func (l *charLobChunkWriter) flush() error { + nDst, nSrc, err := unicode.Cesu8ToUtf8Transformer.Transform(l.b, l.b, true) // inline cesu8 to utf8 transformation + if err != nil && err != transform.ErrShortSrc { + return err + } + if _, err := l.wr.Write(l.b[:nDst]); err != nil { + return err + } + l.ofs = len(l.b) - nSrc + if l.ofs != 0 && l.ofs != cesu8.CESUMax/2 { // assert remaining bytes + return unicode.ErrInvalidCesu8 + } + l.readOfs += int64(l.runeCount(l.b[:nDst])) + if l.ofs != 0 { + l.readOfs++ // add half encoding + copy(l.b, l.b[nSrc:len(l.b)]) // move half encoding to buffer begin + } + return nil +} + +// Caution: hdb counts 4 byte utf-8 encodings (cesu-8 6 bytes) as 2 (3 byte) chars +func (l *charLobChunkWriter) runeCount(b []byte) int { + numChars := 0 + for len(b) > 0 { + _, size := utf8.DecodeRune(b) + b = b[size:] + numChars++ + if size == utf8.UTFMax { + numChars++ + } + } + return numChars +} + +// helper +func resizeBuffer(b1 []byte, size int) []byte { + if b1 == nil || cap(b1) < size { + b2 := make([]byte, size) + copy(b2, b1) // !!! + return b2 + } + return b1[:size] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/message.go b/vendor/github.com/SAP/go-hdb/internal/protocol/message.go new file mode 100644 index 0000000..9da0095 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/message.go @@ -0,0 +1,75 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + messageHeaderSize = 32 +) + +//message header +type messageHeader struct { + sessionID int64 + packetCount int32 + varPartLength uint32 + varPartSize uint32 + noOfSegm int16 +} + +func (h *messageHeader) String() string { + return fmt.Sprintf("session id %d packetCount %d varPartLength %d, varPartSize %d noOfSegm %d", + h.sessionID, + h.packetCount, + h.varPartLength, + h.varPartSize, + h.noOfSegm) +} + +func (h *messageHeader) write(wr *bufio.Writer) error { + wr.WriteInt64(h.sessionID) + wr.WriteInt32(h.packetCount) + wr.WriteUint32(h.varPartLength) + wr.WriteUint32(h.varPartSize) + wr.WriteInt16(h.noOfSegm) + wr.WriteZeroes(10) //messageHeaderSize + + if trace { + outLogger.Printf("write message header: %s", h) + } + + return nil +} + +func (h *messageHeader) read(rd *bufio.Reader) error { + h.sessionID = rd.ReadInt64() + h.packetCount = rd.ReadInt32() + h.varPartLength = rd.ReadUint32() + h.varPartSize = rd.ReadUint32() + h.noOfSegm = rd.ReadInt16() + rd.Skip(10) //messageHeaderSize + + if trace { + outLogger.Printf("read message header: %s", h) + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype.go b/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype.go new file mode 100644 index 0000000..cba8054 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype.go @@ -0,0 +1,49 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=messageType + +type messageType int8 + +const ( + mtNil messageType = 0 + mtExecuteDirect messageType = 2 + mtPrepare messageType = 3 + mtAbapStream messageType = 4 + mtXAStart messageType = 5 + mtXAJoin messageType = 6 + mtExecute messageType = 13 + mtWriteLob messageType = 16 + mtReadLob messageType = 17 + mtFindLob messageType = 18 + mtAuthenticate messageType = 65 + mtConnect messageType = 66 + mtCommit messageType = 67 + mtRollback messageType = 68 + mtCloseResultset messageType = 69 + mtDropStatementID messageType = 70 + mtFetchNext messageType = 71 + mtFetchAbsolute messageType = 72 + mtFetchRelative messageType = 73 + mtFetchFirst messageType = 74 + mtFetchLast messageType = 75 + mtDisconnect messageType = 77 + mtExecuteITab messageType = 78 + mtFetchNextITab messageType = 79 + mtInsertNextITab messageType = 80 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype_string.go new file mode 100644 index 0000000..5a3b96c --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/messagetype_string.go @@ -0,0 +1,44 @@ +// Code generated by "stringer -type=messageType"; DO NOT EDIT. + +package protocol + +import "strconv" + +const ( + _messageType_name_0 = "mtNil" + _messageType_name_1 = "mtExecuteDirectmtPreparemtAbapStreammtXAStartmtXAJoin" + _messageType_name_2 = "mtExecute" + _messageType_name_3 = "mtWriteLobmtReadLobmtFindLob" + _messageType_name_4 = "mtAuthenticatemtConnectmtCommitmtRollbackmtCloseResultsetmtDropStatementIDmtFetchNextmtFetchAbsolutemtFetchRelativemtFetchFirstmtFetchLast" + _messageType_name_5 = "mtDisconnectmtExecuteITabmtFetchNextITabmtInsertNextITab" +) + +var ( + _messageType_index_1 = [...]uint8{0, 15, 24, 36, 45, 53} + _messageType_index_3 = [...]uint8{0, 10, 19, 28} + _messageType_index_4 = [...]uint8{0, 14, 23, 31, 41, 57, 74, 85, 100, 115, 127, 138} + _messageType_index_5 = [...]uint8{0, 12, 25, 40, 56} +) + +func (i messageType) String() string { + switch { + case i == 0: + return _messageType_name_0 + case 2 <= i && i <= 6: + i -= 2 + return _messageType_name_1[_messageType_index_1[i]:_messageType_index_1[i+1]] + case i == 13: + return _messageType_name_2 + case 16 <= i && i <= 18: + i -= 16 + return _messageType_name_3[_messageType_index_3[i]:_messageType_index_3[i+1]] + case 65 <= i && i <= 75: + i -= 65 + return _messageType_name_4[_messageType_index_4[i]:_messageType_index_4[i+1]] + case 77 <= i && i <= 80: + i -= 77 + return _messageType_name_5[_messageType_index_5[i]:_messageType_index_5[i+1]] + default: + return "messageType(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/option.go b/vendor/github.com/SAP/go-hdb/internal/protocol/option.go new file mode 100644 index 0000000..e0f0eba --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/option.go @@ -0,0 +1,188 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type booleanType bool + +func (t booleanType) String() string { + return fmt.Sprintf("%t", t) +} + +type intType int32 + +func (t intType) String() string { + return fmt.Sprintf("%d", t) +} + +type bigintType int64 + +func (t bigintType) String() string { + return fmt.Sprintf("%d", t) +} + +type doubleType float64 + +func (t doubleType) String() string { + return fmt.Sprintf("%g", t) +} + +type stringType []byte + +type binaryStringType []byte + +func (t binaryStringType) String() string { + return fmt.Sprintf("%v", []byte(t)) +} + +//multi line options (number of lines in part header argumentCount) +type multiLineOptions []plainOptions + +func (o multiLineOptions) size() int { + size := 0 + for _, m := range o { + size += m.size() + } + return size +} + +//pointer: append multiLineOptions itself +func (o *multiLineOptions) read(rd *bufio.Reader, lineCnt int) { + for i := 0; i < lineCnt; i++ { + m := plainOptions{} + cnt := rd.ReadInt16() + m.read(rd, int(cnt)) + *o = append(*o, m) + } +} + +func (o multiLineOptions) write(wr *bufio.Writer) { + for _, m := range o { + wr.WriteInt16(int16(len(m))) + m.write(wr) + } +} + +type plainOptions map[int8]interface{} + +func (o plainOptions) size() int { + size := 2 * len(o) //option + type + for _, v := range o { + switch v := v.(type) { + default: + outLogger.Fatalf("type %T not implemented", v) + case booleanType: + size++ + case intType: + size += 4 + case bigintType: + size += 8 + case doubleType: + size += 8 + case stringType: + size += (2 + len(v)) //length int16 + string length + case binaryStringType: + size += (2 + len(v)) //length int16 + string length + } + } + return size +} + +func (o plainOptions) read(rd *bufio.Reader, cnt int) { + + for i := 0; i < cnt; i++ { + + k := rd.ReadInt8() + tc := rd.ReadB() + + switch TypeCode(tc) { + + default: + outLogger.Fatalf("type code %s not implemented", TypeCode(tc)) + + case tcBoolean: + o[k] = booleanType(rd.ReadBool()) + + case tcInteger: + o[k] = intType(rd.ReadInt32()) + + case tcBigint: + o[k] = bigintType(rd.ReadInt64()) + + case tcDouble: + o[k] = doubleType(rd.ReadFloat64()) + + case tcString: + size := rd.ReadInt16() + v := make([]byte, size) + rd.ReadFull(v) + o[k] = stringType(v) + + case tcBstring: + size := rd.ReadInt16() + v := make([]byte, size) + rd.ReadFull(v) + o[k] = binaryStringType(v) + + } + } +} + +func (o plainOptions) write(wr *bufio.Writer) { + + for k, v := range o { + + wr.WriteInt8(k) + + switch v := v.(type) { + + default: + outLogger.Fatalf("type %T not implemented", v) + + case booleanType: + wr.WriteInt8(int8(tcBoolean)) + wr.WriteBool(bool(v)) + + case intType: + wr.WriteInt8(int8(tcInteger)) + wr.WriteInt32(int32(v)) + + case bigintType: + wr.WriteInt8(int8(tcBigint)) + wr.WriteInt64(int64(v)) + + case doubleType: + wr.WriteInt8(int8(tcDouble)) + wr.WriteFloat64(float64(v)) + + case stringType: + wr.WriteInt8(int8(tcString)) + wr.WriteInt16(int16(len(v))) + wr.Write(v) + + case binaryStringType: + wr.WriteInt8(int8(tcBstring)) + wr.WriteInt16(int16(len(v))) + wr.Write(v) + } + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/parameter.go b/vendor/github.com/SAP/go-hdb/internal/protocol/parameter.go new file mode 100644 index 0000000..7a6e1da --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/parameter.go @@ -0,0 +1,389 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "database/sql/driver" + "fmt" + "io" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type parameterOptions int8 + +const ( + poMandatory parameterOptions = 0x01 + poOptional parameterOptions = 0x02 + poDefault parameterOptions = 0x04 +) + +var parameterOptionsText = map[parameterOptions]string{ + poMandatory: "mandatory", + poOptional: "optional", + poDefault: "default", +} + +func (k parameterOptions) String() string { + t := make([]string, 0, len(parameterOptionsText)) + + for option, text := range parameterOptionsText { + if (k & option) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +type parameterMode int8 + +const ( + pmIn parameterMode = 0x01 + pmInout parameterMode = 0x02 + pmOut parameterMode = 0x04 +) + +var parameterModeText = map[parameterMode]string{ + pmIn: "in", + pmInout: "inout", + pmOut: "out", +} + +func (k parameterMode) String() string { + t := make([]string, 0, len(parameterModeText)) + + for mode, text := range parameterModeText { + if (k & mode) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +// ParameterFieldSet contains database field metadata for parameters. +type ParameterFieldSet struct { + fields []*ParameterField + _inputFields []*ParameterField + _outputFields []*ParameterField + names fieldNames +} + +func newParameterFieldSet(size int) *ParameterFieldSet { + return &ParameterFieldSet{ + fields: make([]*ParameterField, size), + _inputFields: make([]*ParameterField, 0, size), + _outputFields: make([]*ParameterField, 0, size), + names: newFieldNames(), + } +} + +// String implements the Stringer interface. +func (f *ParameterFieldSet) String() string { + a := make([]string, len(f.fields)) + for i, f := range f.fields { + a[i] = f.String() + } + return fmt.Sprintf("%v", a) +} + +func (f *ParameterFieldSet) read(rd *bufio.Reader) { + for i := 0; i < len(f.fields); i++ { + field := newParameterField(f.names) + field.read(rd) + f.fields[i] = field + if field.In() { + f._inputFields = append(f._inputFields, field) + } + if field.Out() { + f._outputFields = append(f._outputFields, field) + } + } + + pos := uint32(0) + for _, offset := range f.names.sortOffsets() { + if diff := int(offset - pos); diff > 0 { + rd.Skip(diff) + } + b, size := readShortUtf8(rd) + f.names.setName(offset, string(b)) + pos += uint32(1 + size) + } +} + +func (f *ParameterFieldSet) inputFields() []*ParameterField { + return f._inputFields +} + +func (f *ParameterFieldSet) outputFields() []*ParameterField { + return f._outputFields +} + +// NumInputField returns the number of input fields in a database statement. +func (f *ParameterFieldSet) NumInputField() int { + return len(f._inputFields) +} + +// NumOutputField returns the number of output fields of a query or stored procedure. +func (f *ParameterFieldSet) NumOutputField() int { + return len(f._outputFields) +} + +// Field returns the field at index idx. +func (f *ParameterFieldSet) Field(idx int) *ParameterField { + return f.fields[idx] +} + +// OutputField returns the output field at index idx. +func (f *ParameterFieldSet) OutputField(idx int) *ParameterField { + return f._outputFields[idx] +} + +// ParameterField contains database field attributes for parameters. +type ParameterField struct { + fieldNames fieldNames + parameterOptions parameterOptions + tc TypeCode + mode parameterMode + fraction int16 + length int16 + offset uint32 + chunkReader lobChunkReader + lobLocatorID locatorID +} + +func newParameterField(fieldNames fieldNames) *ParameterField { + return &ParameterField{fieldNames: fieldNames} +} + +// String implements the Stringer interface. +func (f *ParameterField) String() string { + return fmt.Sprintf("parameterOptions %s typeCode %s mode %s fraction %d length %d name %s", + f.parameterOptions, + f.tc, + f.mode, + f.fraction, + f.length, + f.Name(), + ) +} + +// TypeCode returns the type code of the field. +func (f *ParameterField) TypeCode() TypeCode { + return f.tc +} + +// TypeLength returns the type length of the field. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypeLength +func (f *ParameterField) TypeLength() (int64, bool) { + if f.tc.isVariableLength() { + return int64(f.length), true + } + return 0, false +} + +// TypePrecisionScale returns the type precision and scale (decimal types) of the field. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypePrecisionScale +func (f *ParameterField) TypePrecisionScale() (int64, int64, bool) { + if f.tc.isDecimalType() { + return int64(f.length), int64(f.fraction), true + } + return 0, 0, false +} + +// Nullable returns true if the field may be null, false otherwise. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypeNullable +func (f *ParameterField) Nullable() bool { + return f.parameterOptions == poOptional +} + +// In returns true if the parameter field is an input field. +func (f *ParameterField) In() bool { + return f.mode == pmInout || f.mode == pmIn +} + +// Out returns true if the parameter field is an output field. +func (f *ParameterField) Out() bool { + return f.mode == pmInout || f.mode == pmOut +} + +// Name returns the parameter field name. +func (f *ParameterField) Name() string { + return f.fieldNames.name(f.offset) +} + +// SetLobReader sets the io.Reader if a Lob parameter field. +func (f *ParameterField) SetLobReader(rd io.Reader) error { + f.chunkReader = newLobChunkReader(f.TypeCode().isCharBased(), rd) + return nil +} + +// + +func (f *ParameterField) read(rd *bufio.Reader) { + f.parameterOptions = parameterOptions(rd.ReadInt8()) + f.tc = TypeCode(rd.ReadInt8()) + f.mode = parameterMode(rd.ReadInt8()) + rd.Skip(1) //filler + f.offset = rd.ReadUint32() + f.fieldNames.addOffset(f.offset) + f.length = rd.ReadInt16() + f.fraction = rd.ReadInt16() + rd.Skip(4) //filler +} + +// parameter metadata +type parameterMetadata struct { + prmFieldSet *ParameterFieldSet + numArg int +} + +func (m *parameterMetadata) String() string { + return fmt.Sprintf("parameter metadata: %s", m.prmFieldSet.fields) +} + +func (m *parameterMetadata) kind() partKind { + return pkParameterMetadata +} + +func (m *parameterMetadata) setNumArg(numArg int) { + m.numArg = numArg +} + +func (m *parameterMetadata) read(rd *bufio.Reader) error { + + m.prmFieldSet.read(rd) + + if trace { + outLogger.Printf("read %s", m) + } + + return rd.GetError() +} + +// input parameters +type inputParameters struct { + inputFields []*ParameterField + args []driver.NamedValue +} + +func newInputParameters(inputFields []*ParameterField, args []driver.NamedValue) *inputParameters { + return &inputParameters{inputFields: inputFields, args: args} +} + +func (p *inputParameters) String() string { + return fmt.Sprintf("input parameters: %v", p.args) +} + +func (p *inputParameters) kind() partKind { + return pkParameters +} + +func (p *inputParameters) size() (int, error) { + + size := len(p.args) + cnt := len(p.inputFields) + + for i, arg := range p.args { + + if arg.Value == nil { // null value + continue + } + + // mass insert + field := p.inputFields[i%cnt] + + fieldSize, err := fieldSize(field.TypeCode(), arg) + if err != nil { + return 0, err + } + + size += fieldSize + } + + return size, nil +} + +func (p *inputParameters) numArg() int { + cnt := len(p.inputFields) + + if cnt == 0 { // avoid divide-by-zero (e.g. prepare without parameters) + return 0 + } + + return len(p.args) / cnt +} + +func (p *inputParameters) write(wr *bufio.Writer) error { + + cnt := len(p.inputFields) + + for i, arg := range p.args { + + //mass insert + field := p.inputFields[i%cnt] + + if err := writeField(wr, field.TypeCode(), arg); err != nil { + return err + } + } + + if trace { + outLogger.Printf("input parameters: %s", p) + } + + return nil +} + +// output parameter +type outputParameters struct { + numArg int + s *Session + outputFields []*ParameterField + fieldValues *FieldValues +} + +func (p *outputParameters) String() string { + return fmt.Sprintf("output parameters: %v", p.fieldValues) +} + +func (p *outputParameters) kind() partKind { + return pkOutputParameters +} + +func (p *outputParameters) setNumArg(numArg int) { + p.numArg = numArg // should always be 1 +} + +func (p *outputParameters) read(rd *bufio.Reader) error { + + cols := len(p.outputFields) + p.fieldValues.resize(p.numArg, cols) + + for i := 0; i < p.numArg; i++ { + for j, field := range p.outputFields { + var err error + if p.fieldValues.values[i*cols+j], err = readField(p.s, rd, field.TypeCode()); err != nil { + return err + } + } + } + + if trace { + outLogger.Printf("read %s", p) + } + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/part.go b/vendor/github.com/SAP/go-hdb/internal/protocol/part.go new file mode 100644 index 0000000..b5fe360 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/part.go @@ -0,0 +1,144 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + partHeaderSize = 16 +) + +type requestPart interface { + kind() partKind + size() (int, error) + numArg() int + write(*bufio.Writer) error +} + +type replyPart interface { + //kind() partKind + setNumArg(int) + read(*bufio.Reader) error +} + +// PartAttributes is an interface defining methods for reading query resultset parts. +type PartAttributes interface { + ResultsetClosed() bool + LastPacket() bool + NoRows() bool +} + +type partAttributes int8 + +const ( + paLastPacket partAttributes = 0x01 + paNextPacket partAttributes = 0x02 + paFirstPacket partAttributes = 0x04 + paRowNotFound partAttributes = 0x08 + paResultsetClosed partAttributes = 0x10 +) + +var partAttributesText = map[partAttributes]string{ + paLastPacket: "lastPacket", + paNextPacket: "nextPacket", + paFirstPacket: "firstPacket", + paRowNotFound: "rowNotFound", + paResultsetClosed: "resultsetClosed", +} + +func (k partAttributes) String() string { + t := make([]string, 0, len(partAttributesText)) + + for attr, text := range partAttributesText { + if (k & attr) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +func (k partAttributes) ResultsetClosed() bool { + return (k & paResultsetClosed) == paResultsetClosed +} + +func (k partAttributes) LastPacket() bool { + return (k & paLastPacket) == paLastPacket +} + +func (k partAttributes) NoRows() bool { + attrs := paLastPacket | paRowNotFound + return (k & attrs) == attrs +} + +// part header +type partHeader struct { + partKind partKind + partAttributes partAttributes + argumentCount int16 + bigArgumentCount int32 + bufferLength int32 + bufferSize int32 +} + +func (h *partHeader) String() string { + return fmt.Sprintf("part kind %s partAttributes %s argumentCount %d bigArgumentCount %d bufferLength %d bufferSize %d", + h.partKind, + h.partAttributes, + h.argumentCount, + h.bigArgumentCount, + h.bufferLength, + h.bufferSize, + ) +} + +func (h *partHeader) write(wr *bufio.Writer) error { + wr.WriteInt8(int8(h.partKind)) + wr.WriteInt8(int8(h.partAttributes)) + wr.WriteInt16(h.argumentCount) + wr.WriteInt32(h.bigArgumentCount) + wr.WriteInt32(h.bufferLength) + wr.WriteInt32(h.bufferSize) + + //no filler + + if trace { + outLogger.Printf("write part header: %s", h) + } + + return nil +} + +func (h *partHeader) read(rd *bufio.Reader) error { + h.partKind = partKind(rd.ReadInt8()) + h.partAttributes = partAttributes(rd.ReadInt8()) + h.argumentCount = rd.ReadInt16() + h.bigArgumentCount = rd.ReadInt32() + h.bufferLength = rd.ReadInt32() + h.bufferSize = rd.ReadInt32() + + // no filler + + if trace { + outLogger.Printf("read part header: %s", h) + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/partkind.go b/vendor/github.com/SAP/go-hdb/internal/protocol/partkind.go new file mode 100644 index 0000000..92febf1 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/partkind.go @@ -0,0 +1,79 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=partKind + +type partKind int8 + +const ( + pkNil partKind = 0 + pkCommand partKind = 3 + pkResultset partKind = 5 + pkError partKind = 6 + pkStatementID partKind = 10 + pkTransactionID partKind = 11 + pkRowsAffected partKind = 12 + pkResultsetID partKind = 13 + pkTopologyInformation partKind = 15 + pkTableLocation partKind = 16 + pkReadLobRequest partKind = 17 + pkReadLobReply partKind = 18 + pkAbapIStream partKind = 25 + pkAbapOStream partKind = 26 + pkCommandInfo partKind = 27 + pkWriteLobRequest partKind = 28 + pkClientContext partKind = 29 + pkWriteLobReply partKind = 30 + pkParameters partKind = 32 + pkAuthentication partKind = 33 + pkSessionContext partKind = 34 + pkClientID partKind = 35 + pkProfile partKind = 38 + pkStatementContext partKind = 39 + pkPartitionInformation partKind = 40 + pkOutputParameters partKind = 41 + pkConnectOptions partKind = 42 + pkCommitOptions partKind = 43 + pkFetchOptions partKind = 44 + pkFetchSize partKind = 45 + pkParameterMetadata partKind = 47 + pkResultMetadata partKind = 48 + pkFindLobRequest partKind = 49 + pkFindLobReply partKind = 50 + pkItabSHM partKind = 51 + pkItabChunkMetadata partKind = 53 + pkItabMetadata partKind = 55 + pkItabResultChunk partKind = 56 + pkClientInfo partKind = 57 + pkStreamData partKind = 58 + pkOStreamResult partKind = 59 + pkFDARequestMetadata partKind = 60 + pkFDAReplyMetadata partKind = 61 + pkBatchPrepare partKind = 62 //Reserved: do not use + pkBatchExecute partKind = 63 //Reserved: do not use + pkTransactionFlags partKind = 64 + pkRowSlotImageParamMetadata partKind = 65 //Reserved: do not use + pkRowSlotImageResultset partKind = 66 //Reserved: do not use + pkDBConnectInfo partKind = 67 + pkLobFlags partKind = 68 + pkResultsetOptions partKind = 69 + pkXATransactionInfo partKind = 70 + pkSessionVariable partKind = 71 + pkWorkLoadReplayContext partKind = 72 + pkSQLReplyOptions partKind = 73 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/partkind_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/partkind_string.go new file mode 100644 index 0000000..9d85d14 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/partkind_string.go @@ -0,0 +1,72 @@ +// Code generated by "stringer -type=partKind"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _partKind_name = "pkNilpkCommandpkResultsetpkErrorpkStatementIDpkTransactionIDpkRowsAffectedpkResultsetIDpkTopologyInformationpkTableLocationpkReadLobRequestpkReadLobReplypkAbapIStreampkAbapOStreampkCommandInfopkWriteLobRequestpkClientContextpkWriteLobReplypkParameterspkAuthenticationpkSessionContextpkClientIDpkProfilepkStatementContextpkPartitionInformationpkOutputParameterspkConnectOptionspkCommitOptionspkFetchOptionspkFetchSizepkParameterMetadatapkResultMetadatapkFindLobRequestpkFindLobReplypkItabSHMpkItabChunkMetadatapkItabMetadatapkItabResultChunkpkClientInfopkStreamDatapkOStreamResultpkFDARequestMetadatapkFDAReplyMetadatapkBatchPreparepkBatchExecutepkTransactionFlagspkRowSlotImageParamMetadatapkRowSlotImageResultsetpkDBConnectInfopkLobFlagspkResultsetOptionspkXATransactionInfopkSessionVariablepkWorkLoadReplayContextpkSQLReplyOptions" + +var _partKind_map = map[partKind]string{ + 0: _partKind_name[0:5], + 3: _partKind_name[5:14], + 5: _partKind_name[14:25], + 6: _partKind_name[25:32], + 10: _partKind_name[32:45], + 11: _partKind_name[45:60], + 12: _partKind_name[60:74], + 13: _partKind_name[74:87], + 15: _partKind_name[87:108], + 16: _partKind_name[108:123], + 17: _partKind_name[123:139], + 18: _partKind_name[139:153], + 25: _partKind_name[153:166], + 26: _partKind_name[166:179], + 27: _partKind_name[179:192], + 28: _partKind_name[192:209], + 29: _partKind_name[209:224], + 30: _partKind_name[224:239], + 32: _partKind_name[239:251], + 33: _partKind_name[251:267], + 34: _partKind_name[267:283], + 35: _partKind_name[283:293], + 38: _partKind_name[293:302], + 39: _partKind_name[302:320], + 40: _partKind_name[320:342], + 41: _partKind_name[342:360], + 42: _partKind_name[360:376], + 43: _partKind_name[376:391], + 44: _partKind_name[391:405], + 45: _partKind_name[405:416], + 47: _partKind_name[416:435], + 48: _partKind_name[435:451], + 49: _partKind_name[451:467], + 50: _partKind_name[467:481], + 51: _partKind_name[481:490], + 53: _partKind_name[490:509], + 55: _partKind_name[509:523], + 56: _partKind_name[523:540], + 57: _partKind_name[540:552], + 58: _partKind_name[552:564], + 59: _partKind_name[564:579], + 60: _partKind_name[579:599], + 61: _partKind_name[599:617], + 62: _partKind_name[617:631], + 63: _partKind_name[631:645], + 64: _partKind_name[645:663], + 65: _partKind_name[663:690], + 66: _partKind_name[690:713], + 67: _partKind_name[713:728], + 68: _partKind_name[728:738], + 69: _partKind_name[738:756], + 70: _partKind_name[756:775], + 71: _partKind_name[775:792], + 72: _partKind_name[792:815], + 73: _partKind_name[815:832], +} + +func (i partKind) String() string { + if str, ok := _partKind_map[i]; ok { + return str + } + return "partKind(" + strconv.FormatInt(int64(i), 10) + ")" +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/querytype.go b/vendor/github.com/SAP/go-hdb/internal/protocol/querytype.go new file mode 100644 index 0000000..d32041a --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/querytype.go @@ -0,0 +1,29 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=QueryType + +// QueryType is the type definition for query types supported by this package. +type QueryType byte + +// Query type constants. +const ( + QtNone QueryType = iota + QtSelect + QtProcedureCall +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/querytype_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/querytype_string.go new file mode 100644 index 0000000..347126a --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/querytype_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=QueryType"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _QueryType_name = "QtNoneQtSelectQtProcedureCall" + +var _QueryType_index = [...]uint8{0, 6, 14, 29} + +func (i QueryType) String() string { + if i >= QueryType(len(_QueryType_index)-1) { + return "QueryType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _QueryType_name[_QueryType_index[i]:_QueryType_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/result.go b/vendor/github.com/SAP/go-hdb/internal/protocol/result.go new file mode 100644 index 0000000..5a9f4be --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/result.go @@ -0,0 +1,294 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + resultsetIDSize = 8 +) + +type columnOptions int8 + +const ( + coMandatory columnOptions = 0x01 + coOptional columnOptions = 0x02 +) + +var columnOptionsText = map[columnOptions]string{ + coMandatory: "mandatory", + coOptional: "optional", +} + +func (k columnOptions) String() string { + t := make([]string, 0, len(columnOptionsText)) + + for option, text := range columnOptionsText { + if (k & option) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +//resultset id +type resultsetID struct { + id *uint64 +} + +func (id *resultsetID) kind() partKind { + return pkResultsetID +} + +func (id *resultsetID) size() (int, error) { + return resultsetIDSize, nil +} + +func (id *resultsetID) numArg() int { + return 1 +} + +func (id *resultsetID) setNumArg(int) { + //ignore - always 1 +} + +func (id *resultsetID) read(rd *bufio.Reader) error { + _id := rd.ReadUint64() + *id.id = _id + + if trace { + outLogger.Printf("resultset id: %d", *id.id) + } + + return rd.GetError() +} + +func (id *resultsetID) write(wr *bufio.Writer) error { + wr.WriteUint64(*id.id) + + if trace { + outLogger.Printf("resultset id: %d", *id.id) + } + + return nil +} + +// ResultFieldSet contains database field metadata for result fields. +type ResultFieldSet struct { + fields []*ResultField + names fieldNames +} + +func newResultFieldSet(size int) *ResultFieldSet { + return &ResultFieldSet{ + fields: make([]*ResultField, size), + names: newFieldNames(), + } +} + +// String implements the Stringer interface. +func (f *ResultFieldSet) String() string { + a := make([]string, len(f.fields)) + for i, f := range f.fields { + a[i] = f.String() + } + return fmt.Sprintf("%v", a) +} + +func (f *ResultFieldSet) read(rd *bufio.Reader) { + for i := 0; i < len(f.fields); i++ { + field := newResultField(f.names) + field.read(rd) + f.fields[i] = field + } + + pos := uint32(0) + for _, offset := range f.names.sortOffsets() { + if diff := int(offset - pos); diff > 0 { + rd.Skip(diff) + } + b, size := readShortUtf8(rd) + f.names.setName(offset, string(b)) + pos += uint32(1 + size) + } +} + +// NumField returns the number of fields of a query. +func (f *ResultFieldSet) NumField() int { + return len(f.fields) +} + +// Field returns the field at index idx. +func (f *ResultFieldSet) Field(idx int) *ResultField { + return f.fields[idx] +} + +const ( + tableName = iota + schemaName + columnName + columnDisplayName + maxNames +) + +// ResultField contains database field attributes for result fields. +type ResultField struct { + fieldNames fieldNames + columnOptions columnOptions + tc TypeCode + fraction int16 + length int16 + offsets [maxNames]uint32 +} + +func newResultField(fieldNames fieldNames) *ResultField { + return &ResultField{fieldNames: fieldNames} +} + +// String implements the Stringer interface. +func (f *ResultField) String() string { + return fmt.Sprintf("columnsOptions %s typeCode %s fraction %d length %d tablename %s schemaname %s columnname %s columnDisplayname %s", + f.columnOptions, + f.tc, + f.fraction, + f.length, + f.fieldNames.name(f.offsets[tableName]), + f.fieldNames.name(f.offsets[schemaName]), + f.fieldNames.name(f.offsets[columnName]), + f.fieldNames.name(f.offsets[columnDisplayName]), + ) +} + +// TypeCode returns the type code of the field. +func (f *ResultField) TypeCode() TypeCode { + return f.tc +} + +// TypeLength returns the type length of the field. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypeLength +func (f *ResultField) TypeLength() (int64, bool) { + if f.tc.isVariableLength() { + return int64(f.length), true + } + return 0, false +} + +// TypePrecisionScale returns the type precision and scale (decimal types) of the field. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypePrecisionScale +func (f *ResultField) TypePrecisionScale() (int64, int64, bool) { + if f.tc.isDecimalType() { + return int64(f.length), int64(f.fraction), true + } + return 0, 0, false +} + +// Nullable returns true if the field may be null, false otherwise. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypeNullable +func (f *ResultField) Nullable() bool { + return f.columnOptions == coOptional +} + +// Name returns the result field name. +func (f *ResultField) Name() string { + return f.fieldNames.name(f.offsets[columnDisplayName]) +} + +func (f *ResultField) read(rd *bufio.Reader) { + f.columnOptions = columnOptions(rd.ReadInt8()) + f.tc = TypeCode(rd.ReadInt8()) + f.fraction = rd.ReadInt16() + f.length = rd.ReadInt16() + rd.Skip(2) //filler + for i := 0; i < maxNames; i++ { + offset := rd.ReadUint32() + f.offsets[i] = offset + f.fieldNames.addOffset(offset) + } +} + +//resultset metadata +type resultMetadata struct { + resultFieldSet *ResultFieldSet + numArg int +} + +func (r *resultMetadata) String() string { + return fmt.Sprintf("result metadata: %s", r.resultFieldSet.fields) +} + +func (r *resultMetadata) kind() partKind { + return pkResultMetadata +} + +func (r *resultMetadata) setNumArg(numArg int) { + r.numArg = numArg +} + +func (r *resultMetadata) read(rd *bufio.Reader) error { + + r.resultFieldSet.read(rd) + + if trace { + outLogger.Printf("read %s", r) + } + + return rd.GetError() +} + +//resultset +type resultset struct { + numArg int + s *Session + resultFieldSet *ResultFieldSet + fieldValues *FieldValues +} + +func (r *resultset) String() string { + return fmt.Sprintf("resultset: %s", r.fieldValues) +} + +func (r *resultset) kind() partKind { + return pkResultset +} + +func (r *resultset) setNumArg(numArg int) { + r.numArg = numArg +} + +func (r *resultset) read(rd *bufio.Reader) error { + + cols := len(r.resultFieldSet.fields) + r.fieldValues.resize(r.numArg, cols) + + for i := 0; i < r.numArg; i++ { + for j, field := range r.resultFieldSet.fields { + var err error + if r.fieldValues.values[i*cols+j], err = readField(r.s, rd, field.TypeCode()); err != nil { + return err + } + } + } + + if trace { + outLogger.Printf("read %s", r) + } + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/rowsaffected.go b/vendor/github.com/SAP/go-hdb/internal/protocol/rowsaffected.go new file mode 100644 index 0000000..3d5560f --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/rowsaffected.go @@ -0,0 +1,72 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "github.com/SAP/go-hdb/internal/bufio" +) + +//rows affected +const ( + raSuccessNoInfo = -2 + raExecutionFailed = -3 +) + +//rows affected +type rowsAffected struct { + rows []int32 + _numArg int +} + +func (r *rowsAffected) kind() partKind { + return pkRowsAffected +} + +func (r *rowsAffected) setNumArg(numArg int) { + r._numArg = numArg +} + +func (r *rowsAffected) read(rd *bufio.Reader) error { + if r.rows == nil || r._numArg > cap(r.rows) { + r.rows = make([]int32, r._numArg) + } else { + r.rows = r.rows[:r._numArg] + } + + for i := 0; i < r._numArg; i++ { + r.rows[i] = rd.ReadInt32() + if trace { + outLogger.Printf("rows affected %d: %d", i, r.rows[i]) + } + } + + return rd.GetError() +} + +func (r *rowsAffected) total() int64 { + if r.rows == nil { + return 0 + } + + total := int64(0) + for _, rows := range r.rows { + if rows > 0 { + total += int64(rows) + } + } + return total +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/scramsha256.go b/vendor/github.com/SAP/go-hdb/internal/protocol/scramsha256.go new file mode 100644 index 0000000..d7ad7e4 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/scramsha256.go @@ -0,0 +1,265 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//Salted Challenge Response Authentication Mechanism (SCRAM) + +import ( + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + clientChallengeSize = 64 + serverChallengeDataSize = 68 + clientProofDataSize = 35 + clientProofSize = 32 +) + +type scramsha256InitialRequest struct { + username []byte + clientChallenge []byte +} + +func (r *scramsha256InitialRequest) kind() partKind { + return pkAuthentication +} + +func (r *scramsha256InitialRequest) size() (int, error) { + return 2 + authFieldSize(r.username) + authFieldSize([]byte(mnSCRAMSHA256)) + authFieldSize(r.clientChallenge), nil +} + +func (r *scramsha256InitialRequest) numArg() int { + return 1 +} + +func (r *scramsha256InitialRequest) write(wr *bufio.Writer) error { + wr.WriteInt16(3) + writeAuthField(wr, r.username) + writeAuthField(wr, []byte(mnSCRAMSHA256)) + writeAuthField(wr, r.clientChallenge) + return nil +} + +type scramsha256InitialReply struct { + salt []byte + serverChallenge []byte +} + +func (r *scramsha256InitialReply) kind() partKind { + return pkAuthentication +} + +func (r *scramsha256InitialReply) setNumArg(int) { + //not needed +} + +func (r *scramsha256InitialReply) read(rd *bufio.Reader) error { + cnt := rd.ReadInt16() + if err := readMethodName(rd); err != nil { + return err + } + size := rd.ReadB() + if size != serverChallengeDataSize { + return fmt.Errorf("invalid server challenge data size %d - %d expected", size, serverChallengeDataSize) + } + + //server challenge data + + cnt = rd.ReadInt16() + if cnt != 2 { + return fmt.Errorf("invalid server challenge data field count %d - %d expected", cnt, 2) + } + + size = rd.ReadB() + if trace { + outLogger.Printf("salt size %d", size) + } + + r.salt = make([]byte, size) + rd.ReadFull(r.salt) + if trace { + outLogger.Printf("salt %v", r.salt) + } + + size = rd.ReadB() + r.serverChallenge = make([]byte, size) + rd.ReadFull(r.serverChallenge) + if trace { + outLogger.Printf("server challenge %v", r.serverChallenge) + } + + return rd.GetError() +} + +type scramsha256FinalRequest struct { + username []byte + clientProof []byte +} + +func newScramsha256FinalRequest() *scramsha256FinalRequest { + return &scramsha256FinalRequest{} +} + +func (r *scramsha256FinalRequest) kind() partKind { + return pkAuthentication +} + +func (r *scramsha256FinalRequest) size() (int, error) { + return 2 + authFieldSize(r.username) + authFieldSize([]byte(mnSCRAMSHA256)) + authFieldSize(r.clientProof), nil +} + +func (r *scramsha256FinalRequest) numArg() int { + return 1 +} + +func (r *scramsha256FinalRequest) write(wr *bufio.Writer) error { + wr.WriteInt16(3) + writeAuthField(wr, r.username) + writeAuthField(wr, []byte(mnSCRAMSHA256)) + writeAuthField(wr, r.clientProof) + return nil +} + +type scramsha256FinalReply struct { + serverProof []byte +} + +func newScramsha256FinalReply() *scramsha256FinalReply { + return &scramsha256FinalReply{} +} + +func (r *scramsha256FinalReply) kind() partKind { + return pkAuthentication +} + +func (r *scramsha256FinalReply) setNumArg(int) { + //not needed +} + +func (r *scramsha256FinalReply) read(rd *bufio.Reader) error { + cnt := rd.ReadInt16() + if cnt != 2 { + return fmt.Errorf("invalid final reply field count %d - %d expected", cnt, 2) + } + if err := readMethodName(rd); err != nil { + return err + } + + //serverProof + size := rd.ReadB() + + serverProof := make([]byte, size) + rd.ReadFull(serverProof) + + return rd.GetError() +} + +//helper +func authFieldSize(f []byte) int { + size := len(f) + if size >= 250 { + // - different indicators compared to db field handling + // - 1-5 bytes? but only 1 resp 3 bytes explained + panic("not implemented error") + } + return size + 1 //length indicator size := 1 +} + +func writeAuthField(wr *bufio.Writer, f []byte) { + size := len(f) + if size >= 250 { + // - different indicators compared to db field handling + // - 1-5 bytes? but only 1 resp 3 bytes explained + panic("not implemented error") + } + + wr.WriteB(byte(size)) + wr.Write(f) +} + +func readMethodName(rd *bufio.Reader) error { + size := rd.ReadB() + methodName := make([]byte, size) + rd.ReadFull(methodName) + if string(methodName) != mnSCRAMSHA256 { + return fmt.Errorf("invalid authentication method %s - %s expected", methodName, mnSCRAMSHA256) + } + return nil +} + +func clientChallenge() []byte { + r := make([]byte, clientChallengeSize) + if _, err := rand.Read(r); err != nil { + outLogger.Fatal("client challenge fatal error") + } + return r +} + +func clientProof(salt, serverChallenge, clientChallenge, password []byte) []byte { + + clientProof := make([]byte, clientProofDataSize) + + buf := make([]byte, 0, len(salt)+len(serverChallenge)+len(clientChallenge)) + buf = append(buf, salt...) + buf = append(buf, serverChallenge...) + buf = append(buf, clientChallenge...) + + key := _sha256(_hmac(password, salt)) + sig := _hmac(_sha256(key), buf) + + proof := xor(sig, key) + //actual implementation: only one salt value? + clientProof[0] = 0 + clientProof[1] = 1 + clientProof[2] = clientProofSize + copy(clientProof[3:], proof) + return clientProof +} + +func _sha256(p []byte) []byte { + hash := sha256.New() + hash.Write(p) + s := hash.Sum(nil) + if trace { + outLogger.Printf("sha length %d value %v", len(s), s) + } + return s +} + +func _hmac(key, p []byte) []byte { + hash := hmac.New(sha256.New, key) + hash.Write(p) + s := hash.Sum(nil) + if trace { + outLogger.Printf("hmac length %d value %v", len(s), s) + } + return s +} + +func xor(sig, key []byte) []byte { + r := make([]byte, len(sig)) + + for i, v := range sig { + r[i] = v ^ key[i] + } + return r +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/segment.go b/vendor/github.com/SAP/go-hdb/internal/protocol/segment.go new file mode 100644 index 0000000..b6aab3b --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/segment.go @@ -0,0 +1,174 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + segmentHeaderSize = 24 +) + +type commandOptions int8 + +const ( + coNil commandOptions = 0x00 + coSelfetchOff commandOptions = 0x01 + coScrollableCursorOn commandOptions = 0x02 + coNoResultsetCloseNeeded commandOptions = 0x04 + coHoldCursorOverCommtit commandOptions = 0x08 + coExecuteLocally commandOptions = 0x10 +) + +var commandOptionsText = map[commandOptions]string{ + coSelfetchOff: "selfetchOff", + coScrollableCursorOn: "scrollabeCursorOn", + coNoResultsetCloseNeeded: "noResltsetCloseNeeded", + coHoldCursorOverCommtit: "holdCursorOverCommit", + coExecuteLocally: "executLocally", +} + +func (k commandOptions) String() string { + t := make([]string, 0, len(commandOptionsText)) + + for option, text := range commandOptionsText { + if (k & option) != 0 { + t = append(t, text) + } + } + return fmt.Sprintf("%v", t) +} + +//segment header +type segmentHeader struct { + segmentLength int32 + segmentOfs int32 + noOfParts int16 + segmentNo int16 + segmentKind segmentKind + messageType messageType + commit bool + commandOptions commandOptions + functionCode functionCode +} + +func (h *segmentHeader) String() string { + switch h.segmentKind { + + default: //error + return fmt.Sprintf( + "segment length %d segment ofs %d noOfParts %d, segmentNo %d segmentKind %s", + h.segmentLength, + h.segmentOfs, + h.noOfParts, + h.segmentNo, + h.segmentKind, + ) + case skRequest: + return fmt.Sprintf( + "segment length %d segment ofs %d noOfParts %d, segmentNo %d segmentKind %s messageType %s commit %t commandOptions %s", + h.segmentLength, + h.segmentOfs, + h.noOfParts, + h.segmentNo, + h.segmentKind, + h.messageType, + h.commit, + h.commandOptions, + ) + case skReply: + return fmt.Sprintf( + "segment length %d segment ofs %d noOfParts %d, segmentNo %d segmentKind %s functionCode %s", + h.segmentLength, + h.segmentOfs, + h.noOfParts, + h.segmentNo, + h.segmentKind, + h.functionCode, + ) + } +} + +// request +func (h *segmentHeader) write(wr *bufio.Writer) error { + wr.WriteInt32(h.segmentLength) + wr.WriteInt32(h.segmentOfs) + wr.WriteInt16(h.noOfParts) + wr.WriteInt16(h.segmentNo) + wr.WriteInt8(int8(h.segmentKind)) + + switch h.segmentKind { + + default: //error + wr.WriteZeroes(11) //segmentHeaderLength + + case skRequest: + wr.WriteInt8(int8(h.messageType)) + wr.WriteBool(h.commit) + wr.WriteInt8(int8(h.commandOptions)) + wr.WriteZeroes(8) //segmentHeaderSize + + case skReply: + + wr.WriteZeroes(1) //reserved + wr.WriteInt16(int16(h.functionCode)) + wr.WriteZeroes(8) //segmentHeaderSize + + } + + if trace { + outLogger.Printf("write segment header: %s", h) + } + + return nil +} + +// reply || error +func (h *segmentHeader) read(rd *bufio.Reader) error { + h.segmentLength = rd.ReadInt32() + h.segmentOfs = rd.ReadInt32() + h.noOfParts = rd.ReadInt16() + h.segmentNo = rd.ReadInt16() + h.segmentKind = segmentKind(rd.ReadInt8()) + + switch h.segmentKind { + + default: //error + rd.Skip(11) //segmentHeaderLength + + case skRequest: + h.messageType = messageType(rd.ReadInt8()) + h.commit = rd.ReadBool() + h.commandOptions = commandOptions(rd.ReadInt8()) + rd.Skip(8) //segmentHeaderLength + + case skReply: + rd.Skip(1) //reserved + h.functionCode = functionCode(rd.ReadInt16()) + rd.Skip(8) //segmentHeaderLength + + } + + if trace { + outLogger.Printf("read segment header: %s", h) + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind.go b/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind.go new file mode 100644 index 0000000..14151b6 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind.go @@ -0,0 +1,28 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=segmentKind + +type segmentKind int8 + +const ( + skInvalid segmentKind = 0 + skRequest segmentKind = 1 + skReply segmentKind = 2 + skError segmentKind = 5 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind_string.go new file mode 100644 index 0000000..aaea08e --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind_string.go @@ -0,0 +1,25 @@ +// Code generated by "stringer -type=segmentKind"; DO NOT EDIT. + +package protocol + +import "strconv" + +const ( + _segmentKind_name_0 = "skInvalidskRequestskReply" + _segmentKind_name_1 = "skError" +) + +var ( + _segmentKind_index_0 = [...]uint8{0, 9, 18, 25} +) + +func (i segmentKind) String() string { + switch { + case 0 <= i && i <= 2: + return _segmentKind_name_0[_segmentKind_index_0[i]:_segmentKind_index_0[i+1]] + case i == 5: + return _segmentKind_name_1 + default: + return "segmentKind(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/session.go b/vendor/github.com/SAP/go-hdb/internal/protocol/session.go new file mode 100644 index 0000000..44cc59c --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/session.go @@ -0,0 +1,975 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "context" + "crypto/tls" + "database/sql/driver" + "flag" + "fmt" + "log" + "math" + "net" + "os" + "sync" + "time" + + "github.com/SAP/go-hdb/internal/bufio" + "github.com/SAP/go-hdb/internal/unicode" + "github.com/SAP/go-hdb/internal/unicode/cesu8" + + "github.com/SAP/go-hdb/driver/sqltrace" +) + +const ( + mnSCRAMSHA256 = "SCRAMSHA256" + mnGSS = "GSS" + mnSAML = "SAML" +) + +var trace bool + +func init() { + flag.BoolVar(&trace, "hdb.protocol.trace", false, "enabling hdb protocol trace") +} + +var ( + outLogger = log.New(os.Stdout, "hdb.protocol ", log.Ldate|log.Ltime|log.Lshortfile) + errLogger = log.New(os.Stderr, "hdb.protocol ", log.Ldate|log.Ltime|log.Lshortfile) +) + +//padding +const ( + padding = 8 +) + +func padBytes(size int) int { + if r := size % padding; r != 0 { + return padding - r + } + return 0 +} + +// SessionConn wraps the database tcp connection. It sets timeouts and handles driver ErrBadConn behavior. +type sessionConn struct { + addr string + timeout time.Duration + conn net.Conn + isBad bool // bad connection + badError error // error cause for session bad state + inTx bool // in transaction +} + +func newSessionConn(ctx context.Context, addr string, timeoutSec int, config *tls.Config) (*sessionConn, error) { + timeout := time.Duration(timeoutSec) * time.Second + dialer := net.Dialer{Timeout: timeout} + conn, err := dialer.DialContext(ctx, "tcp", addr) + if err != nil { + return nil, err + } + + // is TLS connection requested? + if config != nil { + conn = tls.Client(conn, config) + } + + return &sessionConn{addr: addr, timeout: timeout, conn: conn}, nil +} + +func (c *sessionConn) close() error { + return c.conn.Close() +} + +// Read implements the io.Reader interface. +func (c *sessionConn) Read(b []byte) (int, error) { + //set timeout + if err := c.conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil { + return 0, err + } + n, err := c.conn.Read(b) + if err != nil { + errLogger.Printf("Connection read error local address %s remote address %s: %s", c.conn.LocalAddr(), c.conn.RemoteAddr(), err) + c.isBad = true + c.badError = err + return n, driver.ErrBadConn + } + return n, nil +} + +// Write implements the io.Writer interface. +func (c *sessionConn) Write(b []byte) (int, error) { + //set timeout + if err := c.conn.SetWriteDeadline(time.Now().Add(c.timeout)); err != nil { + return 0, err + } + n, err := c.conn.Write(b) + if err != nil { + errLogger.Printf("Connection write error local address %s remote address %s: %s", c.conn.LocalAddr(), c.conn.RemoteAddr(), err) + c.isBad = true + c.badError = err + return n, driver.ErrBadConn + } + return n, nil +} + +type beforeRead func(p replyPart) + +// session parameter +type sessionPrm interface { + Host() string + Username() string + Password() string + Locale() string + FetchSize() int + Timeout() int + TLSConfig() *tls.Config +} + +// Session represents a HDB session. +type Session struct { + prm sessionPrm + + conn *sessionConn + rd *bufio.Reader + wr *bufio.Writer + + // reuse header + mh *messageHeader + sh *segmentHeader + ph *partHeader + + //reuse request / reply parts + scramsha256InitialRequest *scramsha256InitialRequest + scramsha256InitialReply *scramsha256InitialReply + scramsha256FinalRequest *scramsha256FinalRequest + scramsha256FinalReply *scramsha256FinalReply + topologyInformation *topologyInformation + connectOptions *connectOptions + rowsAffected *rowsAffected + statementID *statementID + resultMetadata *resultMetadata + resultsetID *resultsetID + resultset *resultset + parameterMetadata *parameterMetadata + outputParameters *outputParameters + writeLobRequest *writeLobRequest + readLobRequest *readLobRequest + writeLobReply *writeLobReply + readLobReply *readLobReply + + //standard replies + stmtCtx *statementContext + txFlags *transactionFlags + lastError *hdbErrors + + //serialize write request - read reply + //supports calling session methods in go routines (driver methods with context cancellation) + mu sync.Mutex +} + +// NewSession creates a new database session. +func NewSession(ctx context.Context, prm sessionPrm) (*Session, error) { + + if trace { + outLogger.Printf("%s", prm) + } + + conn, err := newSessionConn(ctx, prm.Host(), prm.Timeout(), prm.TLSConfig()) + if err != nil { + return nil, err + } + + rd := bufio.NewReader(conn) + wr := bufio.NewWriter(conn) + + s := &Session{ + prm: prm, + conn: conn, + rd: rd, + wr: wr, + mh: new(messageHeader), + sh: new(segmentHeader), + ph: new(partHeader), + scramsha256InitialRequest: new(scramsha256InitialRequest), + scramsha256InitialReply: new(scramsha256InitialReply), + scramsha256FinalRequest: new(scramsha256FinalRequest), + scramsha256FinalReply: new(scramsha256FinalReply), + topologyInformation: newTopologyInformation(), + connectOptions: newConnectOptions(), + rowsAffected: new(rowsAffected), + statementID: new(statementID), + resultMetadata: new(resultMetadata), + resultsetID: new(resultsetID), + resultset: new(resultset), + parameterMetadata: new(parameterMetadata), + outputParameters: new(outputParameters), + writeLobRequest: new(writeLobRequest), + readLobRequest: new(readLobRequest), + writeLobReply: new(writeLobReply), + readLobReply: new(readLobReply), + stmtCtx: newStatementContext(), + txFlags: newTransactionFlags(), + lastError: new(hdbErrors), + } + + if err = s.init(); err != nil { + return nil, err + } + + return s, nil +} + +// Close closes the session. +func (s *Session) Close() error { + return s.conn.close() +} + +func (s *Session) sessionID() int64 { + return s.mh.sessionID +} + +// InTx indicates, if the session is in transaction mode. +func (s *Session) InTx() bool { + return s.conn.inTx +} + +// SetInTx sets session in transaction mode. +func (s *Session) SetInTx(v bool) { + s.conn.inTx = v +} + +// IsBad indicates, that the session is in bad state. +func (s *Session) IsBad() bool { + return s.conn.isBad +} + +// BadErr returns the error, that caused the bad session state. +func (s *Session) BadErr() error { + return s.conn.badError +} + +func (s *Session) init() error { + + if err := s.initRequest(); err != nil { + return err + } + + // TODO: detect authentication method + // - actually only basic authetication supported + + authentication := mnSCRAMSHA256 + + switch authentication { + default: + return fmt.Errorf("invalid authentication %s", authentication) + + case mnSCRAMSHA256: + if err := s.authenticateScramsha256(); err != nil { + return err + } + case mnGSS: + panic("not implemented error") + case mnSAML: + panic("not implemented error") + } + + id := s.sessionID() + if id <= 0 { + return fmt.Errorf("invalid session id %d", id) + } + + if trace { + outLogger.Printf("sessionId %d", id) + } + + return nil +} + +func (s *Session) authenticateScramsha256() error { + tr := unicode.Utf8ToCesu8Transformer + tr.Reset() + + username := make([]byte, cesu8.StringSize(s.prm.Username())) + if _, _, err := tr.Transform(username, []byte(s.prm.Username()), true); err != nil { + return err // should never happen + } + + password := make([]byte, cesu8.StringSize(s.prm.Password())) + if _, _, err := tr.Transform(password, []byte(s.prm.Password()), true); err != nil { + return err //should never happen + } + + clientChallenge := clientChallenge() + + //initial request + s.scramsha256InitialRequest.username = username + s.scramsha256InitialRequest.clientChallenge = clientChallenge + + if err := s.writeRequest(mtAuthenticate, false, s.scramsha256InitialRequest); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + //final request + s.scramsha256FinalRequest.username = username + s.scramsha256FinalRequest.clientProof = clientProof(s.scramsha256InitialReply.salt, s.scramsha256InitialReply.serverChallenge, clientChallenge, password) + + s.scramsha256InitialReply = nil // !!! next time readReply uses FinalReply + + id := newClientID() + + co := newConnectOptions() + co.set(coDistributionProtocolVersion, booleanType(false)) + co.set(coSelectForUpdateSupported, booleanType(false)) + co.set(coSplitBatchCommands, booleanType(true)) + // cannot use due to HDB protocol error with secondtime datatype + //co.set(coDataFormatVersion2, dfvSPS06) + co.set(coDataFormatVersion2, dfvBaseline) + co.set(coCompleteArrayExecution, booleanType(true)) + if s.prm.Locale() != "" { + co.set(coClientLocale, stringType(s.prm.Locale())) + } + co.set(coClientDistributionMode, cdmOff) + // setting this option has no effect + //co.set(coImplicitLobStreaming, booleanType(true)) + + if err := s.writeRequest(mtConnect, false, s.scramsha256FinalRequest, id, co); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + return nil +} + +// QueryDirect executes a query without query parameters. +func (s *Session) QueryDirect(query string) (uint64, *ResultFieldSet, *FieldValues, PartAttributes, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if err := s.writeRequest(mtExecuteDirect, false, command(query)); err != nil { + return 0, nil, nil, nil, err + } + + var id uint64 + var resultFieldSet *ResultFieldSet + fieldValues := newFieldValues() + + f := func(p replyPart) { + + switch p := p.(type) { + + case *resultsetID: + p.id = &id + case *resultMetadata: + resultFieldSet = newResultFieldSet(p.numArg) + p.resultFieldSet = resultFieldSet + case *resultset: + p.s = s + p.resultFieldSet = resultFieldSet + p.fieldValues = fieldValues + } + } + + if err := s.readReply(f); err != nil { + return 0, nil, nil, nil, err + } + + return id, resultFieldSet, fieldValues, s.ph.partAttributes, nil +} + +// ExecDirect executes a sql statement without statement parameters. +func (s *Session) ExecDirect(query string) (driver.Result, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if err := s.writeRequest(mtExecuteDirect, !s.conn.inTx, command(query)); err != nil { + return nil, err + } + + if err := s.readReply(nil); err != nil { + return nil, err + } + + if s.sh.functionCode == fcDDL { + return driver.ResultNoRows, nil + } + return driver.RowsAffected(s.rowsAffected.total()), nil +} + +// Prepare prepares a sql statement. +func (s *Session) Prepare(query string) (QueryType, uint64, *ParameterFieldSet, *ResultFieldSet, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if err := s.writeRequest(mtPrepare, false, command(query)); err != nil { + return QtNone, 0, nil, nil, err + } + + var id uint64 + var prmFieldSet *ParameterFieldSet + var resultFieldSet *ResultFieldSet + + f := func(p replyPart) { + + switch p := p.(type) { + + case *statementID: + p.id = &id + case *parameterMetadata: + prmFieldSet = newParameterFieldSet(p.numArg) + p.prmFieldSet = prmFieldSet + case *resultMetadata: + resultFieldSet = newResultFieldSet(p.numArg) + p.resultFieldSet = resultFieldSet + } + } + + if err := s.readReply(f); err != nil { + return QtNone, 0, nil, nil, err + } + + return s.sh.functionCode.queryType(), id, prmFieldSet, resultFieldSet, nil +} + +// Exec executes a sql statement. +func (s *Session) Exec(id uint64, prmFieldSet *ParameterFieldSet, args []driver.NamedValue) (driver.Result, error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.statementID.id = &id + if err := s.writeRequest(mtExecute, !s.conn.inTx, s.statementID, newInputParameters(prmFieldSet.inputFields(), args)); err != nil { + return nil, err + } + + if err := s.readReply(nil); err != nil { + return nil, err + } + + var result driver.Result + if s.sh.functionCode == fcDDL { + result = driver.ResultNoRows + } else { + result = driver.RowsAffected(s.rowsAffected.total()) + } + + if err := s.writeLobStream(prmFieldSet, nil, args); err != nil { + return nil, err + } + + return result, nil +} + +// DropStatementID releases the hdb statement handle. +func (s *Session) DropStatementID(id uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.statementID.id = &id + if err := s.writeRequest(mtDropStatementID, false, s.statementID); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + return nil +} + +// Call executes a stored procedure. +func (s *Session) Call(id uint64, prmFieldSet *ParameterFieldSet, args []driver.NamedValue) (*FieldValues, []*TableResult, error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.statementID.id = &id + if err := s.writeRequest(mtExecute, false, s.statementID, newInputParameters(prmFieldSet.inputFields(), args)); err != nil { + return nil, nil, err + } + + prmFieldValues := newFieldValues() + var tableResults []*TableResult + var tableResult *TableResult + + f := func(p replyPart) { + + switch p := p.(type) { + + case *outputParameters: + p.s = s + p.outputFields = prmFieldSet.outputFields() + p.fieldValues = prmFieldValues + + // table output parameters: meta, id, result (only first param?) + case *resultMetadata: + tableResult = newTableResult(s, p.numArg) + tableResults = append(tableResults, tableResult) + p.resultFieldSet = tableResult.resultFieldSet + case *resultsetID: + p.id = &(tableResult.id) + case *resultset: + p.s = s + tableResult.attrs = s.ph.partAttributes + p.resultFieldSet = tableResult.resultFieldSet + p.fieldValues = tableResult.fieldValues + } + } + + if err := s.readReply(f); err != nil { + return nil, nil, err + } + + if err := s.writeLobStream(prmFieldSet, prmFieldValues, args); err != nil { + return nil, nil, err + } + + return prmFieldValues, tableResults, nil +} + +// Query executes a query. +func (s *Session) Query(stmtID uint64, prmFieldSet *ParameterFieldSet, resultFieldSet *ResultFieldSet, args []driver.NamedValue) (uint64, *FieldValues, PartAttributes, error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.statementID.id = &stmtID + if err := s.writeRequest(mtExecute, false, s.statementID, newInputParameters(prmFieldSet.inputFields(), args)); err != nil { + return 0, nil, nil, err + } + + var rsetID uint64 + fieldValues := newFieldValues() + + f := func(p replyPart) { + + switch p := p.(type) { + + case *resultsetID: + p.id = &rsetID + case *resultset: + p.s = s + p.resultFieldSet = resultFieldSet + p.fieldValues = fieldValues + } + } + + if err := s.readReply(f); err != nil { + return 0, nil, nil, err + } + + return rsetID, fieldValues, s.ph.partAttributes, nil +} + +// FetchNext fetches next chunk in query result set. +func (s *Session) FetchNext(id uint64, resultFieldSet *ResultFieldSet, fieldValues *FieldValues) (PartAttributes, error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.resultsetID.id = &id + if err := s.writeRequest(mtFetchNext, false, s.resultsetID, fetchsize(s.prm.FetchSize())); err != nil { + return nil, err + } + + f := func(p replyPart) { + + switch p := p.(type) { + + case *resultset: + p.s = s + p.resultFieldSet = resultFieldSet + p.fieldValues = fieldValues + } + } + + if err := s.readReply(f); err != nil { + return nil, err + } + + return s.ph.partAttributes, nil +} + +// CloseResultsetID releases the hdb resultset handle. +func (s *Session) CloseResultsetID(id uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.resultsetID.id = &id + if err := s.writeRequest(mtCloseResultset, false, s.resultsetID); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + return nil +} + +// Commit executes a database commit. +func (s *Session) Commit() error { + s.mu.Lock() + defer s.mu.Unlock() + + if err := s.writeRequest(mtCommit, false); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + if trace { + outLogger.Printf("transaction flags: %s", s.txFlags) + } + + s.conn.inTx = false + return nil +} + +// Rollback executes a database rollback. +func (s *Session) Rollback() error { + s.mu.Lock() + defer s.mu.Unlock() + + if err := s.writeRequest(mtRollback, false); err != nil { + return err + } + + if err := s.readReply(nil); err != nil { + return err + } + + if trace { + outLogger.Printf("transaction flags: %s", s.txFlags) + } + + s.conn.inTx = false + return nil +} + +// + +func (s *Session) readLobStream(w lobChunkWriter) error { + + s.readLobRequest.w = w + s.readLobReply.w = w + + for !w.eof() { + + if err := s.writeRequest(mtWriteLob, false, s.readLobRequest); err != nil { + return err + } + if err := s.readReply(nil); err != nil { + return err + } + } + return nil +} + +func (s *Session) writeLobStream(prmFieldSet *ParameterFieldSet, prmFieldValues *FieldValues, args []driver.NamedValue) error { + + if s.writeLobReply.numArg == 0 { + return nil + } + + lobPrmFields := make([]*ParameterField, s.writeLobReply.numArg) + + j := 0 + for _, f := range prmFieldSet.fields { + if f.TypeCode().isLob() && f.In() && f.chunkReader != nil { + f.lobLocatorID = s.writeLobReply.ids[j] + lobPrmFields[j] = f + j++ + } + } + if j != s.writeLobReply.numArg { + return fmt.Errorf("protocol error: invalid number of lob parameter ids %d - expected %d", j, s.writeLobReply.numArg) + } + + s.writeLobRequest.lobPrmFields = lobPrmFields + + f := func(p replyPart) { + if p, ok := p.(*outputParameters); ok { + p.s = s + p.outputFields = prmFieldSet.outputFields() + p.fieldValues = prmFieldValues + } + } + + for s.writeLobReply.numArg != 0 { + if err := s.writeRequest(mtReadLob, false, s.writeLobRequest); err != nil { + return err + } + + if err := s.readReply(f); err != nil { + return err + } + } + + return nil +} + +// + +func (s *Session) initRequest() error { + + // init + s.mh.sessionID = -1 + + // handshake + req := newInitRequest() + // TODO: constants + req.product.major = 4 + req.product.minor = 20 + req.protocol.major = 4 + req.protocol.minor = 1 + req.numOptions = 1 + req.endianess = archEndian + if err := req.write(s.wr); err != nil { + return err + } + + rep := newInitReply() + if err := rep.read(s.rd); err != nil { + return err + } + return nil +} + +func (s *Session) writeRequest(messageType messageType, commit bool, requests ...requestPart) error { + + partSize := make([]int, len(requests)) + + size := int64(segmentHeaderSize + len(requests)*partHeaderSize) //int64 to hold MaxUInt32 in 32bit OS + + for i, part := range requests { + s, err := part.size() + if err != nil { + return err + } + size += int64(s + padBytes(s)) + partSize[i] = s // buffer size (expensive calculation) + } + + if size > math.MaxUint32 { + return fmt.Errorf("message size %d exceeds maximum message header value %d", size, int64(math.MaxUint32)) //int64: without cast overflow error in 32bit OS + } + + bufferSize := size + + s.mh.varPartLength = uint32(size) + s.mh.varPartSize = uint32(bufferSize) + s.mh.noOfSegm = 1 + + if err := s.mh.write(s.wr); err != nil { + return err + } + + if size > math.MaxInt32 { + return fmt.Errorf("message size %d exceeds maximum part header value %d", size, math.MaxInt32) + } + + s.sh.messageType = messageType + s.sh.commit = commit + s.sh.segmentKind = skRequest + s.sh.segmentLength = int32(size) + s.sh.segmentOfs = 0 + s.sh.noOfParts = int16(len(requests)) + s.sh.segmentNo = 1 + + if err := s.sh.write(s.wr); err != nil { + return err + } + + bufferSize -= segmentHeaderSize + + for i, part := range requests { + + size := partSize[i] + pad := padBytes(size) + + s.ph.partKind = part.kind() + numArg := part.numArg() + switch { + default: + return fmt.Errorf("maximum number of arguments %d exceeded", numArg) + case numArg <= math.MaxInt16: + s.ph.argumentCount = int16(numArg) + s.ph.bigArgumentCount = 0 + + // TODO: seems not to work: see bulk insert test + case numArg <= math.MaxInt32: + s.ph.argumentCount = 0 + s.ph.bigArgumentCount = int32(numArg) + } + + s.ph.bufferLength = int32(size) + s.ph.bufferSize = int32(bufferSize) + + if err := s.ph.write(s.wr); err != nil { + return err + } + + if err := part.write(s.wr); err != nil { + return err + } + + s.wr.WriteZeroes(pad) + + bufferSize -= int64(partHeaderSize + size + pad) + + } + + return s.wr.Flush() + +} + +func (s *Session) readReply(beforeRead beforeRead) error { + + replyRowsAffected := false + replyError := false + + if err := s.mh.read(s.rd); err != nil { + return err + } + if s.mh.noOfSegm != 1 { + return fmt.Errorf("simple message: no of segments %d - expected 1", s.mh.noOfSegm) + } + if err := s.sh.read(s.rd); err != nil { + return err + } + + // TODO: protocol error (sps 82)?: message header varPartLength < segment header segmentLength (*1) + diff := int(s.mh.varPartLength) - int(s.sh.segmentLength) + if trace && diff != 0 { + outLogger.Printf("+++++diff %d", diff) + } + + noOfParts := int(s.sh.noOfParts) + lastPart := noOfParts - 1 + + for i := 0; i < noOfParts; i++ { + + if err := s.ph.read(s.rd); err != nil { + return err + } + + numArg := int(s.ph.argumentCount) + + var part replyPart + + switch s.ph.partKind { + + case pkAuthentication: + if s.scramsha256InitialReply != nil { // first call: initial reply + part = s.scramsha256InitialReply + } else { // second call: final reply + part = s.scramsha256FinalReply + } + case pkTopologyInformation: + part = s.topologyInformation + case pkConnectOptions: + part = s.connectOptions + case pkStatementID: + part = s.statementID + case pkResultMetadata: + part = s.resultMetadata + case pkResultsetID: + part = s.resultsetID + case pkResultset: + part = s.resultset + case pkParameterMetadata: + part = s.parameterMetadata + case pkOutputParameters: + part = s.outputParameters + case pkError: + replyError = true + part = s.lastError + case pkStatementContext: + part = s.stmtCtx + case pkTransactionFlags: + part = s.txFlags + case pkRowsAffected: + replyRowsAffected = true + part = s.rowsAffected + case pkReadLobReply: + part = s.readLobReply + case pkWriteLobReply: + part = s.writeLobReply + default: + return fmt.Errorf("read not expected part kind %s", s.ph.partKind) + } + + part.setNumArg(numArg) + + if beforeRead != nil { + beforeRead(part) + } + + if err := part.read(s.rd); err != nil { + return err + } + + if i != lastPart { // not last part + // Error padding (protocol error?) + // driver test TestHDBWarning + // --> 18 bytes fix error bytes + 103 bytes error text => 121 bytes (7 bytes padding needed) + // but s.ph.bufferLength = 122 (standard padding would only consume 6 bytes instead of 7) + // driver test TestBulkInsertDuplicates + // --> returns 3 errors (number of total bytes matches s.ph.bufferLength) + // ==> hdbErrors take care about padding + if s.ph.partKind != pkError { + s.rd.Skip(padBytes(int(s.ph.bufferLength))) + } + } + } + + // last part + // TODO: workaround (see *) + if diff == 0 { + s.rd.Skip(padBytes(int(s.ph.bufferLength))) + } + + if err := s.rd.GetError(); err != nil { + return err + } + + if replyError { + if replyRowsAffected { //link statement to error + j := 0 + for i, rows := range s.rowsAffected.rows { + if rows == raExecutionFailed { + s.lastError.setStmtNo(j, i) + j++ + } + } + } + if s.lastError.isWarnings() { + for _, _error := range s.lastError.errors { + sqltrace.Traceln(_error) + } + return nil + } + return s.lastError + } + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/sniffer.go b/vendor/github.com/SAP/go-hdb/internal/protocol/sniffer.go new file mode 100644 index 0000000..33df324 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/sniffer.go @@ -0,0 +1,203 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "log" + "net" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type dir bool + +const ( + maxBinarySize = 128 +) + +type fragment interface { + read(rd *bufio.Reader) error + write(wr *bufio.Writer) error +} + +func (d dir) String() string { + if d { + return "->" + } + return "<-" +} + +// A Sniffer is a simple proxy for logging hdb protocol requests and responses. +type Sniffer struct { + conn net.Conn + dbAddr string + dbConn net.Conn + + //client + clRd *bufio.Reader + clWr *bufio.Writer + //database + dbRd *bufio.Reader + dbWr *bufio.Writer + + mh *messageHeader + sh *segmentHeader + ph *partHeader + + buf []byte +} + +// NewSniffer creates a new sniffer instance. The conn parameter is the net.Conn connection, where the Sniffer +// is listening for hdb protocol calls. The dbAddr is the hdb host port address in "host:port" format. +func NewSniffer(conn net.Conn, dbAddr string) (*Sniffer, error) { + s := &Sniffer{ + conn: conn, + dbAddr: dbAddr, + clRd: bufio.NewReader(conn), + clWr: bufio.NewWriter(conn), + mh: &messageHeader{}, + sh: &segmentHeader{}, + ph: &partHeader{}, + buf: make([]byte, 0), + } + + dbConn, err := net.Dial("tcp", s.dbAddr) + if err != nil { + return nil, err + } + + s.dbRd = bufio.NewReader(dbConn) + s.dbWr = bufio.NewWriter(dbConn) + s.dbConn = dbConn + return s, nil +} + +func (s *Sniffer) getBuffer(size int) []byte { + if cap(s.buf) < size { + s.buf = make([]byte, size) + } + return s.buf[:size] +} + +// Go starts the protocol request and response logging. +func (s *Sniffer) Go() { + defer s.dbConn.Close() + defer s.conn.Close() + + req := newInitRequest() + if err := s.streamFragment(dir(true), s.clRd, s.dbWr, req); err != nil { + return + } + + rep := newInitReply() + if err := s.streamFragment(dir(false), s.dbRd, s.clWr, rep); err != nil { + return + } + + for { + //up stream + if err := s.stream(dir(true), s.clRd, s.dbWr); err != nil { + return + } + //down stream + if err := s.stream(dir(false), s.dbRd, s.clWr); err != nil { + return + } + } +} + +func (s *Sniffer) stream(d dir, from *bufio.Reader, to *bufio.Writer) error { + + if err := s.streamFragment(d, from, to, s.mh); err != nil { + return err + } + + size := int(s.mh.varPartLength) + + for i := 0; i < int(s.mh.noOfSegm); i++ { + + if err := s.streamFragment(d, from, to, s.sh); err != nil { + return err + } + + size -= int(s.sh.segmentLength) + + for j := 0; j < int(s.sh.noOfParts); j++ { + + if err := s.streamFragment(d, from, to, s.ph); err != nil { + return err + } + + // protocol error workaraound + padding := (size == 0) || (j != (int(s.sh.noOfParts) - 1)) + + if err := s.streamPart(d, from, to, s.ph, padding); err != nil { + return err + } + } + } + return to.Flush() +} + +func (s *Sniffer) streamPart(d dir, from *bufio.Reader, to *bufio.Writer, ph *partHeader, padding bool) error { + + switch ph.partKind { + + default: + return s.streamBinary(d, from, to, int(ph.bufferLength), padding) + } +} + +func (s *Sniffer) streamBinary(d dir, from *bufio.Reader, to *bufio.Writer, size int, padding bool) error { + var b []byte + + //protocol error workaraound + if padding { + pad := padBytes(size) + b = s.getBuffer(size + pad) + } else { + b = s.getBuffer(size) + } + + from.ReadFull(b) + err := from.GetError() + if err != nil { + log.Print(err) + return err + } + + if size > maxBinarySize { + log.Printf("%s %v", d, b[:maxBinarySize]) + } else { + log.Printf("%s %v", d, b[:size]) + } + to.Write(b) + return nil +} + +func (s *Sniffer) streamFragment(d dir, from *bufio.Reader, to *bufio.Writer, f fragment) error { + if err := f.read(from); err != nil { + log.Print(err) + return err + } + log.Printf("%s %s", d, f) + if err := f.write(to); err != nil { + log.Print(err) + return err + } + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontext.go b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontext.go new file mode 100644 index 0000000..230fc45 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontext.go @@ -0,0 +1,60 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type statementContext struct { + options plainOptions + _numArg int +} + +func newStatementContext() *statementContext { + return &statementContext{ + options: plainOptions{}, + } +} + +func (c *statementContext) String() string { + typedSc := make(map[statementContextType]interface{}) + for k, v := range c.options { + typedSc[statementContextType(k)] = v + } + return fmt.Sprintf("%s", typedSc) +} + +func (c *statementContext) kind() partKind { + return pkStatementContext +} + +func (c *statementContext) setNumArg(numArg int) { + c._numArg = numArg +} + +func (c *statementContext) read(rd *bufio.Reader) error { + c.options.read(rd, c._numArg) + + if trace { + outLogger.Printf("statement context: %v", c) + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype.go b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype.go new file mode 100644 index 0000000..7e9133b --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype.go @@ -0,0 +1,26 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=statementContextType + +type statementContextType int8 + +const ( + scStatementSequenceInfo statementContextType = 1 + scServerExecutionTime statementContextType = 2 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype_string.go new file mode 100644 index 0000000..3a9ac78 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype_string.go @@ -0,0 +1,17 @@ +// Code generated by "stringer -type=statementContextType"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _statementContextType_name = "scStatementSequenceInfoscServerExecutionTime" + +var _statementContextType_index = [...]uint8{0, 23, 44} + +func (i statementContextType) String() string { + i -= 1 + if i < 0 || i >= statementContextType(len(_statementContextType_index)-1) { + return "statementContextType(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _statementContextType_name[_statementContextType_index[i]:_statementContextType_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/statementid.go b/vendor/github.com/SAP/go-hdb/internal/protocol/statementid.go new file mode 100644 index 0000000..c98f709 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/statementid.go @@ -0,0 +1,66 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "github.com/SAP/go-hdb/internal/bufio" +) + +const ( + statementIDSize = 8 +) + +type statementID struct { + id *uint64 +} + +func (id statementID) kind() partKind { + return pkStatementID +} + +func (id statementID) size() (int, error) { + return statementIDSize, nil +} + +func (id statementID) numArg() int { + return 1 +} + +func (id statementID) setNumArg(int) { + //ignore - always 1 +} + +func (id *statementID) read(rd *bufio.Reader) error { + _id := rd.ReadUint64() + *id.id = _id + + if trace { + outLogger.Printf("statement id: %d", *id.id) + } + + return rd.GetError() +} + +func (id statementID) write(wr *bufio.Writer) error { + wr.WriteUint64(*id.id) + + if trace { + outLogger.Printf("statement id: %d", *id.id) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/tableresult.go b/vendor/github.com/SAP/go-hdb/internal/protocol/tableresult.go new file mode 100644 index 0000000..7492901 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/tableresult.go @@ -0,0 +1,52 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +// TableResult is the package internal representation of a table like output parameter of a stored procedure. +type TableResult struct { + id uint64 + resultFieldSet *ResultFieldSet + fieldValues *FieldValues + attrs partAttributes +} + +func newTableResult(s *Session, size int) *TableResult { + return &TableResult{ + resultFieldSet: newResultFieldSet(size), + fieldValues: newFieldValues(), + } +} + +// ID returns the resultset id. +func (r *TableResult) ID() uint64 { + return r.id +} + +// FieldSet returns the field metadata of the table. +func (r *TableResult) FieldSet() *ResultFieldSet { + return r.resultFieldSet +} + +// FieldValues returns the field values (fetched resultset part) of the table. +func (r *TableResult) FieldValues() *FieldValues { + return r.fieldValues +} + +// Attrs returns the PartAttributes interface of the fetched resultset part. +func (r *TableResult) Attrs() PartAttributes { + return r.attrs +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/time.go b/vendor/github.com/SAP/go-hdb/internal/protocol/time.go new file mode 100644 index 0000000..f4f171f --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/time.go @@ -0,0 +1,64 @@ +/* +Copyright 2017 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "time" +) + +const gregorianDay = 2299161 // Start date of Gregorian Calendar as Julian Day Number +var gregorianDate = julianDayToTime(gregorianDay) // Start date of Gregorian Calendar (1582-10-15) + +// timeToJulianDay returns the Julian Date Number of time's date components. +// The algorithm is taken from https://en.wikipedia.org/wiki/Julian_day. +func timeToJulianDay(t time.Time) int { + + t = t.UTC() + + month := int(t.Month()) + + a := (14 - month) / 12 + y := t.Year() + 4800 - a + m := month + (12 * a) - 3 + + if t.Before(gregorianDate) { // Julian Calendar + return t.Day() + (153*m+2)/5 + 365*y + y/4 - 32083 + } + // Gregorian Calendar + return t.Day() + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045 +} + +// JulianDayToTime returns the correcponding UTC date for a Julian Day Number. +// The algorithm is taken from https://en.wikipedia.org/wiki/Julian_day. +func julianDayToTime(jd int) time.Time { + var f int + + if jd < gregorianDay { + f = jd + 1401 + } else { + f = jd + 1401 + (((4*jd+274277)/146097)*3)/4 - 38 + } + + e := 4*f + 3 + g := (e % 1461) / 4 + h := 5*g + 2 + day := (h%153)/5 + 1 + month := (h/153+2)%12 + 1 + year := (e / 1461) - 4716 + (12+2-month)/12 + + return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/topology.go b/vendor/github.com/SAP/go-hdb/internal/protocol/topology.go new file mode 100644 index 0000000..53555d6 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/topology.go @@ -0,0 +1,85 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type topologyInformation struct { + mlo multiLineOptions + _numArg int +} + +func newTopologyInformation() *topologyInformation { + return &topologyInformation{ + mlo: multiLineOptions{}, + } +} + +func (o *topologyInformation) String() string { + mlo := make([]map[topologyOption]interface{}, len(o.mlo)) + for i, po := range o.mlo { + typedPo := make(map[topologyOption]interface{}) + for k, v := range po { + typedPo[topologyOption(k)] = v + } + mlo[i] = typedPo + } + return fmt.Sprintf("%s", mlo) +} + +func (o *topologyInformation) kind() partKind { + return pkTopologyInformation +} + +func (o *topologyInformation) size() int { + return o.mlo.size() +} + +func (o *topologyInformation) numArg() int { + return len(o.mlo) +} + +func (o *topologyInformation) setNumArg(numArg int) { + o._numArg = numArg +} + +func (o *topologyInformation) read(rd *bufio.Reader) error { + o.mlo.read(rd, o._numArg) + + if trace { + outLogger.Printf("topology options: %v", o) + } + + return rd.GetError() +} + +func (o *topologyInformation) write(wr *bufio.Writer) error { + for _, m := range o.mlo { + wr.WriteInt16(int16(len(m))) + o.mlo.write(wr) + } + + if trace { + outLogger.Printf("topology options: %v", o) + } + + return nil +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption.go b/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption.go new file mode 100644 index 0000000..e5de91e --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption.go @@ -0,0 +1,36 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=topologyOption + +type topologyOption int8 + +const ( + toHostName topologyOption = 1 + toHostPortnumber topologyOption = 2 + toTenantName topologyOption = 3 + toLoadfactor topologyOption = 4 + toVolumeID topologyOption = 5 + toIsMaster topologyOption = 6 + toIsCurrentSession topologyOption = 7 + toServiceType topologyOption = 8 + toNetworkDomain topologyOption = 9 + toIsStandby topologyOption = 10 + toAllIPAddresses topologyOption = 11 + toAllHostNames topologyOption = 12 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption_string.go new file mode 100644 index 0000000..3c77565 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption_string.go @@ -0,0 +1,17 @@ +// Code generated by "stringer -type=topologyOption"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _topologyOption_name = "toHostNametoHostPortnumbertoTenantNametoLoadfactortoVolumeIDtoIsMastertoIsCurrentSessiontoServiceTypetoNetworkDomaintoIsStandbytoAllIPAddressestoAllHostNames" + +var _topologyOption_index = [...]uint8{0, 10, 26, 38, 50, 60, 70, 88, 101, 116, 127, 143, 157} + +func (i topologyOption) String() string { + i -= 1 + if i < 0 || i >= topologyOption(len(_topologyOption_index)-1) { + return "topologyOption(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _topologyOption_name[_topologyOption_index[i]:_topologyOption_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflags.go b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflags.go new file mode 100644 index 0000000..584e338 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflags.go @@ -0,0 +1,60 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "fmt" + + "github.com/SAP/go-hdb/internal/bufio" +) + +type transactionFlags struct { + options plainOptions + _numArg int +} + +func newTransactionFlags() *transactionFlags { + return &transactionFlags{ + options: plainOptions{}, + } +} + +func (f *transactionFlags) String() string { + typedSc := make(map[transactionFlagType]interface{}) + for k, v := range f.options { + typedSc[transactionFlagType(k)] = v + } + return fmt.Sprintf("%s", typedSc) +} + +func (f *transactionFlags) kind() partKind { + return pkTransactionFlags +} + +func (f *transactionFlags) setNumArg(numArg int) { + f._numArg = numArg +} + +func (f *transactionFlags) read(rd *bufio.Reader) error { + f.options.read(rd, f._numArg) + + if trace { + outLogger.Printf("transaction flags: %v", f) + } + + return rd.GetError() +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype.go b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype.go new file mode 100644 index 0000000..28ad7d3 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype.go @@ -0,0 +1,32 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +//go:generate stringer -type=transactionFlagType + +//transaction flags +type transactionFlagType int8 + +const ( + tfRolledback transactionFlagType = 0 + tfCommited transactionFlagType = 1 + tfNewIsolationLevel transactionFlagType = 2 + tfDDLCommitmodeChanged transactionFlagType = 3 + tfWriteTransactionStarted transactionFlagType = 4 + tfNowriteTransactionStarted transactionFlagType = 5 + tfSessionClosingTransactionError transactionFlagType = 6 +) diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype_string.go new file mode 100644 index 0000000..9140322 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=transactionFlagType"; DO NOT EDIT. + +package protocol + +import "strconv" + +const _transactionFlagType_name = "tfRolledbacktfCommitedtfNewIsolationLeveltfDDLCommitmodeChangedtfWriteTransactionStartedtfNowriteTransactionStartedtfSessionClosingTransactionError" + +var _transactionFlagType_index = [...]uint8{0, 12, 22, 41, 63, 88, 115, 147} + +func (i transactionFlagType) String() string { + if i < 0 || i >= transactionFlagType(len(_transactionFlagType_index)-1) { + return "transactionFlagType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _transactionFlagType_name[_transactionFlagType_index[i]:_transactionFlagType_index[i+1]] +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/typecode.go b/vendor/github.com/SAP/go-hdb/internal/protocol/typecode.go new file mode 100644 index 0000000..c4c2265 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/typecode.go @@ -0,0 +1,159 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protocol + +import ( + "strings" +) + +//go:generate stringer -type=TypeCode + +// TypeCode identify the type of a field transferred to or from the database. +type TypeCode byte + +// null value indicator is high bit + +const ( + tcNull TypeCode = 0 + tcTinyint TypeCode = 1 + tcSmallint TypeCode = 2 + tcInteger TypeCode = 3 + tcBigint TypeCode = 4 + tcDecimal TypeCode = 5 + tcReal TypeCode = 6 + tcDouble TypeCode = 7 + tcChar TypeCode = 8 + tcVarchar TypeCode = 9 + tcNchar TypeCode = 10 + tcNvarchar TypeCode = 11 + tcBinary TypeCode = 12 + tcVarbinary TypeCode = 13 + // deprecated with 3 (doku) - but table 'date' field uses it + tcDate TypeCode = 14 + // deprecated with 3 (doku) - but table 'time' field uses it + tcTime TypeCode = 15 + // deprecated with 3 (doku) - but table 'timestamp' field uses it + tcTimestamp TypeCode = 16 + //tcTimetz TypeCode = 17 // reserved: do not use + //tcTimeltz TypeCode = 18 // reserved: do not use + //tcTimestamptz TypeCode = 19 // reserved: do not use + //tcTimestampltz TypeCode = 20 // reserved: do not use + //tcInvervalym TypeCode = 21 // reserved: do not use + //tcInvervalds TypeCode = 22 // reserved: do not use + //tcRowid TypeCode = 23 // reserved: do not use + //tcUrowid TypeCode = 24 // reserved: do not use + tcClob TypeCode = 25 + tcNclob TypeCode = 26 + tcBlob TypeCode = 27 + tcBoolean TypeCode = 28 + tcString TypeCode = 29 + tcNstring TypeCode = 30 + tcBlocator TypeCode = 31 + tcNlocator TypeCode = 32 + tcBstring TypeCode = 33 + //tcDecimaldigitarray TypeCode = 34 // reserved: do not use + tcVarchar2 TypeCode = 35 + tcVarchar3 TypeCode = 36 + tcNvarchar3 TypeCode = 37 + tcVarbinary3 TypeCode = 38 + //tcVargroup TypeCode = 39 // reserved: do not use + //tcTinyintnotnull TypeCode = 40 // reserved: do not use + //tcSmallintnotnull TypeCode = 41 // reserved: do not use + //tcIntnotnull TypeCode = 42 // reserved: do not use + //tcBigintnotnull TypeCode = 43 // reserved: do not use + //tcArgument TypeCode = 44 // reserved: do not use + //tcTable TypeCode = 45 // reserved: do not use + //tcCursor TypeCode = 46 // reserved: do not use + tcSmalldecimal TypeCode = 47 + //tcAbapitab TypeCode = 48 // not supported by GO hdb driver + //tcAbapstruct TypeCode = 49 // not supported by GO hdb driver + tcArray TypeCode = 50 + tcText TypeCode = 51 + tcShorttext TypeCode = 52 + //tcFixedString TypeCode = 53 // reserved: do not use + //tcFixedpointdecimal TypeCode = 54 // reserved: do not use + tcAlphanum TypeCode = 55 + //tcTlocator TypeCode = 56 // reserved: do not use + tcLongdate TypeCode = 61 + tcSeconddate TypeCode = 62 + tcDaydate TypeCode = 63 + tcSecondtime TypeCode = 64 + //tcCte TypeCode = 65 // reserved: do not use + //tcCstimesda TypeCode = 66 // reserved: do not use + //tcBlobdisk TypeCode = 71 // reserved: do not use + //tcClobdisk TypeCode = 72 // reserved: do not use + //tcNclobdisk TypeCode = 73 // reserved: do not use + //tcGeometry TypeCode = 74 // reserved: do not use + //tcPoint TypeCode = 75 // reserved: do not use + //tcFixed16 TypeCode = 76 // reserved: do not use + //tcBlobhybrid TypeCode = 77 // reserved: do not use + //tcClobhybrid TypeCode = 78 // reserved: do not use + //tcNclobhybrid TypeCode = 79 // reserved: do not use + //tcPointz TypeCode = 80 // reserved: do not use +) + +func (k TypeCode) isLob() bool { + return k == tcClob || k == tcNclob || k == tcBlob +} + +func (k TypeCode) isCharBased() bool { + return k == tcNvarchar || k == tcNstring || k == tcNclob +} + +func (k TypeCode) isVariableLength() bool { + return k == tcChar || k == tcNchar || k == tcVarchar || k == tcNvarchar || k == tcBinary || k == tcVarbinary || k == tcShorttext || k == tcAlphanum +} + +func (k TypeCode) isDecimalType() bool { + return k == tcSmalldecimal || k == tcDecimal +} + +// DataType converts a type code into one of the supported data types by the driver. +func (k TypeCode) DataType() DataType { + switch k { + default: + return DtUnknown + case tcTinyint: + return DtTinyint + case tcSmallint: + return DtSmallint + case tcInteger: + return DtInteger + case tcBigint: + return DtBigint + case tcReal: + return DtReal + case tcDouble: + return DtDouble + case tcDate, tcTime, tcTimestamp, tcLongdate, tcSeconddate, tcDaydate, tcSecondtime: + return DtTime + case tcDecimal: + return DtDecimal + case tcChar, tcVarchar, tcString, tcNchar, tcNvarchar, tcNstring: + return DtString + case tcBinary, tcVarbinary: + return DtBytes + case tcBlob, tcClob, tcNclob: + return DtLob + } +} + +// TypeName returns the database type name. +// see https://golang.org/pkg/database/sql/driver/#RowsColumnTypeDatabaseTypeName +func (k TypeCode) TypeName() string { + return strings.ToUpper(k.String()[2:]) +} diff --git a/vendor/github.com/SAP/go-hdb/internal/protocol/typecode_string.go b/vendor/github.com/SAP/go-hdb/internal/protocol/typecode_string.go new file mode 100644 index 0000000..9a534f7 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/protocol/typecode_string.go @@ -0,0 +1,48 @@ +// Code generated by "stringer -type=TypeCode"; DO NOT EDIT. + +package protocol + +import "strconv" + +const ( + _TypeCode_name_0 = "tcNulltcTinyinttcSmallinttcIntegertcBiginttcDecimaltcRealtcDoubletcChartcVarchartcNchartcNvarchartcBinarytcVarbinarytcDatetcTimetcTimestamp" + _TypeCode_name_1 = "tcClobtcNclobtcBlobtcBooleantcStringtcNstringtcBlocatortcNlocatortcBstring" + _TypeCode_name_2 = "tcVarchar2tcVarchar3tcNvarchar3tcVarbinary3" + _TypeCode_name_3 = "tcSmalldecimal" + _TypeCode_name_4 = "tcArraytcTexttcShorttext" + _TypeCode_name_5 = "tcAlphanum" + _TypeCode_name_6 = "tcLongdatetcSeconddatetcDaydatetcSecondtime" +) + +var ( + _TypeCode_index_0 = [...]uint8{0, 6, 15, 25, 34, 42, 51, 57, 65, 71, 80, 87, 97, 105, 116, 122, 128, 139} + _TypeCode_index_1 = [...]uint8{0, 6, 13, 19, 28, 36, 45, 55, 65, 74} + _TypeCode_index_2 = [...]uint8{0, 10, 20, 31, 43} + _TypeCode_index_4 = [...]uint8{0, 7, 13, 24} + _TypeCode_index_6 = [...]uint8{0, 10, 22, 31, 43} +) + +func (i TypeCode) String() string { + switch { + case 0 <= i && i <= 16: + return _TypeCode_name_0[_TypeCode_index_0[i]:_TypeCode_index_0[i+1]] + case 25 <= i && i <= 33: + i -= 25 + return _TypeCode_name_1[_TypeCode_index_1[i]:_TypeCode_index_1[i+1]] + case 35 <= i && i <= 38: + i -= 35 + return _TypeCode_name_2[_TypeCode_index_2[i]:_TypeCode_index_2[i+1]] + case i == 47: + return _TypeCode_name_3 + case 50 <= i && i <= 52: + i -= 50 + return _TypeCode_name_4[_TypeCode_index_4[i]:_TypeCode_index_4[i+1]] + case i == 55: + return _TypeCode_name_5 + case 61 <= i && i <= 64: + i -= 61 + return _TypeCode_name_6[_TypeCode_index_6[i]:_TypeCode_index_6[i+1]] + default: + return "TypeCode(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/github.com/SAP/go-hdb/internal/unicode/cesu8/cesu8.go b/vendor/github.com/SAP/go-hdb/internal/unicode/cesu8/cesu8.go new file mode 100644 index 0000000..882dbf6 --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/unicode/cesu8/cesu8.go @@ -0,0 +1,240 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package cesu8 implements functions and constants to support text encoded in CESU-8. +// It implements functions comparable to the unicode/utf8 package for UTF-8 de- and encoding. +package cesu8 + +import ( + "unicode/utf16" + "unicode/utf8" +) + +const ( + // CESUMax is the maximum amount of bytes used by an CESU-8 codepoint encoding. + CESUMax = 6 +) + +// Size returns the amount of bytes needed to encode an UTF-8 byte slice to CESU-8. +func Size(p []byte) int { + n := 0 + for i := 0; i < len(p); { + r, size, _ := decodeRune(p[i:]) + i += size + n += RuneLen(r) + } + return n +} + +// StringSize is like Size with a string as parameter. +func StringSize(s string) int { + n := 0 + for _, r := range s { + n += RuneLen(r) + } + return n +} + +// EncodeRune writes into p (which must be large enough) the CESU-8 encoding of the rune. It returns the number of bytes written. +func EncodeRune(p []byte, r rune) int { + if r <= rune3Max { + return encodeRune(p, r) + } + high, low := utf16.EncodeRune(r) + n := encodeRune(p, high) + n += encodeRune(p[n:], low) + return n +} + +// FullRune reports whether the bytes in p begin with a full CESU-8 encoding of a rune. +func FullRune(p []byte) bool { + high, n, short := decodeRune(p) + if short { + return false + } + if !utf16.IsSurrogate(high) { + return true + } + _, _, short = decodeRune(p[n:]) + return !short +} + +// DecodeRune unpacks the first CESU-8 encoding in p and returns the rune and its width in bytes. +func DecodeRune(p []byte) (rune, int) { + high, n1, _ := decodeRune(p) + if !utf16.IsSurrogate(high) { + return high, n1 + } + low, n2, _ := decodeRune(p[n1:]) + if low == utf8.RuneError { + return low, n1 + n2 + } + return utf16.DecodeRune(high, low), n1 + n2 +} + +// RuneLen returns the number of bytes required to encode the rune. +func RuneLen(r rune) int { + switch { + case r < 0: + return -1 + case r <= rune1Max: + return 1 + case r <= rune2Max: + return 2 + case r <= rune3Max: + return 3 + case r <= utf8.MaxRune: + return CESUMax + } + return -1 +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// Copied from unicode utf8 +// - allow utf8 encoding of utf16 surrogate values +// - see (*) for code changes + +// Code points in the surrogate range are not valid for UTF-8. +const ( + surrogateMin = 0xD800 + surrogateMax = 0xDFFF +) + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 +) + +func encodeRune(p []byte, r rune) int { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p[0] = byte(r) + return 1 + case i <= rune2Max: + p[0] = t2 | byte(r>>6) + p[1] = tx | byte(r)&maskx + return 2 + //case i > MaxRune, surrogateMin <= i && i <= surrogateMax: // replaced (*) + case i > utf8.MaxRune: // (*) + r = utf8.RuneError + fallthrough + case i <= rune3Max: + p[0] = t3 | byte(r>>12) + p[1] = tx | byte(r>>6)&maskx + p[2] = tx | byte(r)&maskx + return 3 + default: + p[0] = t4 | byte(r>>18) + p[1] = tx | byte(r>>12)&maskx + p[2] = tx | byte(r>>6)&maskx + p[3] = tx | byte(r)&maskx + return 4 + } +} + +func decodeRune(p []byte) (r rune, size int, short bool) { + n := len(p) + if n < 1 { + return utf8.RuneError, 0, true + } + c0 := p[0] + + // 1-byte, 7-bit sequence? + if c0 < tx { + return rune(c0), 1, false + } + + // unexpected continuation byte? + if c0 < t2 { + return utf8.RuneError, 1, false + } + + // need first continuation byte + if n < 2 { + return utf8.RuneError, 1, true + } + c1 := p[1] + if c1 < tx || t2 <= c1 { + return utf8.RuneError, 1, false + } + + // 2-byte, 11-bit sequence? + if c0 < t3 { + r = rune(c0&mask2)<<6 | rune(c1&maskx) + if r <= rune1Max { + return utf8.RuneError, 1, false + } + return r, 2, false + } + + // need second continuation byte + if n < 3 { + return utf8.RuneError, 1, true + } + c2 := p[2] + if c2 < tx || t2 <= c2 { + return utf8.RuneError, 1, false + } + + // 3-byte, 16-bit sequence? + if c0 < t4 { + r = rune(c0&mask3)<<12 | rune(c1&maskx)<<6 | rune(c2&maskx) + if r <= rune2Max { + return utf8.RuneError, 1, false + } + // do not throw error on surrogates // (*) + //if surrogateMin <= r && r <= surrogateMax { + // return RuneError, 1, false + //} + return r, 3, false + } + + // need third continuation byte + if n < 4 { + return utf8.RuneError, 1, true + } + c3 := p[3] + if c3 < tx || t2 <= c3 { + return utf8.RuneError, 1, false + } + + // 4-byte, 21-bit sequence? + if c0 < t5 { + r = rune(c0&mask4)<<18 | rune(c1&maskx)<<12 | rune(c2&maskx)<<6 | rune(c3&maskx) + if r <= rune3Max || utf8.MaxRune < r { + return utf8.RuneError, 1, false + } + return r, 4, false + } + + // error + return utf8.RuneError, 1, false +} diff --git a/vendor/github.com/SAP/go-hdb/internal/unicode/unicode.go b/vendor/github.com/SAP/go-hdb/internal/unicode/unicode.go new file mode 100644 index 0000000..be9cf3c --- /dev/null +++ b/vendor/github.com/SAP/go-hdb/internal/unicode/unicode.go @@ -0,0 +1,111 @@ +/* +Copyright 2014 SAP SE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package unicode implements UTF-8 to CESU-8 and vice versa transformations. +package unicode + +import ( + "errors" + "unicode/utf8" + + "github.com/SAP/go-hdb/internal/unicode/cesu8" + "golang.org/x/text/transform" +) + +var ( + // Utf8ToCesu8Transformer implements the golang.org/x/text/transform/Transformer interface for UTF-8 to CESU-8 transformation. + Utf8ToCesu8Transformer = new(utf8ToCesu8Transformer) + // Cesu8ToUtf8Transformer implements the golang.org/x/text/transform/Transformer interface for CESU-8 to UTF-8 transformation. + Cesu8ToUtf8Transformer = new(cesu8ToUtf8Transformer) + // ErrInvalidUtf8 means that a transformer detected invalid UTF-8 data. + ErrInvalidUtf8 = errors.New("Invalid UTF-8") + // ErrInvalidCesu8 means that a transformer detected invalid CESU-8 data. + ErrInvalidCesu8 = errors.New("Invalid CESU-8") +) + +type utf8ToCesu8Transformer struct{ transform.NopResetter } + +func (t *utf8ToCesu8Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + i, j := 0, 0 + for i < len(src) { + if src[i] < utf8.RuneSelf { + if j < len(dst) { + dst[j] = src[i] + i++ + j++ + } else { + return j, i, transform.ErrShortDst + } + } else { + if !utf8.FullRune(src[i:]) { + return j, i, transform.ErrShortSrc + } + r, n := utf8.DecodeRune(src[i:]) + if r == utf8.RuneError { + return j, i, ErrInvalidUtf8 + } + m := cesu8.RuneLen(r) + if m == -1 { + panic("internal UTF-8 to CESU-8 transformation error") + } + if j+m <= len(dst) { + cesu8.EncodeRune(dst[j:], r) + i += n + j += m + } else { + return j, i, transform.ErrShortDst + } + } + } + return j, i, nil +} + +type cesu8ToUtf8Transformer struct{ transform.NopResetter } + +func (t *cesu8ToUtf8Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + i, j := 0, 0 + for i < len(src) { + if src[i] < utf8.RuneSelf { + if j < len(dst) { + dst[j] = src[i] + i++ + j++ + } else { + return j, i, transform.ErrShortDst + } + } else { + if !cesu8.FullRune(src[i:]) { + return j, i, transform.ErrShortSrc + } + r, n := cesu8.DecodeRune(src[i:]) + if r == utf8.RuneError { + return j, i, ErrInvalidCesu8 + } + m := utf8.RuneLen(r) + if m == -1 { + panic("internal CESU-8 to UTF-8 transformation error") + } + if j+m <= len(dst) { + utf8.EncodeRune(dst[j:], r) + i += n + j += m + } else { + return j, i, transform.ErrShortDst + } + } + } + return j, i, nil +} diff --git a/vendor/github.com/SermoDigital/jose/.gitignore b/vendor/github.com/SermoDigital/jose/.gitignore new file mode 100644 index 0000000..7bae159 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/.gitignore @@ -0,0 +1,29 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +*.out +*.tmp +tags + diff --git a/vendor/github.com/SermoDigital/jose/.travis.yml b/vendor/github.com/SermoDigital/jose/.travis.yml new file mode 100644 index 0000000..6f70d93 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.6 + - 1.7 + - tip + +sudo: false + +install: + - go get -u github.com/golang/lint/golint + +script: + - ./_test.sh diff --git a/vendor/github.com/SermoDigital/jose/LICENSE b/vendor/github.com/SermoDigital/jose/LICENSE new file mode 100644 index 0000000..d2d35b6 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Sermo Digital LLC + +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/vendor/github.com/SermoDigital/jose/README.md b/vendor/github.com/SermoDigital/jose/README.md new file mode 100644 index 0000000..44edd54 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/README.md @@ -0,0 +1,40 @@ +JOSE +============ +[![Build Status](https://travis-ci.org/SermoDigital/jose.svg?branch=master)](https://travis-ci.org/SermoDigital/jose) +[![GoDoc](https://godoc.org/github.com/SermoDigital/jose?status.svg)](https://godoc.org/github.com/SermoDigital/jose) + +JOSE is a comprehensive set of JWT, JWS, and JWE libraries. + +## Why + +The only other JWS/JWE/JWT implementations are specific to JWT, and none +were particularly pleasant to work with. + +These libraries should provide an easy, straightforward way to securely +create, parse, and validate JWS, JWE, and JWTs. + +## Notes: +JWE is currently unimplemented. + +## Version 0.9: + +## Documentation + +The docs can be found at [godoc.org] [docs], as usual. + +A gopkg.in mirror can be found at https://gopkg.in/jose.v1, thanks to +@zia-newversion. (For context, see #30.) + +### [JWS RFC][jws] +### [JWE RFC][jwe] +### [JWT RFC][jwt] + +## License + +[MIT] [license]. + +[docs]: https://godoc.org/github.com/SermoDigital/jose +[license]: https://github.com/SermoDigital/jose/blob/master/LICENSE.md +[jws]: https://tools.ietf.org/html/rfc7515 +[jwe]: https://tools.ietf.org/html/rfc7516 +[jwt]: https://tools.ietf.org/html/rfc7519 diff --git a/vendor/github.com/SermoDigital/jose/_test.sh b/vendor/github.com/SermoDigital/jose/_test.sh new file mode 100755 index 0000000..a36a470 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/_test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +go build ./... +go test ./... +golint ./... +go vet ./... \ No newline at end of file diff --git a/vendor/github.com/SermoDigital/jose/base64.go b/vendor/github.com/SermoDigital/jose/base64.go new file mode 100644 index 0000000..f7275fb --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/base64.go @@ -0,0 +1,44 @@ +package jose + +import "encoding/base64" + +// Encoder is satisfied if the type can marshal itself into a valid +// structure for a JWS. +type Encoder interface { + // Base64 implies T -> JSON -> RawURLEncodingBase64 + Base64() ([]byte, error) +} + +// Base64Decode decodes a base64-encoded byte slice. +func Base64Decode(b []byte) ([]byte, error) { + buf := make([]byte, base64.RawURLEncoding.DecodedLen(len(b))) + n, err := base64.RawURLEncoding.Decode(buf, b) + return buf[:n], err +} + +// Base64Encode encodes a byte slice. +func Base64Encode(b []byte) []byte { + buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(b))) + base64.RawURLEncoding.Encode(buf, b) + return buf +} + +// EncodeEscape base64-encodes a byte slice but escapes it for JSON. +// It'll return the format: `"base64"` +func EncodeEscape(b []byte) []byte { + buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(b))+2) + buf[0] = '"' + base64.RawURLEncoding.Encode(buf[1:], b) + buf[len(buf)-1] = '"' + return buf +} + +// DecodeEscaped decodes a base64-encoded byte slice straight from a JSON +// structure. It assumes it's in the format: `"base64"`, but can handle +// cases where it's not. +func DecodeEscaped(b []byte) ([]byte, error) { + if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' { + b = b[1 : len(b)-1] + } + return Base64Decode(b) +} diff --git a/vendor/github.com/SermoDigital/jose/crypto/doc.go b/vendor/github.com/SermoDigital/jose/crypto/doc.go new file mode 100644 index 0000000..16cf476 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/doc.go @@ -0,0 +1,4 @@ +// Package crypto implements "SigningMethods" and "EncryptionMethods"; +// that is, ways to sign and encrypt JWS and JWEs, respectively, as well +// as JWTs. +package crypto diff --git a/vendor/github.com/SermoDigital/jose/crypto/ecdsa.go b/vendor/github.com/SermoDigital/jose/crypto/ecdsa.go new file mode 100644 index 0000000..3ef12ba --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/ecdsa.go @@ -0,0 +1,117 @@ +package crypto + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "encoding/json" + "errors" + "math/big" +) + +// ErrECDSAVerification is missing from crypto/ecdsa compared to crypto/rsa +var ErrECDSAVerification = errors.New("crypto/ecdsa: verification error") + +// SigningMethodECDSA implements the ECDSA family of signing methods signing +// methods +type SigningMethodECDSA struct { + Name string + Hash crypto.Hash + _ struct{} +} + +// ECPoint is a marshalling structure for the EC points R and S. +type ECPoint struct { + R *big.Int + S *big.Int +} + +// Specific instances of EC SigningMethods. +var ( + // SigningMethodES256 implements ES256. + SigningMethodES256 = &SigningMethodECDSA{ + Name: "ES256", + Hash: crypto.SHA256, + } + + // SigningMethodES384 implements ES384. + SigningMethodES384 = &SigningMethodECDSA{ + Name: "ES384", + Hash: crypto.SHA384, + } + + // SigningMethodES512 implements ES512. + SigningMethodES512 = &SigningMethodECDSA{ + Name: "ES512", + Hash: crypto.SHA512, + } +) + +// Alg returns the name of the SigningMethodECDSA instance. +func (m *SigningMethodECDSA) Alg() string { return m.Name } + +// Verify implements the Verify method from SigningMethod. +// For this verify method, key must be an *ecdsa.PublicKey. +func (m *SigningMethodECDSA) Verify(raw []byte, signature Signature, key interface{}) error { + + ecdsaKey, ok := key.(*ecdsa.PublicKey) + if !ok { + return ErrInvalidKey + } + + // Unmarshal asn1 ECPoint + var ecpoint ECPoint + if _, err := asn1.Unmarshal(signature, &ecpoint); err != nil { + return err + } + + // Verify the signature + if !ecdsa.Verify(ecdsaKey, m.sum(raw), ecpoint.R, ecpoint.S) { + return ErrECDSAVerification + } + return nil +} + +// Sign implements the Sign method from SigningMethod. +// For this signing method, key must be an *ecdsa.PrivateKey. +func (m *SigningMethodECDSA) Sign(data []byte, key interface{}) (Signature, error) { + + ecdsaKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, ErrInvalidKey + } + + r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, m.sum(data)) + if err != nil { + return nil, err + } + + signature, err := asn1.Marshal(ECPoint{R: r, S: s}) + if err != nil { + return nil, err + } + return Signature(signature), nil +} + +func (m *SigningMethodECDSA) sum(b []byte) []byte { + h := m.Hash.New() + h.Write(b) + return h.Sum(nil) +} + +// Hasher implements the Hasher method from SigningMethod. +func (m *SigningMethodECDSA) Hasher() crypto.Hash { + return m.Hash +} + +// MarshalJSON is in case somebody decides to place SigningMethodECDSA +// inside the Header, presumably because they (wrongly) decided it was a good +// idea to use the SigningMethod itself instead of the SigningMethod's Alg +// method. In order to keep things sane, marshalling this will simply +// return the JSON-compatible representation of m.Alg(). +func (m *SigningMethodECDSA) MarshalJSON() ([]byte, error) { + return []byte(`"` + m.Alg() + `"`), nil +} + +var _ json.Marshaler = (*SigningMethodECDSA)(nil) diff --git a/vendor/github.com/SermoDigital/jose/crypto/ecdsa_utils.go b/vendor/github.com/SermoDigital/jose/crypto/ecdsa_utils.go new file mode 100644 index 0000000..4bd75d2 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/ecdsa_utils.go @@ -0,0 +1,48 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "errors" +) + +// ECDSA parsing errors. +var ( + ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") + ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key") +) + +// ParseECPrivateKeyFromPEM will parse a PEM encoded EC Private +// Key Structure. +func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { + block, _ := pem.Decode(key) + if block == nil { + return nil, ErrKeyMustBePEMEncoded + } + return x509.ParseECPrivateKey(block.Bytes) +} + +// ParseECPublicKeyFromPEM will parse a PEM encoded PKCS1 or PKCS8 public key +func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) { + + block, _ := pem.Decode(key) + if block == nil { + return nil, ErrKeyMustBePEMEncoded + } + + parsedKey, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + parsedKey = cert.PublicKey + } + + pkey, ok := parsedKey.(*ecdsa.PublicKey) + if !ok { + return nil, ErrNotECPublicKey + } + return pkey, nil +} diff --git a/vendor/github.com/SermoDigital/jose/crypto/errors.go b/vendor/github.com/SermoDigital/jose/crypto/errors.go new file mode 100644 index 0000000..34fbd25 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/errors.go @@ -0,0 +1,9 @@ +package crypto + +import "errors" + +var ( + // ErrInvalidKey means the key argument passed to SigningMethod.Verify + // was not the correct type. + ErrInvalidKey = errors.New("key is invalid") +) diff --git a/vendor/github.com/SermoDigital/jose/crypto/hmac.go b/vendor/github.com/SermoDigital/jose/crypto/hmac.go new file mode 100644 index 0000000..1cb7f6e --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/hmac.go @@ -0,0 +1,81 @@ +package crypto + +import ( + "crypto" + "crypto/hmac" + "encoding/json" + "errors" +) + +// SigningMethodHMAC implements the HMAC-SHA family of SigningMethods. +type SigningMethodHMAC struct { + Name string + Hash crypto.Hash + _ struct{} +} + +// Specific instances of HMAC-SHA SigningMethods. +var ( + // SigningMethodHS256 implements HS256. + SigningMethodHS256 = &SigningMethodHMAC{ + Name: "HS256", + Hash: crypto.SHA256, + } + + // SigningMethodHS384 implements HS384. + SigningMethodHS384 = &SigningMethodHMAC{ + Name: "HS384", + Hash: crypto.SHA384, + } + + // SigningMethodHS512 implements HS512. + SigningMethodHS512 = &SigningMethodHMAC{ + Name: "HS512", + Hash: crypto.SHA512, + } + + // ErrSignatureInvalid is returned when the provided signature is found + // to be invalid. + ErrSignatureInvalid = errors.New("signature is invalid") +) + +// Alg implements the SigningMethod interface. +func (m *SigningMethodHMAC) Alg() string { return m.Name } + +// Verify implements the Verify method from SigningMethod. +// For this signing method, must be a []byte. +func (m *SigningMethodHMAC) Verify(raw []byte, signature Signature, key interface{}) error { + keyBytes, ok := key.([]byte) + if !ok { + return ErrInvalidKey + } + hasher := hmac.New(m.Hash.New, keyBytes) + hasher.Write(raw) + if hmac.Equal(signature, hasher.Sum(nil)) { + return nil + } + return ErrSignatureInvalid +} + +// Sign implements the Sign method from SigningMethod for this signing method. +// Key must be a []byte. +func (m *SigningMethodHMAC) Sign(data []byte, key interface{}) (Signature, error) { + keyBytes, ok := key.([]byte) + if !ok { + return nil, ErrInvalidKey + } + hasher := hmac.New(m.Hash.New, keyBytes) + hasher.Write(data) + return Signature(hasher.Sum(nil)), nil +} + +// Hasher implements the SigningMethod interface. +func (m *SigningMethodHMAC) Hasher() crypto.Hash { return m.Hash } + +// MarshalJSON implements json.Marshaler. +// See SigningMethodECDSA.MarshalJSON() for information. +func (m *SigningMethodHMAC) MarshalJSON() ([]byte, error) { + return []byte(`"` + m.Alg() + `"`), nil +} + +var _ json.Marshaler = (*SigningMethodHMAC)(nil) diff --git a/vendor/github.com/SermoDigital/jose/crypto/none.go b/vendor/github.com/SermoDigital/jose/crypto/none.go new file mode 100644 index 0000000..db3d139 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/none.go @@ -0,0 +1,72 @@ +package crypto + +import ( + "crypto" + "encoding/json" + "hash" + "io" +) + +func init() { + crypto.RegisterHash(crypto.Hash(0), h) +} + +// h is passed to crypto.RegisterHash. +func h() hash.Hash { + return &f{Writer: nil} +} + +type f struct{ io.Writer } + +// Sum helps implement the hash.Hash interface. +func (_ *f) Sum(b []byte) []byte { return nil } + +// Reset helps implement the hash.Hash interface. +func (_ *f) Reset() {} + +// Size helps implement the hash.Hash interface. +func (_ *f) Size() int { return -1 } + +// BlockSize helps implement the hash.Hash interface. +func (_ *f) BlockSize() int { return -1 } + +// Unsecured is the default "none" algorithm. +var Unsecured = &SigningMethodNone{ + Name: "none", + Hash: crypto.Hash(0), +} + +// SigningMethodNone is the default "none" algorithm. +type SigningMethodNone struct { + Name string + Hash crypto.Hash + _ struct{} +} + +// Verify helps implement the SigningMethod interface. +func (_ *SigningMethodNone) Verify(_ []byte, _ Signature, _ interface{}) error { + return nil +} + +// Sign helps implement the SigningMethod interface. +func (_ *SigningMethodNone) Sign(_ []byte, _ interface{}) (Signature, error) { + return nil, nil +} + +// Alg helps implement the SigningMethod interface. +func (m *SigningMethodNone) Alg() string { + return m.Name +} + +// Hasher helps implement the SigningMethod interface. +func (m *SigningMethodNone) Hasher() crypto.Hash { + return m.Hash +} + +// MarshalJSON implements json.Marshaler. +// See SigningMethodECDSA.MarshalJSON() for information. +func (m *SigningMethodNone) MarshalJSON() ([]byte, error) { + return []byte(`"` + m.Alg() + `"`), nil +} + +var _ json.Marshaler = (*SigningMethodNone)(nil) diff --git a/vendor/github.com/SermoDigital/jose/crypto/rsa.go b/vendor/github.com/SermoDigital/jose/crypto/rsa.go new file mode 100644 index 0000000..80596df --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/rsa.go @@ -0,0 +1,80 @@ +package crypto + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "encoding/json" +) + +// SigningMethodRSA implements the RSA family of SigningMethods. +type SigningMethodRSA struct { + Name string + Hash crypto.Hash + _ struct{} +} + +// Specific instances of RSA SigningMethods. +var ( + // SigningMethodRS256 implements RS256. + SigningMethodRS256 = &SigningMethodRSA{ + Name: "RS256", + Hash: crypto.SHA256, + } + + // SigningMethodRS384 implements RS384. + SigningMethodRS384 = &SigningMethodRSA{ + Name: "RS384", + Hash: crypto.SHA384, + } + + // SigningMethodRS512 implements RS512. + SigningMethodRS512 = &SigningMethodRSA{ + Name: "RS512", + Hash: crypto.SHA512, + } +) + +// Alg implements the SigningMethod interface. +func (m *SigningMethodRSA) Alg() string { return m.Name } + +// Verify implements the Verify method from SigningMethod. +// For this signing method, must be an *rsa.PublicKey. +func (m *SigningMethodRSA) Verify(raw []byte, sig Signature, key interface{}) error { + rsaKey, ok := key.(*rsa.PublicKey) + if !ok { + return ErrInvalidKey + } + return rsa.VerifyPKCS1v15(rsaKey, m.Hash, m.sum(raw), sig) +} + +// Sign implements the Sign method from SigningMethod. +// For this signing method, must be an *rsa.PrivateKey structure. +func (m *SigningMethodRSA) Sign(data []byte, key interface{}) (Signature, error) { + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, ErrInvalidKey + } + sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, m.sum(data)) + if err != nil { + return nil, err + } + return Signature(sigBytes), nil +} + +func (m *SigningMethodRSA) sum(b []byte) []byte { + h := m.Hash.New() + h.Write(b) + return h.Sum(nil) +} + +// Hasher implements the SigningMethod interface. +func (m *SigningMethodRSA) Hasher() crypto.Hash { return m.Hash } + +// MarshalJSON implements json.Marshaler. +// See SigningMethodECDSA.MarshalJSON() for information. +func (m *SigningMethodRSA) MarshalJSON() ([]byte, error) { + return []byte(`"` + m.Alg() + `"`), nil +} + +var _ json.Marshaler = (*SigningMethodRSA)(nil) diff --git a/vendor/github.com/SermoDigital/jose/crypto/rsa_pss.go b/vendor/github.com/SermoDigital/jose/crypto/rsa_pss.go new file mode 100644 index 0000000..3847ae2 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/rsa_pss.go @@ -0,0 +1,96 @@ +// +build go1.4 + +package crypto + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "encoding/json" +) + +// SigningMethodRSAPSS implements the RSAPSS family of SigningMethods. +type SigningMethodRSAPSS struct { + *SigningMethodRSA + Options *rsa.PSSOptions +} + +// Specific instances for RS/PS SigningMethods. +var ( + // SigningMethodPS256 implements PS256. + SigningMethodPS256 = &SigningMethodRSAPSS{ + &SigningMethodRSA{ + Name: "PS256", + Hash: crypto.SHA256, + }, + &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthAuto, + Hash: crypto.SHA256, + }, + } + + // SigningMethodPS384 implements PS384. + SigningMethodPS384 = &SigningMethodRSAPSS{ + &SigningMethodRSA{ + Name: "PS384", + Hash: crypto.SHA384, + }, + &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthAuto, + Hash: crypto.SHA384, + }, + } + + // SigningMethodPS512 implements PS512. + SigningMethodPS512 = &SigningMethodRSAPSS{ + &SigningMethodRSA{ + Name: "PS512", + Hash: crypto.SHA512, + }, + &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthAuto, + Hash: crypto.SHA512, + }, + } +) + +// Verify implements the Verify method from SigningMethod. +// For this verify method, key must be an *rsa.PublicKey. +func (m *SigningMethodRSAPSS) Verify(raw []byte, signature Signature, key interface{}) error { + rsaKey, ok := key.(*rsa.PublicKey) + if !ok { + return ErrInvalidKey + } + return rsa.VerifyPSS(rsaKey, m.Hash, m.sum(raw), signature, m.Options) +} + +// Sign implements the Sign method from SigningMethod. +// For this signing method, key must be an *rsa.PrivateKey. +func (m *SigningMethodRSAPSS) Sign(raw []byte, key interface{}) (Signature, error) { + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, ErrInvalidKey + } + sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, m.sum(raw), m.Options) + if err != nil { + return nil, err + } + return Signature(sigBytes), nil +} + +func (m *SigningMethodRSAPSS) sum(b []byte) []byte { + h := m.Hash.New() + h.Write(b) + return h.Sum(nil) +} + +// Hasher implements the Hasher method from SigningMethod. +func (m *SigningMethodRSAPSS) Hasher() crypto.Hash { return m.Hash } + +// MarshalJSON implements json.Marshaler. +// See SigningMethodECDSA.MarshalJSON() for information. +func (m *SigningMethodRSAPSS) MarshalJSON() ([]byte, error) { + return []byte(`"` + m.Alg() + `"`), nil +} + +var _ json.Marshaler = (*SigningMethodRSAPSS)(nil) diff --git a/vendor/github.com/SermoDigital/jose/crypto/rsa_utils.go b/vendor/github.com/SermoDigital/jose/crypto/rsa_utils.go new file mode 100644 index 0000000..43aeff3 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/rsa_utils.go @@ -0,0 +1,70 @@ +package crypto + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" +) + +// Errors specific to rsa_utils. +var ( + ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be PEM encoded PKCS1 or PKCS8 private key") + ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key") + ErrNotRSAPublicKey = errors.New("key is not a valid RSA public key") +) + +// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key. +func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { + var err error + + // Parse PEM block + var block *pem.Block + if block, _ = pem.Decode(key); block == nil { + return nil, ErrKeyMustBePEMEncoded + } + + var parsedKey interface{} + if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { + if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { + return nil, err + } + } + + var pkey *rsa.PrivateKey + var ok bool + if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { + return nil, ErrNotRSAPrivateKey + } + + return pkey, nil +} + +// ParseRSAPublicKeyFromPEM parses PEM encoded PKCS1 or PKCS8 public key. +func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { + var err error + + // Parse PEM block + var block *pem.Block + if block, _ = pem.Decode(key); block == nil { + return nil, ErrKeyMustBePEMEncoded + } + + // Parse the key + var parsedKey interface{} + if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { + if cert, err := x509.ParseCertificate(block.Bytes); err == nil { + parsedKey = cert.PublicKey + } else { + return nil, err + } + } + + var pkey *rsa.PublicKey + var ok bool + if pkey, ok = parsedKey.(*rsa.PublicKey); !ok { + return nil, ErrNotRSAPublicKey + } + + return pkey, nil +} diff --git a/vendor/github.com/SermoDigital/jose/crypto/signature.go b/vendor/github.com/SermoDigital/jose/crypto/signature.go new file mode 100644 index 0000000..37571f9 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/signature.go @@ -0,0 +1,36 @@ +package crypto + +import ( + "encoding/json" + + "github.com/SermoDigital/jose" +) + +// Signature is a JWS signature. +type Signature []byte + +// MarshalJSON implements json.Marshaler for a signature. +func (s Signature) MarshalJSON() ([]byte, error) { + return jose.EncodeEscape(s), nil +} + +// Base64 helps implements jose.Encoder for Signature. +func (s Signature) Base64() ([]byte, error) { + return jose.Base64Encode(s), nil +} + +// UnmarshalJSON implements json.Unmarshaler for signature. +func (s *Signature) UnmarshalJSON(b []byte) error { + dec, err := jose.DecodeEscaped(b) + if err != nil { + return err + } + *s = Signature(dec) + return nil +} + +var ( + _ json.Marshaler = (Signature)(nil) + _ json.Unmarshaler = (*Signature)(nil) + _ jose.Encoder = (Signature)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/crypto/signing_method.go b/vendor/github.com/SermoDigital/jose/crypto/signing_method.go new file mode 100644 index 0000000..c8b8874 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/crypto/signing_method.go @@ -0,0 +1,24 @@ +package crypto + +import "crypto" + +// SigningMethod is an interface that provides a way to sign JWS tokens. +type SigningMethod interface { + // Alg describes the signing algorithm, and is used to uniquely + // describe the specific crypto.SigningMethod. + Alg() string + + // Verify accepts the raw content, the signature, and the key used + // to sign the raw content, and returns any errors found while validating + // the signature and content. + Verify(raw []byte, sig Signature, key interface{}) error + + // Sign returns a Signature for the raw bytes, as well as any errors + // that occurred during the signing. + Sign(raw []byte, key interface{}) (Signature, error) + + // Used to cause quick panics when a crypto.SigningMethod whose form of hashing + // isn't linked in the binary when you register a crypto.SigningMethod. + // To spoof this, see "crypto.SigningMethodNone". + Hasher() crypto.Hash +} diff --git a/vendor/github.com/SermoDigital/jose/doc.go b/vendor/github.com/SermoDigital/jose/doc.go new file mode 100644 index 0000000..7abb7bf --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/doc.go @@ -0,0 +1,3 @@ +// Package jose implements some helper functions and types for the children +// packages, jws, jwt, and jwe. +package jose diff --git a/vendor/github.com/SermoDigital/jose/header.go b/vendor/github.com/SermoDigital/jose/header.go new file mode 100644 index 0000000..4499a76 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/header.go @@ -0,0 +1,124 @@ +package jose + +import "encoding/json" + +// Header implements a JOSE Header with the addition of some helper +// methods, similar to net/url.Values. +type Header map[string]interface{} + +// Get retrieves the value corresponding with key from the Header. +func (h Header) Get(key string) interface{} { + if h == nil { + return nil + } + return h[key] +} + +// Set sets Claims[key] = val. It'll overwrite without warning. +func (h Header) Set(key string, val interface{}) { + h[key] = val +} + +// Del removes the value that corresponds with key from the Header. +func (h Header) Del(key string) { + delete(h, key) +} + +// Has returns true if a value for the given key exists inside the Header. +func (h Header) Has(key string) bool { + _, ok := h[key] + return ok +} + +// MarshalJSON implements json.Marshaler for Header. +func (h Header) MarshalJSON() ([]byte, error) { + if len(h) == 0 { + return nil, nil + } + b, err := json.Marshal(map[string]interface{}(h)) + if err != nil { + return nil, err + } + return EncodeEscape(b), nil +} + +// Base64 implements the Encoder interface. +func (h Header) Base64() ([]byte, error) { + return h.MarshalJSON() +} + +// UnmarshalJSON implements json.Unmarshaler for Header. +func (h *Header) UnmarshalJSON(b []byte) error { + if b == nil { + return nil + } + b, err := DecodeEscaped(b) + if err != nil { + return err + } + return json.Unmarshal(b, (*map[string]interface{})(h)) +} + +// Protected Headers are base64-encoded after they're marshaled into +// JSON. +type Protected Header + +// Get retrieves the value corresponding with key from the Protected Header. +func (p Protected) Get(key string) interface{} { + if p == nil { + return nil + } + return p[key] +} + +// Set sets Protected[key] = val. It'll overwrite without warning. +func (p Protected) Set(key string, val interface{}) { + p[key] = val +} + +// Del removes the value that corresponds with key from the Protected Header. +func (p Protected) Del(key string) { + delete(p, key) +} + +// Has returns true if a value for the given key exists inside the Protected +// Header. +func (p Protected) Has(key string) bool { + _, ok := p[key] + return ok +} + +// MarshalJSON implements json.Marshaler for Protected. +func (p Protected) MarshalJSON() ([]byte, error) { + b, err := json.Marshal(map[string]interface{}(p)) + if err != nil { + return nil, err + } + return EncodeEscape(b), nil +} + +// Base64 implements the Encoder interface. +func (p Protected) Base64() ([]byte, error) { + b, err := json.Marshal(map[string]interface{}(p)) + if err != nil { + return nil, err + } + return Base64Encode(b), nil +} + +// UnmarshalJSON implements json.Unmarshaler for Protected. +func (p *Protected) UnmarshalJSON(b []byte) error { + var h Header + if err := h.UnmarshalJSON(b); err != nil { + return err + } + *p = Protected(h) + return nil +} + +var ( + _ json.Marshaler = (Protected)(nil) + _ json.Unmarshaler = (*Protected)(nil) + _ json.Marshaler = (Header)(nil) + _ json.Unmarshaler = (*Header)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/jws/claims.go b/vendor/github.com/SermoDigital/jose/jws/claims.go new file mode 100644 index 0000000..4cc616c --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/claims.go @@ -0,0 +1,190 @@ +package jws + +import ( + "encoding/json" + "time" + + "github.com/SermoDigital/jose" + "github.com/SermoDigital/jose/jwt" +) + +// Claims represents a set of JOSE Claims. +type Claims jwt.Claims + +// Get retrieves the value corresponding with key from the Claims. +func (c Claims) Get(key string) interface{} { + return jwt.Claims(c).Get(key) +} + +// Set sets Claims[key] = val. It'll overwrite without warning. +func (c Claims) Set(key string, val interface{}) { + jwt.Claims(c).Set(key, val) +} + +// Del removes the value that corresponds with key from the Claims. +func (c Claims) Del(key string) { + jwt.Claims(c).Del(key) +} + +// Has returns true if a value for the given key exists inside the Claims. +func (c Claims) Has(key string) bool { + return jwt.Claims(c).Has(key) +} + +// MarshalJSON implements json.Marshaler for Claims. +func (c Claims) MarshalJSON() ([]byte, error) { + return jwt.Claims(c).MarshalJSON() +} + +// Base64 implements the Encoder interface. +func (c Claims) Base64() ([]byte, error) { + return jwt.Claims(c).Base64() +} + +// UnmarshalJSON implements json.Unmarshaler for Claims. +func (c *Claims) UnmarshalJSON(b []byte) error { + if b == nil { + return nil + } + + b, err := jose.DecodeEscaped(b) + if err != nil { + return err + } + + // Since json.Unmarshal calls UnmarshalJSON, + // calling json.Unmarshal on *p would be infinitely recursive + // A temp variable is needed because &map[string]interface{}(*p) is + // invalid Go. + + tmp := map[string]interface{}(*c) + if err = json.Unmarshal(b, &tmp); err != nil { + return err + } + *c = Claims(tmp) + return nil +} + +// Issuer retrieves claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.1 +func (c Claims) Issuer() (string, bool) { + return jwt.Claims(c).Issuer() +} + +// Subject retrieves claim "sub" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.2 +func (c Claims) Subject() (string, bool) { + return jwt.Claims(c).Subject() +} + +// Audience retrieves claim "aud" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.3 +func (c Claims) Audience() ([]string, bool) { + return jwt.Claims(c).Audience() +} + +// Expiration retrieves claim "exp" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.4 +func (c Claims) Expiration() (time.Time, bool) { + return jwt.Claims(c).Expiration() +} + +// NotBefore retrieves claim "nbf" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.5 +func (c Claims) NotBefore() (time.Time, bool) { + return jwt.Claims(c).NotBefore() +} + +// IssuedAt retrieves claim "iat" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.6 +func (c Claims) IssuedAt() (time.Time, bool) { + return jwt.Claims(c).IssuedAt() +} + +// JWTID retrieves claim "jti" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.7 +func (c Claims) JWTID() (string, bool) { + return jwt.Claims(c).JWTID() +} + +// RemoveIssuer deletes claim "iss" from c. +func (c Claims) RemoveIssuer() { + jwt.Claims(c).RemoveIssuer() +} + +// RemoveSubject deletes claim "sub" from c. +func (c Claims) RemoveSubject() { + jwt.Claims(c).RemoveIssuer() +} + +// RemoveAudience deletes claim "aud" from c. +func (c Claims) RemoveAudience() { + jwt.Claims(c).Audience() +} + +// RemoveExpiration deletes claim "exp" from c. +func (c Claims) RemoveExpiration() { + jwt.Claims(c).RemoveExpiration() +} + +// RemoveNotBefore deletes claim "nbf" from c. +func (c Claims) RemoveNotBefore() { + jwt.Claims(c).NotBefore() +} + +// RemoveIssuedAt deletes claim "iat" from c. +func (c Claims) RemoveIssuedAt() { + jwt.Claims(c).IssuedAt() +} + +// RemoveJWTID deletes claim "jti" from c. +func (c Claims) RemoveJWTID() { + jwt.Claims(c).RemoveJWTID() +} + +// SetIssuer sets claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.1 +func (c Claims) SetIssuer(issuer string) { + jwt.Claims(c).SetIssuer(issuer) +} + +// SetSubject sets claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.2 +func (c Claims) SetSubject(subject string) { + jwt.Claims(c).SetSubject(subject) +} + +// SetAudience sets claim "aud" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.3 +func (c Claims) SetAudience(audience ...string) { + jwt.Claims(c).SetAudience(audience...) +} + +// SetExpiration sets claim "exp" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.4 +func (c Claims) SetExpiration(expiration time.Time) { + jwt.Claims(c).SetExpiration(expiration) +} + +// SetNotBefore sets claim "nbf" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.5 +func (c Claims) SetNotBefore(notBefore time.Time) { + jwt.Claims(c).SetNotBefore(notBefore) +} + +// SetIssuedAt sets claim "iat" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.6 +func (c Claims) SetIssuedAt(issuedAt time.Time) { + jwt.Claims(c).SetIssuedAt(issuedAt) +} + +// SetJWTID sets claim "jti" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.7 +func (c Claims) SetJWTID(uniqueID string) { + jwt.Claims(c).SetJWTID(uniqueID) +} + +var ( + _ json.Marshaler = (Claims)(nil) + _ json.Unmarshaler = (*Claims)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/jws/doc.go b/vendor/github.com/SermoDigital/jose/jws/doc.go new file mode 100644 index 0000000..165836d --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/doc.go @@ -0,0 +1,2 @@ +// Package jws implements JWSs per RFC 7515 +package jws diff --git a/vendor/github.com/SermoDigital/jose/jws/errors.go b/vendor/github.com/SermoDigital/jose/jws/errors.go new file mode 100644 index 0000000..0512a0e --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/errors.go @@ -0,0 +1,62 @@ +package jws + +import "errors" + +var ( + + // ErrNotEnoughMethods is returned if New was called _or_ the Flat/Compact + // methods were called with 0 SigningMethods. + ErrNotEnoughMethods = errors.New("not enough methods provided") + + // ErrCouldNotUnmarshal is returned when Parse's json.Unmarshaler + // parameter returns an error. + ErrCouldNotUnmarshal = errors.New("custom unmarshal failed") + + // ErrNotCompact signals that the provided potential JWS is not + // in its compact representation. + ErrNotCompact = errors.New("not a compact JWS") + + // ErrDuplicateHeaderParameter signals that there are duplicate parameters + // in the provided Headers. + ErrDuplicateHeaderParameter = errors.New("duplicate parameters in the JOSE Header") + + // ErrTwoEmptyHeaders is returned if both Headers are empty. + ErrTwoEmptyHeaders = errors.New("both headers cannot be empty") + + // ErrNotEnoughKeys is returned when not enough keys are provided for + // the given SigningMethods. + ErrNotEnoughKeys = errors.New("not enough keys (for given methods)") + + // ErrDidNotValidate means the given JWT did not properly validate + ErrDidNotValidate = errors.New("did not validate") + + // ErrNoAlgorithm means no algorithm ("alg") was found in the Protected + // Header. + ErrNoAlgorithm = errors.New("no algorithm found") + + // ErrAlgorithmDoesntExist means the algorithm asked for cannot be + // found inside the signingMethod cache. + ErrAlgorithmDoesntExist = errors.New("algorithm doesn't exist") + + // ErrMismatchedAlgorithms means the algorithm inside the JWT was + // different than the algorithm the caller wanted to use. + ErrMismatchedAlgorithms = errors.New("mismatched algorithms") + + // ErrCannotValidate means the JWS cannot be validated for various + // reasons. For example, if there aren't any signatures/payloads/headers + // to actually validate. + ErrCannotValidate = errors.New("cannot validate") + + // ErrIsNotJWT means the given JWS is not a JWT. + ErrIsNotJWT = errors.New("JWS is not a JWT") + + // ErrHoldsJWE means the given JWS holds a JWE inside its payload. + ErrHoldsJWE = errors.New("JWS holds JWE") + + // ErrNotEnoughValidSignatures means the JWS did not meet the required + // number of signatures. + ErrNotEnoughValidSignatures = errors.New("not enough valid signatures in the JWS") + + // ErrNoTokenInRequest means there's no token present inside the *http.Request. + ErrNoTokenInRequest = errors.New("no token present in request") +) diff --git a/vendor/github.com/SermoDigital/jose/jws/jws.go b/vendor/github.com/SermoDigital/jose/jws/jws.go new file mode 100644 index 0000000..49e7b97 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/jws.go @@ -0,0 +1,490 @@ +package jws + +import ( + "bytes" + "encoding/json" + "net/http" + "strings" + + "github.com/SermoDigital/jose" + "github.com/SermoDigital/jose/crypto" +) + +// JWS implements a JWS per RFC 7515. +type JWS interface { + // Payload Returns the payload. + Payload() interface{} + + // SetPayload sets the payload with the given value. + SetPayload(p interface{}) + + // Protected returns the JWS' Protected Header. + Protected() jose.Protected + + // ProtectedAt returns the JWS' Protected Header. + // i represents the index of the Protected Header. + ProtectedAt(i int) jose.Protected + + // Header returns the JWS' unprotected Header. + Header() jose.Header + + // HeaderAt returns the JWS' unprotected Header. + // i represents the index of the unprotected Header. + HeaderAt(i int) jose.Header + + // Verify validates the current JWS' signature as-is. Refer to + // ValidateMulti for more information. + Verify(key interface{}, method crypto.SigningMethod) error + + // ValidateMulti validates the current JWS' signature as-is. Since it's + // meant to be called after parsing a stream of bytes into a JWS, it + // shouldn't do any internal parsing like the Sign, Flat, Compact, or + // General methods do. + VerifyMulti(keys []interface{}, methods []crypto.SigningMethod, o *SigningOpts) error + + // VerifyCallback validates the current JWS' signature as-is. It + // accepts a callback function that can be used to access header + // parameters to lookup needed information. For example, looking + // up the "kid" parameter. + // The return slice must be a slice of keys used in the verification + // of the JWS. + VerifyCallback(fn VerifyCallback, methods []crypto.SigningMethod, o *SigningOpts) error + + // General serializes the JWS into its "general" form per + // https://tools.ietf.org/html/rfc7515#section-7.2.1 + General(keys ...interface{}) ([]byte, error) + + // Flat serializes the JWS to its "flattened" form per + // https://tools.ietf.org/html/rfc7515#section-7.2.2 + Flat(key interface{}) ([]byte, error) + + // Compact serializes the JWS into its "compact" form per + // https://tools.ietf.org/html/rfc7515#section-7.1 + Compact(key interface{}) ([]byte, error) + + // IsJWT returns true if the JWS is a JWT. + IsJWT() bool +} + +// jws represents a specific jws. +type jws struct { + payload *payload + plcache rawBase64 + clean bool + + sb []sigHead + + isJWT bool +} + +// Payload returns the jws' payload. +func (j *jws) Payload() interface{} { + return j.payload.v +} + +// SetPayload sets the jws' raw, unexported payload. +func (j *jws) SetPayload(val interface{}) { + j.payload.v = val +} + +// Protected returns the JWS' Protected Header. +func (j *jws) Protected() jose.Protected { + return j.sb[0].protected +} + +// Protected returns the JWS' Protected Header. +// i represents the index of the Protected Header. +// Left empty, it defaults to 0. +func (j *jws) ProtectedAt(i int) jose.Protected { + return j.sb[i].protected +} + +// Header returns the JWS' unprotected Header. +func (j *jws) Header() jose.Header { + return j.sb[0].unprotected +} + +// HeaderAt returns the JWS' unprotected Header. +// |i| is the index of the unprotected Header. +func (j *jws) HeaderAt(i int) jose.Header { + return j.sb[i].unprotected +} + +// sigHead represents the 'signatures' member of the jws' "general" +// serialization form per +// https://tools.ietf.org/html/rfc7515#section-7.2.1 +// +// It's embedded inside the "flat" structure in order to properly +// create the "flat" jws. +type sigHead struct { + Protected rawBase64 `json:"protected,omitempty"` + Unprotected rawBase64 `json:"header,omitempty"` + Signature crypto.Signature `json:"signature"` + + protected jose.Protected + unprotected jose.Header + clean bool + + method crypto.SigningMethod +} + +func (s *sigHead) unmarshal() error { + if err := s.protected.UnmarshalJSON(s.Protected); err != nil { + return err + } + return s.unprotected.UnmarshalJSON(s.Unprotected) +} + +// New creates a JWS with the provided crypto.SigningMethods. +func New(content interface{}, methods ...crypto.SigningMethod) JWS { + sb := make([]sigHead, len(methods)) + for i := range methods { + sb[i] = sigHead{ + protected: jose.Protected{ + "alg": methods[i].Alg(), + }, + unprotected: jose.Header{}, + method: methods[i], + } + } + return &jws{ + payload: &payload{v: content}, + sb: sb, + } +} + +func (s *sigHead) assignMethod(p jose.Protected) error { + alg, ok := p.Get("alg").(string) + if !ok { + return ErrNoAlgorithm + } + + sm := GetSigningMethod(alg) + if sm == nil { + return ErrNoAlgorithm + } + s.method = sm + return nil +} + +type generic struct { + Payload rawBase64 `json:"payload"` + sigHead + Signatures []sigHead `json:"signatures,omitempty"` +} + +// Parse parses any of the three serialized jws forms into a physical +// jws per https://tools.ietf.org/html/rfc7515#section-5.2 +// +// It accepts a json.Unmarshaler in order to properly parse +// the payload. In order to keep the caller from having to do extra +// parsing of the payload, a json.Unmarshaler can be passed +// which will be then to unmarshal the payload however the caller +// wishes. Do note that if json.Unmarshal returns an error the +// original payload will be used as if no json.Unmarshaler was +// passed. +// +// Internally, Parse applies some heuristics and then calls either +// ParseGeneral, ParseFlat, or ParseCompact. +// It should only be called if, for whatever reason, you do not +// know which form the serialized JWT is in. +// +// It cannot parse a JWT. +func Parse(encoded []byte, u ...json.Unmarshaler) (JWS, error) { + // Try and unmarshal into a generic struct that'll + // hopefully hold either of the two JSON serialization + // formats. + var g generic + + // Not valid JSON. Let's try compact. + if err := json.Unmarshal(encoded, &g); err != nil { + return ParseCompact(encoded, u...) + } + + if g.Signatures == nil { + return g.parseFlat(u...) + } + return g.parseGeneral(u...) +} + +// ParseGeneral parses a jws serialized into its "general" form per +// https://tools.ietf.org/html/rfc7515#section-7.2.1 +// into a physical jws per +// https://tools.ietf.org/html/rfc7515#section-5.2 +// +// For information on the json.Unmarshaler parameter, see Parse. +func ParseGeneral(encoded []byte, u ...json.Unmarshaler) (JWS, error) { + var g generic + if err := json.Unmarshal(encoded, &g); err != nil { + return nil, err + } + return g.parseGeneral(u...) +} + +func (g *generic) parseGeneral(u ...json.Unmarshaler) (JWS, error) { + + var p payload + if len(u) > 0 { + p.u = u[0] + } + + if err := p.UnmarshalJSON(g.Payload); err != nil { + return nil, err + } + + for i := range g.Signatures { + if err := g.Signatures[i].unmarshal(); err != nil { + return nil, err + } + if err := checkHeaders(jose.Header(g.Signatures[i].protected), g.Signatures[i].unprotected); err != nil { + return nil, err + } + + if err := g.Signatures[i].assignMethod(g.Signatures[i].protected); err != nil { + return nil, err + } + } + + g.clean = len(g.Signatures) != 0 + + return &jws{ + payload: &p, + plcache: g.Payload, + clean: true, + sb: g.Signatures, + }, nil +} + +// ParseFlat parses a jws serialized into its "flat" form per +// https://tools.ietf.org/html/rfc7515#section-7.2.2 +// into a physical jws per +// https://tools.ietf.org/html/rfc7515#section-5.2 +// +// For information on the json.Unmarshaler parameter, see Parse. +func ParseFlat(encoded []byte, u ...json.Unmarshaler) (JWS, error) { + var g generic + if err := json.Unmarshal(encoded, &g); err != nil { + return nil, err + } + return g.parseFlat(u...) +} + +func (g *generic) parseFlat(u ...json.Unmarshaler) (JWS, error) { + + var p payload + if len(u) > 0 { + p.u = u[0] + } + + if err := p.UnmarshalJSON(g.Payload); err != nil { + return nil, err + } + + if err := g.sigHead.unmarshal(); err != nil { + return nil, err + } + g.sigHead.clean = true + + if err := checkHeaders(jose.Header(g.sigHead.protected), g.sigHead.unprotected); err != nil { + return nil, err + } + + if err := g.sigHead.assignMethod(g.sigHead.protected); err != nil { + return nil, err + } + + return &jws{ + payload: &p, + plcache: g.Payload, + clean: true, + sb: []sigHead{g.sigHead}, + }, nil +} + +// ParseCompact parses a jws serialized into its "compact" form per +// https://tools.ietf.org/html/rfc7515#section-7.1 +// into a physical jws per +// https://tools.ietf.org/html/rfc7515#section-5.2 +// +// For information on the json.Unmarshaler parameter, see Parse. +func ParseCompact(encoded []byte, u ...json.Unmarshaler) (JWS, error) { + return parseCompact(encoded, false, u...) +} + +func parseCompact(encoded []byte, jwt bool, u ...json.Unmarshaler) (*jws, error) { + + // This section loosely follows + // https://tools.ietf.org/html/rfc7519#section-7.2 + // because it's used to parse _both_ jws and JWTs. + + parts := bytes.Split(encoded, []byte{'.'}) + if len(parts) != 3 { + return nil, ErrNotCompact + } + + var p jose.Protected + if err := p.UnmarshalJSON(parts[0]); err != nil { + return nil, err + } + + s := sigHead{ + Protected: parts[0], + protected: p, + Signature: parts[2], + clean: true, + } + + if err := s.assignMethod(p); err != nil { + return nil, err + } + + var pl payload + if len(u) > 0 { + pl.u = u[0] + } + + j := jws{ + payload: &pl, + plcache: parts[1], + sb: []sigHead{s}, + isJWT: jwt, + } + + if err := j.payload.UnmarshalJSON(parts[1]); err != nil { + return nil, err + } + + j.clean = true + + if err := j.sb[0].Signature.UnmarshalJSON(parts[2]); err != nil { + return nil, err + } + + // https://tools.ietf.org/html/rfc7519#section-7.2.8 + cty, ok := p.Get("cty").(string) + if ok && cty == "JWT" { + return &j, ErrHoldsJWE + } + return &j, nil +} + +var ( + // JWSFormKey is the form "key" which should be used inside + // ParseFromRequest if the request is a multipart.Form. + JWSFormKey = "access_token" + + // MaxMemory is maximum amount of memory which should be used + // inside ParseFromRequest while parsing the multipart.Form + // if the request is a multipart.Form. + MaxMemory int64 = 10e6 +) + +// Format specifies which "format" the JWS is in -- Flat, General, +// or compact. Additionally, constants for JWT/Unknown are added. +type Format uint8 + +const ( + // Unknown format. + Unknown Format = iota + + // Flat format. + Flat + + // General format. + General + + // Compact format. + Compact +) + +var parseJumpTable = [...]func([]byte, ...json.Unmarshaler) (JWS, error){ + Unknown: Parse, + Flat: ParseFlat, + General: ParseGeneral, + Compact: ParseCompact, + 1<<8 - 1: Parse, // Max uint8. +} + +func init() { + for i := range parseJumpTable { + if parseJumpTable[i] == nil { + parseJumpTable[i] = Parse + } + } +} + +func fromHeader(req *http.Request) ([]byte, bool) { + if ah := req.Header.Get("Authorization"); len(ah) > 7 && strings.EqualFold(ah[0:7], "BEARER ") { + return []byte(ah[7:]), true + } + return nil, false +} + +func fromForm(req *http.Request) ([]byte, bool) { + if err := req.ParseMultipartForm(MaxMemory); err != nil { + return nil, false + } + if tokStr := req.Form.Get(JWSFormKey); tokStr != "" { + return []byte(tokStr), true + } + return nil, false +} + +// ParseFromHeader tries to find the JWS in an http.Request header. +func ParseFromHeader(req *http.Request, format Format, u ...json.Unmarshaler) (JWS, error) { + if b, ok := fromHeader(req); ok { + return parseJumpTable[format](b, u...) + } + return nil, ErrNoTokenInRequest +} + +// ParseFromForm tries to find the JWS in an http.Request form request. +func ParseFromForm(req *http.Request, format Format, u ...json.Unmarshaler) (JWS, error) { + if b, ok := fromForm(req); ok { + return parseJumpTable[format](b, u...) + } + return nil, ErrNoTokenInRequest +} + +// ParseFromRequest tries to find the JWS in an http.Request. +// This method will call ParseMultipartForm if there's no token in the header. +func ParseFromRequest(req *http.Request, format Format, u ...json.Unmarshaler) (JWS, error) { + token, err := ParseFromHeader(req, format, u...) + if err == nil { + return token, nil + } + + token, err = ParseFromForm(req, format, u...) + if err == nil { + return token, nil + } + + return nil, err +} + +// IgnoreDupes should be set to true if the internal duplicate header key check +// should ignore duplicate Header keys instead of reporting an error when +// duplicate Header keys are found. +// +// Note: +// Duplicate Header keys are defined in +// https://tools.ietf.org/html/rfc7515#section-5.2 +// meaning keys that both the protected and unprotected +// Headers possess. +var IgnoreDupes bool + +// checkHeaders returns an error per the constraints described in +// IgnoreDupes' comment. +func checkHeaders(a, b jose.Header) error { + if len(a)+len(b) == 0 { + return ErrTwoEmptyHeaders + } + for key := range a { + if b.Has(key) && !IgnoreDupes { + return ErrDuplicateHeaderParameter + } + } + return nil +} + +var _ JWS = (*jws)(nil) diff --git a/vendor/github.com/SermoDigital/jose/jws/jws_serialize.go b/vendor/github.com/SermoDigital/jose/jws/jws_serialize.go new file mode 100644 index 0000000..923fdc2 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/jws_serialize.go @@ -0,0 +1,132 @@ +package jws + +import ( + "bytes" + "encoding/json" +) + +// Flat serializes the JWS to its "flattened" form per +// https://tools.ietf.org/html/rfc7515#section-7.2.2 +func (j *jws) Flat(key interface{}) ([]byte, error) { + if len(j.sb) < 1 { + return nil, ErrNotEnoughMethods + } + if err := j.sign(key); err != nil { + return nil, err + } + return json.Marshal(struct { + Payload rawBase64 `json:"payload"` + sigHead + }{ + Payload: j.plcache, + sigHead: j.sb[0], + }) +} + +// General serializes the JWS into its "general" form per +// https://tools.ietf.org/html/rfc7515#section-7.2.1 +// +// If only one key is passed it's used for all the provided +// crypto.SigningMethods. Otherwise, len(keys) must equal the number +// of crypto.SigningMethods added. +func (j *jws) General(keys ...interface{}) ([]byte, error) { + if err := j.sign(keys...); err != nil { + return nil, err + } + return json.Marshal(struct { + Payload rawBase64 `json:"payload"` + Signatures []sigHead `json:"signatures"` + }{ + Payload: j.plcache, + Signatures: j.sb, + }) +} + +// Compact serializes the JWS into its "compact" form per +// https://tools.ietf.org/html/rfc7515#section-7.1 +func (j *jws) Compact(key interface{}) ([]byte, error) { + if len(j.sb) < 1 { + return nil, ErrNotEnoughMethods + } + + if err := j.sign(key); err != nil { + return nil, err + } + + sig, err := j.sb[0].Signature.Base64() + if err != nil { + return nil, err + } + return format( + j.sb[0].Protected, + j.plcache, + sig, + ), nil +} + +// sign signs each index of j's sb member. +func (j *jws) sign(keys ...interface{}) error { + if err := j.cache(); err != nil { + return err + } + + if len(keys) < 1 || + len(keys) > 1 && len(keys) != len(j.sb) { + return ErrNotEnoughKeys + } + + if len(keys) == 1 { + k := keys[0] + keys = make([]interface{}, len(j.sb)) + for i := range keys { + keys[i] = k + } + } + + for i := range j.sb { + if err := j.sb[i].cache(); err != nil { + return err + } + + raw := format(j.sb[i].Protected, j.plcache) + sig, err := j.sb[i].method.Sign(raw, keys[i]) + if err != nil { + return err + } + j.sb[i].Signature = sig + } + + return nil +} + +// cache marshals the payload, but only if it's changed since the last cache. +func (j *jws) cache() (err error) { + if !j.clean { + j.plcache, err = j.payload.Base64() + j.clean = err == nil + } + return err +} + +// cache marshals the protected and unprotected headers, but only if +// they've changed since their last cache. +func (s *sigHead) cache() (err error) { + if !s.clean { + s.Protected, err = s.protected.Base64() + if err != nil { + return err + } + s.Unprotected, err = s.unprotected.Base64() + if err != nil { + return err + } + } + s.clean = true + return nil +} + +// format formats a slice of bytes in the order given, joining +// them with a period. +func format(a ...[]byte) []byte { + return bytes.Join(a, []byte{'.'}) +} diff --git a/vendor/github.com/SermoDigital/jose/jws/jws_validate.go b/vendor/github.com/SermoDigital/jose/jws/jws_validate.go new file mode 100644 index 0000000..e5e3abd --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/jws_validate.go @@ -0,0 +1,203 @@ +package jws + +import ( + "fmt" + + "github.com/SermoDigital/jose/crypto" +) + +// VerifyCallback is a callback function that can be used to access header +// parameters to lookup needed information. For example, looking +// up the "kid" parameter. +// The return slice must be a slice of keys used in the verification +// of the JWS. +type VerifyCallback func(JWS) ([]interface{}, error) + +// VerifyCallback validates the current JWS' signature as-is. It +// accepts a callback function that can be used to access header +// parameters to lookup needed information. For example, looking +// up the "kid" parameter. +// The return slice must be a slice of keys used in the verification +// of the JWS. +func (j *jws) VerifyCallback(fn VerifyCallback, methods []crypto.SigningMethod, o *SigningOpts) error { + keys, err := fn(j) + if err != nil { + return err + } + return j.VerifyMulti(keys, methods, o) +} + +// IsMultiError returns true if the given error is type *MultiError. +func IsMultiError(err error) bool { + _, ok := err.(*MultiError) + return ok +} + +// MultiError is a slice of errors. +type MultiError []error + +// Errors implements the error interface. +func (m *MultiError) Error() string { + var s string + var n int + for _, err := range *m { + if err != nil { + if n == 0 { + s = err.Error() + } + n++ + } + } + switch n { + case 0: + return "" + case 1: + return s + case 2: + return s + " and 1 other error" + } + return fmt.Sprintf("%s (and %d other errors)", s, n-1) +} + +// Any means any of the JWS signatures need to verify. +// Refer to verifyMulti for more information. +const Any int = 0 + +// VerifyMulti verifies the current JWS as-is. Since it's meant to be +// called after parsing a stream of bytes into a JWS, it doesn't do any +// internal parsing like the Sign, Flat, Compact, or General methods do. +func (j *jws) VerifyMulti(keys []interface{}, methods []crypto.SigningMethod, o *SigningOpts) error { + + // Catch a simple mistake. Parameter o is irrelevant in this scenario. + if len(keys) == 1 && + len(methods) == 1 && + len(j.sb) == 1 { + return j.Verify(keys[0], methods[0]) + } + + if len(j.sb) != len(methods) { + return ErrNotEnoughMethods + } + + if len(keys) < 1 || + len(keys) > 1 && len(keys) != len(j.sb) { + return ErrNotEnoughKeys + } + + // TODO do this better. + if len(keys) == 1 { + k := keys[0] + keys = make([]interface{}, len(methods)) + for i := range keys { + keys[i] = k + } + } + + var o2 SigningOpts + if o == nil { + o = new(SigningOpts) + } + + var m MultiError + for i := range j.sb { + err := j.sb[i].verify(j.plcache, keys[i], methods[i]) + if err != nil { + m = append(m, err) + } else { + o2.Inc() + if o.Needs(i) { + o.ptr++ + o2.Append(i) + } + } + } + + err := o.Validate(&o2) + if err != nil { + m = append(m, err) + } + if len(m) == 0 { + return nil + } + return &m +} + +// SigningOpts is a struct which holds options for validating +// JWS signatures. +// Number represents the cumulative which signatures need to verify +// in order for the JWS to be considered valid. +// Leave 'Number' empty or set it to the constant 'Any' if any number of +// valid signatures (greater than one) should verify the JWS. +// +// Use the indices of the signatures that need to verify in order +// for the JWS to be considered valid if specific signatures need +// to verify in order for the JWS to be considered valid. +// +// Note: +// The JWS spec requires *at least* one +// signature to verify in order for the JWS to be considered valid. +type SigningOpts struct { + // Minimum of signatures which need to verify. + Number int + + // Indices of specific signatures which need to verify. + Indices []int + ptr int + + _ struct{} +} + +// Append appends x to s' Indices member. +func (s *SigningOpts) Append(x int) { + s.Indices = append(s.Indices, x) +} + +// Needs returns true if x resides inside s' Indices member +// for the given index. It's used to match two SigningOpts Indices members. +func (s *SigningOpts) Needs(x int) bool { + return s.ptr < len(s.Indices) && s.Indices[s.ptr] == x +} + +// Inc increments s' Number member by one. +func (s *SigningOpts) Inc() { s.Number++ } + +// Validate returns any errors found while validating the +// provided SigningOpts. The receiver validates |have|. +// It'll return an error if the passed SigningOpts' Number member is less +// than s' or if the passed SigningOpts' Indices slice isn't equal to s'. +func (s *SigningOpts) Validate(have *SigningOpts) error { + if have.Number < s.Number || + (s.Indices != nil && + !eq(s.Indices, have.Indices)) { + return ErrNotEnoughValidSignatures + } + return nil +} + +func eq(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +// Verify verifies the current JWS as-is. Refer to verifyMulti +// for more information. +func (j *jws) Verify(key interface{}, method crypto.SigningMethod) error { + if len(j.sb) < 1 { + return ErrCannotValidate + } + return j.sb[0].verify(j.plcache, key, method) +} + +func (s *sigHead) verify(pl []byte, key interface{}, method crypto.SigningMethod) error { + if s.method.Alg() != method.Alg() || s.method.Hasher() != method.Hasher() { + return ErrMismatchedAlgorithms + } + return method.Verify(format(s.Protected, pl), s.Signature, key) +} diff --git a/vendor/github.com/SermoDigital/jose/jws/jwt.go b/vendor/github.com/SermoDigital/jose/jws/jwt.go new file mode 100644 index 0000000..53da1fc --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/jwt.go @@ -0,0 +1,115 @@ +package jws + +import ( + "net/http" + "time" + + "github.com/SermoDigital/jose" + "github.com/SermoDigital/jose/crypto" + "github.com/SermoDigital/jose/jwt" +) + +// NewJWT creates a new JWT with the given claims. +func NewJWT(claims Claims, method crypto.SigningMethod) jwt.JWT { + j, ok := New(claims, method).(*jws) + if !ok { + panic("jws.NewJWT: runtime panic: New(...).(*jws) != true") + } + j.sb[0].protected.Set("typ", "JWT") + j.isJWT = true + return j +} + +// Serialize helps implements jwt.JWT. +func (j *jws) Serialize(key interface{}) ([]byte, error) { + if j.isJWT { + return j.Compact(key) + } + return nil, ErrIsNotJWT +} + +// Claims helps implements jwt.JWT. +func (j *jws) Claims() jwt.Claims { + if j.isJWT { + if c, ok := j.payload.v.(Claims); ok { + return jwt.Claims(c) + } + } + return nil +} + +// ParseJWTFromRequest tries to find the JWT in an http.Request. +// This method will call ParseMultipartForm if there's no token in the header. +func ParseJWTFromRequest(req *http.Request) (jwt.JWT, error) { + if b, ok := fromHeader(req); ok { + return ParseJWT(b) + } + if b, ok := fromForm(req); ok { + return ParseJWT(b) + } + return nil, ErrNoTokenInRequest +} + +// ParseJWT parses a serialized jwt.JWT into a physical jwt.JWT. +// If its payload isn't a set of claims (or able to be coerced into +// a set of claims) it'll return an error stating the +// JWT isn't a JWT. +func ParseJWT(encoded []byte) (jwt.JWT, error) { + t, err := parseCompact(encoded, true) + if err != nil { + return nil, err + } + c, ok := t.Payload().(map[string]interface{}) + if !ok { + return nil, ErrIsNotJWT + } + t.SetPayload(Claims(c)) + return t, nil +} + +// IsJWT returns true if the JWS is a JWT. +func (j *jws) IsJWT() bool { + return j.isJWT +} + +func (j *jws) Validate(key interface{}, m crypto.SigningMethod, v ...*jwt.Validator) error { + if j.isJWT { + if err := j.Verify(key, m); err != nil { + return err + } + var v1 jwt.Validator + if len(v) > 0 { + v1 = *v[0] + } + c, ok := j.payload.v.(Claims) + if ok { + if err := v1.Validate(j); err != nil { + return err + } + return jwt.Claims(c).Validate(jose.Now(), v1.EXP, v1.NBF) + } + } + return ErrIsNotJWT +} + +// Conv converts a func(Claims) error to type jwt.ValidateFunc. +func Conv(fn func(Claims) error) jwt.ValidateFunc { + if fn == nil { + return nil + } + return func(c jwt.Claims) error { + return fn(Claims(c)) + } +} + +// NewValidator returns a jwt.Validator. +func NewValidator(c Claims, exp, nbf time.Duration, fn func(Claims) error) *jwt.Validator { + return &jwt.Validator{ + Expected: jwt.Claims(c), + EXP: exp, + NBF: nbf, + Fn: Conv(fn), + } +} + +var _ jwt.JWT = (*jws)(nil) diff --git a/vendor/github.com/SermoDigital/jose/jws/payload.go b/vendor/github.com/SermoDigital/jose/jws/payload.go new file mode 100644 index 0000000..58bfd06 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/payload.go @@ -0,0 +1,52 @@ +package jws + +import ( + "encoding/json" + + "github.com/SermoDigital/jose" +) + +// payload represents the payload of a JWS. +type payload struct { + v interface{} + u json.Unmarshaler + _ struct{} +} + +// MarshalJSON implements json.Marshaler for payload. +func (p *payload) MarshalJSON() ([]byte, error) { + b, err := json.Marshal(p.v) + if err != nil { + return nil, err + } + return jose.EncodeEscape(b), nil +} + +// Base64 implements jose.Encoder. +func (p *payload) Base64() ([]byte, error) { + b, err := json.Marshal(p.v) + if err != nil { + return nil, err + } + return jose.Base64Encode(b), nil +} + +// MarshalJSON implements json.Unmarshaler for payload. +func (p *payload) UnmarshalJSON(b []byte) error { + b2, err := jose.DecodeEscaped(b) + if err != nil { + return err + } + if p.u != nil { + err := p.u.UnmarshalJSON(b2) + p.v = p.u + return err + } + return json.Unmarshal(b2, &p.v) +} + +var ( + _ json.Marshaler = (*payload)(nil) + _ json.Unmarshaler = (*payload)(nil) + _ jose.Encoder = (*payload)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/jws/rawbase64.go b/vendor/github.com/SermoDigital/jose/jws/rawbase64.go new file mode 100644 index 0000000..f2c4060 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/rawbase64.go @@ -0,0 +1,28 @@ +package jws + +import "encoding/json" + +type rawBase64 []byte + +// MarshalJSON implements json.Marshaler for rawBase64. +func (r rawBase64) MarshalJSON() ([]byte, error) { + buf := make([]byte, len(r)+2) + buf[0] = '"' + copy(buf[1:], r) + buf[len(buf)-1] = '"' + return buf, nil +} + +// MarshalJSON implements json.Unmarshaler for rawBase64. +func (r *rawBase64) UnmarshalJSON(b []byte) error { + if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' { + b = b[1 : len(b)-1] + } + *r = rawBase64(b) + return nil +} + +var ( + _ json.Marshaler = (rawBase64)(nil) + _ json.Unmarshaler = (*rawBase64)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/jws/signing_methods.go b/vendor/github.com/SermoDigital/jose/jws/signing_methods.go new file mode 100644 index 0000000..525806f --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jws/signing_methods.go @@ -0,0 +1,63 @@ +package jws + +import ( + "sync" + + "github.com/SermoDigital/jose/crypto" +) + +var ( + mu sync.RWMutex + + signingMethods = map[string]crypto.SigningMethod{ + crypto.SigningMethodES256.Alg(): crypto.SigningMethodES256, + crypto.SigningMethodES384.Alg(): crypto.SigningMethodES384, + crypto.SigningMethodES512.Alg(): crypto.SigningMethodES512, + + crypto.SigningMethodPS256.Alg(): crypto.SigningMethodPS256, + crypto.SigningMethodPS384.Alg(): crypto.SigningMethodPS384, + crypto.SigningMethodPS512.Alg(): crypto.SigningMethodPS512, + + crypto.SigningMethodRS256.Alg(): crypto.SigningMethodRS256, + crypto.SigningMethodRS384.Alg(): crypto.SigningMethodRS384, + crypto.SigningMethodRS512.Alg(): crypto.SigningMethodRS512, + + crypto.SigningMethodHS256.Alg(): crypto.SigningMethodHS256, + crypto.SigningMethodHS384.Alg(): crypto.SigningMethodHS384, + crypto.SigningMethodHS512.Alg(): crypto.SigningMethodHS512, + + crypto.Unsecured.Alg(): crypto.Unsecured, + } +) + +// RegisterSigningMethod registers the crypto.SigningMethod in the global map. +// This is typically done inside the caller's init function. +func RegisterSigningMethod(sm crypto.SigningMethod) { + alg := sm.Alg() + if GetSigningMethod(alg) != nil { + panic("jose/jws: cannot duplicate signing methods") + } + + if !sm.Hasher().Available() { + panic("jose/jws: specific hash is unavailable") + } + + mu.Lock() + signingMethods[alg] = sm + mu.Unlock() +} + +// RemoveSigningMethod removes the crypto.SigningMethod from the global map. +func RemoveSigningMethod(sm crypto.SigningMethod) { + mu.Lock() + delete(signingMethods, sm.Alg()) + mu.Unlock() +} + +// GetSigningMethod retrieves a crypto.SigningMethod from the global map. +func GetSigningMethod(alg string) (method crypto.SigningMethod) { + mu.RLock() + method = signingMethods[alg] + mu.RUnlock() + return method +} diff --git a/vendor/github.com/SermoDigital/jose/jwt/claims.go b/vendor/github.com/SermoDigital/jose/jwt/claims.go new file mode 100644 index 0000000..d3d93bf --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jwt/claims.go @@ -0,0 +1,274 @@ +package jwt + +import ( + "encoding/json" + "time" + + "github.com/SermoDigital/jose" +) + +// Claims implements a set of JOSE Claims with the addition of some helper +// methods, similar to net/url.Values. +type Claims map[string]interface{} + +// Validate validates the Claims per the claims found in +// https://tools.ietf.org/html/rfc7519#section-4.1 +func (c Claims) Validate(now time.Time, expLeeway, nbfLeeway time.Duration) error { + if exp, ok := c.Expiration(); ok { + if now.After(exp.Add(expLeeway)) { + return ErrTokenIsExpired + } + } + + if nbf, ok := c.NotBefore(); ok { + if !now.After(nbf.Add(-nbfLeeway)) { + return ErrTokenNotYetValid + } + } + return nil +} + +// Get retrieves the value corresponding with key from the Claims. +func (c Claims) Get(key string) interface{} { + if c == nil { + return nil + } + return c[key] +} + +// Set sets Claims[key] = val. It'll overwrite without warning. +func (c Claims) Set(key string, val interface{}) { + c[key] = val +} + +// Del removes the value that corresponds with key from the Claims. +func (c Claims) Del(key string) { + delete(c, key) +} + +// Has returns true if a value for the given key exists inside the Claims. +func (c Claims) Has(key string) bool { + _, ok := c[key] + return ok +} + +// MarshalJSON implements json.Marshaler for Claims. +func (c Claims) MarshalJSON() ([]byte, error) { + if c == nil || len(c) == 0 { + return nil, nil + } + return json.Marshal(map[string]interface{}(c)) +} + +// Base64 implements the jose.Encoder interface. +func (c Claims) Base64() ([]byte, error) { + b, err := c.MarshalJSON() + if err != nil { + return nil, err + } + return jose.Base64Encode(b), nil +} + +// UnmarshalJSON implements json.Unmarshaler for Claims. +func (c *Claims) UnmarshalJSON(b []byte) error { + if b == nil { + return nil + } + + b, err := jose.DecodeEscaped(b) + if err != nil { + return err + } + + // Since json.Unmarshal calls UnmarshalJSON, + // calling json.Unmarshal on *p would be infinitely recursive + // A temp variable is needed because &map[string]interface{}(*p) is + // invalid Go. (Address of unaddressable object and all that...) + + tmp := map[string]interface{}(*c) + if err = json.Unmarshal(b, &tmp); err != nil { + return err + } + *c = Claims(tmp) + return nil +} + +// Issuer retrieves claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.1 +func (c Claims) Issuer() (string, bool) { + v, ok := c.Get("iss").(string) + return v, ok +} + +// Subject retrieves claim "sub" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.2 +func (c Claims) Subject() (string, bool) { + v, ok := c.Get("sub").(string) + return v, ok +} + +// Audience retrieves claim "aud" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.3 +func (c Claims) Audience() ([]string, bool) { + // Audience claim must be stringy. That is, it may be one string + // or multiple strings but it should not be anything else. E.g. an int. + switch t := c.Get("aud").(type) { + case string: + return []string{t}, true + case []string: + return t, true + case []interface{}: + return stringify(t...) + case interface{}: + return stringify(t) + } + return nil, false +} + +func stringify(a ...interface{}) ([]string, bool) { + if len(a) == 0 { + return nil, false + } + + s := make([]string, len(a)) + for i := range a { + str, ok := a[i].(string) + if !ok { + return nil, false + } + s[i] = str + } + return s, true +} + +// Expiration retrieves claim "exp" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.4 +func (c Claims) Expiration() (time.Time, bool) { + return c.GetTime("exp") +} + +// NotBefore retrieves claim "nbf" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.5 +func (c Claims) NotBefore() (time.Time, bool) { + return c.GetTime("nbf") +} + +// IssuedAt retrieves claim "iat" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.6 +func (c Claims) IssuedAt() (time.Time, bool) { + return c.GetTime("iat") +} + +// JWTID retrieves claim "jti" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.7 +func (c Claims) JWTID() (string, bool) { + v, ok := c.Get("jti").(string) + return v, ok +} + +// RemoveIssuer deletes claim "iss" from c. +func (c Claims) RemoveIssuer() { c.Del("iss") } + +// RemoveSubject deletes claim "sub" from c. +func (c Claims) RemoveSubject() { c.Del("sub") } + +// RemoveAudience deletes claim "aud" from c. +func (c Claims) RemoveAudience() { c.Del("aud") } + +// RemoveExpiration deletes claim "exp" from c. +func (c Claims) RemoveExpiration() { c.Del("exp") } + +// RemoveNotBefore deletes claim "nbf" from c. +func (c Claims) RemoveNotBefore() { c.Del("nbf") } + +// RemoveIssuedAt deletes claim "iat" from c. +func (c Claims) RemoveIssuedAt() { c.Del("iat") } + +// RemoveJWTID deletes claim "jti" from c. +func (c Claims) RemoveJWTID() { c.Del("jti") } + +// SetIssuer sets claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.1 +func (c Claims) SetIssuer(issuer string) { + c.Set("iss", issuer) +} + +// SetSubject sets claim "iss" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.2 +func (c Claims) SetSubject(subject string) { + c.Set("sub", subject) +} + +// SetAudience sets claim "aud" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.3 +func (c Claims) SetAudience(audience ...string) { + if len(audience) == 1 { + c.Set("aud", audience[0]) + } else { + c.Set("aud", audience) + } +} + +// SetExpiration sets claim "exp" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.4 +func (c Claims) SetExpiration(expiration time.Time) { + c.SetTime("exp", expiration) +} + +// SetNotBefore sets claim "nbf" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.5 +func (c Claims) SetNotBefore(notBefore time.Time) { + c.SetTime("nbf", notBefore) +} + +// SetIssuedAt sets claim "iat" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.6 +func (c Claims) SetIssuedAt(issuedAt time.Time) { + c.SetTime("iat", issuedAt) +} + +// SetJWTID sets claim "jti" per its type in +// https://tools.ietf.org/html/rfc7519#section-4.1.7 +func (c Claims) SetJWTID(uniqueID string) { + c.Set("jti", uniqueID) +} + +// GetTime returns a Unix timestamp for the given key. +// +// It converts an int, int32, int64, uint, uint32, uint64 or float64 into a Unix +// timestamp (epoch seconds). float32 does not have sufficient precision to +// store a Unix timestamp. +// +// Numeric values parsed from JSON will always be stored as float64 since +// Claims is a map[string]interface{}. However, the values may be stored directly +// in the claims as a different type. +func (c Claims) GetTime(key string) (time.Time, bool) { + switch t := c.Get(key).(type) { + case int: + return time.Unix(int64(t), 0), true + case int32: + return time.Unix(int64(t), 0), true + case int64: + return time.Unix(int64(t), 0), true + case uint: + return time.Unix(int64(t), 0), true + case uint32: + return time.Unix(int64(t), 0), true + case uint64: + return time.Unix(int64(t), 0), true + case float64: + return time.Unix(int64(t), 0), true + default: + return time.Time{}, false + } +} + +// SetTime stores a UNIX time for the given key. +func (c Claims) SetTime(key string, t time.Time) { + c.Set(key, t.Unix()) +} + +var ( + _ json.Marshaler = (Claims)(nil) + _ json.Unmarshaler = (*Claims)(nil) +) diff --git a/vendor/github.com/SermoDigital/jose/jwt/doc.go b/vendor/github.com/SermoDigital/jose/jwt/doc.go new file mode 100644 index 0000000..6004d0f --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jwt/doc.go @@ -0,0 +1,2 @@ +// Package jwt implements JWTs per RFC 7519 +package jwt diff --git a/vendor/github.com/SermoDigital/jose/jwt/eq.go b/vendor/github.com/SermoDigital/jose/jwt/eq.go new file mode 100644 index 0000000..3113269 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jwt/eq.go @@ -0,0 +1,47 @@ +package jwt + +func verifyPrincipals(pcpls, auds []string) bool { + // "Each principal intended to process the JWT MUST + // identify itself with a value in the audience claim." + // - https://tools.ietf.org/html/rfc7519#section-4.1.3 + + found := -1 + for i, p := range pcpls { + for _, v := range auds { + if p == v { + found++ + break + } + } + if found != i { + return false + } + } + return true +} + +// ValidAudience returns true iff: +// - a and b are strings and a == b +// - a is string, b is []string and a is in b +// - a is []string, b is []string and all of a is in b +// - a is []string, b is string and len(a) == 1 and a[0] == b +func ValidAudience(a, b interface{}) bool { + s1, ok := a.(string) + if ok { + if s2, ok := b.(string); ok { + return s1 == s2 + } + a2, ok := b.([]string) + return ok && verifyPrincipals([]string{s1}, a2) + } + + a1, ok := a.([]string) + if !ok { + return false + } + if a2, ok := b.([]string); ok { + return verifyPrincipals(a1, a2) + } + s2, ok := b.(string) + return ok && len(a1) == 1 && a1[0] == s2 +} diff --git a/vendor/github.com/SermoDigital/jose/jwt/errors.go b/vendor/github.com/SermoDigital/jose/jwt/errors.go new file mode 100644 index 0000000..96b240d --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jwt/errors.go @@ -0,0 +1,28 @@ +package jwt + +import "errors" + +var ( + // ErrTokenIsExpired is return when time.Now().Unix() is after + // the token's "exp" claim. + ErrTokenIsExpired = errors.New("token is expired") + + // ErrTokenNotYetValid is return when time.Now().Unix() is before + // the token's "nbf" claim. + ErrTokenNotYetValid = errors.New("token is not yet valid") + + // ErrInvalidISSClaim means the "iss" claim is invalid. + ErrInvalidISSClaim = errors.New("claim \"iss\" is invalid") + + // ErrInvalidSUBClaim means the "sub" claim is invalid. + ErrInvalidSUBClaim = errors.New("claim \"sub\" is invalid") + + // ErrInvalidIATClaim means the "iat" claim is invalid. + ErrInvalidIATClaim = errors.New("claim \"iat\" is invalid") + + // ErrInvalidJTIClaim means the "jti" claim is invalid. + ErrInvalidJTIClaim = errors.New("claim \"jti\" is invalid") + + // ErrInvalidAUDClaim means the "aud" claim is invalid. + ErrInvalidAUDClaim = errors.New("claim \"aud\" is invalid") +) diff --git a/vendor/github.com/SermoDigital/jose/jwt/jwt.go b/vendor/github.com/SermoDigital/jose/jwt/jwt.go new file mode 100644 index 0000000..feb1712 --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/jwt/jwt.go @@ -0,0 +1,144 @@ +package jwt + +import ( + "time" + + "github.com/SermoDigital/jose/crypto" +) + +// JWT represents a JWT per RFC 7519. +// It's described as an interface instead of a physical structure +// because both JWS and JWEs can be JWTs. So, in order to use either, +// import one of those two packages and use their "NewJWT" (and other) +// functions. +type JWT interface { + // Claims returns the set of Claims. + Claims() Claims + + // Validate returns an error describing any issues found while + // validating the JWT. For info on the fn parameter, see the + // comment on ValidateFunc. + Validate(key interface{}, method crypto.SigningMethod, v ...*Validator) error + + // Serialize serializes the JWT into its on-the-wire + // representation. + Serialize(key interface{}) ([]byte, error) +} + +// ValidateFunc is a function that provides access to the JWT +// and allows for custom validation. Keep in mind that the Verify +// methods in the JWS/JWE sibling packages call ValidateFunc *after* +// validating the JWS/JWE, but *before* any validation per the JWT +// RFC. Therefore, the ValidateFunc can be used to short-circuit +// verification, but cannot be used to circumvent the RFC. +// Custom JWT implementations are free to abuse this, but it is +// not recommended. +type ValidateFunc func(Claims) error + +// Validator represents some of the validation options. +type Validator struct { + Expected Claims // If non-nil, these are required to match. + EXP time.Duration // EXPLeeway + NBF time.Duration // NBFLeeway + Fn ValidateFunc // See ValidateFunc for more information. + + _ struct{} // Require explicitly-named struct fields. +} + +// Validate validates the JWT based on the expected claims in v. +// Note: it only validates the registered claims per +// https://tools.ietf.org/html/rfc7519#section-4.1 +// +// Custom claims should be validated using v's Fn member. +func (v *Validator) Validate(j JWT) error { + if iss, ok := v.Expected.Issuer(); ok && + j.Claims().Get("iss") != iss { + return ErrInvalidISSClaim + } + if sub, ok := v.Expected.Subject(); ok && + j.Claims().Get("sub") != sub { + return ErrInvalidSUBClaim + } + if iat, ok := v.Expected.IssuedAt(); ok { + if t, ok := j.Claims().GetTime("iat"); !t.Equal(iat) || !ok { + return ErrInvalidIATClaim + } + } + if jti, ok := v.Expected.JWTID(); ok && + j.Claims().Get("jti") != jti { + return ErrInvalidJTIClaim + } + + if aud, ok := v.Expected.Audience(); ok { + aud2, ok := j.Claims().Audience() + if !ok || !ValidAudience(aud, aud2) { + return ErrInvalidAUDClaim + } + } + + if v.Fn != nil { + return v.Fn(j.Claims()) + } + return nil +} + +// SetClaim sets the claim with the given val. +func (v *Validator) SetClaim(claim string, val interface{}) { + v.expect() + v.Expected.Set(claim, val) +} + +// SetIssuer sets the "iss" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.1 +func (v *Validator) SetIssuer(iss string) { + v.expect() + v.Expected.Set("iss", iss) +} + +// SetSubject sets the "sub" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.2 +func (v *Validator) SetSubject(sub string) { + v.expect() + v.Expected.Set("sub", sub) +} + +// SetAudience sets the "aud" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.3 +func (v *Validator) SetAudience(aud string) { + v.expect() + v.Expected.Set("aud", aud) +} + +// SetExpiration sets the "exp" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.4 +func (v *Validator) SetExpiration(exp time.Time) { + v.expect() + v.Expected.Set("exp", exp) +} + +// SetNotBefore sets the "nbf" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.5 +func (v *Validator) SetNotBefore(nbf time.Time) { + v.expect() + v.Expected.Set("nbf", nbf) +} + +// SetIssuedAt sets the "iat" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.6 +func (v *Validator) SetIssuedAt(iat time.Time) { + v.expect() + v.Expected.Set("iat", iat) +} + +// SetJWTID sets the "jti" claim per +// https://tools.ietf.org/html/rfc7519#section-4.1.7 +func (v *Validator) SetJWTID(jti string) { + v.expect() + v.Expected.Set("jti", jti) +} + +func (v *Validator) expect() { + if v.Expected == nil { + v.Expected = make(Claims) + } +} diff --git a/vendor/github.com/SermoDigital/jose/time.go b/vendor/github.com/SermoDigital/jose/time.go new file mode 100644 index 0000000..f366a7a --- /dev/null +++ b/vendor/github.com/SermoDigital/jose/time.go @@ -0,0 +1,6 @@ +package jose + +import "time" + +// Now returns the current time in UTC. +func Now() time.Time { return time.Now().UTC() } diff --git a/vendor/github.com/armon/go-metrics/.gitignore b/vendor/github.com/armon/go-metrics/.gitignore new file mode 100644 index 0000000..8c03ec1 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +/metrics.out diff --git a/vendor/github.com/armon/go-metrics/LICENSE b/vendor/github.com/armon/go-metrics/LICENSE new file mode 100644 index 0000000..106569e --- /dev/null +++ b/vendor/github.com/armon/go-metrics/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Armon Dadgar + +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/vendor/github.com/armon/go-metrics/README.md b/vendor/github.com/armon/go-metrics/README.md new file mode 100644 index 0000000..a7399cd --- /dev/null +++ b/vendor/github.com/armon/go-metrics/README.md @@ -0,0 +1,74 @@ +go-metrics +========== + +This library provides a `metrics` package which can be used to instrument code, +expose application metrics, and profile runtime performance in a flexible manner. + +Current API: [![GoDoc](https://godoc.org/github.com/armon/go-metrics?status.svg)](https://godoc.org/github.com/armon/go-metrics) + +Sinks +===== + +The `metrics` package makes use of a `MetricSink` interface to support delivery +to any type of backend. Currently the following sinks are provided: + +* StatsiteSink : Sinks to a [statsite](https://github.com/armon/statsite/) instance (TCP) +* StatsdSink: Sinks to a [StatsD](https://github.com/etsy/statsd/) / statsite instance (UDP) +* PrometheusSink: Sinks to a [Prometheus](http://prometheus.io/) metrics endpoint (exposed via HTTP for scrapes) +* InmemSink : Provides in-memory aggregation, can be used to export stats +* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example. +* BlackholeSink : Sinks to nowhere + +In addition to the sinks, the `InmemSignal` can be used to catch a signal, +and dump a formatted output of recent metrics. For example, when a process gets +a SIGUSR1, it can dump to stderr recent performance metrics for debugging. + +Examples +======== + +Here is an example of using the package: + +```go +func SlowMethod() { + // Profiling the runtime of a method + defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now()) +} + +// Configure a statsite sink as the global metrics sink +sink, _ := metrics.NewStatsiteSink("statsite:8125") +metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink) + +// Emit a Key/Value pair +metrics.EmitKey([]string{"questions", "meaning of life"}, 42) +``` + +Here is an example of setting up a signal handler: + +```go +// Setup the inmem sink and signal handler +inm := metrics.NewInmemSink(10*time.Second, time.Minute) +sig := metrics.DefaultInmemSignal(inm) +metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm) + +// Run some code +inm.SetGauge([]string{"foo"}, 42) +inm.EmitKey([]string{"bar"}, 30) + +inm.IncrCounter([]string{"baz"}, 42) +inm.IncrCounter([]string{"baz"}, 1) +inm.IncrCounter([]string{"baz"}, 80) + +inm.AddSample([]string{"method", "wow"}, 42) +inm.AddSample([]string{"method", "wow"}, 100) +inm.AddSample([]string{"method", "wow"}, 22) + +.... +``` + +When a signal comes in, output like the following will be dumped to stderr: + + [2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000 + [2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000 + [2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509 + [2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513 + diff --git a/vendor/github.com/armon/go-metrics/const_unix.go b/vendor/github.com/armon/go-metrics/const_unix.go new file mode 100644 index 0000000..31098dd --- /dev/null +++ b/vendor/github.com/armon/go-metrics/const_unix.go @@ -0,0 +1,12 @@ +// +build !windows + +package metrics + +import ( + "syscall" +) + +const ( + // DefaultSignal is used with DefaultInmemSignal + DefaultSignal = syscall.SIGUSR1 +) diff --git a/vendor/github.com/armon/go-metrics/const_windows.go b/vendor/github.com/armon/go-metrics/const_windows.go new file mode 100644 index 0000000..38136af --- /dev/null +++ b/vendor/github.com/armon/go-metrics/const_windows.go @@ -0,0 +1,13 @@ +// +build windows + +package metrics + +import ( + "syscall" +) + +const ( + // DefaultSignal is used with DefaultInmemSignal + // Windows has no SIGUSR1, use SIGBREAK + DefaultSignal = syscall.Signal(21) +) diff --git a/vendor/github.com/armon/go-metrics/inmem.go b/vendor/github.com/armon/go-metrics/inmem.go new file mode 100644 index 0000000..4e2d6a7 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/inmem.go @@ -0,0 +1,348 @@ +package metrics + +import ( + "bytes" + "fmt" + "math" + "net/url" + "strings" + "sync" + "time" +) + +// InmemSink provides a MetricSink that does in-memory aggregation +// without sending metrics over a network. It can be embedded within +// an application to provide profiling information. +type InmemSink struct { + // How long is each aggregation interval + interval time.Duration + + // Retain controls how many metrics interval we keep + retain time.Duration + + // maxIntervals is the maximum length of intervals. + // It is retain / interval. + maxIntervals int + + // intervals is a slice of the retained intervals + intervals []*IntervalMetrics + intervalLock sync.RWMutex + + rateDenom float64 +} + +// IntervalMetrics stores the aggregated metrics +// for a specific interval +type IntervalMetrics struct { + sync.RWMutex + + // The start time of the interval + Interval time.Time + + // Gauges maps the key to the last set value + Gauges map[string]GaugeValue + + // Points maps the string to the list of emitted values + // from EmitKey + Points map[string][]float32 + + // Counters maps the string key to a sum of the counter + // values + Counters map[string]SampledValue + + // Samples maps the key to an AggregateSample, + // which has the rolled up view of a sample + Samples map[string]SampledValue +} + +// NewIntervalMetrics creates a new IntervalMetrics for a given interval +func NewIntervalMetrics(intv time.Time) *IntervalMetrics { + return &IntervalMetrics{ + Interval: intv, + Gauges: make(map[string]GaugeValue), + Points: make(map[string][]float32), + Counters: make(map[string]SampledValue), + Samples: make(map[string]SampledValue), + } +} + +// AggregateSample is used to hold aggregate metrics +// about a sample +type AggregateSample struct { + Count int // The count of emitted pairs + Rate float64 // The values rate per time unit (usually 1 second) + Sum float64 // The sum of values + SumSq float64 `json:"-"` // The sum of squared values + Min float64 // Minimum value + Max float64 // Maximum value + LastUpdated time.Time `json:"-"` // When value was last updated +} + +// Computes a Stddev of the values +func (a *AggregateSample) Stddev() float64 { + num := (float64(a.Count) * a.SumSq) - math.Pow(a.Sum, 2) + div := float64(a.Count * (a.Count - 1)) + if div == 0 { + return 0 + } + return math.Sqrt(num / div) +} + +// Computes a mean of the values +func (a *AggregateSample) Mean() float64 { + if a.Count == 0 { + return 0 + } + return a.Sum / float64(a.Count) +} + +// Ingest is used to update a sample +func (a *AggregateSample) Ingest(v float64, rateDenom float64) { + a.Count++ + a.Sum += v + a.SumSq += (v * v) + if v < a.Min || a.Count == 1 { + a.Min = v + } + if v > a.Max || a.Count == 1 { + a.Max = v + } + a.Rate = float64(a.Sum) / rateDenom + a.LastUpdated = time.Now() +} + +func (a *AggregateSample) String() string { + if a.Count == 0 { + return "Count: 0" + } else if a.Stddev() == 0 { + return fmt.Sprintf("Count: %d Sum: %0.3f LastUpdated: %s", a.Count, a.Sum, a.LastUpdated) + } else { + return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f LastUpdated: %s", + a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum, a.LastUpdated) + } +} + +// NewInmemSinkFromURL creates an InmemSink from a URL. It is used +// (and tested) from NewMetricSinkFromURL. +func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) { + params := u.Query() + + interval, err := time.ParseDuration(params.Get("interval")) + if err != nil { + return nil, fmt.Errorf("Bad 'interval' param: %s", err) + } + + retain, err := time.ParseDuration(params.Get("retain")) + if err != nil { + return nil, fmt.Errorf("Bad 'retain' param: %s", err) + } + + return NewInmemSink(interval, retain), nil +} + +// NewInmemSink is used to construct a new in-memory sink. +// Uses an aggregation interval and maximum retention period. +func NewInmemSink(interval, retain time.Duration) *InmemSink { + rateTimeUnit := time.Second + i := &InmemSink{ + interval: interval, + retain: retain, + maxIntervals: int(retain / interval), + rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()), + } + i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals) + return i +} + +func (i *InmemSink) SetGauge(key []string, val float32) { + i.SetGaugeWithLabels(key, val, nil) +} + +func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label) { + k, name := i.flattenKeyLabels(key, labels) + intv := i.getInterval() + + intv.Lock() + defer intv.Unlock() + intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels} +} + +func (i *InmemSink) EmitKey(key []string, val float32) { + k := i.flattenKey(key) + intv := i.getInterval() + + intv.Lock() + defer intv.Unlock() + vals := intv.Points[k] + intv.Points[k] = append(vals, val) +} + +func (i *InmemSink) IncrCounter(key []string, val float32) { + i.IncrCounterWithLabels(key, val, nil) +} + +func (i *InmemSink) IncrCounterWithLabels(key []string, val float32, labels []Label) { + k, name := i.flattenKeyLabels(key, labels) + intv := i.getInterval() + + intv.Lock() + defer intv.Unlock() + + agg, ok := intv.Counters[k] + if !ok { + agg = SampledValue{ + Name: name, + AggregateSample: &AggregateSample{}, + Labels: labels, + } + intv.Counters[k] = agg + } + agg.Ingest(float64(val), i.rateDenom) +} + +func (i *InmemSink) AddSample(key []string, val float32) { + i.AddSampleWithLabels(key, val, nil) +} + +func (i *InmemSink) AddSampleWithLabels(key []string, val float32, labels []Label) { + k, name := i.flattenKeyLabels(key, labels) + intv := i.getInterval() + + intv.Lock() + defer intv.Unlock() + + agg, ok := intv.Samples[k] + if !ok { + agg = SampledValue{ + Name: name, + AggregateSample: &AggregateSample{}, + Labels: labels, + } + intv.Samples[k] = agg + } + agg.Ingest(float64(val), i.rateDenom) +} + +// Data is used to retrieve all the aggregated metrics +// Intervals may be in use, and a read lock should be acquired +func (i *InmemSink) Data() []*IntervalMetrics { + // Get the current interval, forces creation + i.getInterval() + + i.intervalLock.RLock() + defer i.intervalLock.RUnlock() + + n := len(i.intervals) + intervals := make([]*IntervalMetrics, n) + + copy(intervals[:n-1], i.intervals[:n-1]) + current := i.intervals[n-1] + + // make its own copy for current interval + intervals[n-1] = &IntervalMetrics{} + copyCurrent := intervals[n-1] + current.RLock() + *copyCurrent = *current + + copyCurrent.Gauges = make(map[string]GaugeValue, len(current.Gauges)) + for k, v := range current.Gauges { + copyCurrent.Gauges[k] = v + } + // saved values will be not change, just copy its link + copyCurrent.Points = make(map[string][]float32, len(current.Points)) + for k, v := range current.Points { + copyCurrent.Points[k] = v + } + copyCurrent.Counters = make(map[string]SampledValue, len(current.Counters)) + for k, v := range current.Counters { + copyCurrent.Counters[k] = v + } + copyCurrent.Samples = make(map[string]SampledValue, len(current.Samples)) + for k, v := range current.Samples { + copyCurrent.Samples[k] = v + } + current.RUnlock() + + return intervals +} + +func (i *InmemSink) getExistingInterval(intv time.Time) *IntervalMetrics { + i.intervalLock.RLock() + defer i.intervalLock.RUnlock() + + n := len(i.intervals) + if n > 0 && i.intervals[n-1].Interval == intv { + return i.intervals[n-1] + } + return nil +} + +func (i *InmemSink) createInterval(intv time.Time) *IntervalMetrics { + i.intervalLock.Lock() + defer i.intervalLock.Unlock() + + // Check for an existing interval + n := len(i.intervals) + if n > 0 && i.intervals[n-1].Interval == intv { + return i.intervals[n-1] + } + + // Add the current interval + current := NewIntervalMetrics(intv) + i.intervals = append(i.intervals, current) + n++ + + // Truncate the intervals if they are too long + if n >= i.maxIntervals { + copy(i.intervals[0:], i.intervals[n-i.maxIntervals:]) + i.intervals = i.intervals[:i.maxIntervals] + } + return current +} + +// getInterval returns the current interval to write to +func (i *InmemSink) getInterval() *IntervalMetrics { + intv := time.Now().Truncate(i.interval) + if m := i.getExistingInterval(intv); m != nil { + return m + } + return i.createInterval(intv) +} + +// Flattens the key for formatting, removes spaces +func (i *InmemSink) flattenKey(parts []string) string { + buf := &bytes.Buffer{} + replacer := strings.NewReplacer(" ", "_") + + if len(parts) > 0 { + replacer.WriteString(buf, parts[0]) + } + for _, part := range parts[1:] { + replacer.WriteString(buf, ".") + replacer.WriteString(buf, part) + } + + return buf.String() +} + +// Flattens the key for formatting along with its labels, removes spaces +func (i *InmemSink) flattenKeyLabels(parts []string, labels []Label) (string, string) { + buf := &bytes.Buffer{} + replacer := strings.NewReplacer(" ", "_") + + if len(parts) > 0 { + replacer.WriteString(buf, parts[0]) + } + for _, part := range parts[1:] { + replacer.WriteString(buf, ".") + replacer.WriteString(buf, part) + } + + key := buf.String() + + for _, label := range labels { + replacer.WriteString(buf, fmt.Sprintf(";%s=%s", label.Name, label.Value)) + } + + return buf.String(), key +} diff --git a/vendor/github.com/armon/go-metrics/inmem_endpoint.go b/vendor/github.com/armon/go-metrics/inmem_endpoint.go new file mode 100644 index 0000000..504f1b3 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/inmem_endpoint.go @@ -0,0 +1,118 @@ +package metrics + +import ( + "fmt" + "net/http" + "sort" + "time" +) + +// MetricsSummary holds a roll-up of metrics info for a given interval +type MetricsSummary struct { + Timestamp string + Gauges []GaugeValue + Points []PointValue + Counters []SampledValue + Samples []SampledValue +} + +type GaugeValue struct { + Name string + Hash string `json:"-"` + Value float32 + + Labels []Label `json:"-"` + DisplayLabels map[string]string `json:"Labels"` +} + +type PointValue struct { + Name string + Points []float32 +} + +type SampledValue struct { + Name string + Hash string `json:"-"` + *AggregateSample + Mean float64 + Stddev float64 + + Labels []Label `json:"-"` + DisplayLabels map[string]string `json:"Labels"` +} + +// DisplayMetrics returns a summary of the metrics from the most recent finished interval. +func (i *InmemSink) DisplayMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + data := i.Data() + + var interval *IntervalMetrics + n := len(data) + switch { + case n == 0: + return nil, fmt.Errorf("no metric intervals have been initialized yet") + case n == 1: + // Show the current interval if it's all we have + interval = i.intervals[0] + default: + // Show the most recent finished interval if we have one + interval = i.intervals[n-2] + } + + summary := MetricsSummary{ + Timestamp: interval.Interval.Round(time.Second).UTC().String(), + Gauges: make([]GaugeValue, 0, len(interval.Gauges)), + Points: make([]PointValue, 0, len(interval.Points)), + } + + // Format and sort the output of each metric type, so it gets displayed in a + // deterministic order. + for name, points := range interval.Points { + summary.Points = append(summary.Points, PointValue{name, points}) + } + sort.Slice(summary.Points, func(i, j int) bool { + return summary.Points[i].Name < summary.Points[j].Name + }) + + for hash, value := range interval.Gauges { + value.Hash = hash + value.DisplayLabels = make(map[string]string) + for _, label := range value.Labels { + value.DisplayLabels[label.Name] = label.Value + } + value.Labels = nil + + summary.Gauges = append(summary.Gauges, value) + } + sort.Slice(summary.Gauges, func(i, j int) bool { + return summary.Gauges[i].Hash < summary.Gauges[j].Hash + }) + + summary.Counters = formatSamples(interval.Counters) + summary.Samples = formatSamples(interval.Samples) + + return summary, nil +} + +func formatSamples(source map[string]SampledValue) []SampledValue { + output := make([]SampledValue, 0, len(source)) + for hash, sample := range source { + displayLabels := make(map[string]string) + for _, label := range sample.Labels { + displayLabels[label.Name] = label.Value + } + + output = append(output, SampledValue{ + Name: sample.Name, + Hash: hash, + AggregateSample: sample.AggregateSample, + Mean: sample.AggregateSample.Mean(), + Stddev: sample.AggregateSample.Stddev(), + DisplayLabels: displayLabels, + }) + } + sort.Slice(output, func(i, j int) bool { + return output[i].Hash < output[j].Hash + }) + + return output +} diff --git a/vendor/github.com/armon/go-metrics/inmem_signal.go b/vendor/github.com/armon/go-metrics/inmem_signal.go new file mode 100644 index 0000000..0937f4a --- /dev/null +++ b/vendor/github.com/armon/go-metrics/inmem_signal.go @@ -0,0 +1,117 @@ +package metrics + +import ( + "bytes" + "fmt" + "io" + "os" + "os/signal" + "strings" + "sync" + "syscall" +) + +// InmemSignal is used to listen for a given signal, and when received, +// to dump the current metrics from the InmemSink to an io.Writer +type InmemSignal struct { + signal syscall.Signal + inm *InmemSink + w io.Writer + sigCh chan os.Signal + + stop bool + stopCh chan struct{} + stopLock sync.Mutex +} + +// NewInmemSignal creates a new InmemSignal which listens for a given signal, +// and dumps the current metrics out to a writer +func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal { + i := &InmemSignal{ + signal: sig, + inm: inmem, + w: w, + sigCh: make(chan os.Signal, 1), + stopCh: make(chan struct{}), + } + signal.Notify(i.sigCh, sig) + go i.run() + return i +} + +// DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1 +// and writes output to stderr. Windows uses SIGBREAK +func DefaultInmemSignal(inmem *InmemSink) *InmemSignal { + return NewInmemSignal(inmem, DefaultSignal, os.Stderr) +} + +// Stop is used to stop the InmemSignal from listening +func (i *InmemSignal) Stop() { + i.stopLock.Lock() + defer i.stopLock.Unlock() + + if i.stop { + return + } + i.stop = true + close(i.stopCh) + signal.Stop(i.sigCh) +} + +// run is a long running routine that handles signals +func (i *InmemSignal) run() { + for { + select { + case <-i.sigCh: + i.dumpStats() + case <-i.stopCh: + return + } + } +} + +// dumpStats is used to dump the data to output writer +func (i *InmemSignal) dumpStats() { + buf := bytes.NewBuffer(nil) + + data := i.inm.Data() + // Skip the last period which is still being aggregated + for j := 0; j < len(data)-1; j++ { + intv := data[j] + intv.RLock() + for _, val := range intv.Gauges { + name := i.flattenLabels(val.Name, val.Labels) + fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value) + } + for name, vals := range intv.Points { + for _, val := range vals { + fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val) + } + } + for _, agg := range intv.Counters { + name := i.flattenLabels(agg.Name, agg.Labels) + fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg.AggregateSample) + } + for _, agg := range intv.Samples { + name := i.flattenLabels(agg.Name, agg.Labels) + fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg.AggregateSample) + } + intv.RUnlock() + } + + // Write out the bytes + i.w.Write(buf.Bytes()) +} + +// Flattens the key for formatting along with its labels, removes spaces +func (i *InmemSignal) flattenLabels(name string, labels []Label) string { + buf := bytes.NewBufferString(name) + replacer := strings.NewReplacer(" ", "_", ":", "_") + + for _, label := range labels { + replacer.WriteString(buf, ".") + replacer.WriteString(buf, label.Value) + } + + return buf.String() +} diff --git a/vendor/github.com/armon/go-metrics/metrics.go b/vendor/github.com/armon/go-metrics/metrics.go new file mode 100644 index 0000000..d260bd4 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/metrics.go @@ -0,0 +1,216 @@ +package metrics + +import ( + "runtime" + "strings" + "time" + + "github.com/hashicorp/go-immutable-radix" +) + +type Label struct { + Name string + Value string +} + +func (m *Metrics) SetGauge(key []string, val float32) { + m.SetGaugeWithLabels(key, val, nil) +} + +func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label) { + if m.HostName != "" { + if m.EnableHostnameLabel { + labels = append(labels, Label{"host", m.HostName}) + } else if m.EnableHostname { + key = insert(0, m.HostName, key) + } + } + if m.EnableTypePrefix { + key = insert(0, "gauge", key) + } + if m.ServiceName != "" { + if m.EnableServiceLabel { + labels = append(labels, Label{"service", m.ServiceName}) + } else { + key = insert(0, m.ServiceName, key) + } + } + if !m.allowMetric(key) { + return + } + m.sink.SetGaugeWithLabels(key, val, labels) +} + +func (m *Metrics) EmitKey(key []string, val float32) { + if m.EnableTypePrefix { + key = insert(0, "kv", key) + } + if m.ServiceName != "" { + key = insert(0, m.ServiceName, key) + } + if !m.allowMetric(key) { + return + } + m.sink.EmitKey(key, val) +} + +func (m *Metrics) IncrCounter(key []string, val float32) { + m.IncrCounterWithLabels(key, val, nil) +} + +func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label) { + if m.HostName != "" && m.EnableHostnameLabel { + labels = append(labels, Label{"host", m.HostName}) + } + if m.EnableTypePrefix { + key = insert(0, "counter", key) + } + if m.ServiceName != "" { + if m.EnableServiceLabel { + labels = append(labels, Label{"service", m.ServiceName}) + } else { + key = insert(0, m.ServiceName, key) + } + } + if !m.allowMetric(key) { + return + } + m.sink.IncrCounterWithLabels(key, val, labels) +} + +func (m *Metrics) AddSample(key []string, val float32) { + m.AddSampleWithLabels(key, val, nil) +} + +func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label) { + if m.HostName != "" && m.EnableHostnameLabel { + labels = append(labels, Label{"host", m.HostName}) + } + if m.EnableTypePrefix { + key = insert(0, "sample", key) + } + if m.ServiceName != "" { + if m.EnableServiceLabel { + labels = append(labels, Label{"service", m.ServiceName}) + } else { + key = insert(0, m.ServiceName, key) + } + } + if !m.allowMetric(key) { + return + } + m.sink.AddSampleWithLabels(key, val, labels) +} + +func (m *Metrics) MeasureSince(key []string, start time.Time) { + m.MeasureSinceWithLabels(key, start, nil) +} + +func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label) { + if m.HostName != "" && m.EnableHostnameLabel { + labels = append(labels, Label{"host", m.HostName}) + } + if m.EnableTypePrefix { + key = insert(0, "timer", key) + } + if m.ServiceName != "" { + if m.EnableServiceLabel { + labels = append(labels, Label{"service", m.ServiceName}) + } else { + key = insert(0, m.ServiceName, key) + } + } + if !m.allowMetric(key) { + return + } + now := time.Now() + elapsed := now.Sub(start) + msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity) + m.sink.AddSampleWithLabels(key, msec, labels) +} + +// UpdateFilter overwrites the existing filter with the given rules. +func (m *Metrics) UpdateFilter(allow, block []string) { + m.filterLock.Lock() + defer m.filterLock.Unlock() + + m.AllowedPrefixes = allow + m.BlockedPrefixes = block + + m.filter = iradix.New() + for _, prefix := range m.AllowedPrefixes { + m.filter, _, _ = m.filter.Insert([]byte(prefix), true) + } + for _, prefix := range m.BlockedPrefixes { + m.filter, _, _ = m.filter.Insert([]byte(prefix), false) + } +} + +// Returns whether the metric should be allowed based on configured prefix filters +func (m *Metrics) allowMetric(key []string) bool { + m.filterLock.RLock() + defer m.filterLock.RUnlock() + + if m.filter == nil || m.filter.Len() == 0 { + return m.Config.FilterDefault + } + + _, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, "."))) + if !ok { + return m.Config.FilterDefault + } + return allowed.(bool) +} + +// Periodically collects runtime stats to publish +func (m *Metrics) collectStats() { + for { + time.Sleep(m.ProfileInterval) + m.emitRuntimeStats() + } +} + +// Emits various runtime statsitics +func (m *Metrics) emitRuntimeStats() { + // Export number of Goroutines + numRoutines := runtime.NumGoroutine() + m.SetGauge([]string{"runtime", "num_goroutines"}, float32(numRoutines)) + + // Export memory stats + var stats runtime.MemStats + runtime.ReadMemStats(&stats) + m.SetGauge([]string{"runtime", "alloc_bytes"}, float32(stats.Alloc)) + m.SetGauge([]string{"runtime", "sys_bytes"}, float32(stats.Sys)) + m.SetGauge([]string{"runtime", "malloc_count"}, float32(stats.Mallocs)) + m.SetGauge([]string{"runtime", "free_count"}, float32(stats.Frees)) + m.SetGauge([]string{"runtime", "heap_objects"}, float32(stats.HeapObjects)) + m.SetGauge([]string{"runtime", "total_gc_pause_ns"}, float32(stats.PauseTotalNs)) + m.SetGauge([]string{"runtime", "total_gc_runs"}, float32(stats.NumGC)) + + // Export info about the last few GC runs + num := stats.NumGC + + // Handle wrap around + if num < m.lastNumGC { + m.lastNumGC = 0 + } + + // Ensure we don't scan more than 256 + if num-m.lastNumGC >= 256 { + m.lastNumGC = num - 255 + } + + for i := m.lastNumGC; i < num; i++ { + pause := stats.PauseNs[i%256] + m.AddSample([]string{"runtime", "gc_pause_ns"}, float32(pause)) + } + m.lastNumGC = num +} + +// Inserts a string value at an index into the slice +func insert(i int, v string, s []string) []string { + s = append(s, "") + copy(s[i+1:], s[i:]) + s[i] = v + return s +} diff --git a/vendor/github.com/armon/go-metrics/sink.go b/vendor/github.com/armon/go-metrics/sink.go new file mode 100644 index 0000000..0b7d6e4 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/sink.go @@ -0,0 +1,115 @@ +package metrics + +import ( + "fmt" + "net/url" +) + +// The MetricSink interface is used to transmit metrics information +// to an external system +type MetricSink interface { + // A Gauge should retain the last value it is set to + SetGauge(key []string, val float32) + SetGaugeWithLabels(key []string, val float32, labels []Label) + + // Should emit a Key/Value pair for each call + EmitKey(key []string, val float32) + + // Counters should accumulate values + IncrCounter(key []string, val float32) + IncrCounterWithLabels(key []string, val float32, labels []Label) + + // Samples are for timing information, where quantiles are used + AddSample(key []string, val float32) + AddSampleWithLabels(key []string, val float32, labels []Label) +} + +// BlackholeSink is used to just blackhole messages +type BlackholeSink struct{} + +func (*BlackholeSink) SetGauge(key []string, val float32) {} +func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {} +func (*BlackholeSink) EmitKey(key []string, val float32) {} +func (*BlackholeSink) IncrCounter(key []string, val float32) {} +func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {} +func (*BlackholeSink) AddSample(key []string, val float32) {} +func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {} + +// FanoutSink is used to sink to fanout values to multiple sinks +type FanoutSink []MetricSink + +func (fh FanoutSink) SetGauge(key []string, val float32) { + fh.SetGaugeWithLabels(key, val, nil) +} + +func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) { + for _, s := range fh { + s.SetGaugeWithLabels(key, val, labels) + } +} + +func (fh FanoutSink) EmitKey(key []string, val float32) { + for _, s := range fh { + s.EmitKey(key, val) + } +} + +func (fh FanoutSink) IncrCounter(key []string, val float32) { + fh.IncrCounterWithLabels(key, val, nil) +} + +func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) { + for _, s := range fh { + s.IncrCounterWithLabels(key, val, labels) + } +} + +func (fh FanoutSink) AddSample(key []string, val float32) { + fh.AddSampleWithLabels(key, val, nil) +} + +func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) { + for _, s := range fh { + s.AddSampleWithLabels(key, val, labels) + } +} + +// sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided +// by each sink type +type sinkURLFactoryFunc func(*url.URL) (MetricSink, error) + +// sinkRegistry supports the generic NewMetricSink function by mapping URL +// schemes to metric sink factory functions +var sinkRegistry = map[string]sinkURLFactoryFunc{ + "statsd": NewStatsdSinkFromURL, + "statsite": NewStatsiteSinkFromURL, + "inmem": NewInmemSinkFromURL, +} + +// NewMetricSinkFromURL allows a generic URL input to configure any of the +// supported sinks. The scheme of the URL identifies the type of the sink, the +// and query parameters are used to set options. +// +// "statsd://" - Initializes a StatsdSink. The host and port are passed through +// as the "addr" of the sink +// +// "statsite://" - Initializes a StatsiteSink. The host and port become the +// "addr" of the sink +// +// "inmem://" - Initializes an InmemSink. The host and port are ignored. The +// "interval" and "duration" query parameters must be specified with valid +// durations, see NewInmemSink for details. +func NewMetricSinkFromURL(urlStr string) (MetricSink, error) { + u, err := url.Parse(urlStr) + if err != nil { + return nil, err + } + + sinkURLFactoryFunc := sinkRegistry[u.Scheme] + if sinkURLFactoryFunc == nil { + return nil, fmt.Errorf( + "cannot create metric sink, unrecognized sink name: %q", u.Scheme) + } + + return sinkURLFactoryFunc(u) +} diff --git a/vendor/github.com/armon/go-metrics/start.go b/vendor/github.com/armon/go-metrics/start.go new file mode 100644 index 0000000..dd41861 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/start.go @@ -0,0 +1,129 @@ +package metrics + +import ( + "os" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/go-immutable-radix" +) + +// Config is used to configure metrics settings +type Config struct { + ServiceName string // Prefixed with keys to separate services + HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname + EnableHostname bool // Enable prefixing gauge values with hostname + EnableHostnameLabel bool // Enable adding hostname to labels + EnableServiceLabel bool // Enable adding service to labels + EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory) + EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer") + TimerGranularity time.Duration // Granularity of timers. + ProfileInterval time.Duration // Interval to profile runtime metrics + + AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator + BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator + FilterDefault bool // Whether to allow metrics by default +} + +// Metrics represents an instance of a metrics sink that can +// be used to emit +type Metrics struct { + Config + lastNumGC uint32 + sink MetricSink + filter *iradix.Tree + filterLock sync.RWMutex +} + +// Shared global metrics instance +var globalMetrics atomic.Value // *Metrics + +func init() { + // Initialize to a blackhole sink to avoid errors + globalMetrics.Store(&Metrics{sink: &BlackholeSink{}}) +} + +// DefaultConfig provides a sane default configuration +func DefaultConfig(serviceName string) *Config { + c := &Config{ + ServiceName: serviceName, // Use client provided service + HostName: "", + EnableHostname: true, // Enable hostname prefix + EnableRuntimeMetrics: true, // Enable runtime profiling + EnableTypePrefix: false, // Disable type prefix + TimerGranularity: time.Millisecond, // Timers are in milliseconds + ProfileInterval: time.Second, // Poll runtime every second + FilterDefault: true, // Don't filter metrics by default + } + + // Try to get the hostname + name, _ := os.Hostname() + c.HostName = name + return c +} + +// New is used to create a new instance of Metrics +func New(conf *Config, sink MetricSink) (*Metrics, error) { + met := &Metrics{} + met.Config = *conf + met.sink = sink + met.UpdateFilter(conf.AllowedPrefixes, conf.BlockedPrefixes) + + // Start the runtime collector + if conf.EnableRuntimeMetrics { + go met.collectStats() + } + return met, nil +} + +// NewGlobal is the same as New, but it assigns the metrics object to be +// used globally as well as returning it. +func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) { + metrics, err := New(conf, sink) + if err == nil { + globalMetrics.Store(metrics) + } + return metrics, err +} + +// Proxy all the methods to the globalMetrics instance +func SetGauge(key []string, val float32) { + globalMetrics.Load().(*Metrics).SetGauge(key, val) +} + +func SetGaugeWithLabels(key []string, val float32, labels []Label) { + globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels) +} + +func EmitKey(key []string, val float32) { + globalMetrics.Load().(*Metrics).EmitKey(key, val) +} + +func IncrCounter(key []string, val float32) { + globalMetrics.Load().(*Metrics).IncrCounter(key, val) +} + +func IncrCounterWithLabels(key []string, val float32, labels []Label) { + globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels) +} + +func AddSample(key []string, val float32) { + globalMetrics.Load().(*Metrics).AddSample(key, val) +} + +func AddSampleWithLabels(key []string, val float32, labels []Label) { + globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels) +} + +func MeasureSince(key []string, start time.Time) { + globalMetrics.Load().(*Metrics).MeasureSince(key, start) +} + +func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) { + globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels) +} + +func UpdateFilter(allow, block []string) { + globalMetrics.Load().(*Metrics).UpdateFilter(allow, block) +} diff --git a/vendor/github.com/armon/go-metrics/statsd.go b/vendor/github.com/armon/go-metrics/statsd.go new file mode 100644 index 0000000..1bfffce --- /dev/null +++ b/vendor/github.com/armon/go-metrics/statsd.go @@ -0,0 +1,184 @@ +package metrics + +import ( + "bytes" + "fmt" + "log" + "net" + "net/url" + "strings" + "time" +) + +const ( + // statsdMaxLen is the maximum size of a packet + // to send to statsd + statsdMaxLen = 1400 +) + +// StatsdSink provides a MetricSink that can be used +// with a statsite or statsd metrics server. It uses +// only UDP packets, while StatsiteSink uses TCP. +type StatsdSink struct { + addr string + metricQueue chan string +} + +// NewStatsdSinkFromURL creates an StatsdSink from a URL. It is used +// (and tested) from NewMetricSinkFromURL. +func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) { + return NewStatsdSink(u.Host) +} + +// NewStatsdSink is used to create a new StatsdSink +func NewStatsdSink(addr string) (*StatsdSink, error) { + s := &StatsdSink{ + addr: addr, + metricQueue: make(chan string, 4096), + } + go s.flushMetrics() + return s, nil +} + +// Close is used to stop flushing to statsd +func (s *StatsdSink) Shutdown() { + close(s.metricQueue) +} + +func (s *StatsdSink) SetGauge(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val)) +} + +func (s *StatsdSink) SetGaugeWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val)) +} + +func (s *StatsdSink) EmitKey(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val)) +} + +func (s *StatsdSink) IncrCounter(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val)) +} + +func (s *StatsdSink) IncrCounterWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val)) +} + +func (s *StatsdSink) AddSample(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val)) +} + +func (s *StatsdSink) AddSampleWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val)) +} + +// Flattens the key for formatting, removes spaces +func (s *StatsdSink) flattenKey(parts []string) string { + joined := strings.Join(parts, ".") + return strings.Map(func(r rune) rune { + switch r { + case ':': + fallthrough + case ' ': + return '_' + default: + return r + } + }, joined) +} + +// Flattens the key along with labels for formatting, removes spaces +func (s *StatsdSink) flattenKeyLabels(parts []string, labels []Label) string { + for _, label := range labels { + parts = append(parts, label.Value) + } + return s.flattenKey(parts) +} + +// Does a non-blocking push to the metrics queue +func (s *StatsdSink) pushMetric(m string) { + select { + case s.metricQueue <- m: + default: + } +} + +// Flushes metrics +func (s *StatsdSink) flushMetrics() { + var sock net.Conn + var err error + var wait <-chan time.Time + ticker := time.NewTicker(flushInterval) + defer ticker.Stop() + +CONNECT: + // Create a buffer + buf := bytes.NewBuffer(nil) + + // Attempt to connect + sock, err = net.Dial("udp", s.addr) + if err != nil { + log.Printf("[ERR] Error connecting to statsd! Err: %s", err) + goto WAIT + } + + for { + select { + case metric, ok := <-s.metricQueue: + // Get a metric from the queue + if !ok { + goto QUIT + } + + // Check if this would overflow the packet size + if len(metric)+buf.Len() > statsdMaxLen { + _, err := sock.Write(buf.Bytes()) + buf.Reset() + if err != nil { + log.Printf("[ERR] Error writing to statsd! Err: %s", err) + goto WAIT + } + } + + // Append to the buffer + buf.WriteString(metric) + + case <-ticker.C: + if buf.Len() == 0 { + continue + } + + _, err := sock.Write(buf.Bytes()) + buf.Reset() + if err != nil { + log.Printf("[ERR] Error flushing to statsd! Err: %s", err) + goto WAIT + } + } + } + +WAIT: + // Wait for a while + wait = time.After(time.Duration(5) * time.Second) + for { + select { + // Dequeue the messages to avoid backlog + case _, ok := <-s.metricQueue: + if !ok { + goto QUIT + } + case <-wait: + goto CONNECT + } + } +QUIT: + s.metricQueue = nil +} diff --git a/vendor/github.com/armon/go-metrics/statsite.go b/vendor/github.com/armon/go-metrics/statsite.go new file mode 100644 index 0000000..6c0d284 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/statsite.go @@ -0,0 +1,172 @@ +package metrics + +import ( + "bufio" + "fmt" + "log" + "net" + "net/url" + "strings" + "time" +) + +const ( + // We force flush the statsite metrics after this period of + // inactivity. Prevents stats from getting stuck in a buffer + // forever. + flushInterval = 100 * time.Millisecond +) + +// NewStatsiteSinkFromURL creates an StatsiteSink from a URL. It is used +// (and tested) from NewMetricSinkFromURL. +func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) { + return NewStatsiteSink(u.Host) +} + +// StatsiteSink provides a MetricSink that can be used with a +// statsite metrics server +type StatsiteSink struct { + addr string + metricQueue chan string +} + +// NewStatsiteSink is used to create a new StatsiteSink +func NewStatsiteSink(addr string) (*StatsiteSink, error) { + s := &StatsiteSink{ + addr: addr, + metricQueue: make(chan string, 4096), + } + go s.flushMetrics() + return s, nil +} + +// Close is used to stop flushing to statsite +func (s *StatsiteSink) Shutdown() { + close(s.metricQueue) +} + +func (s *StatsiteSink) SetGauge(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val)) +} + +func (s *StatsiteSink) SetGaugeWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val)) +} + +func (s *StatsiteSink) EmitKey(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val)) +} + +func (s *StatsiteSink) IncrCounter(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val)) +} + +func (s *StatsiteSink) IncrCounterWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val)) +} + +func (s *StatsiteSink) AddSample(key []string, val float32) { + flatKey := s.flattenKey(key) + s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val)) +} + +func (s *StatsiteSink) AddSampleWithLabels(key []string, val float32, labels []Label) { + flatKey := s.flattenKeyLabels(key, labels) + s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val)) +} + +// Flattens the key for formatting, removes spaces +func (s *StatsiteSink) flattenKey(parts []string) string { + joined := strings.Join(parts, ".") + return strings.Map(func(r rune) rune { + switch r { + case ':': + fallthrough + case ' ': + return '_' + default: + return r + } + }, joined) +} + +// Flattens the key along with labels for formatting, removes spaces +func (s *StatsiteSink) flattenKeyLabels(parts []string, labels []Label) string { + for _, label := range labels { + parts = append(parts, label.Value) + } + return s.flattenKey(parts) +} + +// Does a non-blocking push to the metrics queue +func (s *StatsiteSink) pushMetric(m string) { + select { + case s.metricQueue <- m: + default: + } +} + +// Flushes metrics +func (s *StatsiteSink) flushMetrics() { + var sock net.Conn + var err error + var wait <-chan time.Time + var buffered *bufio.Writer + ticker := time.NewTicker(flushInterval) + defer ticker.Stop() + +CONNECT: + // Attempt to connect + sock, err = net.Dial("tcp", s.addr) + if err != nil { + log.Printf("[ERR] Error connecting to statsite! Err: %s", err) + goto WAIT + } + + // Create a buffered writer + buffered = bufio.NewWriter(sock) + + for { + select { + case metric, ok := <-s.metricQueue: + // Get a metric from the queue + if !ok { + goto QUIT + } + + // Try to send to statsite + _, err := buffered.Write([]byte(metric)) + if err != nil { + log.Printf("[ERR] Error writing to statsite! Err: %s", err) + goto WAIT + } + case <-ticker.C: + if err := buffered.Flush(); err != nil { + log.Printf("[ERR] Error flushing to statsite! Err: %s", err) + goto WAIT + } + } + } + +WAIT: + // Wait for a while + wait = time.After(time.Duration(5) * time.Second) + for { + select { + // Dequeue the messages to avoid backlog + case _, ok := <-s.metricQueue: + if !ok { + goto QUIT + } + case <-wait: + goto CONNECT + } + } +QUIT: + s.metricQueue = nil +} diff --git a/vendor/github.com/armon/go-radix/.gitignore b/vendor/github.com/armon/go-radix/.gitignore new file mode 100644 index 0000000..0026861 --- /dev/null +++ b/vendor/github.com/armon/go-radix/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/armon/go-radix/.travis.yml b/vendor/github.com/armon/go-radix/.travis.yml new file mode 100644 index 0000000..1a0bbea --- /dev/null +++ b/vendor/github.com/armon/go-radix/.travis.yml @@ -0,0 +1,3 @@ +language: go +go: + - tip diff --git a/vendor/github.com/armon/go-radix/LICENSE b/vendor/github.com/armon/go-radix/LICENSE new file mode 100644 index 0000000..a5df10e --- /dev/null +++ b/vendor/github.com/armon/go-radix/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Armon Dadgar + +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/vendor/github.com/armon/go-radix/README.md b/vendor/github.com/armon/go-radix/README.md new file mode 100644 index 0000000..26f42a2 --- /dev/null +++ b/vendor/github.com/armon/go-radix/README.md @@ -0,0 +1,38 @@ +go-radix [![Build Status](https://travis-ci.org/armon/go-radix.png)](https://travis-ci.org/armon/go-radix) +========= + +Provides the `radix` package that implements a [radix tree](http://en.wikipedia.org/wiki/Radix_tree). +The package only provides a single `Tree` implementation, optimized for sparse nodes. + +As a radix tree, it provides the following: + * O(k) operations. In many cases, this can be faster than a hash table since + the hash function is an O(k) operation, and hash tables have very poor cache locality. + * Minimum / Maximum value lookups + * Ordered iteration + +For an immutable variant, see [go-immutable-radix](https://github.com/hashicorp/go-immutable-radix). + +Documentation +============= + +The full documentation is available on [Godoc](http://godoc.org/github.com/armon/go-radix). + +Example +======= + +Below is a simple example of usage + +```go +// Create a tree +r := radix.New() +r.Insert("foo", 1) +r.Insert("bar", 2) +r.Insert("foobar", 2) + +// Find the longest prefix match +m, _, _ := r.LongestPrefix("foozip") +if m != "foo" { + panic("should be foo") +} +``` + diff --git a/vendor/github.com/armon/go-radix/radix.go b/vendor/github.com/armon/go-radix/radix.go new file mode 100644 index 0000000..f9655a1 --- /dev/null +++ b/vendor/github.com/armon/go-radix/radix.go @@ -0,0 +1,543 @@ +package radix + +import ( + "sort" + "strings" +) + +// WalkFn is used when walking the tree. Takes a +// key and value, returning if iteration should +// be terminated. +type WalkFn func(s string, v interface{}) bool + +// leafNode is used to represent a value +type leafNode struct { + key string + val interface{} +} + +// edge is used to represent an edge node +type edge struct { + label byte + node *node +} + +type node struct { + // leaf is used to store possible leaf + leaf *leafNode + + // prefix is the common prefix we ignore + prefix string + + // Edges should be stored in-order for iteration. + // We avoid a fully materialized slice to save memory, + // since in most cases we expect to be sparse + edges edges +} + +func (n *node) isLeaf() bool { + return n.leaf != nil +} + +func (n *node) addEdge(e edge) { + n.edges = append(n.edges, e) + n.edges.Sort() +} + +func (n *node) replaceEdge(e edge) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= e.label + }) + if idx < num && n.edges[idx].label == e.label { + n.edges[idx].node = e.node + return + } + panic("replacing missing edge") +} + +func (n *node) getEdge(label byte) *node { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + return n.edges[idx].node + } + return nil +} + +func (n *node) delEdge(label byte) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + copy(n.edges[idx:], n.edges[idx+1:]) + n.edges[len(n.edges)-1] = edge{} + n.edges = n.edges[:len(n.edges)-1] + } +} + +type edges []edge + +func (e edges) Len() int { + return len(e) +} + +func (e edges) Less(i, j int) bool { + return e[i].label < e[j].label +} + +func (e edges) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e edges) Sort() { + sort.Sort(e) +} + +// Tree implements a radix tree. This can be treated as a +// Dictionary abstract data type. The main advantage over +// a standard hash map is prefix-based lookups and +// ordered iteration, +type Tree struct { + root *node + size int +} + +// New returns an empty Tree +func New() *Tree { + return NewFromMap(nil) +} + +// NewFromMap returns a new tree containing the keys +// from an existing map +func NewFromMap(m map[string]interface{}) *Tree { + t := &Tree{root: &node{}} + for k, v := range m { + t.Insert(k, v) + } + return t +} + +// Len is used to return the number of elements in the tree +func (t *Tree) Len() int { + return t.size +} + +// longestPrefix finds the length of the shared prefix +// of two strings +func longestPrefix(k1, k2 string) int { + max := len(k1) + if l := len(k2); l < max { + max = l + } + var i int + for i = 0; i < max; i++ { + if k1[i] != k2[i] { + break + } + } + return i +} + +// Insert is used to add a newentry or update +// an existing entry. Returns if updated. +func (t *Tree) Insert(s string, v interface{}) (interface{}, bool) { + var parent *node + n := t.root + search := s + for { + // Handle key exhaution + if len(search) == 0 { + if n.isLeaf() { + old := n.leaf.val + n.leaf.val = v + return old, true + } + + n.leaf = &leafNode{ + key: s, + val: v, + } + t.size++ + return nil, false + } + + // Look for the edge + parent = n + n = n.getEdge(search[0]) + + // No edge, create one + if n == nil { + e := edge{ + label: search[0], + node: &node{ + leaf: &leafNode{ + key: s, + val: v, + }, + prefix: search, + }, + } + parent.addEdge(e) + t.size++ + return nil, false + } + + // Determine longest prefix of the search key on match + commonPrefix := longestPrefix(search, n.prefix) + if commonPrefix == len(n.prefix) { + search = search[commonPrefix:] + continue + } + + // Split the node + t.size++ + child := &node{ + prefix: search[:commonPrefix], + } + parent.replaceEdge(edge{ + label: search[0], + node: child, + }) + + // Restore the existing node + child.addEdge(edge{ + label: n.prefix[commonPrefix], + node: n, + }) + n.prefix = n.prefix[commonPrefix:] + + // Create a new leaf node + leaf := &leafNode{ + key: s, + val: v, + } + + // If the new key is a subset, add to to this node + search = search[commonPrefix:] + if len(search) == 0 { + child.leaf = leaf + return nil, false + } + + // Create a new edge for the node + child.addEdge(edge{ + label: search[0], + node: &node{ + leaf: leaf, + prefix: search, + }, + }) + return nil, false + } +} + +// Delete is used to delete a key, returning the previous +// value and if it was deleted +func (t *Tree) Delete(s string) (interface{}, bool) { + var parent *node + var label byte + n := t.root + search := s + for { + // Check for key exhaution + if len(search) == 0 { + if !n.isLeaf() { + break + } + goto DELETE + } + + // Look for an edge + parent = n + label = search[0] + n = n.getEdge(label) + if n == nil { + break + } + + // Consume the search prefix + if strings.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + return nil, false + +DELETE: + // Delete the leaf + leaf := n.leaf + n.leaf = nil + t.size-- + + // Check if we should delete this node from the parent + if parent != nil && len(n.edges) == 0 { + parent.delEdge(label) + } + + // Check if we should merge this node + if n != t.root && len(n.edges) == 1 { + n.mergeChild() + } + + // Check if we should merge the parent's other child + if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() { + parent.mergeChild() + } + + return leaf.val, true +} + +// DeletePrefix is used to delete the subtree under a prefix +// Returns how many nodes were deleted +// Use this to delete large subtrees efficiently +func (t *Tree) DeletePrefix(s string) int { + return t.deletePrefix(nil, t.root, s) +} + +// delete does a recursive deletion +func (t *Tree) deletePrefix(parent, n *node, prefix string) int { + // Check for key exhaustion + if len(prefix) == 0 { + // Remove the leaf node + subTreeSize := 0 + //recursively walk from all edges of the node to be deleted + recursiveWalk(n, func(s string, v interface{}) bool { + subTreeSize++ + return false + }) + if n.isLeaf() { + n.leaf = nil + } + n.edges = nil // deletes the entire subtree + + // Check if we should merge the parent's other child + if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() { + parent.mergeChild() + } + t.size -= subTreeSize + return subTreeSize + } + + // Look for an edge + label := prefix[0] + child := n.getEdge(label) + if child == nil || (!strings.HasPrefix(child.prefix, prefix) && !strings.HasPrefix(prefix, child.prefix)) { + return 0 + } + + // Consume the search prefix + if len(child.prefix) > len(prefix) { + prefix = prefix[len(prefix):] + } else { + prefix = prefix[len(child.prefix):] + } + return t.deletePrefix(n, child, prefix) +} + +func (n *node) mergeChild() { + e := n.edges[0] + child := e.node + n.prefix = n.prefix + child.prefix + n.leaf = child.leaf + n.edges = child.edges +} + +// Get is used to lookup a specific key, returning +// the value and if it was found +func (t *Tree) Get(s string) (interface{}, bool) { + n := t.root + search := s + for { + // Check for key exhaution + if len(search) == 0 { + if n.isLeaf() { + return n.leaf.val, true + } + break + } + + // Look for an edge + n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if strings.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + return nil, false +} + +// LongestPrefix is like Get, but instead of an +// exact match, it will return the longest prefix match. +func (t *Tree) LongestPrefix(s string) (string, interface{}, bool) { + var last *leafNode + n := t.root + search := s + for { + // Look for a leaf node + if n.isLeaf() { + last = n.leaf + } + + // Check for key exhaution + if len(search) == 0 { + break + } + + // Look for an edge + n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if strings.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + if last != nil { + return last.key, last.val, true + } + return "", nil, false +} + +// Minimum is used to return the minimum value in the tree +func (t *Tree) Minimum() (string, interface{}, bool) { + n := t.root + for { + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } + if len(n.edges) > 0 { + n = n.edges[0].node + } else { + break + } + } + return "", nil, false +} + +// Maximum is used to return the maximum value in the tree +func (t *Tree) Maximum() (string, interface{}, bool) { + n := t.root + for { + if num := len(n.edges); num > 0 { + n = n.edges[num-1].node + continue + } + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } + break + } + return "", nil, false +} + +// Walk is used to walk the tree +func (t *Tree) Walk(fn WalkFn) { + recursiveWalk(t.root, fn) +} + +// WalkPrefix is used to walk the tree under a prefix +func (t *Tree) WalkPrefix(prefix string, fn WalkFn) { + n := t.root + search := prefix + for { + // Check for key exhaution + if len(search) == 0 { + recursiveWalk(n, fn) + return + } + + // Look for an edge + n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if strings.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + + } else if strings.HasPrefix(n.prefix, search) { + // Child may be under our search prefix + recursiveWalk(n, fn) + return + } else { + break + } + } + +} + +// WalkPath is used to walk the tree, but only visiting nodes +// from the root down to a given leaf. Where WalkPrefix walks +// all the entries *under* the given prefix, this walks the +// entries *above* the given prefix. +func (t *Tree) WalkPath(path string, fn WalkFn) { + n := t.root + search := path + for { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return + } + + // Check for key exhaution + if len(search) == 0 { + return + } + + // Look for an edge + n = n.getEdge(search[0]) + if n == nil { + return + } + + // Consume the search prefix + if strings.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } +} + +// recursiveWalk is used to do a pre-order walk of a node +// recursively. Returns true if the walk should be aborted +func recursiveWalk(n *node, fn WalkFn) bool { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return true + } + + // Recurse on the children + for _, e := range n.edges { + if recursiveWalk(e.node, fn) { + return true + } + } + return false +} + +// ToMap is used to walk the tree and convert it into a map +func (t *Tree) ToMap() map[string]interface{} { + out := make(map[string]interface{}, t.size) + t.Walk(func(k string, v interface{}) bool { + out[k] = v + return false + }) + return out +} diff --git a/vendor/github.com/bgentry/speakeasy/.gitignore b/vendor/github.com/bgentry/speakeasy/.gitignore new file mode 100644 index 0000000..9e13114 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/.gitignore @@ -0,0 +1,2 @@ +example/example +example/example.exe diff --git a/vendor/github.com/bgentry/speakeasy/LICENSE b/vendor/github.com/bgentry/speakeasy/LICENSE new file mode 100644 index 0000000..37d60fc --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/LICENSE @@ -0,0 +1,24 @@ +MIT License + +Copyright (c) 2017 Blake Gentry + +This license applies to the non-Windows portions of this library. The Windows +portion maintains its own Apache 2.0 license. + +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/vendor/github.com/bgentry/speakeasy/LICENSE_WINDOWS b/vendor/github.com/bgentry/speakeasy/LICENSE_WINDOWS new file mode 100644 index 0000000..ff177f6 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/LICENSE_WINDOWS @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [2013] [the CloudFoundry Authors] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/bgentry/speakeasy/Readme.md b/vendor/github.com/bgentry/speakeasy/Readme.md new file mode 100644 index 0000000..fceda75 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/Readme.md @@ -0,0 +1,30 @@ +# Speakeasy + +This package provides cross-platform Go (#golang) helpers for taking user input +from the terminal while not echoing the input back (similar to `getpasswd`). The +package uses syscalls to avoid any dependence on cgo, and is therefore +compatible with cross-compiling. + +[![GoDoc](https://godoc.org/github.com/bgentry/speakeasy?status.png)][godoc] + +## Unicode + +Multi-byte unicode characters work successfully on Mac OS X. On Windows, +however, this may be problematic (as is UTF in general on Windows). Other +platforms have not been tested. + +## License + +The code herein was not written by me, but was compiled from two separate open +source packages. Unix portions were imported from [gopass][gopass], while +Windows portions were imported from the [CloudFoundry Go CLI][cf-cli]'s +[Windows terminal helpers][cf-ui-windows]. + +The [license for the windows portion](./LICENSE_WINDOWS) has been copied exactly +from the source (though I attempted to fill in the correct owner in the +boilerplate copyright notice). + +[cf-cli]: https://github.com/cloudfoundry/cli "CloudFoundry Go CLI" +[cf-ui-windows]: https://github.com/cloudfoundry/cli/blob/master/src/cf/terminal/ui_windows.go "CloudFoundry Go CLI Windows input helpers" +[godoc]: https://godoc.org/github.com/bgentry/speakeasy "speakeasy on Godoc.org" +[gopass]: https://code.google.com/p/gopass "gopass" diff --git a/vendor/github.com/bgentry/speakeasy/speakeasy.go b/vendor/github.com/bgentry/speakeasy/speakeasy.go new file mode 100644 index 0000000..71c1dd1 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/speakeasy.go @@ -0,0 +1,49 @@ +package speakeasy + +import ( + "fmt" + "io" + "os" + "strings" +) + +// Ask the user to enter a password with input hidden. prompt is a string to +// display before the user's input. Returns the provided password, or an error +// if the command failed. +func Ask(prompt string) (password string, err error) { + return FAsk(os.Stdout, prompt) +} + +// FAsk is the same as Ask, except it is possible to specify the file to write +// the prompt to. If 'nil' is passed as the writer, no prompt will be written. +func FAsk(wr io.Writer, prompt string) (password string, err error) { + if wr != nil && prompt != "" { + fmt.Fprint(wr, prompt) // Display the prompt. + } + password, err = getPassword() + + // Carriage return after the user input. + if wr != nil { + fmt.Fprintln(wr, "") + } + return +} + +func readline() (value string, err error) { + var valb []byte + var n int + b := make([]byte, 1) + for { + // read one byte at a time so we don't accidentally read extra bytes + n, err = os.Stdin.Read(b) + if err != nil && err != io.EOF { + return "", err + } + if n == 0 || b[0] == '\n' { + break + } + valb = append(valb, b[0]) + } + + return strings.TrimSuffix(string(valb), "\r"), nil +} diff --git a/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go new file mode 100644 index 0000000..d99fda1 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go @@ -0,0 +1,93 @@ +// based on https://code.google.com/p/gopass +// Author: johnsiilver@gmail.com (John Doak) +// +// Original code is based on code by RogerV in the golang-nuts thread: +// https://groups.google.com/group/golang-nuts/browse_thread/thread/40cc41e9d9fc9247 + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package speakeasy + +import ( + "fmt" + "os" + "os/signal" + "strings" + "syscall" +) + +const sttyArg0 = "/bin/stty" + +var ( + sttyArgvEOff = []string{"stty", "-echo"} + sttyArgvEOn = []string{"stty", "echo"} +) + +// getPassword gets input hidden from the terminal from a user. This is +// accomplished by turning off terminal echo, reading input from the user and +// finally turning on terminal echo. +func getPassword() (password string, err error) { + sig := make(chan os.Signal, 10) + brk := make(chan bool) + + // File descriptors for stdin, stdout, and stderr. + fd := []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()} + + // Setup notifications of termination signals to channel sig, create a process to + // watch for these signals so we can turn back on echo if need be. + signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, + syscall.SIGTERM) + go catchSignal(fd, sig, brk) + + // Turn off the terminal echo. + pid, err := echoOff(fd) + if err != nil { + return "", err + } + + // Turn on the terminal echo and stop listening for signals. + defer signal.Stop(sig) + defer close(brk) + defer echoOn(fd) + + syscall.Wait4(pid, nil, 0, nil) + + line, err := readline() + if err == nil { + password = strings.TrimSpace(line) + } else { + err = fmt.Errorf("failed during password entry: %s", err) + } + + return password, err +} + +// echoOff turns off the terminal echo. +func echoOff(fd []uintptr) (int, error) { + pid, err := syscall.ForkExec(sttyArg0, sttyArgvEOff, &syscall.ProcAttr{Dir: "", Files: fd}) + if err != nil { + return 0, fmt.Errorf("failed turning off console echo for password entry:\n\t%s", err) + } + return pid, nil +} + +// echoOn turns back on the terminal echo. +func echoOn(fd []uintptr) { + // Turn on the terminal echo. + pid, e := syscall.ForkExec(sttyArg0, sttyArgvEOn, &syscall.ProcAttr{Dir: "", Files: fd}) + if e == nil { + syscall.Wait4(pid, nil, 0, nil) + } +} + +// catchSignal tries to catch SIGKILL, SIGQUIT and SIGINT so that we can turn +// terminal echo back on before the program ends. Otherwise the user is left +// with echo off on their terminal. +func catchSignal(fd []uintptr, sig chan os.Signal, brk chan bool) { + select { + case <-sig: + echoOn(fd) + os.Exit(-1) + case <-brk: + } +} diff --git a/vendor/github.com/bgentry/speakeasy/speakeasy_windows.go b/vendor/github.com/bgentry/speakeasy/speakeasy_windows.go new file mode 100644 index 0000000..c2093a8 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/speakeasy_windows.go @@ -0,0 +1,41 @@ +// +build windows + +package speakeasy + +import ( + "syscall" +) + +// SetConsoleMode function can be used to change value of ENABLE_ECHO_INPUT: +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx +const ENABLE_ECHO_INPUT = 0x0004 + +func getPassword() (password string, err error) { + var oldMode uint32 + + err = syscall.GetConsoleMode(syscall.Stdin, &oldMode) + if err != nil { + return + } + + var newMode uint32 = (oldMode &^ ENABLE_ECHO_INPUT) + + err = setConsoleMode(syscall.Stdin, newMode) + defer setConsoleMode(syscall.Stdin, oldMode) + if err != nil { + return + } + + return readline() +} + +func setConsoleMode(console syscall.Handle, mode uint32) (err error) { + dll := syscall.MustLoadDLL("kernel32") + proc := dll.MustFindProc("SetConsoleMode") + r, _, err := proc.Call(uintptr(console), uintptr(mode)) + + if r == 0 { + return err + } + return nil +} diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE new file mode 100644 index 0000000..c836416 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go new file mode 100644 index 0000000..8a4a658 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go @@ -0,0 +1,152 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build !js,!appengine,!safe,!disableunsafe + +package spew + +import ( + "reflect" + "unsafe" +) + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = false + + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +var ( + // offsetPtr, offsetScalar, and offsetFlag are the offsets for the + // internal reflect.Value fields. These values are valid before golang + // commit ecccf07e7f9d which changed the format. The are also valid + // after commit 82f48826c6c7 which changed the format again to mirror + // the original format. Code in the init function updates these offsets + // as necessary. + offsetPtr = uintptr(ptrSize) + offsetScalar = uintptr(0) + offsetFlag = uintptr(ptrSize * 2) + + // flagKindWidth and flagKindShift indicate various bits that the + // reflect package uses internally to track kind information. + // + // flagRO indicates whether or not the value field of a reflect.Value is + // read-only. + // + // flagIndir indicates whether the value field of a reflect.Value is + // the actual data or a pointer to the data. + // + // These values are valid before golang commit 90a7c3c86944 which + // changed their positions. Code in the init function updates these + // flags as necessary. + flagKindWidth = uintptr(5) + flagKindShift = uintptr(flagKindWidth - 1) + flagRO = uintptr(1 << 0) + flagIndir = uintptr(1 << 1) +) + +func init() { + // Older versions of reflect.Value stored small integers directly in the + // ptr field (which is named val in the older versions). Versions + // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named + // scalar for this purpose which unfortunately came before the flag + // field, so the offset of the flag field is different for those + // versions. + // + // This code constructs a new reflect.Value from a known small integer + // and checks if the size of the reflect.Value struct indicates it has + // the scalar field. When it does, the offsets are updated accordingly. + vv := reflect.ValueOf(0xf00) + if unsafe.Sizeof(vv) == (ptrSize * 4) { + offsetScalar = ptrSize * 2 + offsetFlag = ptrSize * 3 + } + + // Commit 90a7c3c86944 changed the flag positions such that the low + // order bits are the kind. This code extracts the kind from the flags + // field and ensures it's the correct type. When it's not, the flag + // order has been changed to the newer format, so the flags are updated + // accordingly. + upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) + upfv := *(*uintptr)(upf) + flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { + flagKindShift = 0 + flagRO = 1 << 5 + flagIndir = 1 << 6 + + // Commit adf9b30e5594 modified the flags to separate the + // flagRO flag into two bits which specifies whether or not the + // field is embedded. This causes flagIndir to move over a bit + // and means that flagRO is the combination of either of the + // original flagRO bit and the new bit. + // + // This code detects the change by extracting what used to be + // the indirect bit to ensure it's set. When it's not, the flag + // order has been changed to the newer format, so the flags are + // updated accordingly. + if upfv&flagIndir == 0 { + flagRO = 3 << 5 + flagIndir = 1 << 7 + } + } +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { + indirects := 1 + vt := v.Type() + upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) + rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) + if rvf&flagIndir != 0 { + vt = reflect.PtrTo(v.Type()) + indirects++ + } else if offsetScalar != 0 { + // The value is in the scalar field when it's not one of the + // reference types. + switch vt.Kind() { + case reflect.Uintptr: + case reflect.Chan: + case reflect.Func: + case reflect.Map: + case reflect.Ptr: + case reflect.UnsafePointer: + default: + upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + + offsetScalar) + } + } + + pv := reflect.NewAt(vt, upv) + rv = pv + for i := 0; i < indirects; i++ { + rv = rv.Elem() + } + return rv +} diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go new file mode 100644 index 0000000..1fe3cf3 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go @@ -0,0 +1,38 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is running on Google App Engine, compiled by GopherJS, or +// "-tags safe" is added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build js appengine safe disableunsafe + +package spew + +import "reflect" + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = true +) + +// unsafeReflectValue typically converts the passed reflect.Value into a one +// that bypasses the typical safety restrictions preventing access to +// unaddressable and unexported data. However, doing this relies on access to +// the unsafe package. This is a stub version which simply returns the passed +// reflect.Value when the unsafe package is not available. +func unsafeReflectValue(v reflect.Value) reflect.Value { + return v +} diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go new file mode 100644 index 0000000..7c519ff --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/common.go @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "reflect" + "sort" + "strconv" +) + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe, when it's available, + // to bypass these restrictions since this package does not mutate the + // values. + if !v.CanInterface() { + if UnsafeDisabled { + return false + } + + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { + v = unsafeReflectValue(v) + } + if v.CanAddr() { + v = v.Addr() + } + + // Is it an error or Stringer? + switch iface := v.Interface().(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } +} + +// valueSortLess returns whether the first value should sort before the second +// value. It is used by valueSorter.Less as part of the sort.Interface +// implementation. +func valueSortLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Bool: + return !a.Bool() && b.Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return a.Int() < b.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return a.Uint() < b.Uint() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.String: + return a.String() < b.String() + case reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Array: + // Compare the contents of both arrays. + l := a.Len() + for i := 0; i < l; i++ { + av := a.Index(i) + bv := b.Index(i) + if av.Interface() == bv.Interface() { + continue + } + return valueSortLess(av, bv) + } + } + return a.String() < b.String() +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] +} + +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { + if len(values) == 0 { + return + } + sort.Sort(newValuesSorter(values, cs)) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go new file mode 100644 index 0000000..2e3d22f --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. As a result, this option relies on + // access to the unsafe package, so it will not have any effect when + // running in environments without access to the unsafe package such as + // Google App Engine or with the "safe" build tag specified. + DisablePointerMethods bool + + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) and types + // that support the error or Stringer interfaces (if methods are + // enabled) are supported, with other types sorted according to the + // reflect.Value.String() output which guarantees display stability. + SortKeys bool + + // SpewKeys specifies that, as a last resort attempt, map keys should + // be spewed to strings and sorted by those strings. This is only + // considered if SortKeys is true. + SpewKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go new file mode 100644 index 0000000..aacaac6 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/doc.go @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + * Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + * A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + * Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + * MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + * DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + * DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + * DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + * DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + + * ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + * SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. + + * SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +Sample Formatter Output + +Double pointer to a uint8: + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go new file mode 100644 index 0000000..df1d582 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound == true: + d.w.Write(nilAngleBytes) + + case cycleFound == true: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type + // to a byte slice. However, the reflect package won't + // give us an interface on certain things like + // unexported struct fields in order to enforce + // visibility rules. We use unsafe, when available, to + // bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + if !UnsafeDisabled { + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be + // type asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if !d.cs.DisableCapacities && valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys, d.cs) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go new file mode 100644 index 0000000..c49875b --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/format.go @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound == true: + f.fs.Write(nilAngleBytes) + + case cycleFound == true: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys, f.cs) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go new file mode 100644 index 0000000..32c0e33 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/spew.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt b/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt new file mode 100644 index 0000000..7448756 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. 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/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md new file mode 100644 index 0000000..4562f99 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/README.md @@ -0,0 +1,205 @@ +# A pure Go MSSQL driver for Go's database/sql package + +[![GoDoc](https://godoc.org/github.com/denisenkom/go-mssqldb?status.svg)](http://godoc.org/github.com/denisenkom/go-mssqldb) +[![Build status](https://ci.appveyor.com/api/projects/status/jrln8cs62wj9i0a2?svg=true)](https://ci.appveyor.com/project/denisenkom/go-mssqldb) +[![codecov](https://codecov.io/gh/denisenkom/go-mssqldb/branch/master/graph/badge.svg)](https://codecov.io/gh/denisenkom/go-mssqldb) + +## Install + +Requires Go 1.8 or above. + +Install with `go get github.com/denisenkom/go-mssqldb` . + +## Connection Parameters and DSN + +The recommended connection string uses a URL format: +`sqlserver://username:password@host/instance?param1=value¶m2=value` +Other supported formats are listed below. + +### Common parameters: + +* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. +* `password` +* `database` +* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts. +* `dial timeout` - in seconds (default is 15), set to 0 for no timeout +* `encrypt` + * `disable` - Data send between client and server is not encrypted. + * `false` - Data sent between client and server is not encrypted beyond the login packet. (Default) + * `true` - Data sent between client and server is encrypted. +* `app name` - The application name (default is go-mssqldb) + +### Connection parameters for ODBC and ADO style connection strings: + +* `server` - host or host\instance (default localhost) +* `port` - used only when there is no instance in server (default 1433) + +### Less common parameters: + +* `keepAlive` - in seconds; 0 to disable (default is 30) +* `failoverpartner` - host or host\instance (default is no partner). +* `failoverport` - used only when there is no instance in failoverpartner (default 1433) +* `packet size` - in bytes; 512 to 32767 (default is 4096) + * Encrypted connections have a maximum packet size of 16383 bytes + * Further information on usage: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option +* `log` - logging flags (default 0/no logging, 63 for full logging) + * 1 log errors + * 2 log messages + * 4 log rows affected + * 8 trace sql statements + * 16 log statement parameters + * 32 log transaction begin/end +* `TrustServerCertificate` + * false - Server certificate is checked. Default is false if encypt is specified. + * true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing. +* `certificate` - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. +* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host. +* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. +* `Workstation ID` - The workstation name (default is the host name) +* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. + +### The connection string can be specified in one of three formats: + + +1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as + the first segment in the path. All other options are query parameters. Examples: + + * `sqlserver://username:password@host/instance?param1=value¶m2=value` + * `sqlserver://username:password@host:port?param1=value¶m2=value` + * `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance. + * `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass. + * `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30` // port 1234 on localhost. + * `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass" + + A string of this format can be constructed using the `URL` type in the `net/url` package. + +```go + query := url.Values{} + query.Add("app name", "MyAppName") + + u := &url.URL{ + Scheme: "sqlserver", + User: url.UserPassword(username, password), + Host: fmt.Sprintf("%s:%d", hostname, port), + // Path: instance, // if connecting to an instance instead of a port + RawQuery: query.Encode(), + } + db, err := sql.Open("sqlserver", u.String()) +``` + +2. ADO: `key=value` pairs separated by `;`. Values may not contain `;`, leading and trailing whitespace is ignored. + Examples: + + * `server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `server=localhost;user id=sa;database=master;app name=MyAppName` + +3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping + values in `{}`. Examples: + + * `odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar " + * `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar" + +## Executing Stored Procedures + +To run a stored procedure, set the query text to the procedure name: +```go +var account = "abc" +_, err := db.ExecContext(ctx, "sp_RunMe", + sql.Named("ID", 123), + sql.Named("Account", sql.Out{Dest: &account}), +) +``` + +## Parameters + +The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in +the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position). + +```go +db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob") +``` + +### Parameter Types + +To pass specific types to the query parameters, say `varchar` or `date` types, +you must convert the types to the type before passing in. The following types +are supported: + + * string -> nvarchar + * mssql.VarChar -> varchar + * time.Time -> datetimeoffset or datetime (TDS version dependent) + * mssql.DateTime1 -> datetime + * mssql.DateTimeOffset -> datetimeoffset + * "cloud.google.com/go/civil".Date -> date + * "cloud.google.com/go/civil".DateTime -> datetime2 + * "cloud.google.com/go/civil".Time -> time + +## Important Notes + + * [LastInsertId](https://golang.org/pkg/database/sql/#Result.LastInsertId) should + not be used with this driver (or SQL Server) due to how the TDS protocol + works. Please use the [OUTPUT Clause](https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql) + or add a `select ID = convert(bigint, SCOPE_IDENTITY());` to the end of your + query (ref [SCOPE_IDENTITY](https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql)). + This will ensure you are getting the correct ID and will prevent a network round trip. + * [NewConnector](https://godoc.org/github.com/denisenkom/go-mssqldb#NewConnector) + may be used with [OpenDB](https://golang.org/pkg/database/sql/#OpenDB). + * [Connector.SessionInitSQL](https://godoc.org/github.com/denisenkom/go-mssqldb#Connector.SessionInitSQL) + may be set to set any driver specific session settings after the session + has been reset. If empty the session will still be reset but use the database + defaults in Go1.10+. + +## Features + +* Can be used with SQL Server 2005 or newer +* Can be used with Microsoft Azure SQL Database +* Can be used on all go supported platforms (e.g. Linux, Mac OS X and Windows) +* Supports new date/time types: date, time, datetime2, datetimeoffset +* Supports string parameters longer than 8000 characters +* Supports encryption using SSL/TLS +* Supports SQL Server and Windows Authentication +* Supports Single-Sign-On on Windows +* Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas. +* Supports query notifications + +## Tests + +`go test` is used for testing. A running instance of MSSQL server is required. +Environment variables are used to pass login information. + +Example: + + env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test + +## Deprecated + +These features still exist in the driver, but they are are deprecated. + +### Query Parameter Token Replace (driver "mssql") + +If you use the driver name "mssql" (rather then "sqlserver") the SQL text +will be loosly parsed and an attempt to extract identifiers using one of + +* ? +* ?nnn +* :nnn +* $nnn + +will be used. This is not recommended with SQL Server. +There is at least one existing `won't fix` issue with the query parsing. + +Use the native "@Name" parameters instead with the "sqlserver" driver name. + +## Known Issues + +* SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled. +To fix SQL Server 2008 R2 issue, install SQL Server 2008 R2 Service Pack 2. +To fix SQL Server 2008 issue, install Microsoft SQL Server 2008 Service Pack 3 and Cumulative update package 3 for SQL Server 2008 SP3. +More information: http://support.microsoft.com/kb/2653857 diff --git a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml new file mode 100644 index 0000000..c91551c --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -0,0 +1,46 @@ +version: 1.0.{build} + +os: Windows Server 2012 R2 + +clone_folder: c:\gopath\src\github.com\denisenkom\go-mssqldb + +environment: + GOPATH: c:\gopath + HOST: localhost + SQLUSER: sa + SQLPASSWORD: Password12! + DATABASE: test + GOVERSION: 110 + matrix: + - GOVERSION: 18 + SQLINSTANCE: SQL2016 + - GOVERSION: 110 + SQLINSTANCE: SQL2016 + - SQLINSTANCE: SQL2014 + - SQLINSTANCE: SQL2012SP1 + - SQLINSTANCE: SQL2008R2SP2 + +install: + - set GOROOT=c:\go%GOVERSION% + - set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH% + - go version + - go env + - go get -u cloud.google.com/go/civil + +build_script: + - go build + +before_test: + # setup SQL Server + - ps: | + $instanceName = $env:SQLINSTANCE + Start-Service "MSSQL`$$instanceName" + Start-Service "SQLBrowser" + - sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;" + - sqlcmd -S "(local)\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version" + - pip install codecov + + +test_script: + - go test -race -cpu 4 -coverprofile=coverage.txt -covermode=atomic + - codecov -f coverage.txt diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf.go b/vendor/github.com/denisenkom/go-mssqldb/buf.go new file mode 100644 index 0000000..bf8a7c7 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -0,0 +1,259 @@ +package mssql + +import ( + "encoding/binary" + "errors" + "io" +) + +type packetType uint8 + +type header struct { + PacketType packetType + Status uint8 + Size uint16 + Spid uint16 + PacketNo uint8 + Pad uint8 +} + +// tdsBuffer reads and writes TDS packets of data to the transport. +// The write and read buffers are separate to make sending attn signals +// possible without locks. Currently attn signals are only sent during +// reads, not writes. +type tdsBuffer struct { + transport io.ReadWriteCloser + + packetSize int + + // Write fields. + wbuf []byte + wpos int + wPacketSeq byte + wPacketType packetType + + // Read fields. + rbuf []byte + rpos int + rsize int + final bool + rPacketType packetType + + // afterFirst is assigned to right after tdsBuffer is created and + // before the first use. It is executed after the first packet is + // written and then removed. + afterFirst func() +} + +func newTdsBuffer(bufsize uint16, transport io.ReadWriteCloser) *tdsBuffer { + return &tdsBuffer{ + packetSize: int(bufsize), + wbuf: make([]byte, 1<<16), + rbuf: make([]byte, 1<<16), + rpos: 8, + transport: transport, + } +} + +func (rw *tdsBuffer) ResizeBuffer(packetSize int) { + rw.packetSize = packetSize +} + +func (w *tdsBuffer) PackageSize() int { + return w.packetSize +} + +func (w *tdsBuffer) flush() (err error) { + // Write packet size. + w.wbuf[0] = byte(w.wPacketType) + binary.BigEndian.PutUint16(w.wbuf[2:], uint16(w.wpos)) + w.wbuf[6] = w.wPacketSeq + + // Write packet into underlying transport. + if _, err = w.transport.Write(w.wbuf[:w.wpos]); err != nil { + return err + } + // It is possible to create a whole new buffer after a flush. + // Useful for debugging. Normally reuse the buffer. + // w.wbuf = make([]byte, 1<<16) + + // Execute afterFirst hook if it is set. + if w.afterFirst != nil { + w.afterFirst() + w.afterFirst = nil + } + + w.wpos = 8 + w.wPacketSeq++ + return nil +} + +func (w *tdsBuffer) Write(p []byte) (total int, err error) { + for { + copied := copy(w.wbuf[w.wpos:w.packetSize], p) + w.wpos += copied + total += copied + if copied == len(p) { + return + } + if err = w.flush(); err != nil { + return + } + p = p[copied:] + } + return +} + +func (w *tdsBuffer) WriteByte(b byte) error { + if int(w.wpos) == len(w.wbuf) { + if err := w.flush(); err != nil { + return err + } + } + w.wbuf[w.wpos] = b + w.wpos += 1 + return nil +} + +func (w *tdsBuffer) BeginPacket(packetType packetType, resetSession bool) { + status := byte(0) + if resetSession { + switch packetType { + // Reset session can only be set on the following packet types. + case packSQLBatch, packRPCRequest, packTransMgrReq: + status = 0x8 + } + } + w.wbuf[1] = status // Packet is incomplete. This byte is set again in FinishPacket. + w.wpos = 8 + w.wPacketSeq = 1 + w.wPacketType = packetType +} + +func (w *tdsBuffer) FinishPacket() error { + w.wbuf[1] |= 1 // Mark this as the last packet in the message. + return w.flush() +} + +var headerSize = binary.Size(header{}) + +func (r *tdsBuffer) readNextPacket() error { + h := header{} + var err error + err = binary.Read(r.transport, binary.BigEndian, &h) + if err != nil { + return err + } + if int(h.Size) > len(r.rbuf) { + return errors.New("Invalid packet size, it is longer than buffer size") + } + if headerSize > int(h.Size) { + return errors.New("Invalid packet size, it is shorter than header size") + } + _, err = io.ReadFull(r.transport, r.rbuf[headerSize:h.Size]) + if err != nil { + return err + } + r.rpos = headerSize + r.rsize = int(h.Size) + r.final = h.Status != 0 + r.rPacketType = h.PacketType + return nil +} + +func (r *tdsBuffer) BeginRead() (packetType, error) { + err := r.readNextPacket() + if err != nil { + return 0, err + } + return r.rPacketType, nil +} + +func (r *tdsBuffer) ReadByte() (res byte, err error) { + if r.rpos == r.rsize { + if r.final { + return 0, io.EOF + } + err = r.readNextPacket() + if err != nil { + return 0, err + } + } + res = r.rbuf[r.rpos] + r.rpos++ + return res, nil +} + +func (r *tdsBuffer) byte() byte { + b, err := r.ReadByte() + if err != nil { + badStreamPanic(err) + } + return b +} + +func (r *tdsBuffer) ReadFull(buf []byte) { + _, err := io.ReadFull(r, buf[:]) + if err != nil { + badStreamPanic(err) + } +} + +func (r *tdsBuffer) uint64() uint64 { + var buf [8]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint64(buf[:]) +} + +func (r *tdsBuffer) int32() int32 { + return int32(r.uint32()) +} + +func (r *tdsBuffer) uint32() uint32 { + var buf [4]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint32(buf[:]) +} + +func (r *tdsBuffer) uint16() uint16 { + var buf [2]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint16(buf[:]) +} + +func (r *tdsBuffer) BVarChar() string { + l := int(r.byte()) + return r.readUcs2(l) +} + +func (r *tdsBuffer) UsVarChar() string { + l := int(r.uint16()) + return r.readUcs2(l) +} + +func (r *tdsBuffer) readUcs2(numchars int) string { + b := make([]byte, numchars*2) + r.ReadFull(b) + res, err := ucs22str(b) + if err != nil { + badStreamPanic(err) + } + return res +} + +func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { + copied = 0 + err = nil + if r.rpos == r.rsize { + if r.final { + return 0, io.EOF + } + err = r.readNextPacket() + if err != nil { + return + } + } + copied = copy(buf, r.rbuf[r.rpos:r.rsize]) + r.rpos += copied + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go new file mode 100644 index 0000000..abd2e21 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -0,0 +1,604 @@ +package mssql + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "time" +) + +type Bulk struct { + // ctx is used only for AddRow and Done methods. + // This could be removed if AddRow and Done accepted + // a ctx field as well, which is available with the + // database/sql call. + ctx context.Context + + cn *Conn + metadata []columnStruct + bulkColumns []columnStruct + columnsName []string + tablename string + numRows int + + headerSent bool + Options BulkOptions + Debug bool +} +type BulkOptions struct { + CheckConstraints bool + FireTriggers bool + KeepNulls bool + KilobytesPerBatch int + RowsPerBatch int + Order []string + Tablock bool +} + +type DataValue interface{} + +func (cn *Conn) CreateBulk(table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: context.Background(), cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (cn *Conn) CreateBulkContext(ctx context.Context, table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: ctx, cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (b *Bulk) sendBulkCommand(ctx context.Context) (err error) { + //get table columns info + err = b.getMetadata(ctx) + if err != nil { + return err + } + + //match the columns + for _, colname := range b.columnsName { + var bulkCol *columnStruct + + for _, m := range b.metadata { + if m.ColName == colname { + bulkCol = &m + break + } + } + if bulkCol != nil { + + if bulkCol.ti.TypeId == typeUdt { + //send udt as binary + bulkCol.ti.TypeId = typeBigVarBin + } + b.bulkColumns = append(b.bulkColumns, *bulkCol) + b.dlogf("Adding column %s %s %#x", colname, bulkCol.ColName, bulkCol.ti.TypeId) + } else { + return fmt.Errorf("Column %s does not exist in destination table %s", colname, b.tablename) + } + } + + //create the bulk command + + //columns definitions + var col_defs bytes.Buffer + for i, col := range b.bulkColumns { + if i != 0 { + col_defs.WriteString(", ") + } + col_defs.WriteString("[" + col.ColName + "] " + makeDecl(col.ti)) + } + + //options + var with_opts []string + + if b.Options.CheckConstraints { + with_opts = append(with_opts, "CHECK_CONSTRAINTS") + } + if b.Options.FireTriggers { + with_opts = append(with_opts, "FIRE_TRIGGERS") + } + if b.Options.KeepNulls { + with_opts = append(with_opts, "KEEP_NULLS") + } + if b.Options.KilobytesPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("KILOBYTES_PER_BATCH = %d", b.Options.KilobytesPerBatch)) + } + if b.Options.RowsPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("ROWS_PER_BATCH = %d", b.Options.RowsPerBatch)) + } + if len(b.Options.Order) > 0 { + with_opts = append(with_opts, fmt.Sprintf("ORDER(%s)", strings.Join(b.Options.Order, ","))) + } + if b.Options.Tablock { + with_opts = append(with_opts, "TABLOCK") + } + var with_part string + if len(with_opts) > 0 { + with_part = fmt.Sprintf("WITH (%s)", strings.Join(with_opts, ",")) + } + + query := fmt.Sprintf("INSERT BULK %s (%s) %s", b.tablename, col_defs.String(), with_part) + + stmt, err := b.cn.PrepareContext(ctx, query) + if err != nil { + return fmt.Errorf("Prepare failed: %s", err.Error()) + } + b.dlogf(query) + + _, err = stmt.(*Stmt).ExecContext(ctx, nil) + if err != nil { + return err + } + + b.headerSent = true + + var buf = b.cn.sess.buf + buf.BeginPacket(packBulkLoadBCP, false) + + // Send the columns metadata. + columnMetadata := b.createColMetadata() + _, err = buf.Write(columnMetadata) + + return +} + +// AddRow immediately writes the row to the destination table. +// The arguments are the row values in the order they were specified. +func (b *Bulk) AddRow(row []interface{}) (err error) { + if !b.headerSent { + err = b.sendBulkCommand(b.ctx) + if err != nil { + return + } + } + + if len(row) != len(b.bulkColumns) { + return fmt.Errorf("Row does not have the same number of columns than the destination table %d %d", + len(row), len(b.bulkColumns)) + } + + bytes, err := b.makeRowData(row) + if err != nil { + return + } + + _, err = b.cn.sess.buf.Write(bytes) + if err != nil { + return + } + + b.numRows = b.numRows + 1 + return +} + +func (b *Bulk) makeRowData(row []interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenRow)) + + var logcol bytes.Buffer + for i, col := range b.bulkColumns { + + if b.Debug { + logcol.WriteString(fmt.Sprintf(" col[%d]='%v' ", i, row[i])) + } + param, err := b.makeParam(row[i], col) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + + if col.ti.Writer == nil { + return nil, fmt.Errorf("no writer for column: %s, TypeId: %#x", + col.ColName, col.ti.TypeId) + } + err = col.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + } + + b.dlogf("row[%d] %s\n", b.numRows, logcol.String()) + + return buf.Bytes(), nil +} + +func (b *Bulk) Done() (rowcount int64, err error) { + if b.headerSent == false { + //no rows had been sent + return 0, nil + } + var buf = b.cn.sess.buf + buf.WriteByte(byte(tokenDone)) + + binary.Write(buf, binary.LittleEndian, uint16(doneFinal)) + binary.Write(buf, binary.LittleEndian, uint16(0)) // curcmd + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint64(0)) //rowcount 0 + } else { + binary.Write(buf, binary.LittleEndian, uint32(0)) //rowcount 0 + } + + buf.FinishPacket() + + tokchan := make(chan tokenStruct, 5) + go processResponse(b.ctx, b.cn.sess, tokchan, nil) + + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneStruct: + if token.Status&doneCount != 0 { + rowCount = int64(token.RowCount) + } + if token.isError() { + return 0, token.getError() + } + case error: + return 0, b.cn.checkBadConn(token) + } + } + return rowCount, nil +} + +func (b *Bulk) createColMetadata() []byte { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenColMetadata)) // token + binary.Write(buf, binary.LittleEndian, uint16(len(b.bulkColumns))) // column count + + for i, col := range b.bulkColumns { + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint32(col.UserType)) // usertype, always 0? + } else { + binary.Write(buf, binary.LittleEndian, uint16(col.UserType)) + } + binary.Write(buf, binary.LittleEndian, uint16(col.Flags)) + + writeTypeInfo(buf, &b.bulkColumns[i].ti) + + if col.ti.TypeId == typeNText || + col.ti.TypeId == typeText || + col.ti.TypeId == typeImage { + + tablename_ucs2 := str2ucs2(b.tablename) + binary.Write(buf, binary.LittleEndian, uint16(len(tablename_ucs2)/2)) + buf.Write(tablename_ucs2) + } + colname_ucs2 := str2ucs2(col.ColName) + buf.WriteByte(uint8(len(colname_ucs2) / 2)) + buf.Write(colname_ucs2) + } + + return buf.Bytes() +} + +func (b *Bulk) getMetadata(ctx context.Context) (err error) { + stmt, err := b.cn.prepareContext(ctx, "SET FMTONLY ON") + if err != nil { + return + } + + _, err = stmt.ExecContext(ctx, nil) + if err != nil { + return + } + + // Get columns info. + stmt, err = b.cn.prepareContext(ctx, fmt.Sprintf("select * from %s SET FMTONLY OFF", b.tablename)) + if err != nil { + return + } + rows, err := stmt.QueryContext(ctx, nil) + if err != nil { + return fmt.Errorf("get columns info failed: %v", err) + } + b.metadata = rows.(*Rows).cols + + if b.Debug { + for _, col := range b.metadata { + b.dlogf("col: %s typeId: %#x size: %d scale: %d prec: %d flags: %d lcid: %#x\n", + col.ColName, col.ti.TypeId, col.ti.Size, col.ti.Scale, col.ti.Prec, + col.Flags, col.ti.Collation.LcidAndFlags) + } + } + + return rows.Close() +} + +func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) { + res.ti.Size = col.ti.Size + res.ti.TypeId = col.ti.TypeId + + if val == nil { + res.ti.Size = 0 + return + } + + switch col.ti.TypeId { + + case typeInt1, typeInt2, typeInt4, typeInt8, typeIntN: + var intvalue int64 + + switch val := val.(type) { + case int: + intvalue = int64(val) + case int32: + intvalue = int64(val) + case int64: + intvalue = val + default: + err = fmt.Errorf("mssql: invalid type for int column") + return + } + + res.buffer = make([]byte, res.ti.Size) + if col.ti.Size == 1 { + res.buffer[0] = byte(intvalue) + } else if col.ti.Size == 2 { + binary.LittleEndian.PutUint16(res.buffer, uint16(intvalue)) + } else if col.ti.Size == 4 { + binary.LittleEndian.PutUint32(res.buffer, uint32(intvalue)) + } else if col.ti.Size == 8 { + binary.LittleEndian.PutUint64(res.buffer, uint64(intvalue)) + } + case typeFlt4, typeFlt8, typeFltN: + var floatvalue float64 + + switch val := val.(type) { + case float32: + floatvalue = float64(val) + case float64: + floatvalue = val + case int: + floatvalue = float64(val) + case int64: + floatvalue = float64(val) + default: + err = fmt.Errorf("mssql: invalid type for float column: %s", val) + return + } + + if col.ti.Size == 4 { + res.buffer = make([]byte, 4) + binary.LittleEndian.PutUint32(res.buffer, math.Float32bits(float32(floatvalue))) + } else if col.ti.Size == 8 { + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(floatvalue)) + } + case typeNVarChar, typeNText, typeNChar: + + switch val := val.(type) { + case string: + res.buffer = str2ucs2(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for nvarchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeVarChar, typeBigVarChar, typeText, typeChar, typeBigChar: + switch val := val.(type) { + case string: + res.buffer = []byte(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for varchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeBit, typeBitN: + if reflect.TypeOf(val).Kind() != reflect.Bool { + err = fmt.Errorf("mssql: invalid type for bit column: %s", val) + return + } + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val.(bool) { + res.buffer[0] = 1 + } + + case typeDateTime2N, typeDateTimeOffsetN: + switch val := val.(type) { + case time.Time: + days, ns := dateTime2(val) + ns /= int64(math.Pow10(int(col.ti.Scale)*-1) * 1000000000) + + var data = make([]byte, 5) + + data[0] = byte(ns) + data[1] = byte(ns >> 8) + data[2] = byte(ns >> 16) + data[3] = byte(ns >> 24) + data[4] = byte(ns >> 32) + + if col.ti.Scale <= 2 { + res.ti.Size = 6 + } else if col.ti.Scale <= 4 { + res.ti.Size = 7 + } else { + res.ti.Size = 8 + } + var buf []byte + buf = make([]byte, res.ti.Size) + copy(buf, data[0:res.ti.Size-3]) + + buf[res.ti.Size-3] = byte(days) + buf[res.ti.Size-2] = byte(days >> 8) + buf[res.ti.Size-1] = byte(days >> 16) + + if col.ti.TypeId == typeDateTimeOffsetN { + _, offset := val.Zone() + var offsetMinute = uint16(offset / 60) + buf = append(buf, byte(offsetMinute)) + buf = append(buf, byte(offsetMinute>>8)) + res.ti.Size = res.ti.Size + 2 + } + + res.buffer = buf + + default: + err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + return + } + case typeDateN: + switch val := val.(type) { + case time.Time: + days, _ := dateTime2(val) + + res.ti.Size = 3 + res.buffer = make([]byte, 3) + res.buffer[0] = byte(days) + res.buffer[1] = byte(days >> 8) + res.buffer[2] = byte(days >> 16) + default: + err = fmt.Errorf("mssql: invalid type for date column: %s", val) + return + } + case typeDateTime, typeDateTimeN, typeDateTim4: + switch val := val.(type) { + case time.Time: + if col.ti.Size == 4 { + res.ti.Size = 4 + res.buffer = make([]byte, 4) + + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + if days < 0 { + err = fmt.Errorf("mssql: Date %s is out of range", val) + return + } + mins := val.Hour()*60 + val.Minute() + + binary.LittleEndian.PutUint16(res.buffer[0:2], uint16(days)) + binary.LittleEndian.PutUint16(res.buffer[2:4], uint16(mins)) + } else if col.ti.Size == 8 { + res.ti.Size = 8 + res.buffer = make([]byte, 8) + + days := divFloor(val.Unix(), 24*60*60) + //25567 - number of days since Jan 1 1900 UTC to Jan 1 1970 + days = days + 25567 + tm := (val.Hour()*60*60+val.Minute()*60+val.Second())*300 + int(val.Nanosecond()/10000000*3) + + binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) + } else { + err = fmt.Errorf("mssql: invalid size of column") + } + + default: + err = fmt.Errorf("mssql: invalid type for datetime column: %s", val) + } + + // case typeMoney, typeMoney4, typeMoneyN: + case typeDecimal, typeDecimalN, typeNumeric, typeNumericN: + var value float64 + switch v := val.(type) { + case int: + value = float64(v) + case int8: + value = float64(v) + case int16: + value = float64(v) + case int32: + value = float64(v) + case int64: + value = float64(v) + case float32: + value = float64(v) + case float64: + value = v + case string: + if value, err = strconv.ParseFloat(v, 64); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to float: %v", err) + } + default: + return res, fmt.Errorf("unknown value for decimal: %#v", v) + } + + perc := col.ti.Prec + scale := col.ti.Scale + var dec Decimal + dec, err = Float64ToDecimalScale(value, scale) + if err != nil { + return res, err + } + dec.prec = perc + + var length byte + switch { + case perc <= 9: + length = 4 + case perc <= 19: + length = 8 + case perc <= 28: + length = 12 + default: + length = 16 + } + + buf := make([]byte, length+1) + // first byte length written by typeInfo.writer + res.ti.Size = int(length) + 1 + // second byte sign + if value < 0 { + buf[0] = 0 + } else { + buf[0] = 1 + } + + ub := dec.UnscaledBytes() + l := len(ub) + if l > int(length) { + err = fmt.Errorf("decimal out of range: %s", dec) + return res, err + } + // reverse the bytes + for i, j := 1, l-1; j >= 0; i, j = i+1, j-1 { + buf[i] = ub[j] + } + res.buffer = buf + case typeBigVarBin: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Binary column: %s", val) + return + } + case typeGuid: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Guid column: %s", val) + return + } + + default: + err = fmt.Errorf("mssql: type %x not implemented", col.ti.TypeId) + } + return + +} + +func (b *Bulk) dlogf(format string, v ...interface{}) { + if b.Debug { + b.cn.sess.log.Printf(format, v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go new file mode 100644 index 0000000..4824df9 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go @@ -0,0 +1,93 @@ +package mssql + +import ( + "context" + "database/sql/driver" + "encoding/json" + "errors" +) + +type copyin struct { + cn *Conn + bulkcopy *Bulk + closed bool +} + +type serializableBulkConfig struct { + TableName string + ColumnsName []string + Options BulkOptions +} + +func (d *Driver) OpenConnection(dsn string) (*Conn, error) { + return d.open(context.Background(), dsn) +} + +func (c *Conn) prepareCopyIn(ctx context.Context, query string) (_ driver.Stmt, err error) { + config_json := query[11:] + + bulkconfig := serializableBulkConfig{} + err = json.Unmarshal([]byte(config_json), &bulkconfig) + if err != nil { + return + } + + bulkcopy := c.CreateBulkContext(ctx, bulkconfig.TableName, bulkconfig.ColumnsName) + bulkcopy.Options = bulkconfig.Options + + ci := ©in{ + cn: c, + bulkcopy: bulkcopy, + } + + return ci, nil +} + +func CopyIn(table string, options BulkOptions, columns ...string) string { + bulkconfig := &serializableBulkConfig{TableName: table, Options: options, ColumnsName: columns} + + config_json, err := json.Marshal(bulkconfig) + if err != nil { + panic(err) + } + + stmt := "INSERTBULK " + string(config_json) + + return stmt +} + +func (ci *copyin) NumInput() int { + return -1 +} + +func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { + panic("should never be called") +} + +func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { + if ci.closed { + return nil, errors.New("errCopyInClosed") + } + + if len(v) == 0 { + rowCount, err := ci.bulkcopy.Done() + ci.closed = true + return driver.RowsAffected(rowCount), err + } + + t := make([]interface{}, len(v)) + for i, val := range v { + t[i] = val + } + + err = ci.bulkcopy.AddRow(t) + if err != nil { + return + } + + return driver.RowsAffected(0), nil +} + +func (ci *copyin) Close() (err error) { + return nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/decimal.go new file mode 100644 index 0000000..372f64b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/decimal.go @@ -0,0 +1,131 @@ +package mssql + +import ( + "encoding/binary" + "errors" + "math" + "math/big" +) + +// http://msdn.microsoft.com/en-us/library/ee780893.aspx +type Decimal struct { + integer [4]uint32 + positive bool + prec uint8 + scale uint8 +} + +var scaletblflt64 [39]float64 + +func (d Decimal) ToFloat64() float64 { + val := float64(0) + for i := 3; i >= 0; i-- { + val *= 0x100000000 + val += float64(d.integer[i]) + } + if !d.positive { + val = -val + } + if d.scale != 0 { + val /= scaletblflt64[d.scale] + } + return val +} + +const autoScale = 100 + +func Float64ToDecimal(f float64) (Decimal, error) { + return Float64ToDecimalScale(f, autoScale) +} + +func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { + var dec Decimal + if math.IsNaN(f) { + return dec, errors.New("NaN") + } + if math.IsInf(f, 0) { + return dec, errors.New("Infinity can't be converted to decimal") + } + dec.positive = f >= 0 + if !dec.positive { + f = math.Abs(f) + } + if f > 3.402823669209385e+38 { + return dec, errors.New("Float value is out of range") + } + dec.prec = 20 + var integer float64 + for dec.scale = 0; dec.scale <= scale; dec.scale++ { + integer = f * scaletblflt64[dec.scale] + _, frac := math.Modf(integer) + if frac == 0 && scale == autoScale { + break + } + } + for i := 0; i < 4; i++ { + mod := math.Mod(integer, 0x100000000) + integer -= mod + integer /= 0x100000000 + dec.integer[i] = uint32(mod) + } + return dec, nil +} + +func init() { + var acc float64 = 1 + for i := 0; i <= 38; i++ { + scaletblflt64[i] = acc + acc *= 10 + } +} + +func (d Decimal) BigInt() big.Int { + bytes := make([]byte, 16) + binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) + binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) + binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) + binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) + var x big.Int + x.SetBytes(bytes) + if !d.positive { + x.Neg(&x) + } + return x +} + +func (d Decimal) Bytes() []byte { + x := d.BigInt() + return scaleBytes(x.String(), d.scale) +} + +func (d Decimal) UnscaledBytes() []byte { + x := d.BigInt() + return x.Bytes() +} + +func scaleBytes(s string, scale uint8) []byte { + z := make([]byte, 0, len(s)+1) + if s[0] == '-' || s[0] == '+' { + z = append(z, byte(s[0])) + s = s[1:] + } + pos := len(s) - int(scale) + if pos <= 0 { + z = append(z, byte('0')) + } else if pos > 0 { + z = append(z, []byte(s[:pos])...) + } + if scale > 0 { + z = append(z, byte('.')) + for pos < 0 { + z = append(z, byte('0')) + pos++ + } + z = append(z, []byte(s[pos:])...) + } + return z +} + +func (d Decimal) String() string { + return string(d.Bytes()) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/doc.go b/vendor/github.com/denisenkom/go-mssqldb/doc.go new file mode 100644 index 0000000..2e54929 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/doc.go @@ -0,0 +1,14 @@ +// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver) +// database servers. +// +// This package registers the driver: +// sqlserver: uses native "@" parameter placeholder names and does no pre-processing. +// +// If the ordinal position is used for query parameters, identifiers will be named +// "@p1", "@p2", ... "@pN". +// +// Please refer to the README for the format of the DSN. There are multiple DSN +// formats accepted: ADO style, ODBC style, and URL style. The following is an +// example of a URL style DSN: +// sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30 +package mssql diff --git a/vendor/github.com/denisenkom/go-mssqldb/error.go b/vendor/github.com/denisenkom/go-mssqldb/error.go new file mode 100644 index 0000000..2e5bace --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/error.go @@ -0,0 +1,73 @@ +package mssql + +import ( + "fmt" +) + +// Error represents an SQL Server error. This +// type includes methods for reading the contents +// of the struct, which allows calling programs +// to check for specific error conditions without +// having to import this package directly. +type Error struct { + Number int32 + State uint8 + Class uint8 + Message string + ServerName string + ProcName string + LineNo int32 +} + +func (e Error) Error() string { + return "mssql: " + e.Message +} + +// SQLErrorNumber returns the SQL Server error number. +func (e Error) SQLErrorNumber() int32 { + return e.Number +} + +func (e Error) SQLErrorState() uint8 { + return e.State +} + +func (e Error) SQLErrorClass() uint8 { + return e.Class +} + +func (e Error) SQLErrorMessage() string { + return e.Message +} + +func (e Error) SQLErrorServerName() string { + return e.ServerName +} + +func (e Error) SQLErrorProcName() string { + return e.ProcName +} + +func (e Error) SQLErrorLineNo() int32 { + return e.LineNo +} + +type StreamError struct { + Message string +} + +func (e StreamError) Error() string { + return e.Message +} + +func streamErrorf(format string, v ...interface{}) StreamError { + return StreamError{"Invalid TDS stream: " + fmt.Sprintf(format, v...)} +} + +func badStreamPanic(err error) { + panic(err) +} + +func badStreamPanicf(format string, v ...interface{}) { + panic(streamErrorf(format, v...)) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go new file mode 100644 index 0000000..8dc2279 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go @@ -0,0 +1,113 @@ +package cp + +type charsetMap struct { + sb [256]rune // single byte runes, -1 for a double byte character lead byte + db map[int]rune // double byte runes +} + +func collation2charset(col Collation) *charsetMap { + // http://msdn.microsoft.com/en-us/library/ms144250.aspx + // http://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx + switch col.SortId { + case 30, 31, 32, 33, 34: + return cp437 + case 40, 41, 42, 44, 49, 55, 56, 57, 58, 59, 60, 61: + return cp850 + case 50, 51, 52, 53, 54, 71, 72, 73, 74, 75: + return cp1252 + case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96: + return cp1250 + case 104, 105, 106, 107, 108: + return cp1251 + case 112, 113, 114, 121, 124: + return cp1253 + case 128, 129, 130: + return cp1254 + case 136, 137, 138: + return cp1255 + case 144, 145, 146: + return cp1256 + case 152, 153, 154, 155, 156, 157, 158, 159, 160: + return cp1257 + case 183, 184, 185, 186: + return cp1252 + case 192, 193: + return cp932 + case 194, 195: + return cp949 + case 196, 197: + return cp950 + case 198, 199: + return cp936 + case 200: + return cp932 + case 201: + return cp949 + case 202: + return cp950 + case 203: + return cp936 + case 204, 205, 206: + return cp874 + case 210, 211, 212, 213, 214, 215, 216, 217: + return cp1252 + } + // http://technet.microsoft.com/en-us/library/aa176553(v=sql.80).aspx + switch col.getLcid() { + case 0x001e, 0x041e: + return cp874 + case 0x0411, 0x10411: + return cp932 + case 0x0804, 0x1004, 0x20804: + return cp936 + case 0x0012, 0x0412: + return cp949 + case 0x0404, 0x1404, 0x0c04, 0x7c04, 0x30404: + return cp950 + case 0x041c, 0x041a, 0x0405, 0x040e, 0x104e, 0x0415, 0x0418, 0x041b, 0x0424, 0x1040e: + return cp1250 + case 0x0423, 0x0402, 0x042f, 0x0419, 0x081a, 0x0c1a, 0x0422, 0x043f, 0x0444, 0x082c: + return cp1251 + case 0x0408: + return cp1253 + case 0x041f, 0x042c, 0x0443: + return cp1254 + case 0x040d: + return cp1255 + case 0x0401, 0x0801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x0429, 0x0420: + return cp1256 + case 0x0425, 0x0426, 0x0427, 0x0827: + return cp1257 + case 0x042a: + return cp1258 + case 0x0439, 0x045a, 0x0465: + return nil + } + return cp1252 +} + +func CharsetToUTF8(col Collation, s []byte) string { + cm := collation2charset(col) + if cm == nil { + return string(s) + } + buf := make([]rune, 0, len(s)) + for i := 0; i < len(s); i++ { + ch := cm.sb[s[i]] + if ch == -1 { + if i+1 == len(s) { + ch = 0xfffd + } else { + n := int(s[i+1]) + (int(s[i]) << 8) + i++ + var ok bool + ch, ok = cm.db[n] + if !ok { + ch = 0xfffd + } + } + } + buf = append(buf, ch) + } + return string(buf) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go new file mode 100644 index 0000000..ae7b03b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go @@ -0,0 +1,20 @@ +package cp + +// http://msdn.microsoft.com/en-us/library/dd340437.aspx + +type Collation struct { + LcidAndFlags uint32 + SortId uint8 +} + +func (c Collation) getLcid() uint32 { + return c.LcidAndFlags & 0x000fffff +} + +func (c Collation) getFlags() uint32 { + return (c.LcidAndFlags & 0x0ff00000) >> 20 +} + +func (c Collation) getVersion() uint32 { + return (c.LcidAndFlags & 0xf0000000) >> 28 +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go new file mode 100644 index 0000000..5c8094e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go @@ -0,0 +1,262 @@ +package cp + +var cp1250 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x015A, //LATIN CAPITAL LETTER S WITH ACUTE + 0x0164, //LATIN CAPITAL LETTER T WITH CARON + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x015B, //LATIN SMALL LETTER S WITH ACUTE + 0x0165, //LATIN SMALL LETTER T WITH CARON + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x017A, //LATIN SMALL LETTER Z WITH ACUTE + 0x00A0, //NO-BREAK SPACE + 0x02C7, //CARON + 0x02D8, //BREVE + 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0x00A4, //CURRENCY SIGN + 0x0104, //LATIN CAPITAL LETTER A WITH OGONEK + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x02DB, //OGONEK + 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x0105, //LATIN SMALL LETTER A WITH OGONEK + 0x015F, //LATIN SMALL LETTER S WITH CEDILLA + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x013D, //LATIN CAPITAL LETTER L WITH CARON + 0x02DD, //DOUBLE ACUTE ACCENT + 0x013E, //LATIN SMALL LETTER L WITH CARON + 0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE + 0x0154, //LATIN CAPITAL LETTER R WITH ACUTE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x0102, //LATIN CAPITAL LETTER A WITH BREVE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x0139, //LATIN CAPITAL LETTER L WITH ACUTE + 0x0106, //LATIN CAPITAL LETTER C WITH ACUTE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x010C, //LATIN CAPITAL LETTER C WITH CARON + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x0118, //LATIN CAPITAL LETTER E WITH OGONEK + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x011A, //LATIN CAPITAL LETTER E WITH CARON + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x010E, //LATIN CAPITAL LETTER D WITH CARON + 0x0110, //LATIN CAPITAL LETTER D WITH STROKE + 0x0143, //LATIN CAPITAL LETTER N WITH ACUTE + 0x0147, //LATIN CAPITAL LETTER N WITH CARON + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x0150, //LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x0158, //LATIN CAPITAL LETTER R WITH CARON + 0x016E, //LATIN CAPITAL LETTER U WITH RING ABOVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x0170, //LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x0162, //LATIN CAPITAL LETTER T WITH CEDILLA + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x0155, //LATIN SMALL LETTER R WITH ACUTE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0103, //LATIN SMALL LETTER A WITH BREVE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x013A, //LATIN SMALL LETTER L WITH ACUTE + 0x0107, //LATIN SMALL LETTER C WITH ACUTE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x010D, //LATIN SMALL LETTER C WITH CARON + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x0119, //LATIN SMALL LETTER E WITH OGONEK + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x011B, //LATIN SMALL LETTER E WITH CARON + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x010F, //LATIN SMALL LETTER D WITH CARON + 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0x0148, //LATIN SMALL LETTER N WITH CARON + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x0151, //LATIN SMALL LETTER O WITH DOUBLE ACUTE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x0159, //LATIN SMALL LETTER R WITH CARON + 0x016F, //LATIN SMALL LETTER U WITH RING ABOVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x0171, //LATIN SMALL LETTER U WITH DOUBLE ACUTE + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00FD, //LATIN SMALL LETTER Y WITH ACUTE + 0x0163, //LATIN SMALL LETTER T WITH CEDILLA + 0x02D9, //DOT ABOVE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go new file mode 100644 index 0000000..dc58967 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go @@ -0,0 +1,262 @@ +package cp + +var cp1251 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x0402, //CYRILLIC CAPITAL LETTER DJE + 0x0403, //CYRILLIC CAPITAL LETTER GJE + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0453, //CYRILLIC SMALL LETTER GJE + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x20AC, //EURO SIGN + 0x2030, //PER MILLE SIGN + 0x0409, //CYRILLIC CAPITAL LETTER LJE + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x040A, //CYRILLIC CAPITAL LETTER NJE + 0x040C, //CYRILLIC CAPITAL LETTER KJE + 0x040B, //CYRILLIC CAPITAL LETTER TSHE + 0x040F, //CYRILLIC CAPITAL LETTER DZHE + 0x0452, //CYRILLIC SMALL LETTER DJE + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0x0459, //CYRILLIC SMALL LETTER LJE + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x045A, //CYRILLIC SMALL LETTER NJE + 0x045C, //CYRILLIC SMALL LETTER KJE + 0x045B, //CYRILLIC SMALL LETTER TSHE + 0x045F, //CYRILLIC SMALL LETTER DZHE + 0x00A0, //NO-BREAK SPACE + 0x040E, //CYRILLIC CAPITAL LETTER SHORT U + 0x045E, //CYRILLIC SMALL LETTER SHORT U + 0x0408, //CYRILLIC CAPITAL LETTER JE + 0x00A4, //CURRENCY SIGN + 0x0490, //CYRILLIC CAPITAL LETTER GHE WITH UPTURN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x0401, //CYRILLIC CAPITAL LETTER IO + 0x00A9, //COPYRIGHT SIGN + 0x0404, //CYRILLIC CAPITAL LETTER UKRAINIAN IE + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x0407, //CYRILLIC CAPITAL LETTER YI + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x0406, //CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + 0x0456, //CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + 0x0491, //CYRILLIC SMALL LETTER GHE WITH UPTURN + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x0451, //CYRILLIC SMALL LETTER IO + 0x2116, //NUMERO SIGN + 0x0454, //CYRILLIC SMALL LETTER UKRAINIAN IE + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x0458, //CYRILLIC SMALL LETTER JE + 0x0405, //CYRILLIC CAPITAL LETTER DZE + 0x0455, //CYRILLIC SMALL LETTER DZE + 0x0457, //CYRILLIC SMALL LETTER YI + 0x0410, //CYRILLIC CAPITAL LETTER A + 0x0411, //CYRILLIC CAPITAL LETTER BE + 0x0412, //CYRILLIC CAPITAL LETTER VE + 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0x0414, //CYRILLIC CAPITAL LETTER DE + 0x0415, //CYRILLIC CAPITAL LETTER IE + 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0x0418, //CYRILLIC CAPITAL LETTER I + 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0x041A, //CYRILLIC CAPITAL LETTER KA + 0x041B, //CYRILLIC CAPITAL LETTER EL + 0x041C, //CYRILLIC CAPITAL LETTER EM + 0x041D, //CYRILLIC CAPITAL LETTER EN + 0x041E, //CYRILLIC CAPITAL LETTER O + 0x041F, //CYRILLIC CAPITAL LETTER PE + 0x0420, //CYRILLIC CAPITAL LETTER ER + 0x0421, //CYRILLIC CAPITAL LETTER ES + 0x0422, //CYRILLIC CAPITAL LETTER TE + 0x0423, //CYRILLIC CAPITAL LETTER U + 0x0424, //CYRILLIC CAPITAL LETTER EF + 0x0425, //CYRILLIC CAPITAL LETTER HA + 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0x042D, //CYRILLIC CAPITAL LETTER E + 0x042E, //CYRILLIC CAPITAL LETTER YU + 0x042F, //CYRILLIC CAPITAL LETTER YA + 0x0430, //CYRILLIC SMALL LETTER A + 0x0431, //CYRILLIC SMALL LETTER BE + 0x0432, //CYRILLIC SMALL LETTER VE + 0x0433, //CYRILLIC SMALL LETTER GHE + 0x0434, //CYRILLIC SMALL LETTER DE + 0x0435, //CYRILLIC SMALL LETTER IE + 0x0436, //CYRILLIC SMALL LETTER ZHE + 0x0437, //CYRILLIC SMALL LETTER ZE + 0x0438, //CYRILLIC SMALL LETTER I + 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0x043A, //CYRILLIC SMALL LETTER KA + 0x043B, //CYRILLIC SMALL LETTER EL + 0x043C, //CYRILLIC SMALL LETTER EM + 0x043D, //CYRILLIC SMALL LETTER EN + 0x043E, //CYRILLIC SMALL LETTER O + 0x043F, //CYRILLIC SMALL LETTER PE + 0x0440, //CYRILLIC SMALL LETTER ER + 0x0441, //CYRILLIC SMALL LETTER ES + 0x0442, //CYRILLIC SMALL LETTER TE + 0x0443, //CYRILLIC SMALL LETTER U + 0x0444, //CYRILLIC SMALL LETTER EF + 0x0445, //CYRILLIC SMALL LETTER HA + 0x0446, //CYRILLIC SMALL LETTER TSE + 0x0447, //CYRILLIC SMALL LETTER CHE + 0x0448, //CYRILLIC SMALL LETTER SHA + 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0x044B, //CYRILLIC SMALL LETTER YERU + 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0x044D, //CYRILLIC SMALL LETTER E + 0x044E, //CYRILLIC SMALL LETTER YU + 0x044F, //CYRILLIC SMALL LETTER YA + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go new file mode 100644 index 0000000..5ae8703 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go @@ -0,0 +1,262 @@ +package cp + +var cp1252 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00C3, //LATIN CAPITAL LETTER A WITH TILDE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x00D0, //LATIN CAPITAL LETTER ETH + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x00DE, //LATIN CAPITAL LETTER THORN + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00E3, //LATIN SMALL LETTER A WITH TILDE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00F0, //LATIN SMALL LETTER ETH + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00FD, //LATIN SMALL LETTER Y WITH ACUTE + 0x00FE, //LATIN SMALL LETTER THORN + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go new file mode 100644 index 0000000..52c8e07 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go @@ -0,0 +1,262 @@ +package cp + +var cp1253 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x0385, //GREEK DIALYTIKA TONOS + 0x0386, //GREEK CAPITAL LETTER ALPHA WITH TONOS + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0xFFFD, //UNDEFINED + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x2015, //HORIZONTAL BAR + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x0384, //GREEK TONOS + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x0388, //GREEK CAPITAL LETTER EPSILON WITH TONOS + 0x0389, //GREEK CAPITAL LETTER ETA WITH TONOS + 0x038A, //GREEK CAPITAL LETTER IOTA WITH TONOS + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x038C, //GREEK CAPITAL LETTER OMICRON WITH TONOS + 0x00BD, //VULGAR FRACTION ONE HALF + 0x038E, //GREEK CAPITAL LETTER UPSILON WITH TONOS + 0x038F, //GREEK CAPITAL LETTER OMEGA WITH TONOS + 0x0390, //GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + 0x0391, //GREEK CAPITAL LETTER ALPHA + 0x0392, //GREEK CAPITAL LETTER BETA + 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x0394, //GREEK CAPITAL LETTER DELTA + 0x0395, //GREEK CAPITAL LETTER EPSILON + 0x0396, //GREEK CAPITAL LETTER ZETA + 0x0397, //GREEK CAPITAL LETTER ETA + 0x0398, //GREEK CAPITAL LETTER THETA + 0x0399, //GREEK CAPITAL LETTER IOTA + 0x039A, //GREEK CAPITAL LETTER KAPPA + 0x039B, //GREEK CAPITAL LETTER LAMDA + 0x039C, //GREEK CAPITAL LETTER MU + 0x039D, //GREEK CAPITAL LETTER NU + 0x039E, //GREEK CAPITAL LETTER XI + 0x039F, //GREEK CAPITAL LETTER OMICRON + 0x03A0, //GREEK CAPITAL LETTER PI + 0x03A1, //GREEK CAPITAL LETTER RHO + 0xFFFD, //UNDEFINED + 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0x03A4, //GREEK CAPITAL LETTER TAU + 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0x03A6, //GREEK CAPITAL LETTER PHI + 0x03A7, //GREEK CAPITAL LETTER CHI + 0x03A8, //GREEK CAPITAL LETTER PSI + 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0x03AA, //GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + 0x03AB, //GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + 0x03AC, //GREEK SMALL LETTER ALPHA WITH TONOS + 0x03AD, //GREEK SMALL LETTER EPSILON WITH TONOS + 0x03AE, //GREEK SMALL LETTER ETA WITH TONOS + 0x03AF, //GREEK SMALL LETTER IOTA WITH TONOS + 0x03B0, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + 0x03B1, //GREEK SMALL LETTER ALPHA + 0x03B2, //GREEK SMALL LETTER BETA + 0x03B3, //GREEK SMALL LETTER GAMMA + 0x03B4, //GREEK SMALL LETTER DELTA + 0x03B5, //GREEK SMALL LETTER EPSILON + 0x03B6, //GREEK SMALL LETTER ZETA + 0x03B7, //GREEK SMALL LETTER ETA + 0x03B8, //GREEK SMALL LETTER THETA + 0x03B9, //GREEK SMALL LETTER IOTA + 0x03BA, //GREEK SMALL LETTER KAPPA + 0x03BB, //GREEK SMALL LETTER LAMDA + 0x03BC, //GREEK SMALL LETTER MU + 0x03BD, //GREEK SMALL LETTER NU + 0x03BE, //GREEK SMALL LETTER XI + 0x03BF, //GREEK SMALL LETTER OMICRON + 0x03C0, //GREEK SMALL LETTER PI + 0x03C1, //GREEK SMALL LETTER RHO + 0x03C2, //GREEK SMALL LETTER FINAL SIGMA + 0x03C3, //GREEK SMALL LETTER SIGMA + 0x03C4, //GREEK SMALL LETTER TAU + 0x03C5, //GREEK SMALL LETTER UPSILON + 0x03C6, //GREEK SMALL LETTER PHI + 0x03C7, //GREEK SMALL LETTER CHI + 0x03C8, //GREEK SMALL LETTER PSI + 0x03C9, //GREEK SMALL LETTER OMEGA + 0x03CA, //GREEK SMALL LETTER IOTA WITH DIALYTIKA + 0x03CB, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA + 0x03CC, //GREEK SMALL LETTER OMICRON WITH TONOS + 0x03CD, //GREEK SMALL LETTER UPSILON WITH TONOS + 0x03CE, //GREEK SMALL LETTER OMEGA WITH TONOS + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go new file mode 100644 index 0000000..5d8864a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go @@ -0,0 +1,262 @@ +package cp + +var cp1254 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00C3, //LATIN CAPITAL LETTER A WITH TILDE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x011E, //LATIN CAPITAL LETTER G WITH BREVE + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x0130, //LATIN CAPITAL LETTER I WITH DOT ABOVE + 0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00E3, //LATIN SMALL LETTER A WITH TILDE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x011F, //LATIN SMALL LETTER G WITH BREVE + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x0131, //LATIN SMALL LETTER DOTLESS I + 0x015F, //LATIN SMALL LETTER S WITH CEDILLA + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go new file mode 100644 index 0000000..6061989 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go @@ -0,0 +1,262 @@ +package cp + +var cp1255 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x20AA, //NEW SHEQEL SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00D7, //MULTIPLICATION SIGN + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00F7, //DIVISION SIGN + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x05B0, //HEBREW POINT SHEVA + 0x05B1, //HEBREW POINT HATAF SEGOL + 0x05B2, //HEBREW POINT HATAF PATAH + 0x05B3, //HEBREW POINT HATAF QAMATS + 0x05B4, //HEBREW POINT HIRIQ + 0x05B5, //HEBREW POINT TSERE + 0x05B6, //HEBREW POINT SEGOL + 0x05B7, //HEBREW POINT PATAH + 0x05B8, //HEBREW POINT QAMATS + 0x05B9, //HEBREW POINT HOLAM + 0xFFFD, //UNDEFINED + 0x05BB, //HEBREW POINT QUBUTS + 0x05BC, //HEBREW POINT DAGESH OR MAPIQ + 0x05BD, //HEBREW POINT METEG + 0x05BE, //HEBREW PUNCTUATION MAQAF + 0x05BF, //HEBREW POINT RAFE + 0x05C0, //HEBREW PUNCTUATION PASEQ + 0x05C1, //HEBREW POINT SHIN DOT + 0x05C2, //HEBREW POINT SIN DOT + 0x05C3, //HEBREW PUNCTUATION SOF PASUQ + 0x05F0, //HEBREW LIGATURE YIDDISH DOUBLE VAV + 0x05F1, //HEBREW LIGATURE YIDDISH VAV YOD + 0x05F2, //HEBREW LIGATURE YIDDISH DOUBLE YOD + 0x05F3, //HEBREW PUNCTUATION GERESH + 0x05F4, //HEBREW PUNCTUATION GERSHAYIM + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x05D0, //HEBREW LETTER ALEF + 0x05D1, //HEBREW LETTER BET + 0x05D2, //HEBREW LETTER GIMEL + 0x05D3, //HEBREW LETTER DALET + 0x05D4, //HEBREW LETTER HE + 0x05D5, //HEBREW LETTER VAV + 0x05D6, //HEBREW LETTER ZAYIN + 0x05D7, //HEBREW LETTER HET + 0x05D8, //HEBREW LETTER TET + 0x05D9, //HEBREW LETTER YOD + 0x05DA, //HEBREW LETTER FINAL KAF + 0x05DB, //HEBREW LETTER KAF + 0x05DC, //HEBREW LETTER LAMED + 0x05DD, //HEBREW LETTER FINAL MEM + 0x05DE, //HEBREW LETTER MEM + 0x05DF, //HEBREW LETTER FINAL NUN + 0x05E0, //HEBREW LETTER NUN + 0x05E1, //HEBREW LETTER SAMEKH + 0x05E2, //HEBREW LETTER AYIN + 0x05E3, //HEBREW LETTER FINAL PE + 0x05E4, //HEBREW LETTER PE + 0x05E5, //HEBREW LETTER FINAL TSADI + 0x05E6, //HEBREW LETTER TSADI + 0x05E7, //HEBREW LETTER QOF + 0x05E8, //HEBREW LETTER RESH + 0x05E9, //HEBREW LETTER SHIN + 0x05EA, //HEBREW LETTER TAV + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x200E, //LEFT-TO-RIGHT MARK + 0x200F, //RIGHT-TO-LEFT MARK + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go new file mode 100644 index 0000000..ffd04b3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go @@ -0,0 +1,262 @@ +package cp + +var cp1256 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0x067E, //ARABIC LETTER PEH + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0679, //ARABIC LETTER TTEH + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0x0686, //ARABIC LETTER TCHEH + 0x0698, //ARABIC LETTER JEH + 0x0688, //ARABIC LETTER DDAL + 0x06AF, //ARABIC LETTER GAF + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x06A9, //ARABIC LETTER KEHEH + 0x2122, //TRADE MARK SIGN + 0x0691, //ARABIC LETTER RREH + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0x200C, //ZERO WIDTH NON-JOINER + 0x200D, //ZERO WIDTH JOINER + 0x06BA, //ARABIC LETTER NOON GHUNNA + 0x00A0, //NO-BREAK SPACE + 0x060C, //ARABIC COMMA + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x06BE, //ARABIC LETTER HEH DOACHASHMEE + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x061B, //ARABIC SEMICOLON + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x061F, //ARABIC QUESTION MARK + 0x06C1, //ARABIC LETTER HEH GOAL + 0x0621, //ARABIC LETTER HAMZA + 0x0622, //ARABIC LETTER ALEF WITH MADDA ABOVE + 0x0623, //ARABIC LETTER ALEF WITH HAMZA ABOVE + 0x0624, //ARABIC LETTER WAW WITH HAMZA ABOVE + 0x0625, //ARABIC LETTER ALEF WITH HAMZA BELOW + 0x0626, //ARABIC LETTER YEH WITH HAMZA ABOVE + 0x0627, //ARABIC LETTER ALEF + 0x0628, //ARABIC LETTER BEH + 0x0629, //ARABIC LETTER TEH MARBUTA + 0x062A, //ARABIC LETTER TEH + 0x062B, //ARABIC LETTER THEH + 0x062C, //ARABIC LETTER JEEM + 0x062D, //ARABIC LETTER HAH + 0x062E, //ARABIC LETTER KHAH + 0x062F, //ARABIC LETTER DAL + 0x0630, //ARABIC LETTER THAL + 0x0631, //ARABIC LETTER REH + 0x0632, //ARABIC LETTER ZAIN + 0x0633, //ARABIC LETTER SEEN + 0x0634, //ARABIC LETTER SHEEN + 0x0635, //ARABIC LETTER SAD + 0x0636, //ARABIC LETTER DAD + 0x00D7, //MULTIPLICATION SIGN + 0x0637, //ARABIC LETTER TAH + 0x0638, //ARABIC LETTER ZAH + 0x0639, //ARABIC LETTER AIN + 0x063A, //ARABIC LETTER GHAIN + 0x0640, //ARABIC TATWEEL + 0x0641, //ARABIC LETTER FEH + 0x0642, //ARABIC LETTER QAF + 0x0643, //ARABIC LETTER KAF + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x0644, //ARABIC LETTER LAM + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0645, //ARABIC LETTER MEEM + 0x0646, //ARABIC LETTER NOON + 0x0647, //ARABIC LETTER HEH + 0x0648, //ARABIC LETTER WAW + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x0649, //ARABIC LETTER ALEF MAKSURA + 0x064A, //ARABIC LETTER YEH + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x064B, //ARABIC FATHATAN + 0x064C, //ARABIC DAMMATAN + 0x064D, //ARABIC KASRATAN + 0x064E, //ARABIC FATHA + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x064F, //ARABIC DAMMA + 0x0650, //ARABIC KASRA + 0x00F7, //DIVISION SIGN + 0x0651, //ARABIC SHADDA + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x0652, //ARABIC SUKUN + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x200E, //LEFT-TO-RIGHT MARK + 0x200F, //RIGHT-TO-LEFT MARK + 0x06D2, //ARABIC LETTER YEH BARREE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go new file mode 100644 index 0000000..492da72 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go @@ -0,0 +1,262 @@ +package cp + +var cp1257 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x00A8, //DIAERESIS + 0x02C7, //CARON + 0x00B8, //CEDILLA + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x00AF, //MACRON + 0x02DB, //OGONEK + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0xFFFD, //UNDEFINED + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0xFFFD, //UNDEFINED + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00A9, //COPYRIGHT SIGN + 0x0156, //LATIN CAPITAL LETTER R WITH CEDILLA + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00B9, //SUPERSCRIPT ONE + 0x0157, //LATIN SMALL LETTER R WITH CEDILLA + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00E6, //LATIN SMALL LETTER AE + 0x0104, //LATIN CAPITAL LETTER A WITH OGONEK + 0x012E, //LATIN CAPITAL LETTER I WITH OGONEK + 0x0100, //LATIN CAPITAL LETTER A WITH MACRON + 0x0106, //LATIN CAPITAL LETTER C WITH ACUTE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x0118, //LATIN CAPITAL LETTER E WITH OGONEK + 0x0112, //LATIN CAPITAL LETTER E WITH MACRON + 0x010C, //LATIN CAPITAL LETTER C WITH CARON + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE + 0x0116, //LATIN CAPITAL LETTER E WITH DOT ABOVE + 0x0122, //LATIN CAPITAL LETTER G WITH CEDILLA + 0x0136, //LATIN CAPITAL LETTER K WITH CEDILLA + 0x012A, //LATIN CAPITAL LETTER I WITH MACRON + 0x013B, //LATIN CAPITAL LETTER L WITH CEDILLA + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x0143, //LATIN CAPITAL LETTER N WITH ACUTE + 0x0145, //LATIN CAPITAL LETTER N WITH CEDILLA + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x014C, //LATIN CAPITAL LETTER O WITH MACRON + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x0172, //LATIN CAPITAL LETTER U WITH OGONEK + 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0x015A, //LATIN CAPITAL LETTER S WITH ACUTE + 0x016A, //LATIN CAPITAL LETTER U WITH MACRON + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x0105, //LATIN SMALL LETTER A WITH OGONEK + 0x012F, //LATIN SMALL LETTER I WITH OGONEK + 0x0101, //LATIN SMALL LETTER A WITH MACRON + 0x0107, //LATIN SMALL LETTER C WITH ACUTE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x0119, //LATIN SMALL LETTER E WITH OGONEK + 0x0113, //LATIN SMALL LETTER E WITH MACRON + 0x010D, //LATIN SMALL LETTER C WITH CARON + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x017A, //LATIN SMALL LETTER Z WITH ACUTE + 0x0117, //LATIN SMALL LETTER E WITH DOT ABOVE + 0x0123, //LATIN SMALL LETTER G WITH CEDILLA + 0x0137, //LATIN SMALL LETTER K WITH CEDILLA + 0x012B, //LATIN SMALL LETTER I WITH MACRON + 0x013C, //LATIN SMALL LETTER L WITH CEDILLA + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0x0146, //LATIN SMALL LETTER N WITH CEDILLA + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x014D, //LATIN SMALL LETTER O WITH MACRON + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x0173, //LATIN SMALL LETTER U WITH OGONEK + 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0x015B, //LATIN SMALL LETTER S WITH ACUTE + 0x016B, //LATIN SMALL LETTER U WITH MACRON + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x02D9, //DOT ABOVE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go new file mode 100644 index 0000000..80be52c --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go @@ -0,0 +1,262 @@ +package cp + +var cp1258 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x0102, //LATIN CAPITAL LETTER A WITH BREVE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x0300, //COMBINING GRAVE ACCENT + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x0110, //LATIN CAPITAL LETTER D WITH STROKE + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x0309, //COMBINING HOOK ABOVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x01A0, //LATIN CAPITAL LETTER O WITH HORN + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x01AF, //LATIN CAPITAL LETTER U WITH HORN + 0x0303, //COMBINING TILDE + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0103, //LATIN SMALL LETTER A WITH BREVE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x0301, //COMBINING ACUTE ACCENT + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x0323, //COMBINING DOT BELOW + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x01A1, //LATIN SMALL LETTER O WITH HORN + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x01B0, //LATIN SMALL LETTER U WITH HORN + 0x20AB, //DONG SIGN + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go new file mode 100644 index 0000000..76dedfb --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go @@ -0,0 +1,262 @@ +package cp + +var cp437 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000a, //LINE FEED + 0x000b, //VERTICAL TABULATION + 0x000c, //FORM FEED + 0x000d, //CARRIAGE RETURN + 0x000e, //SHIFT OUT + 0x000f, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001a, //SUBSTITUTE + 0x001b, //ESCAPE + 0x001c, //FILE SEPARATOR + 0x001d, //GROUP SEPARATOR + 0x001e, //RECORD SEPARATOR + 0x001f, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002a, //ASTERISK + 0x002b, //PLUS SIGN + 0x002c, //COMMA + 0x002d, //HYPHEN-MINUS + 0x002e, //FULL STOP + 0x002f, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003a, //COLON + 0x003b, //SEMICOLON + 0x003c, //LESS-THAN SIGN + 0x003d, //EQUALS SIGN + 0x003e, //GREATER-THAN SIGN + 0x003f, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004a, //LATIN CAPITAL LETTER J + 0x004b, //LATIN CAPITAL LETTER K + 0x004c, //LATIN CAPITAL LETTER L + 0x004d, //LATIN CAPITAL LETTER M + 0x004e, //LATIN CAPITAL LETTER N + 0x004f, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005a, //LATIN CAPITAL LETTER Z + 0x005b, //LEFT SQUARE BRACKET + 0x005c, //REVERSE SOLIDUS + 0x005d, //RIGHT SQUARE BRACKET + 0x005e, //CIRCUMFLEX ACCENT + 0x005f, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006a, //LATIN SMALL LETTER J + 0x006b, //LATIN SMALL LETTER K + 0x006c, //LATIN SMALL LETTER L + 0x006d, //LATIN SMALL LETTER M + 0x006e, //LATIN SMALL LETTER N + 0x006f, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007a, //LATIN SMALL LETTER Z + 0x007b, //LEFT CURLY BRACKET + 0x007c, //VERTICAL LINE + 0x007d, //RIGHT CURLY BRACKET + 0x007e, //TILDE + 0x007f, //DELETE + 0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9, //LATIN SMALL LETTER E WITH ACUTE + 0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0, //LATIN SMALL LETTER A WITH GRAVE + 0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8, //LATIN SMALL LETTER E WITH GRAVE + 0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec, //LATIN SMALL LETTER I WITH GRAVE + 0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6, //LATIN SMALL LIGATURE AE + 0x00c6, //LATIN CAPITAL LIGATURE AE + 0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2, //LATIN SMALL LETTER O WITH GRAVE + 0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9, //LATIN SMALL LETTER U WITH GRAVE + 0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00a2, //CENT SIGN + 0x00a3, //POUND SIGN + 0x00a5, //YEN SIGN + 0x20a7, //PESETA SIGN + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x00e1, //LATIN SMALL LETTER A WITH ACUTE + 0x00ed, //LATIN SMALL LETTER I WITH ACUTE + 0x00f3, //LATIN SMALL LETTER O WITH ACUTE + 0x00fa, //LATIN SMALL LETTER U WITH ACUTE + 0x00f1, //LATIN SMALL LETTER N WITH TILDE + 0x00d1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00aa, //FEMININE ORDINAL INDICATOR + 0x00ba, //MASCULINE ORDINAL INDICATOR + 0x00bf, //INVERTED QUESTION MARK + 0x2310, //REVERSED NOT SIGN + 0x00ac, //NOT SIGN + 0x00bd, //VULGAR FRACTION ONE HALF + 0x00bc, //VULGAR FRACTION ONE QUARTER + 0x00a1, //INVERTED EXCLAMATION MARK + 0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591, //LIGHT SHADE + 0x2592, //MEDIUM SHADE + 0x2593, //DARK SHADE + 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT + 0x255c, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0x255b, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x255e, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0x255f, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0x256b, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0x256a, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588, //FULL BLOCK + 0x2584, //LOWER HALF BLOCK + 0x258c, //LEFT HALF BLOCK + 0x2590, //RIGHT HALF BLOCK + 0x2580, //UPPER HALF BLOCK + 0x03b1, //GREEK SMALL LETTER ALPHA + 0x00df, //LATIN SMALL LETTER SHARP S + 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x03c0, //GREEK SMALL LETTER PI + 0x03a3, //GREEK CAPITAL LETTER SIGMA + 0x03c3, //GREEK SMALL LETTER SIGMA + 0x00b5, //MICRO SIGN + 0x03c4, //GREEK SMALL LETTER TAU + 0x03a6, //GREEK CAPITAL LETTER PHI + 0x0398, //GREEK CAPITAL LETTER THETA + 0x03a9, //GREEK CAPITAL LETTER OMEGA + 0x03b4, //GREEK SMALL LETTER DELTA + 0x221e, //INFINITY + 0x03c6, //GREEK SMALL LETTER PHI + 0x03b5, //GREEK SMALL LETTER EPSILON + 0x2229, //INTERSECTION + 0x2261, //IDENTICAL TO + 0x00b1, //PLUS-MINUS SIGN + 0x2265, //GREATER-THAN OR EQUAL TO + 0x2264, //LESS-THAN OR EQUAL TO + 0x2320, //TOP HALF INTEGRAL + 0x2321, //BOTTOM HALF INTEGRAL + 0x00f7, //DIVISION SIGN + 0x2248, //ALMOST EQUAL TO + 0x00b0, //DEGREE SIGN + 0x2219, //BULLET OPERATOR + 0x00b7, //MIDDLE DOT + 0x221a, //SQUARE ROOT + 0x207f, //SUPERSCRIPT LATIN SMALL LETTER N + 0x00b2, //SUPERSCRIPT TWO + 0x25a0, //BLACK SQUARE + 0x00a0, //NO-BREAK SPACE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go new file mode 100644 index 0000000..927ab24 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go @@ -0,0 +1,262 @@ +package cp + +var cp850 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000a, //LINE FEED + 0x000b, //VERTICAL TABULATION + 0x000c, //FORM FEED + 0x000d, //CARRIAGE RETURN + 0x000e, //SHIFT OUT + 0x000f, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001a, //SUBSTITUTE + 0x001b, //ESCAPE + 0x001c, //FILE SEPARATOR + 0x001d, //GROUP SEPARATOR + 0x001e, //RECORD SEPARATOR + 0x001f, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002a, //ASTERISK + 0x002b, //PLUS SIGN + 0x002c, //COMMA + 0x002d, //HYPHEN-MINUS + 0x002e, //FULL STOP + 0x002f, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003a, //COLON + 0x003b, //SEMICOLON + 0x003c, //LESS-THAN SIGN + 0x003d, //EQUALS SIGN + 0x003e, //GREATER-THAN SIGN + 0x003f, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004a, //LATIN CAPITAL LETTER J + 0x004b, //LATIN CAPITAL LETTER K + 0x004c, //LATIN CAPITAL LETTER L + 0x004d, //LATIN CAPITAL LETTER M + 0x004e, //LATIN CAPITAL LETTER N + 0x004f, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005a, //LATIN CAPITAL LETTER Z + 0x005b, //LEFT SQUARE BRACKET + 0x005c, //REVERSE SOLIDUS + 0x005d, //RIGHT SQUARE BRACKET + 0x005e, //CIRCUMFLEX ACCENT + 0x005f, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006a, //LATIN SMALL LETTER J + 0x006b, //LATIN SMALL LETTER K + 0x006c, //LATIN SMALL LETTER L + 0x006d, //LATIN SMALL LETTER M + 0x006e, //LATIN SMALL LETTER N + 0x006f, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007a, //LATIN SMALL LETTER Z + 0x007b, //LEFT CURLY BRACKET + 0x007c, //VERTICAL LINE + 0x007d, //RIGHT CURLY BRACKET + 0x007e, //TILDE + 0x007f, //DELETE + 0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9, //LATIN SMALL LETTER E WITH ACUTE + 0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0, //LATIN SMALL LETTER A WITH GRAVE + 0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8, //LATIN SMALL LETTER E WITH GRAVE + 0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec, //LATIN SMALL LETTER I WITH GRAVE + 0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6, //LATIN SMALL LIGATURE AE + 0x00c6, //LATIN CAPITAL LIGATURE AE + 0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2, //LATIN SMALL LETTER O WITH GRAVE + 0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9, //LATIN SMALL LETTER U WITH GRAVE + 0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00f8, //LATIN SMALL LETTER O WITH STROKE + 0x00a3, //POUND SIGN + 0x00d8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00d7, //MULTIPLICATION SIGN + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x00e1, //LATIN SMALL LETTER A WITH ACUTE + 0x00ed, //LATIN SMALL LETTER I WITH ACUTE + 0x00f3, //LATIN SMALL LETTER O WITH ACUTE + 0x00fa, //LATIN SMALL LETTER U WITH ACUTE + 0x00f1, //LATIN SMALL LETTER N WITH TILDE + 0x00d1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00aa, //FEMININE ORDINAL INDICATOR + 0x00ba, //MASCULINE ORDINAL INDICATOR + 0x00bf, //INVERTED QUESTION MARK + 0x00ae, //REGISTERED SIGN + 0x00ac, //NOT SIGN + 0x00bd, //VULGAR FRACTION ONE HALF + 0x00bc, //VULGAR FRACTION ONE QUARTER + 0x00a1, //INVERTED EXCLAMATION MARK + 0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591, //LIGHT SHADE + 0x2592, //MEDIUM SHADE + 0x2593, //DARK SHADE + 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x00c1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00c2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00c0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00a9, //COPYRIGHT SIGN + 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT + 0x00a2, //CENT SIGN + 0x00a5, //YEN SIGN + 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x00e3, //LATIN SMALL LETTER A WITH TILDE + 0x00c3, //LATIN CAPITAL LETTER A WITH TILDE + 0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x00a4, //CURRENCY SIGN + 0x00f0, //LATIN SMALL LETTER ETH + 0x00d0, //LATIN CAPITAL LETTER ETH + 0x00ca, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00cb, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00c8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x0131, //LATIN SMALL LETTER DOTLESS I + 0x00cd, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00ce, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00cf, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588, //FULL BLOCK + 0x2584, //LOWER HALF BLOCK + 0x00a6, //BROKEN BAR + 0x00cc, //LATIN CAPITAL LETTER I WITH GRAVE + 0x2580, //UPPER HALF BLOCK + 0x00d3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00df, //LATIN SMALL LETTER SHARP S + 0x00d4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00d2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00f5, //LATIN SMALL LETTER O WITH TILDE + 0x00d5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00b5, //MICRO SIGN + 0x00fe, //LATIN SMALL LETTER THORN + 0x00de, //LATIN CAPITAL LETTER THORN + 0x00da, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00db, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00d9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00fd, //LATIN SMALL LETTER Y WITH ACUTE + 0x00dd, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x00af, //MACRON + 0x00b4, //ACUTE ACCENT + 0x00ad, //SOFT HYPHEN + 0x00b1, //PLUS-MINUS SIGN + 0x2017, //DOUBLE LOW LINE + 0x00be, //VULGAR FRACTION THREE QUARTERS + 0x00b6, //PILCROW SIGN + 0x00a7, //SECTION SIGN + 0x00f7, //DIVISION SIGN + 0x00b8, //CEDILLA + 0x00b0, //DEGREE SIGN + 0x00a8, //DIAERESIS + 0x00b7, //MIDDLE DOT + 0x00b9, //SUPERSCRIPT ONE + 0x00b3, //SUPERSCRIPT THREE + 0x00b2, //SUPERSCRIPT TWO + 0x25a0, //BLACK SQUARE + 0x00a0, //NO-BREAK SPACE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go new file mode 100644 index 0000000..723bf6c --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go @@ -0,0 +1,262 @@ +package cp + +var cp874 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2026, //HORIZONTAL ELLIPSIS + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x0E01, //THAI CHARACTER KO KAI + 0x0E02, //THAI CHARACTER KHO KHAI + 0x0E03, //THAI CHARACTER KHO KHUAT + 0x0E04, //THAI CHARACTER KHO KHWAI + 0x0E05, //THAI CHARACTER KHO KHON + 0x0E06, //THAI CHARACTER KHO RAKHANG + 0x0E07, //THAI CHARACTER NGO NGU + 0x0E08, //THAI CHARACTER CHO CHAN + 0x0E09, //THAI CHARACTER CHO CHING + 0x0E0A, //THAI CHARACTER CHO CHANG + 0x0E0B, //THAI CHARACTER SO SO + 0x0E0C, //THAI CHARACTER CHO CHOE + 0x0E0D, //THAI CHARACTER YO YING + 0x0E0E, //THAI CHARACTER DO CHADA + 0x0E0F, //THAI CHARACTER TO PATAK + 0x0E10, //THAI CHARACTER THO THAN + 0x0E11, //THAI CHARACTER THO NANGMONTHO + 0x0E12, //THAI CHARACTER THO PHUTHAO + 0x0E13, //THAI CHARACTER NO NEN + 0x0E14, //THAI CHARACTER DO DEK + 0x0E15, //THAI CHARACTER TO TAO + 0x0E16, //THAI CHARACTER THO THUNG + 0x0E17, //THAI CHARACTER THO THAHAN + 0x0E18, //THAI CHARACTER THO THONG + 0x0E19, //THAI CHARACTER NO NU + 0x0E1A, //THAI CHARACTER BO BAIMAI + 0x0E1B, //THAI CHARACTER PO PLA + 0x0E1C, //THAI CHARACTER PHO PHUNG + 0x0E1D, //THAI CHARACTER FO FA + 0x0E1E, //THAI CHARACTER PHO PHAN + 0x0E1F, //THAI CHARACTER FO FAN + 0x0E20, //THAI CHARACTER PHO SAMPHAO + 0x0E21, //THAI CHARACTER MO MA + 0x0E22, //THAI CHARACTER YO YAK + 0x0E23, //THAI CHARACTER RO RUA + 0x0E24, //THAI CHARACTER RU + 0x0E25, //THAI CHARACTER LO LING + 0x0E26, //THAI CHARACTER LU + 0x0E27, //THAI CHARACTER WO WAEN + 0x0E28, //THAI CHARACTER SO SALA + 0x0E29, //THAI CHARACTER SO RUSI + 0x0E2A, //THAI CHARACTER SO SUA + 0x0E2B, //THAI CHARACTER HO HIP + 0x0E2C, //THAI CHARACTER LO CHULA + 0x0E2D, //THAI CHARACTER O ANG + 0x0E2E, //THAI CHARACTER HO NOKHUK + 0x0E2F, //THAI CHARACTER PAIYANNOI + 0x0E30, //THAI CHARACTER SARA A + 0x0E31, //THAI CHARACTER MAI HAN-AKAT + 0x0E32, //THAI CHARACTER SARA AA + 0x0E33, //THAI CHARACTER SARA AM + 0x0E34, //THAI CHARACTER SARA I + 0x0E35, //THAI CHARACTER SARA II + 0x0E36, //THAI CHARACTER SARA UE + 0x0E37, //THAI CHARACTER SARA UEE + 0x0E38, //THAI CHARACTER SARA U + 0x0E39, //THAI CHARACTER SARA UU + 0x0E3A, //THAI CHARACTER PHINTHU + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0E3F, //THAI CURRENCY SYMBOL BAHT + 0x0E40, //THAI CHARACTER SARA E + 0x0E41, //THAI CHARACTER SARA AE + 0x0E42, //THAI CHARACTER SARA O + 0x0E43, //THAI CHARACTER SARA AI MAIMUAN + 0x0E44, //THAI CHARACTER SARA AI MAIMALAI + 0x0E45, //THAI CHARACTER LAKKHANGYAO + 0x0E46, //THAI CHARACTER MAIYAMOK + 0x0E47, //THAI CHARACTER MAITAIKHU + 0x0E48, //THAI CHARACTER MAI EK + 0x0E49, //THAI CHARACTER MAI THO + 0x0E4A, //THAI CHARACTER MAI TRI + 0x0E4B, //THAI CHARACTER MAI CHATTAWA + 0x0E4C, //THAI CHARACTER THANTHAKHAT + 0x0E4D, //THAI CHARACTER NIKHAHIT + 0x0E4E, //THAI CHARACTER YAMAKKAN + 0x0E4F, //THAI CHARACTER FONGMAN + 0x0E50, //THAI DIGIT ZERO + 0x0E51, //THAI DIGIT ONE + 0x0E52, //THAI DIGIT TWO + 0x0E53, //THAI DIGIT THREE + 0x0E54, //THAI DIGIT FOUR + 0x0E55, //THAI DIGIT FIVE + 0x0E56, //THAI DIGIT SIX + 0x0E57, //THAI DIGIT SEVEN + 0x0E58, //THAI DIGIT EIGHT + 0x0E59, //THAI DIGIT NINE + 0x0E5A, //THAI CHARACTER ANGKHANKHU + 0x0E5B, //THAI CHARACTER KHOMUT + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go new file mode 100644 index 0000000..5fc1377 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go @@ -0,0 +1,7988 @@ +package cp + +var cp932 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + 0xFF61, //HALFWIDTH IDEOGRAPHIC FULL STOP + 0xFF62, //HALFWIDTH LEFT CORNER BRACKET + 0xFF63, //HALFWIDTH RIGHT CORNER BRACKET + 0xFF64, //HALFWIDTH IDEOGRAPHIC COMMA + 0xFF65, //HALFWIDTH KATAKANA MIDDLE DOT + 0xFF66, //HALFWIDTH KATAKANA LETTER WO + 0xFF67, //HALFWIDTH KATAKANA LETTER SMALL A + 0xFF68, //HALFWIDTH KATAKANA LETTER SMALL I + 0xFF69, //HALFWIDTH KATAKANA LETTER SMALL U + 0xFF6A, //HALFWIDTH KATAKANA LETTER SMALL E + 0xFF6B, //HALFWIDTH KATAKANA LETTER SMALL O + 0xFF6C, //HALFWIDTH KATAKANA LETTER SMALL YA + 0xFF6D, //HALFWIDTH KATAKANA LETTER SMALL YU + 0xFF6E, //HALFWIDTH KATAKANA LETTER SMALL YO + 0xFF6F, //HALFWIDTH KATAKANA LETTER SMALL TU + 0xFF70, //HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0xFF71, //HALFWIDTH KATAKANA LETTER A + 0xFF72, //HALFWIDTH KATAKANA LETTER I + 0xFF73, //HALFWIDTH KATAKANA LETTER U + 0xFF74, //HALFWIDTH KATAKANA LETTER E + 0xFF75, //HALFWIDTH KATAKANA LETTER O + 0xFF76, //HALFWIDTH KATAKANA LETTER KA + 0xFF77, //HALFWIDTH KATAKANA LETTER KI + 0xFF78, //HALFWIDTH KATAKANA LETTER KU + 0xFF79, //HALFWIDTH KATAKANA LETTER KE + 0xFF7A, //HALFWIDTH KATAKANA LETTER KO + 0xFF7B, //HALFWIDTH KATAKANA LETTER SA + 0xFF7C, //HALFWIDTH KATAKANA LETTER SI + 0xFF7D, //HALFWIDTH KATAKANA LETTER SU + 0xFF7E, //HALFWIDTH KATAKANA LETTER SE + 0xFF7F, //HALFWIDTH KATAKANA LETTER SO + 0xFF80, //HALFWIDTH KATAKANA LETTER TA + 0xFF81, //HALFWIDTH KATAKANA LETTER TI + 0xFF82, //HALFWIDTH KATAKANA LETTER TU + 0xFF83, //HALFWIDTH KATAKANA LETTER TE + 0xFF84, //HALFWIDTH KATAKANA LETTER TO + 0xFF85, //HALFWIDTH KATAKANA LETTER NA + 0xFF86, //HALFWIDTH KATAKANA LETTER NI + 0xFF87, //HALFWIDTH KATAKANA LETTER NU + 0xFF88, //HALFWIDTH KATAKANA LETTER NE + 0xFF89, //HALFWIDTH KATAKANA LETTER NO + 0xFF8A, //HALFWIDTH KATAKANA LETTER HA + 0xFF8B, //HALFWIDTH KATAKANA LETTER HI + 0xFF8C, //HALFWIDTH KATAKANA LETTER HU + 0xFF8D, //HALFWIDTH KATAKANA LETTER HE + 0xFF8E, //HALFWIDTH KATAKANA LETTER HO + 0xFF8F, //HALFWIDTH KATAKANA LETTER MA + 0xFF90, //HALFWIDTH KATAKANA LETTER MI + 0xFF91, //HALFWIDTH KATAKANA LETTER MU + 0xFF92, //HALFWIDTH KATAKANA LETTER ME + 0xFF93, //HALFWIDTH KATAKANA LETTER MO + 0xFF94, //HALFWIDTH KATAKANA LETTER YA + 0xFF95, //HALFWIDTH KATAKANA LETTER YU + 0xFF96, //HALFWIDTH KATAKANA LETTER YO + 0xFF97, //HALFWIDTH KATAKANA LETTER RA + 0xFF98, //HALFWIDTH KATAKANA LETTER RI + 0xFF99, //HALFWIDTH KATAKANA LETTER RU + 0xFF9A, //HALFWIDTH KATAKANA LETTER RE + 0xFF9B, //HALFWIDTH KATAKANA LETTER RO + 0xFF9C, //HALFWIDTH KATAKANA LETTER WA + 0xFF9D, //HALFWIDTH KATAKANA LETTER N + 0xFF9E, //HALFWIDTH KATAKANA VOICED SOUND MARK + 0xFF9F, //HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8140: 0x3000, //IDEOGRAPHIC SPACE + 0x8141: 0x3001, //IDEOGRAPHIC COMMA + 0x8142: 0x3002, //IDEOGRAPHIC FULL STOP + 0x8143: 0xFF0C, //FULLWIDTH COMMA + 0x8144: 0xFF0E, //FULLWIDTH FULL STOP + 0x8145: 0x30FB, //KATAKANA MIDDLE DOT + 0x8146: 0xFF1A, //FULLWIDTH COLON + 0x8147: 0xFF1B, //FULLWIDTH SEMICOLON + 0x8148: 0xFF1F, //FULLWIDTH QUESTION MARK + 0x8149: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0x814A: 0x309B, //KATAKANA-HIRAGANA VOICED SOUND MARK + 0x814B: 0x309C, //KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + 0x814C: 0x00B4, //ACUTE ACCENT + 0x814D: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0x814E: 0x00A8, //DIAERESIS + 0x814F: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0x8150: 0xFFE3, //FULLWIDTH MACRON + 0x8151: 0xFF3F, //FULLWIDTH LOW LINE + 0x8152: 0x30FD, //KATAKANA ITERATION MARK + 0x8153: 0x30FE, //KATAKANA VOICED ITERATION MARK + 0x8154: 0x309D, //HIRAGANA ITERATION MARK + 0x8155: 0x309E, //HIRAGANA VOICED ITERATION MARK + 0x8156: 0x3003, //DITTO MARK + 0x8157: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0x8158: 0x3005, //IDEOGRAPHIC ITERATION MARK + 0x8159: 0x3006, //IDEOGRAPHIC CLOSING MARK + 0x815A: 0x3007, //IDEOGRAPHIC NUMBER ZERO + 0x815B: 0x30FC, //KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0x815C: 0x2015, //HORIZONTAL BAR + 0x815D: 0x2010, //HYPHEN + 0x815E: 0xFF0F, //FULLWIDTH SOLIDUS + 0x815F: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0x8160: 0xFF5E, //FULLWIDTH TILDE + 0x8161: 0x2225, //PARALLEL TO + 0x8162: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0x8163: 0x2026, //HORIZONTAL ELLIPSIS + 0x8164: 0x2025, //TWO DOT LEADER + 0x8165: 0x2018, //LEFT SINGLE QUOTATION MARK + 0x8166: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x8167: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x8168: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x8169: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0x816A: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0x816B: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0x816C: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0x816D: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0x816E: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0x816F: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0x8170: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0x8171: 0x3008, //LEFT ANGLE BRACKET + 0x8172: 0x3009, //RIGHT ANGLE BRACKET + 0x8173: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0x8174: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0x8175: 0x300C, //LEFT CORNER BRACKET + 0x8176: 0x300D, //RIGHT CORNER BRACKET + 0x8177: 0x300E, //LEFT WHITE CORNER BRACKET + 0x8178: 0x300F, //RIGHT WHITE CORNER BRACKET + 0x8179: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0x817A: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0x817B: 0xFF0B, //FULLWIDTH PLUS SIGN + 0x817C: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0x817D: 0x00B1, //PLUS-MINUS SIGN + 0x817E: 0x00D7, //MULTIPLICATION SIGN + 0x8180: 0x00F7, //DIVISION SIGN + 0x8181: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0x8182: 0x2260, //NOT EQUAL TO + 0x8183: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0x8184: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0x8185: 0x2266, //LESS-THAN OVER EQUAL TO + 0x8186: 0x2267, //GREATER-THAN OVER EQUAL TO + 0x8187: 0x221E, //INFINITY + 0x8188: 0x2234, //THEREFORE + 0x8189: 0x2642, //MALE SIGN + 0x818A: 0x2640, //FEMALE SIGN + 0x818B: 0x00B0, //DEGREE SIGN + 0x818C: 0x2032, //PRIME + 0x818D: 0x2033, //DOUBLE PRIME + 0x818E: 0x2103, //DEGREE CELSIUS + 0x818F: 0xFFE5, //FULLWIDTH YEN SIGN + 0x8190: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0x8191: 0xFFE0, //FULLWIDTH CENT SIGN + 0x8192: 0xFFE1, //FULLWIDTH POUND SIGN + 0x8193: 0xFF05, //FULLWIDTH PERCENT SIGN + 0x8194: 0xFF03, //FULLWIDTH NUMBER SIGN + 0x8195: 0xFF06, //FULLWIDTH AMPERSAND + 0x8196: 0xFF0A, //FULLWIDTH ASTERISK + 0x8197: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0x8198: 0x00A7, //SECTION SIGN + 0x8199: 0x2606, //WHITE STAR + 0x819A: 0x2605, //BLACK STAR + 0x819B: 0x25CB, //WHITE CIRCLE + 0x819C: 0x25CF, //BLACK CIRCLE + 0x819D: 0x25CE, //BULLSEYE + 0x819E: 0x25C7, //WHITE DIAMOND + 0x819F: 0x25C6, //BLACK DIAMOND + 0x81A0: 0x25A1, //WHITE SQUARE + 0x81A1: 0x25A0, //BLACK SQUARE + 0x81A2: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0x81A3: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0x81A4: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0x81A5: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0x81A6: 0x203B, //REFERENCE MARK + 0x81A7: 0x3012, //POSTAL MARK + 0x81A8: 0x2192, //RIGHTWARDS ARROW + 0x81A9: 0x2190, //LEFTWARDS ARROW + 0x81AA: 0x2191, //UPWARDS ARROW + 0x81AB: 0x2193, //DOWNWARDS ARROW + 0x81AC: 0x3013, //GETA MARK + 0x81B8: 0x2208, //ELEMENT OF + 0x81B9: 0x220B, //CONTAINS AS MEMBER + 0x81BA: 0x2286, //SUBSET OF OR EQUAL TO + 0x81BB: 0x2287, //SUPERSET OF OR EQUAL TO + 0x81BC: 0x2282, //SUBSET OF + 0x81BD: 0x2283, //SUPERSET OF + 0x81BE: 0x222A, //UNION + 0x81BF: 0x2229, //INTERSECTION + 0x81C8: 0x2227, //LOGICAL AND + 0x81C9: 0x2228, //LOGICAL OR + 0x81CA: 0xFFE2, //FULLWIDTH NOT SIGN + 0x81CB: 0x21D2, //RIGHTWARDS DOUBLE ARROW + 0x81CC: 0x21D4, //LEFT RIGHT DOUBLE ARROW + 0x81CD: 0x2200, //FOR ALL + 0x81CE: 0x2203, //THERE EXISTS + 0x81DA: 0x2220, //ANGLE + 0x81DB: 0x22A5, //UP TACK + 0x81DC: 0x2312, //ARC + 0x81DD: 0x2202, //PARTIAL DIFFERENTIAL + 0x81DE: 0x2207, //NABLA + 0x81DF: 0x2261, //IDENTICAL TO + 0x81E0: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0x81E1: 0x226A, //MUCH LESS-THAN + 0x81E2: 0x226B, //MUCH GREATER-THAN + 0x81E3: 0x221A, //SQUARE ROOT + 0x81E4: 0x223D, //REVERSED TILDE + 0x81E5: 0x221D, //PROPORTIONAL TO + 0x81E6: 0x2235, //BECAUSE + 0x81E7: 0x222B, //INTEGRAL + 0x81E8: 0x222C, //DOUBLE INTEGRAL + 0x81F0: 0x212B, //ANGSTROM SIGN + 0x81F1: 0x2030, //PER MILLE SIGN + 0x81F2: 0x266F, //MUSIC SHARP SIGN + 0x81F3: 0x266D, //MUSIC FLAT SIGN + 0x81F4: 0x266A, //EIGHTH NOTE + 0x81F5: 0x2020, //DAGGER + 0x81F6: 0x2021, //DOUBLE DAGGER + 0x81F7: 0x00B6, //PILCROW SIGN + 0x81FC: 0x25EF, //LARGE CIRCLE + 0x824F: 0xFF10, //FULLWIDTH DIGIT ZERO + 0x8250: 0xFF11, //FULLWIDTH DIGIT ONE + 0x8251: 0xFF12, //FULLWIDTH DIGIT TWO + 0x8252: 0xFF13, //FULLWIDTH DIGIT THREE + 0x8253: 0xFF14, //FULLWIDTH DIGIT FOUR + 0x8254: 0xFF15, //FULLWIDTH DIGIT FIVE + 0x8255: 0xFF16, //FULLWIDTH DIGIT SIX + 0x8256: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0x8257: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0x8258: 0xFF19, //FULLWIDTH DIGIT NINE + 0x8260: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0x8261: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0x8262: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0x8263: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0x8264: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0x8265: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0x8266: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0x8267: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0x8268: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0x8269: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0x826A: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0x826B: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0x826C: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0x826D: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0x826E: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0x826F: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0x8270: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0x8271: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0x8272: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0x8273: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0x8274: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0x8275: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0x8276: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0x8277: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0x8278: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0x8279: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0x8281: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0x8282: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0x8283: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0x8284: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0x8285: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0x8286: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0x8287: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0x8288: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0x8289: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0x828A: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0x828B: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0x828C: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0x828D: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0x828E: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0x828F: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0x8290: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0x8291: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0x8292: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0x8293: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0x8294: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0x8295: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0x8296: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0x8297: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0x8298: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0x8299: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0x829A: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0x829F: 0x3041, //HIRAGANA LETTER SMALL A + 0x82A0: 0x3042, //HIRAGANA LETTER A + 0x82A1: 0x3043, //HIRAGANA LETTER SMALL I + 0x82A2: 0x3044, //HIRAGANA LETTER I + 0x82A3: 0x3045, //HIRAGANA LETTER SMALL U + 0x82A4: 0x3046, //HIRAGANA LETTER U + 0x82A5: 0x3047, //HIRAGANA LETTER SMALL E + 0x82A6: 0x3048, //HIRAGANA LETTER E + 0x82A7: 0x3049, //HIRAGANA LETTER SMALL O + 0x82A8: 0x304A, //HIRAGANA LETTER O + 0x82A9: 0x304B, //HIRAGANA LETTER KA + 0x82AA: 0x304C, //HIRAGANA LETTER GA + 0x82AB: 0x304D, //HIRAGANA LETTER KI + 0x82AC: 0x304E, //HIRAGANA LETTER GI + 0x82AD: 0x304F, //HIRAGANA LETTER KU + 0x82AE: 0x3050, //HIRAGANA LETTER GU + 0x82AF: 0x3051, //HIRAGANA LETTER KE + 0x82B0: 0x3052, //HIRAGANA LETTER GE + 0x82B1: 0x3053, //HIRAGANA LETTER KO + 0x82B2: 0x3054, //HIRAGANA LETTER GO + 0x82B3: 0x3055, //HIRAGANA LETTER SA + 0x82B4: 0x3056, //HIRAGANA LETTER ZA + 0x82B5: 0x3057, //HIRAGANA LETTER SI + 0x82B6: 0x3058, //HIRAGANA LETTER ZI + 0x82B7: 0x3059, //HIRAGANA LETTER SU + 0x82B8: 0x305A, //HIRAGANA LETTER ZU + 0x82B9: 0x305B, //HIRAGANA LETTER SE + 0x82BA: 0x305C, //HIRAGANA LETTER ZE + 0x82BB: 0x305D, //HIRAGANA LETTER SO + 0x82BC: 0x305E, //HIRAGANA LETTER ZO + 0x82BD: 0x305F, //HIRAGANA LETTER TA + 0x82BE: 0x3060, //HIRAGANA LETTER DA + 0x82BF: 0x3061, //HIRAGANA LETTER TI + 0x82C0: 0x3062, //HIRAGANA LETTER DI + 0x82C1: 0x3063, //HIRAGANA LETTER SMALL TU + 0x82C2: 0x3064, //HIRAGANA LETTER TU + 0x82C3: 0x3065, //HIRAGANA LETTER DU + 0x82C4: 0x3066, //HIRAGANA LETTER TE + 0x82C5: 0x3067, //HIRAGANA LETTER DE + 0x82C6: 0x3068, //HIRAGANA LETTER TO + 0x82C7: 0x3069, //HIRAGANA LETTER DO + 0x82C8: 0x306A, //HIRAGANA LETTER NA + 0x82C9: 0x306B, //HIRAGANA LETTER NI + 0x82CA: 0x306C, //HIRAGANA LETTER NU + 0x82CB: 0x306D, //HIRAGANA LETTER NE + 0x82CC: 0x306E, //HIRAGANA LETTER NO + 0x82CD: 0x306F, //HIRAGANA LETTER HA + 0x82CE: 0x3070, //HIRAGANA LETTER BA + 0x82CF: 0x3071, //HIRAGANA LETTER PA + 0x82D0: 0x3072, //HIRAGANA LETTER HI + 0x82D1: 0x3073, //HIRAGANA LETTER BI + 0x82D2: 0x3074, //HIRAGANA LETTER PI + 0x82D3: 0x3075, //HIRAGANA LETTER HU + 0x82D4: 0x3076, //HIRAGANA LETTER BU + 0x82D5: 0x3077, //HIRAGANA LETTER PU + 0x82D6: 0x3078, //HIRAGANA LETTER HE + 0x82D7: 0x3079, //HIRAGANA LETTER BE + 0x82D8: 0x307A, //HIRAGANA LETTER PE + 0x82D9: 0x307B, //HIRAGANA LETTER HO + 0x82DA: 0x307C, //HIRAGANA LETTER BO + 0x82DB: 0x307D, //HIRAGANA LETTER PO + 0x82DC: 0x307E, //HIRAGANA LETTER MA + 0x82DD: 0x307F, //HIRAGANA LETTER MI + 0x82DE: 0x3080, //HIRAGANA LETTER MU + 0x82DF: 0x3081, //HIRAGANA LETTER ME + 0x82E0: 0x3082, //HIRAGANA LETTER MO + 0x82E1: 0x3083, //HIRAGANA LETTER SMALL YA + 0x82E2: 0x3084, //HIRAGANA LETTER YA + 0x82E3: 0x3085, //HIRAGANA LETTER SMALL YU + 0x82E4: 0x3086, //HIRAGANA LETTER YU + 0x82E5: 0x3087, //HIRAGANA LETTER SMALL YO + 0x82E6: 0x3088, //HIRAGANA LETTER YO + 0x82E7: 0x3089, //HIRAGANA LETTER RA + 0x82E8: 0x308A, //HIRAGANA LETTER RI + 0x82E9: 0x308B, //HIRAGANA LETTER RU + 0x82EA: 0x308C, //HIRAGANA LETTER RE + 0x82EB: 0x308D, //HIRAGANA LETTER RO + 0x82EC: 0x308E, //HIRAGANA LETTER SMALL WA + 0x82ED: 0x308F, //HIRAGANA LETTER WA + 0x82EE: 0x3090, //HIRAGANA LETTER WI + 0x82EF: 0x3091, //HIRAGANA LETTER WE + 0x82F0: 0x3092, //HIRAGANA LETTER WO + 0x82F1: 0x3093, //HIRAGANA LETTER N + 0x8340: 0x30A1, //KATAKANA LETTER SMALL A + 0x8341: 0x30A2, //KATAKANA LETTER A + 0x8342: 0x30A3, //KATAKANA LETTER SMALL I + 0x8343: 0x30A4, //KATAKANA LETTER I + 0x8344: 0x30A5, //KATAKANA LETTER SMALL U + 0x8345: 0x30A6, //KATAKANA LETTER U + 0x8346: 0x30A7, //KATAKANA LETTER SMALL E + 0x8347: 0x30A8, //KATAKANA LETTER E + 0x8348: 0x30A9, //KATAKANA LETTER SMALL O + 0x8349: 0x30AA, //KATAKANA LETTER O + 0x834A: 0x30AB, //KATAKANA LETTER KA + 0x834B: 0x30AC, //KATAKANA LETTER GA + 0x834C: 0x30AD, //KATAKANA LETTER KI + 0x834D: 0x30AE, //KATAKANA LETTER GI + 0x834E: 0x30AF, //KATAKANA LETTER KU + 0x834F: 0x30B0, //KATAKANA LETTER GU + 0x8350: 0x30B1, //KATAKANA LETTER KE + 0x8351: 0x30B2, //KATAKANA LETTER GE + 0x8352: 0x30B3, //KATAKANA LETTER KO + 0x8353: 0x30B4, //KATAKANA LETTER GO + 0x8354: 0x30B5, //KATAKANA LETTER SA + 0x8355: 0x30B6, //KATAKANA LETTER ZA + 0x8356: 0x30B7, //KATAKANA LETTER SI + 0x8357: 0x30B8, //KATAKANA LETTER ZI + 0x8358: 0x30B9, //KATAKANA LETTER SU + 0x8359: 0x30BA, //KATAKANA LETTER ZU + 0x835A: 0x30BB, //KATAKANA LETTER SE + 0x835B: 0x30BC, //KATAKANA LETTER ZE + 0x835C: 0x30BD, //KATAKANA LETTER SO + 0x835D: 0x30BE, //KATAKANA LETTER ZO + 0x835E: 0x30BF, //KATAKANA LETTER TA + 0x835F: 0x30C0, //KATAKANA LETTER DA + 0x8360: 0x30C1, //KATAKANA LETTER TI + 0x8361: 0x30C2, //KATAKANA LETTER DI + 0x8362: 0x30C3, //KATAKANA LETTER SMALL TU + 0x8363: 0x30C4, //KATAKANA LETTER TU + 0x8364: 0x30C5, //KATAKANA LETTER DU + 0x8365: 0x30C6, //KATAKANA LETTER TE + 0x8366: 0x30C7, //KATAKANA LETTER DE + 0x8367: 0x30C8, //KATAKANA LETTER TO + 0x8368: 0x30C9, //KATAKANA LETTER DO + 0x8369: 0x30CA, //KATAKANA LETTER NA + 0x836A: 0x30CB, //KATAKANA LETTER NI + 0x836B: 0x30CC, //KATAKANA LETTER NU + 0x836C: 0x30CD, //KATAKANA LETTER NE + 0x836D: 0x30CE, //KATAKANA LETTER NO + 0x836E: 0x30CF, //KATAKANA LETTER HA + 0x836F: 0x30D0, //KATAKANA LETTER BA + 0x8370: 0x30D1, //KATAKANA LETTER PA + 0x8371: 0x30D2, //KATAKANA LETTER HI + 0x8372: 0x30D3, //KATAKANA LETTER BI + 0x8373: 0x30D4, //KATAKANA LETTER PI + 0x8374: 0x30D5, //KATAKANA LETTER HU + 0x8375: 0x30D6, //KATAKANA LETTER BU + 0x8376: 0x30D7, //KATAKANA LETTER PU + 0x8377: 0x30D8, //KATAKANA LETTER HE + 0x8378: 0x30D9, //KATAKANA LETTER BE + 0x8379: 0x30DA, //KATAKANA LETTER PE + 0x837A: 0x30DB, //KATAKANA LETTER HO + 0x837B: 0x30DC, //KATAKANA LETTER BO + 0x837C: 0x30DD, //KATAKANA LETTER PO + 0x837D: 0x30DE, //KATAKANA LETTER MA + 0x837E: 0x30DF, //KATAKANA LETTER MI + 0x8380: 0x30E0, //KATAKANA LETTER MU + 0x8381: 0x30E1, //KATAKANA LETTER ME + 0x8382: 0x30E2, //KATAKANA LETTER MO + 0x8383: 0x30E3, //KATAKANA LETTER SMALL YA + 0x8384: 0x30E4, //KATAKANA LETTER YA + 0x8385: 0x30E5, //KATAKANA LETTER SMALL YU + 0x8386: 0x30E6, //KATAKANA LETTER YU + 0x8387: 0x30E7, //KATAKANA LETTER SMALL YO + 0x8388: 0x30E8, //KATAKANA LETTER YO + 0x8389: 0x30E9, //KATAKANA LETTER RA + 0x838A: 0x30EA, //KATAKANA LETTER RI + 0x838B: 0x30EB, //KATAKANA LETTER RU + 0x838C: 0x30EC, //KATAKANA LETTER RE + 0x838D: 0x30ED, //KATAKANA LETTER RO + 0x838E: 0x30EE, //KATAKANA LETTER SMALL WA + 0x838F: 0x30EF, //KATAKANA LETTER WA + 0x8390: 0x30F0, //KATAKANA LETTER WI + 0x8391: 0x30F1, //KATAKANA LETTER WE + 0x8392: 0x30F2, //KATAKANA LETTER WO + 0x8393: 0x30F3, //KATAKANA LETTER N + 0x8394: 0x30F4, //KATAKANA LETTER VU + 0x8395: 0x30F5, //KATAKANA LETTER SMALL KA + 0x8396: 0x30F6, //KATAKANA LETTER SMALL KE + 0x839F: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0x83A0: 0x0392, //GREEK CAPITAL LETTER BETA + 0x83A1: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x83A2: 0x0394, //GREEK CAPITAL LETTER DELTA + 0x83A3: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0x83A4: 0x0396, //GREEK CAPITAL LETTER ZETA + 0x83A5: 0x0397, //GREEK CAPITAL LETTER ETA + 0x83A6: 0x0398, //GREEK CAPITAL LETTER THETA + 0x83A7: 0x0399, //GREEK CAPITAL LETTER IOTA + 0x83A8: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0x83A9: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0x83AA: 0x039C, //GREEK CAPITAL LETTER MU + 0x83AB: 0x039D, //GREEK CAPITAL LETTER NU + 0x83AC: 0x039E, //GREEK CAPITAL LETTER XI + 0x83AD: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0x83AE: 0x03A0, //GREEK CAPITAL LETTER PI + 0x83AF: 0x03A1, //GREEK CAPITAL LETTER RHO + 0x83B0: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0x83B1: 0x03A4, //GREEK CAPITAL LETTER TAU + 0x83B2: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0x83B3: 0x03A6, //GREEK CAPITAL LETTER PHI + 0x83B4: 0x03A7, //GREEK CAPITAL LETTER CHI + 0x83B5: 0x03A8, //GREEK CAPITAL LETTER PSI + 0x83B6: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0x83BF: 0x03B1, //GREEK SMALL LETTER ALPHA + 0x83C0: 0x03B2, //GREEK SMALL LETTER BETA + 0x83C1: 0x03B3, //GREEK SMALL LETTER GAMMA + 0x83C2: 0x03B4, //GREEK SMALL LETTER DELTA + 0x83C3: 0x03B5, //GREEK SMALL LETTER EPSILON + 0x83C4: 0x03B6, //GREEK SMALL LETTER ZETA + 0x83C5: 0x03B7, //GREEK SMALL LETTER ETA + 0x83C6: 0x03B8, //GREEK SMALL LETTER THETA + 0x83C7: 0x03B9, //GREEK SMALL LETTER IOTA + 0x83C8: 0x03BA, //GREEK SMALL LETTER KAPPA + 0x83C9: 0x03BB, //GREEK SMALL LETTER LAMDA + 0x83CA: 0x03BC, //GREEK SMALL LETTER MU + 0x83CB: 0x03BD, //GREEK SMALL LETTER NU + 0x83CC: 0x03BE, //GREEK SMALL LETTER XI + 0x83CD: 0x03BF, //GREEK SMALL LETTER OMICRON + 0x83CE: 0x03C0, //GREEK SMALL LETTER PI + 0x83CF: 0x03C1, //GREEK SMALL LETTER RHO + 0x83D0: 0x03C3, //GREEK SMALL LETTER SIGMA + 0x83D1: 0x03C4, //GREEK SMALL LETTER TAU + 0x83D2: 0x03C5, //GREEK SMALL LETTER UPSILON + 0x83D3: 0x03C6, //GREEK SMALL LETTER PHI + 0x83D4: 0x03C7, //GREEK SMALL LETTER CHI + 0x83D5: 0x03C8, //GREEK SMALL LETTER PSI + 0x83D6: 0x03C9, //GREEK SMALL LETTER OMEGA + 0x8440: 0x0410, //CYRILLIC CAPITAL LETTER A + 0x8441: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0x8442: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0x8443: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0x8444: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0x8445: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0x8446: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0x8447: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0x8448: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0x8449: 0x0418, //CYRILLIC CAPITAL LETTER I + 0x844A: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0x844B: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0x844C: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0x844D: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0x844E: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0x844F: 0x041E, //CYRILLIC CAPITAL LETTER O + 0x8450: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0x8451: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0x8452: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0x8453: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0x8454: 0x0423, //CYRILLIC CAPITAL LETTER U + 0x8455: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0x8456: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0x8457: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0x8458: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0x8459: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0x845A: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0x845B: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0x845C: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0x845D: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0x845E: 0x042D, //CYRILLIC CAPITAL LETTER E + 0x845F: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0x8460: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0x8470: 0x0430, //CYRILLIC SMALL LETTER A + 0x8471: 0x0431, //CYRILLIC SMALL LETTER BE + 0x8472: 0x0432, //CYRILLIC SMALL LETTER VE + 0x8473: 0x0433, //CYRILLIC SMALL LETTER GHE + 0x8474: 0x0434, //CYRILLIC SMALL LETTER DE + 0x8475: 0x0435, //CYRILLIC SMALL LETTER IE + 0x8476: 0x0451, //CYRILLIC SMALL LETTER IO + 0x8477: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0x8478: 0x0437, //CYRILLIC SMALL LETTER ZE + 0x8479: 0x0438, //CYRILLIC SMALL LETTER I + 0x847A: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0x847B: 0x043A, //CYRILLIC SMALL LETTER KA + 0x847C: 0x043B, //CYRILLIC SMALL LETTER EL + 0x847D: 0x043C, //CYRILLIC SMALL LETTER EM + 0x847E: 0x043D, //CYRILLIC SMALL LETTER EN + 0x8480: 0x043E, //CYRILLIC SMALL LETTER O + 0x8481: 0x043F, //CYRILLIC SMALL LETTER PE + 0x8482: 0x0440, //CYRILLIC SMALL LETTER ER + 0x8483: 0x0441, //CYRILLIC SMALL LETTER ES + 0x8484: 0x0442, //CYRILLIC SMALL LETTER TE + 0x8485: 0x0443, //CYRILLIC SMALL LETTER U + 0x8486: 0x0444, //CYRILLIC SMALL LETTER EF + 0x8487: 0x0445, //CYRILLIC SMALL LETTER HA + 0x8488: 0x0446, //CYRILLIC SMALL LETTER TSE + 0x8489: 0x0447, //CYRILLIC SMALL LETTER CHE + 0x848A: 0x0448, //CYRILLIC SMALL LETTER SHA + 0x848B: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0x848C: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0x848D: 0x044B, //CYRILLIC SMALL LETTER YERU + 0x848E: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0x848F: 0x044D, //CYRILLIC SMALL LETTER E + 0x8490: 0x044E, //CYRILLIC SMALL LETTER YU + 0x8491: 0x044F, //CYRILLIC SMALL LETTER YA + 0x849F: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x84A0: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x84A1: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x84A2: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x84A3: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x84A4: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x84A5: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x84A6: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x84A7: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x84A8: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x84A9: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x84AA: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0x84AB: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0x84AC: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0x84AD: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0x84AE: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0x84AF: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0x84B0: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0x84B1: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0x84B2: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0x84B3: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0x84B4: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0x84B5: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0x84B6: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0x84B7: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0x84B8: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0x84B9: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0x84BA: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0x84BB: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0x84BC: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0x84BD: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0x84BE: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0x8740: 0x2460, //CIRCLED DIGIT ONE + 0x8741: 0x2461, //CIRCLED DIGIT TWO + 0x8742: 0x2462, //CIRCLED DIGIT THREE + 0x8743: 0x2463, //CIRCLED DIGIT FOUR + 0x8744: 0x2464, //CIRCLED DIGIT FIVE + 0x8745: 0x2465, //CIRCLED DIGIT SIX + 0x8746: 0x2466, //CIRCLED DIGIT SEVEN + 0x8747: 0x2467, //CIRCLED DIGIT EIGHT + 0x8748: 0x2468, //CIRCLED DIGIT NINE + 0x8749: 0x2469, //CIRCLED NUMBER TEN + 0x874A: 0x246A, //CIRCLED NUMBER ELEVEN + 0x874B: 0x246B, //CIRCLED NUMBER TWELVE + 0x874C: 0x246C, //CIRCLED NUMBER THIRTEEN + 0x874D: 0x246D, //CIRCLED NUMBER FOURTEEN + 0x874E: 0x246E, //CIRCLED NUMBER FIFTEEN + 0x874F: 0x246F, //CIRCLED NUMBER SIXTEEN + 0x8750: 0x2470, //CIRCLED NUMBER SEVENTEEN + 0x8751: 0x2471, //CIRCLED NUMBER EIGHTEEN + 0x8752: 0x2472, //CIRCLED NUMBER NINETEEN + 0x8753: 0x2473, //CIRCLED NUMBER TWENTY + 0x8754: 0x2160, //ROMAN NUMERAL ONE + 0x8755: 0x2161, //ROMAN NUMERAL TWO + 0x8756: 0x2162, //ROMAN NUMERAL THREE + 0x8757: 0x2163, //ROMAN NUMERAL FOUR + 0x8758: 0x2164, //ROMAN NUMERAL FIVE + 0x8759: 0x2165, //ROMAN NUMERAL SIX + 0x875A: 0x2166, //ROMAN NUMERAL SEVEN + 0x875B: 0x2167, //ROMAN NUMERAL EIGHT + 0x875C: 0x2168, //ROMAN NUMERAL NINE + 0x875D: 0x2169, //ROMAN NUMERAL TEN + 0x875F: 0x3349, //SQUARE MIRI + 0x8760: 0x3314, //SQUARE KIRO + 0x8761: 0x3322, //SQUARE SENTI + 0x8762: 0x334D, //SQUARE MEETORU + 0x8763: 0x3318, //SQUARE GURAMU + 0x8764: 0x3327, //SQUARE TON + 0x8765: 0x3303, //SQUARE AARU + 0x8766: 0x3336, //SQUARE HEKUTAARU + 0x8767: 0x3351, //SQUARE RITTORU + 0x8768: 0x3357, //SQUARE WATTO + 0x8769: 0x330D, //SQUARE KARORII + 0x876A: 0x3326, //SQUARE DORU + 0x876B: 0x3323, //SQUARE SENTO + 0x876C: 0x332B, //SQUARE PAASENTO + 0x876D: 0x334A, //SQUARE MIRIBAARU + 0x876E: 0x333B, //SQUARE PEEZI + 0x876F: 0x339C, //SQUARE MM + 0x8770: 0x339D, //SQUARE CM + 0x8771: 0x339E, //SQUARE KM + 0x8772: 0x338E, //SQUARE MG + 0x8773: 0x338F, //SQUARE KG + 0x8774: 0x33C4, //SQUARE CC + 0x8775: 0x33A1, //SQUARE M SQUARED + 0x877E: 0x337B, //SQUARE ERA NAME HEISEI + 0x8780: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0x8781: 0x301F, //LOW DOUBLE PRIME QUOTATION MARK + 0x8782: 0x2116, //NUMERO SIGN + 0x8783: 0x33CD, //SQUARE KK + 0x8784: 0x2121, //TELEPHONE SIGN + 0x8785: 0x32A4, //CIRCLED IDEOGRAPH HIGH + 0x8786: 0x32A5, //CIRCLED IDEOGRAPH CENTRE + 0x8787: 0x32A6, //CIRCLED IDEOGRAPH LOW + 0x8788: 0x32A7, //CIRCLED IDEOGRAPH LEFT + 0x8789: 0x32A8, //CIRCLED IDEOGRAPH RIGHT + 0x878A: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0x878B: 0x3232, //PARENTHESIZED IDEOGRAPH HAVE + 0x878C: 0x3239, //PARENTHESIZED IDEOGRAPH REPRESENT + 0x878D: 0x337E, //SQUARE ERA NAME MEIZI + 0x878E: 0x337D, //SQUARE ERA NAME TAISYOU + 0x878F: 0x337C, //SQUARE ERA NAME SYOUWA + 0x8790: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0x8791: 0x2261, //IDENTICAL TO + 0x8792: 0x222B, //INTEGRAL + 0x8793: 0x222E, //CONTOUR INTEGRAL + 0x8794: 0x2211, //N-ARY SUMMATION + 0x8795: 0x221A, //SQUARE ROOT + 0x8796: 0x22A5, //UP TACK + 0x8797: 0x2220, //ANGLE + 0x8798: 0x221F, //RIGHT ANGLE + 0x8799: 0x22BF, //RIGHT TRIANGLE + 0x879A: 0x2235, //BECAUSE + 0x879B: 0x2229, //INTERSECTION + 0x879C: 0x222A, //UNION + 0x889F: 0x4E9C, //CJK UNIFIED IDEOGRAPH + 0x88A0: 0x5516, //CJK UNIFIED IDEOGRAPH + 0x88A1: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0x88A2: 0x963F, //CJK UNIFIED IDEOGRAPH + 0x88A3: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0x88A4: 0x611B, //CJK UNIFIED IDEOGRAPH + 0x88A5: 0x6328, //CJK UNIFIED IDEOGRAPH + 0x88A6: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0x88A7: 0x9022, //CJK UNIFIED IDEOGRAPH + 0x88A8: 0x8475, //CJK UNIFIED IDEOGRAPH + 0x88A9: 0x831C, //CJK UNIFIED IDEOGRAPH + 0x88AA: 0x7A50, //CJK UNIFIED IDEOGRAPH + 0x88AB: 0x60AA, //CJK UNIFIED IDEOGRAPH + 0x88AC: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0x88AD: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0x88AE: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0x88AF: 0x8466, //CJK UNIFIED IDEOGRAPH + 0x88B0: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0x88B1: 0x9BF5, //CJK UNIFIED IDEOGRAPH + 0x88B2: 0x6893, //CJK UNIFIED IDEOGRAPH + 0x88B3: 0x5727, //CJK UNIFIED IDEOGRAPH + 0x88B4: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0x88B5: 0x6271, //CJK UNIFIED IDEOGRAPH + 0x88B6: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0x88B7: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0x88B8: 0x867B, //CJK UNIFIED IDEOGRAPH + 0x88B9: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0x88BA: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0x88BB: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0x88BC: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0x88BD: 0x6216, //CJK UNIFIED IDEOGRAPH + 0x88BE: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0x88BF: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0x88C0: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0x88C1: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0x88C2: 0x6309, //CJK UNIFIED IDEOGRAPH + 0x88C3: 0x6697, //CJK UNIFIED IDEOGRAPH + 0x88C4: 0x6848, //CJK UNIFIED IDEOGRAPH + 0x88C5: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0x88C6: 0x978D, //CJK UNIFIED IDEOGRAPH + 0x88C7: 0x674F, //CJK UNIFIED IDEOGRAPH + 0x88C8: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0x88C9: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0x88CA: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0x88CB: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0x88CC: 0x5049, //CJK UNIFIED IDEOGRAPH + 0x88CD: 0x56F2, //CJK UNIFIED IDEOGRAPH + 0x88CE: 0x5937, //CJK UNIFIED IDEOGRAPH + 0x88CF: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0x88D0: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0x88D1: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0x88D2: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0x88D3: 0x610F, //CJK UNIFIED IDEOGRAPH + 0x88D4: 0x6170, //CJK UNIFIED IDEOGRAPH + 0x88D5: 0x6613, //CJK UNIFIED IDEOGRAPH + 0x88D6: 0x6905, //CJK UNIFIED IDEOGRAPH + 0x88D7: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0x88D8: 0x754F, //CJK UNIFIED IDEOGRAPH + 0x88D9: 0x7570, //CJK UNIFIED IDEOGRAPH + 0x88DA: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0x88DB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0x88DC: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0x88DD: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0x88DE: 0x840E, //CJK UNIFIED IDEOGRAPH + 0x88DF: 0x8863, //CJK UNIFIED IDEOGRAPH + 0x88E0: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0x88E1: 0x9055, //CJK UNIFIED IDEOGRAPH + 0x88E2: 0x907A, //CJK UNIFIED IDEOGRAPH + 0x88E3: 0x533B, //CJK UNIFIED IDEOGRAPH + 0x88E4: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0x88E5: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0x88E6: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0x88E7: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0x88E8: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0x88E9: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0x88EA: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0x88EB: 0x58F1, //CJK UNIFIED IDEOGRAPH + 0x88EC: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0x88ED: 0x9038, //CJK UNIFIED IDEOGRAPH + 0x88EE: 0x7A32, //CJK UNIFIED IDEOGRAPH + 0x88EF: 0x8328, //CJK UNIFIED IDEOGRAPH + 0x88F0: 0x828B, //CJK UNIFIED IDEOGRAPH + 0x88F1: 0x9C2F, //CJK UNIFIED IDEOGRAPH + 0x88F2: 0x5141, //CJK UNIFIED IDEOGRAPH + 0x88F3: 0x5370, //CJK UNIFIED IDEOGRAPH + 0x88F4: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0x88F5: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0x88F6: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0x88F7: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0x88F8: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0x88F9: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0x88FA: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0x88FB: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0x88FC: 0x852D, //CJK UNIFIED IDEOGRAPH + 0x8940: 0x9662, //CJK UNIFIED IDEOGRAPH + 0x8941: 0x9670, //CJK UNIFIED IDEOGRAPH + 0x8942: 0x96A0, //CJK UNIFIED IDEOGRAPH + 0x8943: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0x8944: 0x540B, //CJK UNIFIED IDEOGRAPH + 0x8945: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0x8946: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0x8947: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0x8948: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0x8949: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0x894A: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0x894B: 0x536F, //CJK UNIFIED IDEOGRAPH + 0x894C: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0x894D: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0x894E: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0x894F: 0x7893, //CJK UNIFIED IDEOGRAPH + 0x8950: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0x8951: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0x8952: 0x5618, //CJK UNIFIED IDEOGRAPH + 0x8953: 0x5504, //CJK UNIFIED IDEOGRAPH + 0x8954: 0x6B1D, //CJK UNIFIED IDEOGRAPH + 0x8955: 0x851A, //CJK UNIFIED IDEOGRAPH + 0x8956: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0x8957: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0x8958: 0x53A9, //CJK UNIFIED IDEOGRAPH + 0x8959: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0x895A: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0x895B: 0x958F, //CJK UNIFIED IDEOGRAPH + 0x895C: 0x5642, //CJK UNIFIED IDEOGRAPH + 0x895D: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0x895E: 0x904B, //CJK UNIFIED IDEOGRAPH + 0x895F: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0x8960: 0x834F, //CJK UNIFIED IDEOGRAPH + 0x8961: 0x990C, //CJK UNIFIED IDEOGRAPH + 0x8962: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0x8963: 0x55B6, //CJK UNIFIED IDEOGRAPH + 0x8964: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0x8965: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0x8966: 0x6620, //CJK UNIFIED IDEOGRAPH + 0x8967: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0x8968: 0x6804, //CJK UNIFIED IDEOGRAPH + 0x8969: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0x896A: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0x896B: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0x896C: 0x745B, //CJK UNIFIED IDEOGRAPH + 0x896D: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0x896E: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0x896F: 0x9834, //CJK UNIFIED IDEOGRAPH + 0x8970: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0x8971: 0x885B, //CJK UNIFIED IDEOGRAPH + 0x8972: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0x8973: 0x92ED, //CJK UNIFIED IDEOGRAPH + 0x8974: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0x8975: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0x8976: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0x8977: 0x99C5, //CJK UNIFIED IDEOGRAPH + 0x8978: 0x60A6, //CJK UNIFIED IDEOGRAPH + 0x8979: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0x897A: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0x897B: 0x95B2, //CJK UNIFIED IDEOGRAPH + 0x897C: 0x698E, //CJK UNIFIED IDEOGRAPH + 0x897D: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0x897E: 0x5186, //CJK UNIFIED IDEOGRAPH + 0x8980: 0x5712, //CJK UNIFIED IDEOGRAPH + 0x8981: 0x5830, //CJK UNIFIED IDEOGRAPH + 0x8982: 0x5944, //CJK UNIFIED IDEOGRAPH + 0x8983: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0x8984: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0x8985: 0x6028, //CJK UNIFIED IDEOGRAPH + 0x8986: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0x8987: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0x8988: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0x8989: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0x898A: 0x708E, //CJK UNIFIED IDEOGRAPH + 0x898B: 0x7114, //CJK UNIFIED IDEOGRAPH + 0x898C: 0x7159, //CJK UNIFIED IDEOGRAPH + 0x898D: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0x898E: 0x733F, //CJK UNIFIED IDEOGRAPH + 0x898F: 0x7E01, //CJK UNIFIED IDEOGRAPH + 0x8990: 0x8276, //CJK UNIFIED IDEOGRAPH + 0x8991: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0x8992: 0x8597, //CJK UNIFIED IDEOGRAPH + 0x8993: 0x9060, //CJK UNIFIED IDEOGRAPH + 0x8994: 0x925B, //CJK UNIFIED IDEOGRAPH + 0x8995: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0x8996: 0x5869, //CJK UNIFIED IDEOGRAPH + 0x8997: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0x8998: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0x8999: 0x7525, //CJK UNIFIED IDEOGRAPH + 0x899A: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0x899B: 0x592E, //CJK UNIFIED IDEOGRAPH + 0x899C: 0x5965, //CJK UNIFIED IDEOGRAPH + 0x899D: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0x899E: 0x5FDC, //CJK UNIFIED IDEOGRAPH + 0x899F: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0x89A0: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0x89A1: 0x6A2A, //CJK UNIFIED IDEOGRAPH + 0x89A2: 0x6B27, //CJK UNIFIED IDEOGRAPH + 0x89A3: 0x6BB4, //CJK UNIFIED IDEOGRAPH + 0x89A4: 0x738B, //CJK UNIFIED IDEOGRAPH + 0x89A5: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0x89A6: 0x8956, //CJK UNIFIED IDEOGRAPH + 0x89A7: 0x9D2C, //CJK UNIFIED IDEOGRAPH + 0x89A8: 0x9D0E, //CJK UNIFIED IDEOGRAPH + 0x89A9: 0x9EC4, //CJK UNIFIED IDEOGRAPH + 0x89AA: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0x89AB: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0x89AC: 0x837B, //CJK UNIFIED IDEOGRAPH + 0x89AD: 0x5104, //CJK UNIFIED IDEOGRAPH + 0x89AE: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0x89AF: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0x89B0: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0x89B1: 0x6876, //CJK UNIFIED IDEOGRAPH + 0x89B2: 0x7261, //CJK UNIFIED IDEOGRAPH + 0x89B3: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0x89B4: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0x89B5: 0x5378, //CJK UNIFIED IDEOGRAPH + 0x89B6: 0x6069, //CJK UNIFIED IDEOGRAPH + 0x89B7: 0x6E29, //CJK UNIFIED IDEOGRAPH + 0x89B8: 0x7A4F, //CJK UNIFIED IDEOGRAPH + 0x89B9: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0x89BA: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0x89BB: 0x5316, //CJK UNIFIED IDEOGRAPH + 0x89BC: 0x4EEE, //CJK UNIFIED IDEOGRAPH + 0x89BD: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0x89BE: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0x89BF: 0x4FA1, //CJK UNIFIED IDEOGRAPH + 0x89C0: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0x89C1: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0x89C2: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0x89C3: 0x5609, //CJK UNIFIED IDEOGRAPH + 0x89C4: 0x590F, //CJK UNIFIED IDEOGRAPH + 0x89C5: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0x89C6: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0x89C7: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0x89C8: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0x89C9: 0x6687, //CJK UNIFIED IDEOGRAPH + 0x89CA: 0x679C, //CJK UNIFIED IDEOGRAPH + 0x89CB: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0x89CC: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0x89CD: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0x89CE: 0x706B, //CJK UNIFIED IDEOGRAPH + 0x89CF: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0x89D0: 0x798D, //CJK UNIFIED IDEOGRAPH + 0x89D1: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0x89D2: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0x89D3: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0x89D4: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0x89D5: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0x89D6: 0x8304, //CJK UNIFIED IDEOGRAPH + 0x89D7: 0x8377, //CJK UNIFIED IDEOGRAPH + 0x89D8: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0x89D9: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0x89DA: 0x8766, //CJK UNIFIED IDEOGRAPH + 0x89DB: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0x89DC: 0x5629, //CJK UNIFIED IDEOGRAPH + 0x89DD: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0x89DE: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0x89DF: 0x904E, //CJK UNIFIED IDEOGRAPH + 0x89E0: 0x971E, //CJK UNIFIED IDEOGRAPH + 0x89E1: 0x868A, //CJK UNIFIED IDEOGRAPH + 0x89E2: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0x89E3: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0x89E4: 0x6211, //CJK UNIFIED IDEOGRAPH + 0x89E5: 0x7259, //CJK UNIFIED IDEOGRAPH + 0x89E6: 0x753B, //CJK UNIFIED IDEOGRAPH + 0x89E7: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0x89E8: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0x89E9: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0x89EA: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0x89EB: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0x89EC: 0x9913, //CJK UNIFIED IDEOGRAPH + 0x89ED: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0x89EE: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0x89EF: 0x4F1A, //CJK UNIFIED IDEOGRAPH + 0x89F0: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0x89F1: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0x89F2: 0x584A, //CJK UNIFIED IDEOGRAPH + 0x89F3: 0x58CA, //CJK UNIFIED IDEOGRAPH + 0x89F4: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0x89F5: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0x89F6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0x89F7: 0x6094, //CJK UNIFIED IDEOGRAPH + 0x89F8: 0x6062, //CJK UNIFIED IDEOGRAPH + 0x89F9: 0x61D0, //CJK UNIFIED IDEOGRAPH + 0x89FA: 0x6212, //CJK UNIFIED IDEOGRAPH + 0x89FB: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0x89FC: 0x6539, //CJK UNIFIED IDEOGRAPH + 0x8A40: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0x8A41: 0x6666, //CJK UNIFIED IDEOGRAPH + 0x8A42: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0x8A43: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0x8A44: 0x7070, //CJK UNIFIED IDEOGRAPH + 0x8A45: 0x754C, //CJK UNIFIED IDEOGRAPH + 0x8A46: 0x7686, //CJK UNIFIED IDEOGRAPH + 0x8A47: 0x7D75, //CJK UNIFIED IDEOGRAPH + 0x8A48: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0x8A49: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0x8A4A: 0x958B, //CJK UNIFIED IDEOGRAPH + 0x8A4B: 0x968E, //CJK UNIFIED IDEOGRAPH + 0x8A4C: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0x8A4D: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0x8A4E: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0x8A4F: 0x5916, //CJK UNIFIED IDEOGRAPH + 0x8A50: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0x8A51: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0x8A52: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0x8A53: 0x6168, //CJK UNIFIED IDEOGRAPH + 0x8A54: 0x6982, //CJK UNIFIED IDEOGRAPH + 0x8A55: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0x8A56: 0x788D, //CJK UNIFIED IDEOGRAPH + 0x8A57: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0x8A58: 0x8857, //CJK UNIFIED IDEOGRAPH + 0x8A59: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0x8A5A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0x8A5B: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0x8A5C: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0x8A5D: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0x8A5E: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0x8A5F: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0x8A60: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0x8A61: 0x86CE, //CJK UNIFIED IDEOGRAPH + 0x8A62: 0x920E, //CJK UNIFIED IDEOGRAPH + 0x8A63: 0x5283, //CJK UNIFIED IDEOGRAPH + 0x8A64: 0x5687, //CJK UNIFIED IDEOGRAPH + 0x8A65: 0x5404, //CJK UNIFIED IDEOGRAPH + 0x8A66: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0x8A67: 0x62E1, //CJK UNIFIED IDEOGRAPH + 0x8A68: 0x64B9, //CJK UNIFIED IDEOGRAPH + 0x8A69: 0x683C, //CJK UNIFIED IDEOGRAPH + 0x8A6A: 0x6838, //CJK UNIFIED IDEOGRAPH + 0x8A6B: 0x6BBB, //CJK UNIFIED IDEOGRAPH + 0x8A6C: 0x7372, //CJK UNIFIED IDEOGRAPH + 0x8A6D: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0x8A6E: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0x8A6F: 0x899A, //CJK UNIFIED IDEOGRAPH + 0x8A70: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0x8A71: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0x8A72: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0x8A73: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0x8A74: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0x8A75: 0x9694, //CJK UNIFIED IDEOGRAPH + 0x8A76: 0x9769, //CJK UNIFIED IDEOGRAPH + 0x8A77: 0x5B66, //CJK UNIFIED IDEOGRAPH + 0x8A78: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0x8A79: 0x697D, //CJK UNIFIED IDEOGRAPH + 0x8A7A: 0x984D, //CJK UNIFIED IDEOGRAPH + 0x8A7B: 0x984E, //CJK UNIFIED IDEOGRAPH + 0x8A7C: 0x639B, //CJK UNIFIED IDEOGRAPH + 0x8A7D: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0x8A7E: 0x6A2B, //CJK UNIFIED IDEOGRAPH + 0x8A80: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0x8A81: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0x8A82: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0x8A83: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0x8A84: 0x5272, //CJK UNIFIED IDEOGRAPH + 0x8A85: 0x559D, //CJK UNIFIED IDEOGRAPH + 0x8A86: 0x6070, //CJK UNIFIED IDEOGRAPH + 0x8A87: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0x8A88: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0x8A89: 0x6E07, //CJK UNIFIED IDEOGRAPH + 0x8A8A: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0x8A8B: 0x845B, //CJK UNIFIED IDEOGRAPH + 0x8A8C: 0x8910, //CJK UNIFIED IDEOGRAPH + 0x8A8D: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0x8A8E: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0x8A8F: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0x8A90: 0x53F6, //CJK UNIFIED IDEOGRAPH + 0x8A91: 0x691B, //CJK UNIFIED IDEOGRAPH + 0x8A92: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0x8A93: 0x9784, //CJK UNIFIED IDEOGRAPH + 0x8A94: 0x682A, //CJK UNIFIED IDEOGRAPH + 0x8A95: 0x515C, //CJK UNIFIED IDEOGRAPH + 0x8A96: 0x7AC3, //CJK UNIFIED IDEOGRAPH + 0x8A97: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0x8A98: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0x8A99: 0x938C, //CJK UNIFIED IDEOGRAPH + 0x8A9A: 0x565B, //CJK UNIFIED IDEOGRAPH + 0x8A9B: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0x8A9C: 0x6822, //CJK UNIFIED IDEOGRAPH + 0x8A9D: 0x8305, //CJK UNIFIED IDEOGRAPH + 0x8A9E: 0x8431, //CJK UNIFIED IDEOGRAPH + 0x8A9F: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0x8AA0: 0x5208, //CJK UNIFIED IDEOGRAPH + 0x8AA1: 0x82C5, //CJK UNIFIED IDEOGRAPH + 0x8AA2: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0x8AA3: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0x8AA4: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0x8AA5: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0x8AA6: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0x8AA7: 0x520A, //CJK UNIFIED IDEOGRAPH + 0x8AA8: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0x8AA9: 0x52E7, //CJK UNIFIED IDEOGRAPH + 0x8AAA: 0x5DFB, //CJK UNIFIED IDEOGRAPH + 0x8AAB: 0x559A, //CJK UNIFIED IDEOGRAPH + 0x8AAC: 0x582A, //CJK UNIFIED IDEOGRAPH + 0x8AAD: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0x8AAE: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0x8AAF: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0x8AB0: 0x5BDB, //CJK UNIFIED IDEOGRAPH + 0x8AB1: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0x8AB2: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0x8AB3: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0x8AB4: 0x611F, //CJK UNIFIED IDEOGRAPH + 0x8AB5: 0x6163, //CJK UNIFIED IDEOGRAPH + 0x8AB6: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0x8AB7: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0x8AB8: 0x6562, //CJK UNIFIED IDEOGRAPH + 0x8AB9: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0x8ABA: 0x6853, //CJK UNIFIED IDEOGRAPH + 0x8ABB: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0x8ABC: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0x8ABD: 0x6B53, //CJK UNIFIED IDEOGRAPH + 0x8ABE: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0x8ABF: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0x8AC0: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0x8AC1: 0x6F45, //CJK UNIFIED IDEOGRAPH + 0x8AC2: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0x8AC3: 0x7518, //CJK UNIFIED IDEOGRAPH + 0x8AC4: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0x8AC5: 0x770B, //CJK UNIFIED IDEOGRAPH + 0x8AC6: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0x8AC7: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0x8AC8: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0x8AC9: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0x8ACA: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0x8ACB: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0x8ACC: 0x809D, //CJK UNIFIED IDEOGRAPH + 0x8ACD: 0x8266, //CJK UNIFIED IDEOGRAPH + 0x8ACE: 0x839E, //CJK UNIFIED IDEOGRAPH + 0x8ACF: 0x89B3, //CJK UNIFIED IDEOGRAPH + 0x8AD0: 0x8ACC, //CJK UNIFIED IDEOGRAPH + 0x8AD1: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0x8AD2: 0x9084, //CJK UNIFIED IDEOGRAPH + 0x8AD3: 0x9451, //CJK UNIFIED IDEOGRAPH + 0x8AD4: 0x9593, //CJK UNIFIED IDEOGRAPH + 0x8AD5: 0x9591, //CJK UNIFIED IDEOGRAPH + 0x8AD6: 0x95A2, //CJK UNIFIED IDEOGRAPH + 0x8AD7: 0x9665, //CJK UNIFIED IDEOGRAPH + 0x8AD8: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0x8AD9: 0x9928, //CJK UNIFIED IDEOGRAPH + 0x8ADA: 0x8218, //CJK UNIFIED IDEOGRAPH + 0x8ADB: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0x8ADC: 0x542B, //CJK UNIFIED IDEOGRAPH + 0x8ADD: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0x8ADE: 0x5DCC, //CJK UNIFIED IDEOGRAPH + 0x8ADF: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0x8AE0: 0x764C, //CJK UNIFIED IDEOGRAPH + 0x8AE1: 0x773C, //CJK UNIFIED IDEOGRAPH + 0x8AE2: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0x8AE3: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0x8AE4: 0x8D0B, //CJK UNIFIED IDEOGRAPH + 0x8AE5: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0x8AE6: 0x9811, //CJK UNIFIED IDEOGRAPH + 0x8AE7: 0x9854, //CJK UNIFIED IDEOGRAPH + 0x8AE8: 0x9858, //CJK UNIFIED IDEOGRAPH + 0x8AE9: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0x8AEA: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0x8AEB: 0x5371, //CJK UNIFIED IDEOGRAPH + 0x8AEC: 0x559C, //CJK UNIFIED IDEOGRAPH + 0x8AED: 0x5668, //CJK UNIFIED IDEOGRAPH + 0x8AEE: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0x8AEF: 0x5947, //CJK UNIFIED IDEOGRAPH + 0x8AF0: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0x8AF1: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0x8AF2: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0x8AF3: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0x8AF4: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0x8AF5: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0x8AF6: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0x8AF7: 0x673A, //CJK UNIFIED IDEOGRAPH + 0x8AF8: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0x8AF9: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0x8AFA: 0x671F, //CJK UNIFIED IDEOGRAPH + 0x8AFB: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0x8AFC: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0x8B40: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0x8B41: 0x5E30, //CJK UNIFIED IDEOGRAPH + 0x8B42: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0x8B43: 0x6C17, //CJK UNIFIED IDEOGRAPH + 0x8B44: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0x8B45: 0x757F, //CJK UNIFIED IDEOGRAPH + 0x8B46: 0x7948, //CJK UNIFIED IDEOGRAPH + 0x8B47: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0x8B48: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0x8B49: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0x8B4A: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0x8B4B: 0x898F, //CJK UNIFIED IDEOGRAPH + 0x8B4C: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0x8B4D: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0x8B4E: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0x8B4F: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0x8B50: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0x8B51: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0x8B52: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0x8B53: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0x8B54: 0x4E80, //CJK UNIFIED IDEOGRAPH + 0x8B55: 0x507D, //CJK UNIFIED IDEOGRAPH + 0x8B56: 0x5100, //CJK UNIFIED IDEOGRAPH + 0x8B57: 0x5993, //CJK UNIFIED IDEOGRAPH + 0x8B58: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0x8B59: 0x622F, //CJK UNIFIED IDEOGRAPH + 0x8B5A: 0x6280, //CJK UNIFIED IDEOGRAPH + 0x8B5B: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0x8B5C: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0x8B5D: 0x72A0, //CJK UNIFIED IDEOGRAPH + 0x8B5E: 0x7591, //CJK UNIFIED IDEOGRAPH + 0x8B5F: 0x7947, //CJK UNIFIED IDEOGRAPH + 0x8B60: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0x8B61: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0x8B62: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0x8B63: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0x8B64: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0x8B65: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0x8B66: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0x8B67: 0x5409, //CJK UNIFIED IDEOGRAPH + 0x8B68: 0x5403, //CJK UNIFIED IDEOGRAPH + 0x8B69: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0x8B6A: 0x6854, //CJK UNIFIED IDEOGRAPH + 0x8B6B: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0x8B6C: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0x8B6D: 0x7827, //CJK UNIFIED IDEOGRAPH + 0x8B6E: 0x6775, //CJK UNIFIED IDEOGRAPH + 0x8B6F: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0x8B70: 0x5374, //CJK UNIFIED IDEOGRAPH + 0x8B71: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0x8B72: 0x811A, //CJK UNIFIED IDEOGRAPH + 0x8B73: 0x8650, //CJK UNIFIED IDEOGRAPH + 0x8B74: 0x9006, //CJK UNIFIED IDEOGRAPH + 0x8B75: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0x8B76: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0x8B77: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0x8B78: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0x8B79: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0x8B7A: 0x5438, //CJK UNIFIED IDEOGRAPH + 0x8B7B: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0x8B7C: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0x8B7D: 0x6025, //CJK UNIFIED IDEOGRAPH + 0x8B7E: 0x6551, //CJK UNIFIED IDEOGRAPH + 0x8B80: 0x673D, //CJK UNIFIED IDEOGRAPH + 0x8B81: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0x8B82: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0x8B83: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0x8B84: 0x7078, //CJK UNIFIED IDEOGRAPH + 0x8B85: 0x7403, //CJK UNIFIED IDEOGRAPH + 0x8B86: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0x8B87: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0x8B88: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0x8B89: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0x8B8A: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0x8B8B: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0x8B8C: 0x65E7, //CJK UNIFIED IDEOGRAPH + 0x8B8D: 0x725B, //CJK UNIFIED IDEOGRAPH + 0x8B8E: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0x8B8F: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0x8B90: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0x8B91: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0x8B92: 0x62E0, //CJK UNIFIED IDEOGRAPH + 0x8B93: 0x6319, //CJK UNIFIED IDEOGRAPH + 0x8B94: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0x8B95: 0x865A, //CJK UNIFIED IDEOGRAPH + 0x8B96: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0x8B97: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0x8B98: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0x8B99: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0x8B9A: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0x8B9B: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0x8B9C: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0x8B9D: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0x8B9E: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0x8B9F: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0x8BA0: 0x4FA0, //CJK UNIFIED IDEOGRAPH + 0x8BA1: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0x8BA2: 0x5147, //CJK UNIFIED IDEOGRAPH + 0x8BA3: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0x8BA4: 0x5171, //CJK UNIFIED IDEOGRAPH + 0x8BA5: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0x8BA6: 0x5354, //CJK UNIFIED IDEOGRAPH + 0x8BA7: 0x5321, //CJK UNIFIED IDEOGRAPH + 0x8BA8: 0x537F, //CJK UNIFIED IDEOGRAPH + 0x8BA9: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0x8BAA: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0x8BAB: 0x5883, //CJK UNIFIED IDEOGRAPH + 0x8BAC: 0x5CE1, //CJK UNIFIED IDEOGRAPH + 0x8BAD: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0x8BAE: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0x8BAF: 0x602F, //CJK UNIFIED IDEOGRAPH + 0x8BB0: 0x6050, //CJK UNIFIED IDEOGRAPH + 0x8BB1: 0x606D, //CJK UNIFIED IDEOGRAPH + 0x8BB2: 0x631F, //CJK UNIFIED IDEOGRAPH + 0x8BB3: 0x6559, //CJK UNIFIED IDEOGRAPH + 0x8BB4: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0x8BB5: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0x8BB6: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0x8BB7: 0x72ED, //CJK UNIFIED IDEOGRAPH + 0x8BB8: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0x8BB9: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0x8BBA: 0x8105, //CJK UNIFIED IDEOGRAPH + 0x8BBB: 0x8208, //CJK UNIFIED IDEOGRAPH + 0x8BBC: 0x854E, //CJK UNIFIED IDEOGRAPH + 0x8BBD: 0x90F7, //CJK UNIFIED IDEOGRAPH + 0x8BBE: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0x8BBF: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0x8BC0: 0x9957, //CJK UNIFIED IDEOGRAPH + 0x8BC1: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0x8BC2: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0x8BC3: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0x8BC4: 0x5C2D, //CJK UNIFIED IDEOGRAPH + 0x8BC5: 0x6681, //CJK UNIFIED IDEOGRAPH + 0x8BC6: 0x696D, //CJK UNIFIED IDEOGRAPH + 0x8BC7: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0x8BC8: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0x8BC9: 0x6975, //CJK UNIFIED IDEOGRAPH + 0x8BCA: 0x7389, //CJK UNIFIED IDEOGRAPH + 0x8BCB: 0x6850, //CJK UNIFIED IDEOGRAPH + 0x8BCC: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0x8BCD: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0x8BCE: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0x8BCF: 0x5747, //CJK UNIFIED IDEOGRAPH + 0x8BD0: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0x8BD1: 0x9326, //CJK UNIFIED IDEOGRAPH + 0x8BD2: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0x8BD3: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0x8BD4: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0x8BD5: 0x7434, //CJK UNIFIED IDEOGRAPH + 0x8BD6: 0x7981, //CJK UNIFIED IDEOGRAPH + 0x8BD7: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0x8BD8: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0x8BD9: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0x8BDA: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0x8BDB: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0x8BDC: 0x887F, //CJK UNIFIED IDEOGRAPH + 0x8BDD: 0x895F, //CJK UNIFIED IDEOGRAPH + 0x8BDE: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0x8BDF: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0x8BE0: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0x8BE1: 0x541F, //CJK UNIFIED IDEOGRAPH + 0x8BE2: 0x9280, //CJK UNIFIED IDEOGRAPH + 0x8BE3: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0x8BE4: 0x5036, //CJK UNIFIED IDEOGRAPH + 0x8BE5: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0x8BE6: 0x533A, //CJK UNIFIED IDEOGRAPH + 0x8BE7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0x8BE8: 0x7396, //CJK UNIFIED IDEOGRAPH + 0x8BE9: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0x8BEA: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0x8BEB: 0x8EAF, //CJK UNIFIED IDEOGRAPH + 0x8BEC: 0x99C6, //CJK UNIFIED IDEOGRAPH + 0x8BED: 0x99C8, //CJK UNIFIED IDEOGRAPH + 0x8BEE: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0x8BEF: 0x5177, //CJK UNIFIED IDEOGRAPH + 0x8BF0: 0x611A, //CJK UNIFIED IDEOGRAPH + 0x8BF1: 0x865E, //CJK UNIFIED IDEOGRAPH + 0x8BF2: 0x55B0, //CJK UNIFIED IDEOGRAPH + 0x8BF3: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0x8BF4: 0x5076, //CJK UNIFIED IDEOGRAPH + 0x8BF5: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0x8BF6: 0x9047, //CJK UNIFIED IDEOGRAPH + 0x8BF7: 0x9685, //CJK UNIFIED IDEOGRAPH + 0x8BF8: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0x8BF9: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0x8BFA: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0x8BFB: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0x8BFC: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0x8C40: 0x6398, //CJK UNIFIED IDEOGRAPH + 0x8C41: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0x8C42: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0x8C43: 0x9774, //CJK UNIFIED IDEOGRAPH + 0x8C44: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0x8C45: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0x8C46: 0x718A, //CJK UNIFIED IDEOGRAPH + 0x8C47: 0x9688, //CJK UNIFIED IDEOGRAPH + 0x8C48: 0x7C82, //CJK UNIFIED IDEOGRAPH + 0x8C49: 0x6817, //CJK UNIFIED IDEOGRAPH + 0x8C4A: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0x8C4B: 0x6851, //CJK UNIFIED IDEOGRAPH + 0x8C4C: 0x936C, //CJK UNIFIED IDEOGRAPH + 0x8C4D: 0x52F2, //CJK UNIFIED IDEOGRAPH + 0x8C4E: 0x541B, //CJK UNIFIED IDEOGRAPH + 0x8C4F: 0x85AB, //CJK UNIFIED IDEOGRAPH + 0x8C50: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0x8C51: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0x8C52: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0x8C53: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0x8C54: 0x5366, //CJK UNIFIED IDEOGRAPH + 0x8C55: 0x8888, //CJK UNIFIED IDEOGRAPH + 0x8C56: 0x7941, //CJK UNIFIED IDEOGRAPH + 0x8C57: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0x8C58: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0x8C59: 0x5211, //CJK UNIFIED IDEOGRAPH + 0x8C5A: 0x5144, //CJK UNIFIED IDEOGRAPH + 0x8C5B: 0x5553, //CJK UNIFIED IDEOGRAPH + 0x8C5C: 0x572D, //CJK UNIFIED IDEOGRAPH + 0x8C5D: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0x8C5E: 0x578B, //CJK UNIFIED IDEOGRAPH + 0x8C5F: 0x5951, //CJK UNIFIED IDEOGRAPH + 0x8C60: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0x8C61: 0x5F84, //CJK UNIFIED IDEOGRAPH + 0x8C62: 0x6075, //CJK UNIFIED IDEOGRAPH + 0x8C63: 0x6176, //CJK UNIFIED IDEOGRAPH + 0x8C64: 0x6167, //CJK UNIFIED IDEOGRAPH + 0x8C65: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0x8C66: 0x63B2, //CJK UNIFIED IDEOGRAPH + 0x8C67: 0x643A, //CJK UNIFIED IDEOGRAPH + 0x8C68: 0x656C, //CJK UNIFIED IDEOGRAPH + 0x8C69: 0x666F, //CJK UNIFIED IDEOGRAPH + 0x8C6A: 0x6842, //CJK UNIFIED IDEOGRAPH + 0x8C6B: 0x6E13, //CJK UNIFIED IDEOGRAPH + 0x8C6C: 0x7566, //CJK UNIFIED IDEOGRAPH + 0x8C6D: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0x8C6E: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0x8C6F: 0x7D4C, //CJK UNIFIED IDEOGRAPH + 0x8C70: 0x7D99, //CJK UNIFIED IDEOGRAPH + 0x8C71: 0x7E4B, //CJK UNIFIED IDEOGRAPH + 0x8C72: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0x8C73: 0x830E, //CJK UNIFIED IDEOGRAPH + 0x8C74: 0x834A, //CJK UNIFIED IDEOGRAPH + 0x8C75: 0x86CD, //CJK UNIFIED IDEOGRAPH + 0x8C76: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0x8C77: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0x8C78: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0x8C79: 0x8EFD, //CJK UNIFIED IDEOGRAPH + 0x8C7A: 0x981A, //CJK UNIFIED IDEOGRAPH + 0x8C7B: 0x9D8F, //CJK UNIFIED IDEOGRAPH + 0x8C7C: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0x8C7D: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0x8C7E: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0x8C80: 0x5287, //CJK UNIFIED IDEOGRAPH + 0x8C81: 0x621F, //CJK UNIFIED IDEOGRAPH + 0x8C82: 0x6483, //CJK UNIFIED IDEOGRAPH + 0x8C83: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0x8C84: 0x9699, //CJK UNIFIED IDEOGRAPH + 0x8C85: 0x6841, //CJK UNIFIED IDEOGRAPH + 0x8C86: 0x5091, //CJK UNIFIED IDEOGRAPH + 0x8C87: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0x8C88: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0x8C89: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0x8C8A: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0x8C8B: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0x8C8C: 0x8840, //CJK UNIFIED IDEOGRAPH + 0x8C8D: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0x8C8E: 0x6708, //CJK UNIFIED IDEOGRAPH + 0x8C8F: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0x8C90: 0x5039, //CJK UNIFIED IDEOGRAPH + 0x8C91: 0x5026, //CJK UNIFIED IDEOGRAPH + 0x8C92: 0x5065, //CJK UNIFIED IDEOGRAPH + 0x8C93: 0x517C, //CJK UNIFIED IDEOGRAPH + 0x8C94: 0x5238, //CJK UNIFIED IDEOGRAPH + 0x8C95: 0x5263, //CJK UNIFIED IDEOGRAPH + 0x8C96: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0x8C97: 0x570F, //CJK UNIFIED IDEOGRAPH + 0x8C98: 0x5805, //CJK UNIFIED IDEOGRAPH + 0x8C99: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0x8C9A: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0x8C9B: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0x8C9C: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0x8C9D: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0x8C9E: 0x6372, //CJK UNIFIED IDEOGRAPH + 0x8C9F: 0x691C, //CJK UNIFIED IDEOGRAPH + 0x8CA0: 0x6A29, //CJK UNIFIED IDEOGRAPH + 0x8CA1: 0x727D, //CJK UNIFIED IDEOGRAPH + 0x8CA2: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0x8CA3: 0x732E, //CJK UNIFIED IDEOGRAPH + 0x8CA4: 0x7814, //CJK UNIFIED IDEOGRAPH + 0x8CA5: 0x786F, //CJK UNIFIED IDEOGRAPH + 0x8CA6: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0x8CA7: 0x770C, //CJK UNIFIED IDEOGRAPH + 0x8CA8: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0x8CA9: 0x898B, //CJK UNIFIED IDEOGRAPH + 0x8CAA: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0x8CAB: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0x8CAC: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0x8CAD: 0x9063, //CJK UNIFIED IDEOGRAPH + 0x8CAE: 0x9375, //CJK UNIFIED IDEOGRAPH + 0x8CAF: 0x967A, //CJK UNIFIED IDEOGRAPH + 0x8CB0: 0x9855, //CJK UNIFIED IDEOGRAPH + 0x8CB1: 0x9A13, //CJK UNIFIED IDEOGRAPH + 0x8CB2: 0x9E78, //CJK UNIFIED IDEOGRAPH + 0x8CB3: 0x5143, //CJK UNIFIED IDEOGRAPH + 0x8CB4: 0x539F, //CJK UNIFIED IDEOGRAPH + 0x8CB5: 0x53B3, //CJK UNIFIED IDEOGRAPH + 0x8CB6: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0x8CB7: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0x8CB8: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0x8CB9: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0x8CBA: 0x7384, //CJK UNIFIED IDEOGRAPH + 0x8CBB: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0x8CBC: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0x8CBD: 0x8237, //CJK UNIFIED IDEOGRAPH + 0x8CBE: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0x8CBF: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0x8CC0: 0x9650, //CJK UNIFIED IDEOGRAPH + 0x8CC1: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0x8CC2: 0x500B, //CJK UNIFIED IDEOGRAPH + 0x8CC3: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0x8CC4: 0x547C, //CJK UNIFIED IDEOGRAPH + 0x8CC5: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0x8CC6: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0x8CC7: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0x8CC8: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0x8CC9: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0x8CCA: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0x8CCB: 0x6238, //CJK UNIFIED IDEOGRAPH + 0x8CCC: 0x6545, //CJK UNIFIED IDEOGRAPH + 0x8CCD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0x8CCE: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0x8CCF: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0x8CD0: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0x8CD1: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0x8CD2: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0x8CD3: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0x8CD4: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0x8CD5: 0x864E, //CJK UNIFIED IDEOGRAPH + 0x8CD6: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0x8CD7: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0x8CD8: 0x9237, //CJK UNIFIED IDEOGRAPH + 0x8CD9: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0x8CDA: 0x9867, //CJK UNIFIED IDEOGRAPH + 0x8CDB: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0x8CDC: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0x8CDD: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0x8CDE: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0x8CDF: 0x5348, //CJK UNIFIED IDEOGRAPH + 0x8CE0: 0x5449, //CJK UNIFIED IDEOGRAPH + 0x8CE1: 0x543E, //CJK UNIFIED IDEOGRAPH + 0x8CE2: 0x5A2F, //CJK UNIFIED IDEOGRAPH + 0x8CE3: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0x8CE4: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0x8CE5: 0x609F, //CJK UNIFIED IDEOGRAPH + 0x8CE6: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0x8CE7: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0x8CE8: 0x745A, //CJK UNIFIED IDEOGRAPH + 0x8CE9: 0x7881, //CJK UNIFIED IDEOGRAPH + 0x8CEA: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0x8CEB: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0x8CEC: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0x8CED: 0x9190, //CJK UNIFIED IDEOGRAPH + 0x8CEE: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0x8CEF: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0x8CF0: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0x8CF1: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0x8CF2: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0x8CF3: 0x5019, //CJK UNIFIED IDEOGRAPH + 0x8CF4: 0x5016, //CJK UNIFIED IDEOGRAPH + 0x8CF5: 0x5149, //CJK UNIFIED IDEOGRAPH + 0x8CF6: 0x516C, //CJK UNIFIED IDEOGRAPH + 0x8CF7: 0x529F, //CJK UNIFIED IDEOGRAPH + 0x8CF8: 0x52B9, //CJK UNIFIED IDEOGRAPH + 0x8CF9: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0x8CFA: 0x539A, //CJK UNIFIED IDEOGRAPH + 0x8CFB: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0x8CFC: 0x5411, //CJK UNIFIED IDEOGRAPH + 0x8D40: 0x540E, //CJK UNIFIED IDEOGRAPH + 0x8D41: 0x5589, //CJK UNIFIED IDEOGRAPH + 0x8D42: 0x5751, //CJK UNIFIED IDEOGRAPH + 0x8D43: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0x8D44: 0x597D, //CJK UNIFIED IDEOGRAPH + 0x8D45: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0x8D46: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0x8D47: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0x8D48: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0x8D49: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0x8D4A: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0x8D4B: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0x8D4C: 0x5E83, //CJK UNIFIED IDEOGRAPH + 0x8D4D: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0x8D4E: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0x8D4F: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0x8D50: 0x6052, //CJK UNIFIED IDEOGRAPH + 0x8D51: 0x614C, //CJK UNIFIED IDEOGRAPH + 0x8D52: 0x6297, //CJK UNIFIED IDEOGRAPH + 0x8D53: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0x8D54: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0x8D55: 0x653B, //CJK UNIFIED IDEOGRAPH + 0x8D56: 0x6602, //CJK UNIFIED IDEOGRAPH + 0x8D57: 0x6643, //CJK UNIFIED IDEOGRAPH + 0x8D58: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0x8D59: 0x676D, //CJK UNIFIED IDEOGRAPH + 0x8D5A: 0x6821, //CJK UNIFIED IDEOGRAPH + 0x8D5B: 0x6897, //CJK UNIFIED IDEOGRAPH + 0x8D5C: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0x8D5D: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0x8D5E: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0x8D5F: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0x8D60: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0x8D61: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0x8D62: 0x7532, //CJK UNIFIED IDEOGRAPH + 0x8D63: 0x7687, //CJK UNIFIED IDEOGRAPH + 0x8D64: 0x786C, //CJK UNIFIED IDEOGRAPH + 0x8D65: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0x8D66: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0x8D67: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0x8D68: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0x8D69: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0x8D6A: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0x8D6B: 0x8015, //CJK UNIFIED IDEOGRAPH + 0x8D6C: 0x8003, //CJK UNIFIED IDEOGRAPH + 0x8D6D: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0x8D6E: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0x8D6F: 0x8154, //CJK UNIFIED IDEOGRAPH + 0x8D70: 0x818F, //CJK UNIFIED IDEOGRAPH + 0x8D71: 0x822A, //CJK UNIFIED IDEOGRAPH + 0x8D72: 0x8352, //CJK UNIFIED IDEOGRAPH + 0x8D73: 0x884C, //CJK UNIFIED IDEOGRAPH + 0x8D74: 0x8861, //CJK UNIFIED IDEOGRAPH + 0x8D75: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0x8D76: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0x8D77: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0x8D78: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0x8D79: 0x9175, //CJK UNIFIED IDEOGRAPH + 0x8D7A: 0x9271, //CJK UNIFIED IDEOGRAPH + 0x8D7B: 0x783F, //CJK UNIFIED IDEOGRAPH + 0x8D7C: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0x8D7D: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0x8D7E: 0x964D, //CJK UNIFIED IDEOGRAPH + 0x8D80: 0x9805, //CJK UNIFIED IDEOGRAPH + 0x8D81: 0x9999, //CJK UNIFIED IDEOGRAPH + 0x8D82: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0x8D83: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0x8D84: 0x525B, //CJK UNIFIED IDEOGRAPH + 0x8D85: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0x8D86: 0x53F7, //CJK UNIFIED IDEOGRAPH + 0x8D87: 0x5408, //CJK UNIFIED IDEOGRAPH + 0x8D88: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0x8D89: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0x8D8A: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0x8D8B: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0x8D8C: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0x8D8D: 0x9EB9, //CJK UNIFIED IDEOGRAPH + 0x8D8E: 0x514B, //CJK UNIFIED IDEOGRAPH + 0x8D8F: 0x523B, //CJK UNIFIED IDEOGRAPH + 0x8D90: 0x544A, //CJK UNIFIED IDEOGRAPH + 0x8D91: 0x56FD, //CJK UNIFIED IDEOGRAPH + 0x8D92: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0x8D93: 0x9177, //CJK UNIFIED IDEOGRAPH + 0x8D94: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0x8D95: 0x9ED2, //CJK UNIFIED IDEOGRAPH + 0x8D96: 0x7344, //CJK UNIFIED IDEOGRAPH + 0x8D97: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0x8D98: 0x8170, //CJK UNIFIED IDEOGRAPH + 0x8D99: 0x7511, //CJK UNIFIED IDEOGRAPH + 0x8D9A: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0x8D9B: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0x8D9C: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0x8D9D: 0x72DB, //CJK UNIFIED IDEOGRAPH + 0x8D9E: 0x8FBC, //CJK UNIFIED IDEOGRAPH + 0x8D9F: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0x8DA0: 0x9803, //CJK UNIFIED IDEOGRAPH + 0x8DA1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0x8DA2: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0x8DA3: 0x5764, //CJK UNIFIED IDEOGRAPH + 0x8DA4: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0x8DA5: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0x8DA6: 0x6068, //CJK UNIFIED IDEOGRAPH + 0x8DA7: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0x8DA8: 0x660F, //CJK UNIFIED IDEOGRAPH + 0x8DA9: 0x6606, //CJK UNIFIED IDEOGRAPH + 0x8DAA: 0x6839, //CJK UNIFIED IDEOGRAPH + 0x8DAB: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0x8DAC: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0x8DAD: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0x8DAE: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0x8DAF: 0x826E, //CJK UNIFIED IDEOGRAPH + 0x8DB0: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0x8DB1: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0x8DB2: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0x8DB3: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0x8DB4: 0x5506, //CJK UNIFIED IDEOGRAPH + 0x8DB5: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0x8DB6: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0x8DB7: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0x8DB8: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0x8DB9: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0x8DBA: 0x7473, //CJK UNIFIED IDEOGRAPH + 0x8DBB: 0x7802, //CJK UNIFIED IDEOGRAPH + 0x8DBC: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0x8DBD: 0x9396, //CJK UNIFIED IDEOGRAPH + 0x8DBE: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0x8DBF: 0x5750, //CJK UNIFIED IDEOGRAPH + 0x8DC0: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0x8DC1: 0x632B, //CJK UNIFIED IDEOGRAPH + 0x8DC2: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0x8DC3: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0x8DC4: 0x518D, //CJK UNIFIED IDEOGRAPH + 0x8DC5: 0x6700, //CJK UNIFIED IDEOGRAPH + 0x8DC6: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0x8DC7: 0x585E, //CJK UNIFIED IDEOGRAPH + 0x8DC8: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0x8DC9: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0x8DCA: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0x8DCB: 0x624D, //CJK UNIFIED IDEOGRAPH + 0x8DCC: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0x8DCD: 0x683D, //CJK UNIFIED IDEOGRAPH + 0x8DCE: 0x6B73, //CJK UNIFIED IDEOGRAPH + 0x8DCF: 0x6E08, //CJK UNIFIED IDEOGRAPH + 0x8DD0: 0x707D, //CJK UNIFIED IDEOGRAPH + 0x8DD1: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0x8DD2: 0x7280, //CJK UNIFIED IDEOGRAPH + 0x8DD3: 0x7815, //CJK UNIFIED IDEOGRAPH + 0x8DD4: 0x7826, //CJK UNIFIED IDEOGRAPH + 0x8DD5: 0x796D, //CJK UNIFIED IDEOGRAPH + 0x8DD6: 0x658E, //CJK UNIFIED IDEOGRAPH + 0x8DD7: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0x8DD8: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0x8DD9: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0x8DDA: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0x8DDB: 0x969B, //CJK UNIFIED IDEOGRAPH + 0x8DDC: 0x5264, //CJK UNIFIED IDEOGRAPH + 0x8DDD: 0x5728, //CJK UNIFIED IDEOGRAPH + 0x8DDE: 0x6750, //CJK UNIFIED IDEOGRAPH + 0x8DDF: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0x8DE0: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0x8DE1: 0x51B4, //CJK UNIFIED IDEOGRAPH + 0x8DE2: 0x5742, //CJK UNIFIED IDEOGRAPH + 0x8DE3: 0x962A, //CJK UNIFIED IDEOGRAPH + 0x8DE4: 0x583A, //CJK UNIFIED IDEOGRAPH + 0x8DE5: 0x698A, //CJK UNIFIED IDEOGRAPH + 0x8DE6: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0x8DE7: 0x54B2, //CJK UNIFIED IDEOGRAPH + 0x8DE8: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0x8DE9: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0x8DEA: 0x7895, //CJK UNIFIED IDEOGRAPH + 0x8DEB: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0x8DEC: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0x8DED: 0x524A, //CJK UNIFIED IDEOGRAPH + 0x8DEE: 0x548B, //CJK UNIFIED IDEOGRAPH + 0x8DEF: 0x643E, //CJK UNIFIED IDEOGRAPH + 0x8DF0: 0x6628, //CJK UNIFIED IDEOGRAPH + 0x8DF1: 0x6714, //CJK UNIFIED IDEOGRAPH + 0x8DF2: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0x8DF3: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0x8DF4: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0x8DF5: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0x8DF6: 0x932F, //CJK UNIFIED IDEOGRAPH + 0x8DF7: 0x685C, //CJK UNIFIED IDEOGRAPH + 0x8DF8: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0x8DF9: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0x8DFA: 0x5319, //CJK UNIFIED IDEOGRAPH + 0x8DFB: 0x518A, //CJK UNIFIED IDEOGRAPH + 0x8DFC: 0x5237, //CJK UNIFIED IDEOGRAPH + 0x8E40: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0x8E41: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0x8E42: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0x8E43: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0x8E44: 0x672D, //CJK UNIFIED IDEOGRAPH + 0x8E45: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0x8E46: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0x8E47: 0x96D1, //CJK UNIFIED IDEOGRAPH + 0x8E48: 0x7690, //CJK UNIFIED IDEOGRAPH + 0x8E49: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0x8E4A: 0x634C, //CJK UNIFIED IDEOGRAPH + 0x8E4B: 0x9306, //CJK UNIFIED IDEOGRAPH + 0x8E4C: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0x8E4D: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0x8E4E: 0x6652, //CJK UNIFIED IDEOGRAPH + 0x8E4F: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0x8E50: 0x5098, //CJK UNIFIED IDEOGRAPH + 0x8E51: 0x53C2, //CJK UNIFIED IDEOGRAPH + 0x8E52: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0x8E53: 0x60E8, //CJK UNIFIED IDEOGRAPH + 0x8E54: 0x6492, //CJK UNIFIED IDEOGRAPH + 0x8E55: 0x6563, //CJK UNIFIED IDEOGRAPH + 0x8E56: 0x685F, //CJK UNIFIED IDEOGRAPH + 0x8E57: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0x8E58: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0x8E59: 0x7523, //CJK UNIFIED IDEOGRAPH + 0x8E5A: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0x8E5B: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0x8E5C: 0x8695, //CJK UNIFIED IDEOGRAPH + 0x8E5D: 0x8B83, //CJK UNIFIED IDEOGRAPH + 0x8E5E: 0x8CDB, //CJK UNIFIED IDEOGRAPH + 0x8E5F: 0x9178, //CJK UNIFIED IDEOGRAPH + 0x8E60: 0x9910, //CJK UNIFIED IDEOGRAPH + 0x8E61: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0x8E62: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0x8E63: 0x6B8B, //CJK UNIFIED IDEOGRAPH + 0x8E64: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0x8E65: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0x8E66: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0x8E67: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0x8E68: 0x523A, //CJK UNIFIED IDEOGRAPH + 0x8E69: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0x8E6A: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0x8E6B: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0x8E6C: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0x8E6D: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0x8E6E: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0x8E6F: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0x8E70: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0x8E71: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0x8E72: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0x8E73: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0x8E74: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0x8E75: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0x8E76: 0x601D, //CJK UNIFIED IDEOGRAPH + 0x8E77: 0x6307, //CJK UNIFIED IDEOGRAPH + 0x8E78: 0x652F, //CJK UNIFIED IDEOGRAPH + 0x8E79: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0x8E7A: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0x8E7B: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0x8E7C: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0x8E7D: 0x679D, //CJK UNIFIED IDEOGRAPH + 0x8E7E: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0x8E80: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0x8E81: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0x8E82: 0x7345, //CJK UNIFIED IDEOGRAPH + 0x8E83: 0x7949, //CJK UNIFIED IDEOGRAPH + 0x8E84: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0x8E85: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0x8E86: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0x8E87: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0x8E88: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0x8E89: 0x8102, //CJK UNIFIED IDEOGRAPH + 0x8E8A: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0x8E8B: 0x8996, //CJK UNIFIED IDEOGRAPH + 0x8E8C: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0x8E8D: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0x8E8E: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0x8E8F: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0x8E90: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0x8E91: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0x8E92: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0x8E93: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0x8E94: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0x8E95: 0x6B6F, //CJK UNIFIED IDEOGRAPH + 0x8E96: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0x8E97: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0x8E98: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0x8E99: 0x5150, //CJK UNIFIED IDEOGRAPH + 0x8E9A: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0x8E9B: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0x8E9C: 0x6148, //CJK UNIFIED IDEOGRAPH + 0x8E9D: 0x6301, //CJK UNIFIED IDEOGRAPH + 0x8E9E: 0x6642, //CJK UNIFIED IDEOGRAPH + 0x8E9F: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0x8EA0: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0x8EA1: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0x8EA2: 0x723E, //CJK UNIFIED IDEOGRAPH + 0x8EA3: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0x8EA4: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0x8EA5: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0x8EA6: 0x793A, //CJK UNIFIED IDEOGRAPH + 0x8EA7: 0x800C, //CJK UNIFIED IDEOGRAPH + 0x8EA8: 0x8033, //CJK UNIFIED IDEOGRAPH + 0x8EA9: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0x8EAA: 0x8494, //CJK UNIFIED IDEOGRAPH + 0x8EAB: 0x8F9E, //CJK UNIFIED IDEOGRAPH + 0x8EAC: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0x8EAD: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0x8EAE: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0x8EAF: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0x8EB0: 0x9D2B, //CJK UNIFIED IDEOGRAPH + 0x8EB1: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0x8EB2: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0x8EB3: 0x5B8D, //CJK UNIFIED IDEOGRAPH + 0x8EB4: 0x96EB, //CJK UNIFIED IDEOGRAPH + 0x8EB5: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0x8EB6: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0x8EB7: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0x8EB8: 0x5931, //CJK UNIFIED IDEOGRAPH + 0x8EB9: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0x8EBA: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0x8EBB: 0x6089, //CJK UNIFIED IDEOGRAPH + 0x8EBC: 0x6E7F, //CJK UNIFIED IDEOGRAPH + 0x8EBD: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0x8EBE: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0x8EBF: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0x8EC0: 0x5B9F, //CJK UNIFIED IDEOGRAPH + 0x8EC1: 0x8500, //CJK UNIFIED IDEOGRAPH + 0x8EC2: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0x8EC3: 0x5072, //CJK UNIFIED IDEOGRAPH + 0x8EC4: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0x8EC5: 0x829D, //CJK UNIFIED IDEOGRAPH + 0x8EC6: 0x5C61, //CJK UNIFIED IDEOGRAPH + 0x8EC7: 0x854A, //CJK UNIFIED IDEOGRAPH + 0x8EC8: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0x8EC9: 0x820E, //CJK UNIFIED IDEOGRAPH + 0x8ECA: 0x5199, //CJK UNIFIED IDEOGRAPH + 0x8ECB: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0x8ECC: 0x6368, //CJK UNIFIED IDEOGRAPH + 0x8ECD: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0x8ECE: 0x659C, //CJK UNIFIED IDEOGRAPH + 0x8ECF: 0x716E, //CJK UNIFIED IDEOGRAPH + 0x8ED0: 0x793E, //CJK UNIFIED IDEOGRAPH + 0x8ED1: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0x8ED2: 0x8005, //CJK UNIFIED IDEOGRAPH + 0x8ED3: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0x8ED4: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0x8ED5: 0x906E, //CJK UNIFIED IDEOGRAPH + 0x8ED6: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0x8ED7: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0x8ED8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0x8ED9: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0x8EDA: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0x8EDB: 0x6753, //CJK UNIFIED IDEOGRAPH + 0x8EDC: 0x707C, //CJK UNIFIED IDEOGRAPH + 0x8EDD: 0x7235, //CJK UNIFIED IDEOGRAPH + 0x8EDE: 0x914C, //CJK UNIFIED IDEOGRAPH + 0x8EDF: 0x91C8, //CJK UNIFIED IDEOGRAPH + 0x8EE0: 0x932B, //CJK UNIFIED IDEOGRAPH + 0x8EE1: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0x8EE2: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0x8EE3: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0x8EE4: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0x8EE5: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0x8EE6: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0x8EE7: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0x8EE8: 0x624B, //CJK UNIFIED IDEOGRAPH + 0x8EE9: 0x6731, //CJK UNIFIED IDEOGRAPH + 0x8EEA: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0x8EEB: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0x8EEC: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0x8EED: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0x8EEE: 0x816B, //CJK UNIFIED IDEOGRAPH + 0x8EEF: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0x8EF0: 0x9152, //CJK UNIFIED IDEOGRAPH + 0x8EF1: 0x9996, //CJK UNIFIED IDEOGRAPH + 0x8EF2: 0x5112, //CJK UNIFIED IDEOGRAPH + 0x8EF3: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0x8EF4: 0x546A, //CJK UNIFIED IDEOGRAPH + 0x8EF5: 0x5BFF, //CJK UNIFIED IDEOGRAPH + 0x8EF6: 0x6388, //CJK UNIFIED IDEOGRAPH + 0x8EF7: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0x8EF8: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0x8EF9: 0x9700, //CJK UNIFIED IDEOGRAPH + 0x8EFA: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0x8EFB: 0x53CE, //CJK UNIFIED IDEOGRAPH + 0x8EFC: 0x5468, //CJK UNIFIED IDEOGRAPH + 0x8F40: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0x8F41: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0x8F42: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0x8F43: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0x8F44: 0x6101, //CJK UNIFIED IDEOGRAPH + 0x8F45: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0x8F46: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0x8F47: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0x8F48: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0x8F49: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0x8F4A: 0x7E4D, //CJK UNIFIED IDEOGRAPH + 0x8F4B: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0x8F4C: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0x8F4D: 0x821F, //CJK UNIFIED IDEOGRAPH + 0x8F4E: 0x8490, //CJK UNIFIED IDEOGRAPH + 0x8F4F: 0x8846, //CJK UNIFIED IDEOGRAPH + 0x8F50: 0x8972, //CJK UNIFIED IDEOGRAPH + 0x8F51: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0x8F52: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0x8F53: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0x8F54: 0x9031, //CJK UNIFIED IDEOGRAPH + 0x8F55: 0x914B, //CJK UNIFIED IDEOGRAPH + 0x8F56: 0x916C, //CJK UNIFIED IDEOGRAPH + 0x8F57: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0x8F58: 0x919C, //CJK UNIFIED IDEOGRAPH + 0x8F59: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0x8F5A: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0x8F5B: 0x5145, //CJK UNIFIED IDEOGRAPH + 0x8F5C: 0x5341, //CJK UNIFIED IDEOGRAPH + 0x8F5D: 0x5F93, //CJK UNIFIED IDEOGRAPH + 0x8F5E: 0x620E, //CJK UNIFIED IDEOGRAPH + 0x8F5F: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0x8F60: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0x8F61: 0x6E0B, //CJK UNIFIED IDEOGRAPH + 0x8F62: 0x7363, //CJK UNIFIED IDEOGRAPH + 0x8F63: 0x7E26, //CJK UNIFIED IDEOGRAPH + 0x8F64: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0x8F65: 0x9283, //CJK UNIFIED IDEOGRAPH + 0x8F66: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0x8F67: 0x5919, //CJK UNIFIED IDEOGRAPH + 0x8F68: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0x8F69: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0x8F6A: 0x795D, //CJK UNIFIED IDEOGRAPH + 0x8F6B: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0x8F6C: 0x7C9B, //CJK UNIFIED IDEOGRAPH + 0x8F6D: 0x587E, //CJK UNIFIED IDEOGRAPH + 0x8F6E: 0x719F, //CJK UNIFIED IDEOGRAPH + 0x8F6F: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0x8F70: 0x8853, //CJK UNIFIED IDEOGRAPH + 0x8F71: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0x8F72: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0x8F73: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0x8F74: 0x6625, //CJK UNIFIED IDEOGRAPH + 0x8F75: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0x8F76: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0x8F77: 0x821C, //CJK UNIFIED IDEOGRAPH + 0x8F78: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0x8F79: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0x8F7A: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0x8F7B: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0x8F7C: 0x696F, //CJK UNIFIED IDEOGRAPH + 0x8F7D: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0x8F7E: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0x8F80: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0x8F81: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0x8F82: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0x8F83: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0x8F84: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0x8F85: 0x9075, //CJK UNIFIED IDEOGRAPH + 0x8F86: 0x9187, //CJK UNIFIED IDEOGRAPH + 0x8F87: 0x9806, //CJK UNIFIED IDEOGRAPH + 0x8F88: 0x51E6, //CJK UNIFIED IDEOGRAPH + 0x8F89: 0x521D, //CJK UNIFIED IDEOGRAPH + 0x8F8A: 0x6240, //CJK UNIFIED IDEOGRAPH + 0x8F8B: 0x6691, //CJK UNIFIED IDEOGRAPH + 0x8F8C: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0x8F8D: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0x8F8E: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0x8F8F: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0x8F90: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0x8F91: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0x8F92: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0x8F93: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0x8F94: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0x8F95: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0x8F96: 0x53D9, //CJK UNIFIED IDEOGRAPH + 0x8F97: 0x5973, //CJK UNIFIED IDEOGRAPH + 0x8F98: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0x8F99: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0x8F9A: 0x6055, //CJK UNIFIED IDEOGRAPH + 0x8F9B: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0x8F9C: 0x9664, //CJK UNIFIED IDEOGRAPH + 0x8F9D: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0x8F9E: 0x511F, //CJK UNIFIED IDEOGRAPH + 0x8F9F: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0x8FA0: 0x5320, //CJK UNIFIED IDEOGRAPH + 0x8FA1: 0x5347, //CJK UNIFIED IDEOGRAPH + 0x8FA2: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0x8FA3: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0x8FA4: 0x5546, //CJK UNIFIED IDEOGRAPH + 0x8FA5: 0x5531, //CJK UNIFIED IDEOGRAPH + 0x8FA6: 0x5617, //CJK UNIFIED IDEOGRAPH + 0x8FA7: 0x5968, //CJK UNIFIED IDEOGRAPH + 0x8FA8: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0x8FA9: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0x8FAA: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0x8FAB: 0x5C06, //CJK UNIFIED IDEOGRAPH + 0x8FAC: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0x8FAD: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0x8FAE: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0x8FAF: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0x8FB0: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0x8FB1: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0x8FB2: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0x8FB3: 0x627F, //CJK UNIFIED IDEOGRAPH + 0x8FB4: 0x6284, //CJK UNIFIED IDEOGRAPH + 0x8FB5: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0x8FB6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0x8FB7: 0x6377, //CJK UNIFIED IDEOGRAPH + 0x8FB8: 0x6607, //CJK UNIFIED IDEOGRAPH + 0x8FB9: 0x660C, //CJK UNIFIED IDEOGRAPH + 0x8FBA: 0x662D, //CJK UNIFIED IDEOGRAPH + 0x8FBB: 0x6676, //CJK UNIFIED IDEOGRAPH + 0x8FBC: 0x677E, //CJK UNIFIED IDEOGRAPH + 0x8FBD: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0x8FBE: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0x8FBF: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0x8FC0: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0x8FC1: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0x8FC2: 0x6E09, //CJK UNIFIED IDEOGRAPH + 0x8FC3: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0x8FC4: 0x713C, //CJK UNIFIED IDEOGRAPH + 0x8FC5: 0x7126, //CJK UNIFIED IDEOGRAPH + 0x8FC6: 0x7167, //CJK UNIFIED IDEOGRAPH + 0x8FC7: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0x8FC8: 0x7701, //CJK UNIFIED IDEOGRAPH + 0x8FC9: 0x785D, //CJK UNIFIED IDEOGRAPH + 0x8FCA: 0x7901, //CJK UNIFIED IDEOGRAPH + 0x8FCB: 0x7965, //CJK UNIFIED IDEOGRAPH + 0x8FCC: 0x79F0, //CJK UNIFIED IDEOGRAPH + 0x8FCD: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0x8FCE: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0x8FCF: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0x8FD0: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0x8FD1: 0x8096, //CJK UNIFIED IDEOGRAPH + 0x8FD2: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0x8FD3: 0x848B, //CJK UNIFIED IDEOGRAPH + 0x8FD4: 0x8549, //CJK UNIFIED IDEOGRAPH + 0x8FD5: 0x885D, //CJK UNIFIED IDEOGRAPH + 0x8FD6: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0x8FD7: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0x8FD8: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0x8FD9: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0x8FDA: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0x8FDB: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0x8FDC: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0x8FDD: 0x91A4, //CJK UNIFIED IDEOGRAPH + 0x8FDE: 0x9266, //CJK UNIFIED IDEOGRAPH + 0x8FDF: 0x937E, //CJK UNIFIED IDEOGRAPH + 0x8FE0: 0x9418, //CJK UNIFIED IDEOGRAPH + 0x8FE1: 0x969C, //CJK UNIFIED IDEOGRAPH + 0x8FE2: 0x9798, //CJK UNIFIED IDEOGRAPH + 0x8FE3: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0x8FE4: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0x8FE5: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0x8FE6: 0x4E57, //CJK UNIFIED IDEOGRAPH + 0x8FE7: 0x5197, //CJK UNIFIED IDEOGRAPH + 0x8FE8: 0x5270, //CJK UNIFIED IDEOGRAPH + 0x8FE9: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0x8FEA: 0x5834, //CJK UNIFIED IDEOGRAPH + 0x8FEB: 0x58CC, //CJK UNIFIED IDEOGRAPH + 0x8FEC: 0x5B22, //CJK UNIFIED IDEOGRAPH + 0x8FED: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0x8FEE: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0x8FEF: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0x8FF0: 0x6761, //CJK UNIFIED IDEOGRAPH + 0x8FF1: 0x6756, //CJK UNIFIED IDEOGRAPH + 0x8FF2: 0x6D44, //CJK UNIFIED IDEOGRAPH + 0x8FF3: 0x72B6, //CJK UNIFIED IDEOGRAPH + 0x8FF4: 0x7573, //CJK UNIFIED IDEOGRAPH + 0x8FF5: 0x7A63, //CJK UNIFIED IDEOGRAPH + 0x8FF6: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0x8FF7: 0x8B72, //CJK UNIFIED IDEOGRAPH + 0x8FF8: 0x91B8, //CJK UNIFIED IDEOGRAPH + 0x8FF9: 0x9320, //CJK UNIFIED IDEOGRAPH + 0x8FFA: 0x5631, //CJK UNIFIED IDEOGRAPH + 0x8FFB: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0x8FFC: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0x9040: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0x9041: 0x690D, //CJK UNIFIED IDEOGRAPH + 0x9042: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0x9043: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0x9044: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0x9045: 0x8077, //CJK UNIFIED IDEOGRAPH + 0x9046: 0x8272, //CJK UNIFIED IDEOGRAPH + 0x9047: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0x9048: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0x9049: 0x8755, //CJK UNIFIED IDEOGRAPH + 0x904A: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0x904B: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0x904C: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0x904D: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0x904E: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0x904F: 0x5507, //CJK UNIFIED IDEOGRAPH + 0x9050: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0x9051: 0x5BDD, //CJK UNIFIED IDEOGRAPH + 0x9052: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0x9053: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0x9054: 0x614E, //CJK UNIFIED IDEOGRAPH + 0x9055: 0x632F, //CJK UNIFIED IDEOGRAPH + 0x9056: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0x9057: 0x664B, //CJK UNIFIED IDEOGRAPH + 0x9058: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0x9059: 0x699B, //CJK UNIFIED IDEOGRAPH + 0x905A: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0x905B: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0x905C: 0x7533, //CJK UNIFIED IDEOGRAPH + 0x905D: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0x905E: 0x771F, //CJK UNIFIED IDEOGRAPH + 0x905F: 0x795E, //CJK UNIFIED IDEOGRAPH + 0x9060: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0x9061: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0x9062: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0x9063: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0x9064: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0x9065: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0x9066: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0x9067: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0x9068: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0x9069: 0x9032, //CJK UNIFIED IDEOGRAPH + 0x906A: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0x906B: 0x9707, //CJK UNIFIED IDEOGRAPH + 0x906C: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0x906D: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0x906E: 0x5203, //CJK UNIFIED IDEOGRAPH + 0x906F: 0x5875, //CJK UNIFIED IDEOGRAPH + 0x9070: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0x9071: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0x9072: 0x751A, //CJK UNIFIED IDEOGRAPH + 0x9073: 0x5C3D, //CJK UNIFIED IDEOGRAPH + 0x9074: 0x814E, //CJK UNIFIED IDEOGRAPH + 0x9075: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0x9076: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0x9077: 0x9663, //CJK UNIFIED IDEOGRAPH + 0x9078: 0x976D, //CJK UNIFIED IDEOGRAPH + 0x9079: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0x907A: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0x907B: 0x9808, //CJK UNIFIED IDEOGRAPH + 0x907C: 0x9162, //CJK UNIFIED IDEOGRAPH + 0x907D: 0x56F3, //CJK UNIFIED IDEOGRAPH + 0x907E: 0x53A8, //CJK UNIFIED IDEOGRAPH + 0x9080: 0x9017, //CJK UNIFIED IDEOGRAPH + 0x9081: 0x5439, //CJK UNIFIED IDEOGRAPH + 0x9082: 0x5782, //CJK UNIFIED IDEOGRAPH + 0x9083: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0x9084: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0x9085: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0x9086: 0x708A, //CJK UNIFIED IDEOGRAPH + 0x9087: 0x7761, //CJK UNIFIED IDEOGRAPH + 0x9088: 0x7C8B, //CJK UNIFIED IDEOGRAPH + 0x9089: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0x908A: 0x8870, //CJK UNIFIED IDEOGRAPH + 0x908B: 0x9042, //CJK UNIFIED IDEOGRAPH + 0x908C: 0x9154, //CJK UNIFIED IDEOGRAPH + 0x908D: 0x9310, //CJK UNIFIED IDEOGRAPH + 0x908E: 0x9318, //CJK UNIFIED IDEOGRAPH + 0x908F: 0x968F, //CJK UNIFIED IDEOGRAPH + 0x9090: 0x745E, //CJK UNIFIED IDEOGRAPH + 0x9091: 0x9AC4, //CJK UNIFIED IDEOGRAPH + 0x9092: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0x9093: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0x9094: 0x6570, //CJK UNIFIED IDEOGRAPH + 0x9095: 0x67A2, //CJK UNIFIED IDEOGRAPH + 0x9096: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0x9097: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0x9098: 0x636E, //CJK UNIFIED IDEOGRAPH + 0x9099: 0x6749, //CJK UNIFIED IDEOGRAPH + 0x909A: 0x6919, //CJK UNIFIED IDEOGRAPH + 0x909B: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0x909C: 0x9817, //CJK UNIFIED IDEOGRAPH + 0x909D: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0x909E: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0x909F: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0x90A0: 0x647A, //CJK UNIFIED IDEOGRAPH + 0x90A1: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0x90A2: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0x90A3: 0x702C, //CJK UNIFIED IDEOGRAPH + 0x90A4: 0x755D, //CJK UNIFIED IDEOGRAPH + 0x90A5: 0x662F, //CJK UNIFIED IDEOGRAPH + 0x90A6: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0x90A7: 0x5236, //CJK UNIFIED IDEOGRAPH + 0x90A8: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0x90A9: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0x90AA: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0x90AB: 0x6027, //CJK UNIFIED IDEOGRAPH + 0x90AC: 0x6210, //CJK UNIFIED IDEOGRAPH + 0x90AD: 0x653F, //CJK UNIFIED IDEOGRAPH + 0x90AE: 0x6574, //CJK UNIFIED IDEOGRAPH + 0x90AF: 0x661F, //CJK UNIFIED IDEOGRAPH + 0x90B0: 0x6674, //CJK UNIFIED IDEOGRAPH + 0x90B1: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0x90B2: 0x6816, //CJK UNIFIED IDEOGRAPH + 0x90B3: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0x90B4: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0x90B5: 0x7272, //CJK UNIFIED IDEOGRAPH + 0x90B6: 0x751F, //CJK UNIFIED IDEOGRAPH + 0x90B7: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0x90B8: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0x90B9: 0x8056, //CJK UNIFIED IDEOGRAPH + 0x90BA: 0x58F0, //CJK UNIFIED IDEOGRAPH + 0x90BB: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0x90BC: 0x897F, //CJK UNIFIED IDEOGRAPH + 0x90BD: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0x90BE: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0x90BF: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0x90C0: 0x901D, //CJK UNIFIED IDEOGRAPH + 0x90C1: 0x9192, //CJK UNIFIED IDEOGRAPH + 0x90C2: 0x9752, //CJK UNIFIED IDEOGRAPH + 0x90C3: 0x9759, //CJK UNIFIED IDEOGRAPH + 0x90C4: 0x6589, //CJK UNIFIED IDEOGRAPH + 0x90C5: 0x7A0E, //CJK UNIFIED IDEOGRAPH + 0x90C6: 0x8106, //CJK UNIFIED IDEOGRAPH + 0x90C7: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0x90C8: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0x90C9: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0x90CA: 0x621A, //CJK UNIFIED IDEOGRAPH + 0x90CB: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0x90CC: 0x6614, //CJK UNIFIED IDEOGRAPH + 0x90CD: 0x6790, //CJK UNIFIED IDEOGRAPH + 0x90CE: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0x90CF: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0x90D0: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0x90D1: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0x90D2: 0x810A, //CJK UNIFIED IDEOGRAPH + 0x90D3: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0x90D4: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0x90D5: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0x90D6: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0x90D7: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0x90D8: 0x5207, //CJK UNIFIED IDEOGRAPH + 0x90D9: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0x90DA: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0x90DB: 0x6442, //CJK UNIFIED IDEOGRAPH + 0x90DC: 0x6298, //CJK UNIFIED IDEOGRAPH + 0x90DD: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0x90DE: 0x7A83, //CJK UNIFIED IDEOGRAPH + 0x90DF: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0x90E0: 0x8AAC, //CJK UNIFIED IDEOGRAPH + 0x90E1: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0x90E2: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0x90E3: 0x820C, //CJK UNIFIED IDEOGRAPH + 0x90E4: 0x8749, //CJK UNIFIED IDEOGRAPH + 0x90E5: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0x90E6: 0x5148, //CJK UNIFIED IDEOGRAPH + 0x90E7: 0x5343, //CJK UNIFIED IDEOGRAPH + 0x90E8: 0x5360, //CJK UNIFIED IDEOGRAPH + 0x90E9: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0x90EA: 0x5C02, //CJK UNIFIED IDEOGRAPH + 0x90EB: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0x90EC: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0x90ED: 0x6226, //CJK UNIFIED IDEOGRAPH + 0x90EE: 0x6247, //CJK UNIFIED IDEOGRAPH + 0x90EF: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0x90F0: 0x6813, //CJK UNIFIED IDEOGRAPH + 0x90F1: 0x6834, //CJK UNIFIED IDEOGRAPH + 0x90F2: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0x90F3: 0x6D45, //CJK UNIFIED IDEOGRAPH + 0x90F4: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0x90F5: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0x90F6: 0x6F5C, //CJK UNIFIED IDEOGRAPH + 0x90F7: 0x714E, //CJK UNIFIED IDEOGRAPH + 0x90F8: 0x717D, //CJK UNIFIED IDEOGRAPH + 0x90F9: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0x90FA: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0x90FB: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0x90FC: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0x9140: 0x7E4A, //CJK UNIFIED IDEOGRAPH + 0x9141: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0x9142: 0x817A, //CJK UNIFIED IDEOGRAPH + 0x9143: 0x821B, //CJK UNIFIED IDEOGRAPH + 0x9144: 0x8239, //CJK UNIFIED IDEOGRAPH + 0x9145: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0x9146: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0x9147: 0x8CCE, //CJK UNIFIED IDEOGRAPH + 0x9148: 0x8DF5, //CJK UNIFIED IDEOGRAPH + 0x9149: 0x9078, //CJK UNIFIED IDEOGRAPH + 0x914A: 0x9077, //CJK UNIFIED IDEOGRAPH + 0x914B: 0x92AD, //CJK UNIFIED IDEOGRAPH + 0x914C: 0x9291, //CJK UNIFIED IDEOGRAPH + 0x914D: 0x9583, //CJK UNIFIED IDEOGRAPH + 0x914E: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0x914F: 0x524D, //CJK UNIFIED IDEOGRAPH + 0x9150: 0x5584, //CJK UNIFIED IDEOGRAPH + 0x9151: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0x9152: 0x7136, //CJK UNIFIED IDEOGRAPH + 0x9153: 0x5168, //CJK UNIFIED IDEOGRAPH + 0x9154: 0x7985, //CJK UNIFIED IDEOGRAPH + 0x9155: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0x9156: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0x9157: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0x9158: 0x564C, //CJK UNIFIED IDEOGRAPH + 0x9159: 0x5851, //CJK UNIFIED IDEOGRAPH + 0x915A: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0x915B: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0x915C: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0x915D: 0x66FD, //CJK UNIFIED IDEOGRAPH + 0x915E: 0x695A, //CJK UNIFIED IDEOGRAPH + 0x915F: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0x9160: 0x758F, //CJK UNIFIED IDEOGRAPH + 0x9161: 0x758E, //CJK UNIFIED IDEOGRAPH + 0x9162: 0x790E, //CJK UNIFIED IDEOGRAPH + 0x9163: 0x7956, //CJK UNIFIED IDEOGRAPH + 0x9164: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0x9165: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0x9166: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0x9167: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0x9168: 0x8607, //CJK UNIFIED IDEOGRAPH + 0x9169: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0x916A: 0x963B, //CJK UNIFIED IDEOGRAPH + 0x916B: 0x9061, //CJK UNIFIED IDEOGRAPH + 0x916C: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0x916D: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0x916E: 0x5275, //CJK UNIFIED IDEOGRAPH + 0x916F: 0x53CC, //CJK UNIFIED IDEOGRAPH + 0x9170: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0x9171: 0x5009, //CJK UNIFIED IDEOGRAPH + 0x9172: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0x9173: 0x58EE, //CJK UNIFIED IDEOGRAPH + 0x9174: 0x594F, //CJK UNIFIED IDEOGRAPH + 0x9175: 0x723D, //CJK UNIFIED IDEOGRAPH + 0x9176: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0x9177: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0x9178: 0x531D, //CJK UNIFIED IDEOGRAPH + 0x9179: 0x60E3, //CJK UNIFIED IDEOGRAPH + 0x917A: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0x917B: 0x635C, //CJK UNIFIED IDEOGRAPH + 0x917C: 0x6383, //CJK UNIFIED IDEOGRAPH + 0x917D: 0x633F, //CJK UNIFIED IDEOGRAPH + 0x917E: 0x63BB, //CJK UNIFIED IDEOGRAPH + 0x9180: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0x9181: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0x9182: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0x9183: 0x5DE3, //CJK UNIFIED IDEOGRAPH + 0x9184: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0x9185: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0x9186: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0x9187: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0x9188: 0x4E89, //CJK UNIFIED IDEOGRAPH + 0x9189: 0x75E9, //CJK UNIFIED IDEOGRAPH + 0x918A: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0x918B: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0x918C: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0x918D: 0x7DCF, //CJK UNIFIED IDEOGRAPH + 0x918E: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0x918F: 0x8061, //CJK UNIFIED IDEOGRAPH + 0x9190: 0x8349, //CJK UNIFIED IDEOGRAPH + 0x9191: 0x8358, //CJK UNIFIED IDEOGRAPH + 0x9192: 0x846C, //CJK UNIFIED IDEOGRAPH + 0x9193: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0x9194: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0x9195: 0x88C5, //CJK UNIFIED IDEOGRAPH + 0x9196: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0x9197: 0x9001, //CJK UNIFIED IDEOGRAPH + 0x9198: 0x906D, //CJK UNIFIED IDEOGRAPH + 0x9199: 0x9397, //CJK UNIFIED IDEOGRAPH + 0x919A: 0x971C, //CJK UNIFIED IDEOGRAPH + 0x919B: 0x9A12, //CJK UNIFIED IDEOGRAPH + 0x919C: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0x919D: 0x5897, //CJK UNIFIED IDEOGRAPH + 0x919E: 0x618E, //CJK UNIFIED IDEOGRAPH + 0x919F: 0x81D3, //CJK UNIFIED IDEOGRAPH + 0x91A0: 0x8535, //CJK UNIFIED IDEOGRAPH + 0x91A1: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0x91A2: 0x9020, //CJK UNIFIED IDEOGRAPH + 0x91A3: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0x91A4: 0x5074, //CJK UNIFIED IDEOGRAPH + 0x91A5: 0x5247, //CJK UNIFIED IDEOGRAPH + 0x91A6: 0x5373, //CJK UNIFIED IDEOGRAPH + 0x91A7: 0x606F, //CJK UNIFIED IDEOGRAPH + 0x91A8: 0x6349, //CJK UNIFIED IDEOGRAPH + 0x91A9: 0x675F, //CJK UNIFIED IDEOGRAPH + 0x91AA: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0x91AB: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0x91AC: 0x901F, //CJK UNIFIED IDEOGRAPH + 0x91AD: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0x91AE: 0x5C5E, //CJK UNIFIED IDEOGRAPH + 0x91AF: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0x91B0: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0x91B1: 0x7D9A, //CJK UNIFIED IDEOGRAPH + 0x91B2: 0x5352, //CJK UNIFIED IDEOGRAPH + 0x91B3: 0x8896, //CJK UNIFIED IDEOGRAPH + 0x91B4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0x91B5: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0x91B6: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0x91B7: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0x91B8: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0x91B9: 0x640D, //CJK UNIFIED IDEOGRAPH + 0x91BA: 0x6751, //CJK UNIFIED IDEOGRAPH + 0x91BB: 0x905C, //CJK UNIFIED IDEOGRAPH + 0x91BC: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0x91BD: 0x591A, //CJK UNIFIED IDEOGRAPH + 0x91BE: 0x592A, //CJK UNIFIED IDEOGRAPH + 0x91BF: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0x91C0: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0x91C1: 0x553E, //CJK UNIFIED IDEOGRAPH + 0x91C2: 0x5815, //CJK UNIFIED IDEOGRAPH + 0x91C3: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0x91C4: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0x91C5: 0x6253, //CJK UNIFIED IDEOGRAPH + 0x91C6: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0x91C7: 0x8235, //CJK UNIFIED IDEOGRAPH + 0x91C8: 0x6955, //CJK UNIFIED IDEOGRAPH + 0x91C9: 0x9640, //CJK UNIFIED IDEOGRAPH + 0x91CA: 0x99C4, //CJK UNIFIED IDEOGRAPH + 0x91CB: 0x9A28, //CJK UNIFIED IDEOGRAPH + 0x91CC: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0x91CD: 0x5806, //CJK UNIFIED IDEOGRAPH + 0x91CE: 0x5BFE, //CJK UNIFIED IDEOGRAPH + 0x91CF: 0x8010, //CJK UNIFIED IDEOGRAPH + 0x91D0: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0x91D1: 0x5E2F, //CJK UNIFIED IDEOGRAPH + 0x91D2: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0x91D3: 0x6020, //CJK UNIFIED IDEOGRAPH + 0x91D4: 0x614B, //CJK UNIFIED IDEOGRAPH + 0x91D5: 0x6234, //CJK UNIFIED IDEOGRAPH + 0x91D6: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0x91D7: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0x91D8: 0x6EDE, //CJK UNIFIED IDEOGRAPH + 0x91D9: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0x91DA: 0x817F, //CJK UNIFIED IDEOGRAPH + 0x91DB: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0x91DC: 0x888B, //CJK UNIFIED IDEOGRAPH + 0x91DD: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0x91DE: 0x9000, //CJK UNIFIED IDEOGRAPH + 0x91DF: 0x902E, //CJK UNIFIED IDEOGRAPH + 0x91E0: 0x968A, //CJK UNIFIED IDEOGRAPH + 0x91E1: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0x91E2: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0x91E3: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0x91E4: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0x91E5: 0x5927, //CJK UNIFIED IDEOGRAPH + 0x91E6: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0x91E7: 0x918D, //CJK UNIFIED IDEOGRAPH + 0x91E8: 0x984C, //CJK UNIFIED IDEOGRAPH + 0x91E9: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0x91EA: 0x6EDD, //CJK UNIFIED IDEOGRAPH + 0x91EB: 0x7027, //CJK UNIFIED IDEOGRAPH + 0x91EC: 0x5353, //CJK UNIFIED IDEOGRAPH + 0x91ED: 0x5544, //CJK UNIFIED IDEOGRAPH + 0x91EE: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0x91EF: 0x6258, //CJK UNIFIED IDEOGRAPH + 0x91F0: 0x629E, //CJK UNIFIED IDEOGRAPH + 0x91F1: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0x91F2: 0x6CA2, //CJK UNIFIED IDEOGRAPH + 0x91F3: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0x91F4: 0x7422, //CJK UNIFIED IDEOGRAPH + 0x91F5: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0x91F6: 0x9438, //CJK UNIFIED IDEOGRAPH + 0x91F7: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0x91F8: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0x91F9: 0x8338, //CJK UNIFIED IDEOGRAPH + 0x91FA: 0x51E7, //CJK UNIFIED IDEOGRAPH + 0x91FB: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0x91FC: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0x9240: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0x9241: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0x9242: 0x9054, //CJK UNIFIED IDEOGRAPH + 0x9243: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0x9244: 0x596A, //CJK UNIFIED IDEOGRAPH + 0x9245: 0x8131, //CJK UNIFIED IDEOGRAPH + 0x9246: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0x9247: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0x9248: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0x9249: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0x924A: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0x924B: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0x924C: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0x924D: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0x924E: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0x924F: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0x9250: 0x5358, //CJK UNIFIED IDEOGRAPH + 0x9251: 0x5606, //CJK UNIFIED IDEOGRAPH + 0x9252: 0x5766, //CJK UNIFIED IDEOGRAPH + 0x9253: 0x62C5, //CJK UNIFIED IDEOGRAPH + 0x9254: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0x9255: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0x9256: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0x9257: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0x9258: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0x9259: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0x925A: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0x925B: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0x925C: 0x7BAA, //CJK UNIFIED IDEOGRAPH + 0x925D: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0x925E: 0x803D, //CJK UNIFIED IDEOGRAPH + 0x925F: 0x80C6, //CJK UNIFIED IDEOGRAPH + 0x9260: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0x9261: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0x9262: 0x935B, //CJK UNIFIED IDEOGRAPH + 0x9263: 0x56E3, //CJK UNIFIED IDEOGRAPH + 0x9264: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0x9265: 0x5F3E, //CJK UNIFIED IDEOGRAPH + 0x9266: 0x65AD, //CJK UNIFIED IDEOGRAPH + 0x9267: 0x6696, //CJK UNIFIED IDEOGRAPH + 0x9268: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0x9269: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0x926A: 0x7537, //CJK UNIFIED IDEOGRAPH + 0x926B: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0x926C: 0x5024, //CJK UNIFIED IDEOGRAPH + 0x926D: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0x926E: 0x5730, //CJK UNIFIED IDEOGRAPH + 0x926F: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0x9270: 0x6065, //CJK UNIFIED IDEOGRAPH + 0x9271: 0x667A, //CJK UNIFIED IDEOGRAPH + 0x9272: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0x9273: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0x9274: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0x9275: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0x9276: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0x9277: 0x8718, //CJK UNIFIED IDEOGRAPH + 0x9278: 0x9045, //CJK UNIFIED IDEOGRAPH + 0x9279: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0x927A: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0x927B: 0x755C, //CJK UNIFIED IDEOGRAPH + 0x927C: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0x927D: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0x927E: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0x9280: 0x9010, //CJK UNIFIED IDEOGRAPH + 0x9281: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0x9282: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0x9283: 0x8336, //CJK UNIFIED IDEOGRAPH + 0x9284: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0x9285: 0x7740, //CJK UNIFIED IDEOGRAPH + 0x9286: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0x9287: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0x9288: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0x9289: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0x928A: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0x928B: 0x663C, //CJK UNIFIED IDEOGRAPH + 0x928C: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0x928D: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0x928E: 0x866B, //CJK UNIFIED IDEOGRAPH + 0x928F: 0x8877, //CJK UNIFIED IDEOGRAPH + 0x9290: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0x9291: 0x914E, //CJK UNIFIED IDEOGRAPH + 0x9292: 0x92F3, //CJK UNIFIED IDEOGRAPH + 0x9293: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0x9294: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0x9295: 0x7026, //CJK UNIFIED IDEOGRAPH + 0x9296: 0x732A, //CJK UNIFIED IDEOGRAPH + 0x9297: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0x9298: 0x8457, //CJK UNIFIED IDEOGRAPH + 0x9299: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0x929A: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0x929B: 0x5146, //CJK UNIFIED IDEOGRAPH + 0x929C: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0x929D: 0x558B, //CJK UNIFIED IDEOGRAPH + 0x929E: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0x929F: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0x92A0: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0x92A1: 0x5E81, //CJK UNIFIED IDEOGRAPH + 0x92A2: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0x92A3: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0x92A4: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0x92A5: 0x5FB4, //CJK UNIFIED IDEOGRAPH + 0x92A6: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0x92A7: 0x6311, //CJK UNIFIED IDEOGRAPH + 0x92A8: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0x92A9: 0x671D, //CJK UNIFIED IDEOGRAPH + 0x92AA: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0x92AB: 0x7252, //CJK UNIFIED IDEOGRAPH + 0x92AC: 0x753A, //CJK UNIFIED IDEOGRAPH + 0x92AD: 0x773A, //CJK UNIFIED IDEOGRAPH + 0x92AE: 0x8074, //CJK UNIFIED IDEOGRAPH + 0x92AF: 0x8139, //CJK UNIFIED IDEOGRAPH + 0x92B0: 0x8178, //CJK UNIFIED IDEOGRAPH + 0x92B1: 0x8776, //CJK UNIFIED IDEOGRAPH + 0x92B2: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0x92B3: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0x92B4: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0x92B5: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0x92B6: 0x929A, //CJK UNIFIED IDEOGRAPH + 0x92B7: 0x9577, //CJK UNIFIED IDEOGRAPH + 0x92B8: 0x9802, //CJK UNIFIED IDEOGRAPH + 0x92B9: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0x92BA: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0x92BB: 0x6357, //CJK UNIFIED IDEOGRAPH + 0x92BC: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0x92BD: 0x6715, //CJK UNIFIED IDEOGRAPH + 0x92BE: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0x92BF: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0x92C0: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0x92C1: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0x92C2: 0x9673, //CJK UNIFIED IDEOGRAPH + 0x92C3: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0x92C4: 0x589C, //CJK UNIFIED IDEOGRAPH + 0x92C5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0x92C6: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0x92C7: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0x92C8: 0x939A, //CJK UNIFIED IDEOGRAPH + 0x92C9: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0x92CA: 0x901A, //CJK UNIFIED IDEOGRAPH + 0x92CB: 0x585A, //CJK UNIFIED IDEOGRAPH + 0x92CC: 0x6802, //CJK UNIFIED IDEOGRAPH + 0x92CD: 0x63B4, //CJK UNIFIED IDEOGRAPH + 0x92CE: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0x92CF: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0x92D0: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0x92D1: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0x92D2: 0x8FBB, //CJK UNIFIED IDEOGRAPH + 0x92D3: 0x8526, //CJK UNIFIED IDEOGRAPH + 0x92D4: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0x92D5: 0x9354, //CJK UNIFIED IDEOGRAPH + 0x92D6: 0x693F, //CJK UNIFIED IDEOGRAPH + 0x92D7: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0x92D8: 0x576A, //CJK UNIFIED IDEOGRAPH + 0x92D9: 0x58F7, //CJK UNIFIED IDEOGRAPH + 0x92DA: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0x92DB: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0x92DC: 0x722A, //CJK UNIFIED IDEOGRAPH + 0x92DD: 0x540A, //CJK UNIFIED IDEOGRAPH + 0x92DE: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0x92DF: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0x92E0: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0x92E1: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0x92E2: 0x505C, //CJK UNIFIED IDEOGRAPH + 0x92E3: 0x5075, //CJK UNIFIED IDEOGRAPH + 0x92E4: 0x5243, //CJK UNIFIED IDEOGRAPH + 0x92E5: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0x92E6: 0x5448, //CJK UNIFIED IDEOGRAPH + 0x92E7: 0x5824, //CJK UNIFIED IDEOGRAPH + 0x92E8: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0x92E9: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0x92EA: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0x92EB: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0x92EC: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0x92ED: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0x92EE: 0x608C, //CJK UNIFIED IDEOGRAPH + 0x92EF: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0x92F0: 0x633A, //CJK UNIFIED IDEOGRAPH + 0x92F1: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0x92F2: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0x92F3: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0x92F4: 0x7887, //CJK UNIFIED IDEOGRAPH + 0x92F5: 0x798E, //CJK UNIFIED IDEOGRAPH + 0x92F6: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0x92F7: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0x92F8: 0x8247, //CJK UNIFIED IDEOGRAPH + 0x92F9: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0x92FA: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0x92FB: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0x92FC: 0x9013, //CJK UNIFIED IDEOGRAPH + 0x9340: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0x9341: 0x912D, //CJK UNIFIED IDEOGRAPH + 0x9342: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0x9343: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0x9344: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0x9345: 0x6458, //CJK UNIFIED IDEOGRAPH + 0x9346: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0x9347: 0x6575, //CJK UNIFIED IDEOGRAPH + 0x9348: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0x9349: 0x7684, //CJK UNIFIED IDEOGRAPH + 0x934A: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0x934B: 0x9069, //CJK UNIFIED IDEOGRAPH + 0x934C: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0x934D: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0x934E: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0x934F: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0x9350: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0x9351: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0x9352: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0x9353: 0x9244, //CJK UNIFIED IDEOGRAPH + 0x9354: 0x5178, //CJK UNIFIED IDEOGRAPH + 0x9355: 0x586B, //CJK UNIFIED IDEOGRAPH + 0x9356: 0x5929, //CJK UNIFIED IDEOGRAPH + 0x9357: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0x9358: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0x9359: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0x935A: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0x935B: 0x751C, //CJK UNIFIED IDEOGRAPH + 0x935C: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0x935D: 0x8EE2, //CJK UNIFIED IDEOGRAPH + 0x935E: 0x985B, //CJK UNIFIED IDEOGRAPH + 0x935F: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0x9360: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0x9361: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0x9362: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0x9363: 0x7530, //CJK UNIFIED IDEOGRAPH + 0x9364: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0x9365: 0x514E, //CJK UNIFIED IDEOGRAPH + 0x9366: 0x5410, //CJK UNIFIED IDEOGRAPH + 0x9367: 0x5835, //CJK UNIFIED IDEOGRAPH + 0x9368: 0x5857, //CJK UNIFIED IDEOGRAPH + 0x9369: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0x936A: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0x936B: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0x936C: 0x6597, //CJK UNIFIED IDEOGRAPH + 0x936D: 0x675C, //CJK UNIFIED IDEOGRAPH + 0x936E: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0x936F: 0x767B, //CJK UNIFIED IDEOGRAPH + 0x9370: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0x9371: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0x9372: 0x9014, //CJK UNIFIED IDEOGRAPH + 0x9373: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0x9374: 0x934D, //CJK UNIFIED IDEOGRAPH + 0x9375: 0x7825, //CJK UNIFIED IDEOGRAPH + 0x9376: 0x783A, //CJK UNIFIED IDEOGRAPH + 0x9377: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0x9378: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0x9379: 0x571F, //CJK UNIFIED IDEOGRAPH + 0x937A: 0x5974, //CJK UNIFIED IDEOGRAPH + 0x937B: 0x6012, //CJK UNIFIED IDEOGRAPH + 0x937C: 0x5012, //CJK UNIFIED IDEOGRAPH + 0x937D: 0x515A, //CJK UNIFIED IDEOGRAPH + 0x937E: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0x9380: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0x9381: 0x5200, //CJK UNIFIED IDEOGRAPH + 0x9382: 0x5510, //CJK UNIFIED IDEOGRAPH + 0x9383: 0x5854, //CJK UNIFIED IDEOGRAPH + 0x9384: 0x5858, //CJK UNIFIED IDEOGRAPH + 0x9385: 0x5957, //CJK UNIFIED IDEOGRAPH + 0x9386: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0x9387: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0x9388: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0x9389: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0x938A: 0x6295, //CJK UNIFIED IDEOGRAPH + 0x938B: 0x642D, //CJK UNIFIED IDEOGRAPH + 0x938C: 0x6771, //CJK UNIFIED IDEOGRAPH + 0x938D: 0x6843, //CJK UNIFIED IDEOGRAPH + 0x938E: 0x68BC, //CJK UNIFIED IDEOGRAPH + 0x938F: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0x9390: 0x76D7, //CJK UNIFIED IDEOGRAPH + 0x9391: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0x9392: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0x9393: 0x6D9B, //CJK UNIFIED IDEOGRAPH + 0x9394: 0x706F, //CJK UNIFIED IDEOGRAPH + 0x9395: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0x9396: 0x5F53, //CJK UNIFIED IDEOGRAPH + 0x9397: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0x9398: 0x7977, //CJK UNIFIED IDEOGRAPH + 0x9399: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0x939A: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0x939B: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0x939C: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0x939D: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0x939E: 0x5230, //CJK UNIFIED IDEOGRAPH + 0x939F: 0x8463, //CJK UNIFIED IDEOGRAPH + 0x93A0: 0x8569, //CJK UNIFIED IDEOGRAPH + 0x93A1: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0x93A2: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0x93A3: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0x93A4: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0x93A5: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0x93A6: 0x9003, //CJK UNIFIED IDEOGRAPH + 0x93A7: 0x900F, //CJK UNIFIED IDEOGRAPH + 0x93A8: 0x9419, //CJK UNIFIED IDEOGRAPH + 0x93A9: 0x9676, //CJK UNIFIED IDEOGRAPH + 0x93AA: 0x982D, //CJK UNIFIED IDEOGRAPH + 0x93AB: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0x93AC: 0x95D8, //CJK UNIFIED IDEOGRAPH + 0x93AD: 0x50CD, //CJK UNIFIED IDEOGRAPH + 0x93AE: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0x93AF: 0x540C, //CJK UNIFIED IDEOGRAPH + 0x93B0: 0x5802, //CJK UNIFIED IDEOGRAPH + 0x93B1: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0x93B2: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0x93B3: 0x649E, //CJK UNIFIED IDEOGRAPH + 0x93B4: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0x93B5: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0x93B6: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0x93B7: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0x93B8: 0x8404, //CJK UNIFIED IDEOGRAPH + 0x93B9: 0x9053, //CJK UNIFIED IDEOGRAPH + 0x93BA: 0x9285, //CJK UNIFIED IDEOGRAPH + 0x93BB: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0x93BC: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0x93BD: 0x533F, //CJK UNIFIED IDEOGRAPH + 0x93BE: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0x93BF: 0x5FB3, //CJK UNIFIED IDEOGRAPH + 0x93C0: 0x6D9C, //CJK UNIFIED IDEOGRAPH + 0x93C1: 0x7279, //CJK UNIFIED IDEOGRAPH + 0x93C2: 0x7763, //CJK UNIFIED IDEOGRAPH + 0x93C3: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0x93C4: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0x93C5: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0x93C6: 0x72EC, //CJK UNIFIED IDEOGRAPH + 0x93C7: 0x8AAD, //CJK UNIFIED IDEOGRAPH + 0x93C8: 0x6803, //CJK UNIFIED IDEOGRAPH + 0x93C9: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0x93CA: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0x93CB: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0x93CC: 0x6934, //CJK UNIFIED IDEOGRAPH + 0x93CD: 0x5C4A, //CJK UNIFIED IDEOGRAPH + 0x93CE: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0x93CF: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0x93D0: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0x93D1: 0x9149, //CJK UNIFIED IDEOGRAPH + 0x93D2: 0x701E, //CJK UNIFIED IDEOGRAPH + 0x93D3: 0x5678, //CJK UNIFIED IDEOGRAPH + 0x93D4: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0x93D5: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0x93D6: 0x6566, //CJK UNIFIED IDEOGRAPH + 0x93D7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0x93D8: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0x93D9: 0x9041, //CJK UNIFIED IDEOGRAPH + 0x93DA: 0x9813, //CJK UNIFIED IDEOGRAPH + 0x93DB: 0x5451, //CJK UNIFIED IDEOGRAPH + 0x93DC: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0x93DD: 0x920D, //CJK UNIFIED IDEOGRAPH + 0x93DE: 0x5948, //CJK UNIFIED IDEOGRAPH + 0x93DF: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0x93E0: 0x5185, //CJK UNIFIED IDEOGRAPH + 0x93E1: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0x93E2: 0x51EA, //CJK UNIFIED IDEOGRAPH + 0x93E3: 0x8599, //CJK UNIFIED IDEOGRAPH + 0x93E4: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0x93E5: 0x7058, //CJK UNIFIED IDEOGRAPH + 0x93E6: 0x637A, //CJK UNIFIED IDEOGRAPH + 0x93E7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0x93E8: 0x6962, //CJK UNIFIED IDEOGRAPH + 0x93E9: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0x93EA: 0x7E04, //CJK UNIFIED IDEOGRAPH + 0x93EB: 0x7577, //CJK UNIFIED IDEOGRAPH + 0x93EC: 0x5357, //CJK UNIFIED IDEOGRAPH + 0x93ED: 0x6960, //CJK UNIFIED IDEOGRAPH + 0x93EE: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0x93EF: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0x93F0: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0x93F1: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0x93F2: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0x93F3: 0x5F10, //CJK UNIFIED IDEOGRAPH + 0x93F4: 0x8FE9, //CJK UNIFIED IDEOGRAPH + 0x93F5: 0x5302, //CJK UNIFIED IDEOGRAPH + 0x93F6: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0x93F7: 0x8089, //CJK UNIFIED IDEOGRAPH + 0x93F8: 0x8679, //CJK UNIFIED IDEOGRAPH + 0x93F9: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0x93FA: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0x93FB: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0x93FC: 0x5165, //CJK UNIFIED IDEOGRAPH + 0x9440: 0x5982, //CJK UNIFIED IDEOGRAPH + 0x9441: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0x9442: 0x97EE, //CJK UNIFIED IDEOGRAPH + 0x9443: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0x9444: 0x598A, //CJK UNIFIED IDEOGRAPH + 0x9445: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0x9446: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0x9447: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0x9448: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0x9449: 0x7962, //CJK UNIFIED IDEOGRAPH + 0x944A: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0x944B: 0x8471, //CJK UNIFIED IDEOGRAPH + 0x944C: 0x732B, //CJK UNIFIED IDEOGRAPH + 0x944D: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0x944E: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0x944F: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0x9450: 0x637B, //CJK UNIFIED IDEOGRAPH + 0x9451: 0x649A, //CJK UNIFIED IDEOGRAPH + 0x9452: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0x9453: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0x9454: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0x9455: 0x5EFC, //CJK UNIFIED IDEOGRAPH + 0x9456: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0x9457: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0x9458: 0x56A2, //CJK UNIFIED IDEOGRAPH + 0x9459: 0x60A9, //CJK UNIFIED IDEOGRAPH + 0x945A: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0x945B: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0x945C: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0x945D: 0x8133, //CJK UNIFIED IDEOGRAPH + 0x945E: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0x945F: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0x9460: 0x8997, //CJK UNIFIED IDEOGRAPH + 0x9461: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0x9462: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0x9463: 0x628A, //CJK UNIFIED IDEOGRAPH + 0x9464: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0x9465: 0x8987, //CJK UNIFIED IDEOGRAPH + 0x9466: 0x6777, //CJK UNIFIED IDEOGRAPH + 0x9467: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0x9468: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0x9469: 0x7436, //CJK UNIFIED IDEOGRAPH + 0x946A: 0x7834, //CJK UNIFIED IDEOGRAPH + 0x946B: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0x946C: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0x946D: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0x946E: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0x946F: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0x9470: 0x5EC3, //CJK UNIFIED IDEOGRAPH + 0x9471: 0x62DD, //CJK UNIFIED IDEOGRAPH + 0x9472: 0x6392, //CJK UNIFIED IDEOGRAPH + 0x9473: 0x6557, //CJK UNIFIED IDEOGRAPH + 0x9474: 0x676F, //CJK UNIFIED IDEOGRAPH + 0x9475: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0x9476: 0x724C, //CJK UNIFIED IDEOGRAPH + 0x9477: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0x9478: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0x9479: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0x947A: 0x914D, //CJK UNIFIED IDEOGRAPH + 0x947B: 0x500D, //CJK UNIFIED IDEOGRAPH + 0x947C: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0x947D: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0x947E: 0x6885, //CJK UNIFIED IDEOGRAPH + 0x9480: 0x6973, //CJK UNIFIED IDEOGRAPH + 0x9481: 0x7164, //CJK UNIFIED IDEOGRAPH + 0x9482: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0x9483: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0x9484: 0x58F2, //CJK UNIFIED IDEOGRAPH + 0x9485: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0x9486: 0x966A, //CJK UNIFIED IDEOGRAPH + 0x9487: 0x9019, //CJK UNIFIED IDEOGRAPH + 0x9488: 0x877F, //CJK UNIFIED IDEOGRAPH + 0x9489: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0x948A: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0x948B: 0x8429, //CJK UNIFIED IDEOGRAPH + 0x948C: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0x948D: 0x5265, //CJK UNIFIED IDEOGRAPH + 0x948E: 0x535A, //CJK UNIFIED IDEOGRAPH + 0x948F: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0x9490: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0x9491: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0x9492: 0x767D, //CJK UNIFIED IDEOGRAPH + 0x9493: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0x9494: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0x9495: 0x8236, //CJK UNIFIED IDEOGRAPH + 0x9496: 0x8584, //CJK UNIFIED IDEOGRAPH + 0x9497: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0x9498: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0x9499: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0x949A: 0x7206, //CJK UNIFIED IDEOGRAPH + 0x949B: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0x949C: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0x949D: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0x949E: 0x9EA6, //CJK UNIFIED IDEOGRAPH + 0x949F: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0x94A0: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0x94A1: 0x7872, //CJK UNIFIED IDEOGRAPH + 0x94A2: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0x94A3: 0x8087, //CJK UNIFIED IDEOGRAPH + 0x94A4: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0x94A5: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0x94A6: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0x94A7: 0x808C, //CJK UNIFIED IDEOGRAPH + 0x94A8: 0x7551, //CJK UNIFIED IDEOGRAPH + 0x94A9: 0x7560, //CJK UNIFIED IDEOGRAPH + 0x94AA: 0x516B, //CJK UNIFIED IDEOGRAPH + 0x94AB: 0x9262, //CJK UNIFIED IDEOGRAPH + 0x94AC: 0x6E8C, //CJK UNIFIED IDEOGRAPH + 0x94AD: 0x767A, //CJK UNIFIED IDEOGRAPH + 0x94AE: 0x9197, //CJK UNIFIED IDEOGRAPH + 0x94AF: 0x9AEA, //CJK UNIFIED IDEOGRAPH + 0x94B0: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0x94B1: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0x94B2: 0x629C, //CJK UNIFIED IDEOGRAPH + 0x94B3: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0x94B4: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0x94B5: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0x94B6: 0x567A, //CJK UNIFIED IDEOGRAPH + 0x94B7: 0x5859, //CJK UNIFIED IDEOGRAPH + 0x94B8: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0x94B9: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0x94BA: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0x94BB: 0x5224, //CJK UNIFIED IDEOGRAPH + 0x94BC: 0x534A, //CJK UNIFIED IDEOGRAPH + 0x94BD: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0x94BE: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0x94BF: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0x94C0: 0x642C, //CJK UNIFIED IDEOGRAPH + 0x94C1: 0x6591, //CJK UNIFIED IDEOGRAPH + 0x94C2: 0x677F, //CJK UNIFIED IDEOGRAPH + 0x94C3: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0x94C4: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0x94C5: 0x7248, //CJK UNIFIED IDEOGRAPH + 0x94C6: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0x94C7: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0x94C8: 0x7554, //CJK UNIFIED IDEOGRAPH + 0x94C9: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0x94CA: 0x822C, //CJK UNIFIED IDEOGRAPH + 0x94CB: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0x94CC: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0x94CD: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0x94CE: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0x94CF: 0x7169, //CJK UNIFIED IDEOGRAPH + 0x94D0: 0x9812, //CJK UNIFIED IDEOGRAPH + 0x94D1: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0x94D2: 0x633D, //CJK UNIFIED IDEOGRAPH + 0x94D3: 0x6669, //CJK UNIFIED IDEOGRAPH + 0x94D4: 0x756A, //CJK UNIFIED IDEOGRAPH + 0x94D5: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0x94D6: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0x94D7: 0x8543, //CJK UNIFIED IDEOGRAPH + 0x94D8: 0x86EE, //CJK UNIFIED IDEOGRAPH + 0x94D9: 0x532A, //CJK UNIFIED IDEOGRAPH + 0x94DA: 0x5351, //CJK UNIFIED IDEOGRAPH + 0x94DB: 0x5426, //CJK UNIFIED IDEOGRAPH + 0x94DC: 0x5983, //CJK UNIFIED IDEOGRAPH + 0x94DD: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0x94DE: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0x94DF: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0x94E0: 0x6249, //CJK UNIFIED IDEOGRAPH + 0x94E1: 0x6279, //CJK UNIFIED IDEOGRAPH + 0x94E2: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0x94E3: 0x6590, //CJK UNIFIED IDEOGRAPH + 0x94E4: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0x94E5: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0x94E6: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0x94E7: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0x94E8: 0x7891, //CJK UNIFIED IDEOGRAPH + 0x94E9: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0x94EA: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0x94EB: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0x94EC: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0x94ED: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0x94EE: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0x94EF: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0x94F0: 0x907F, //CJK UNIFIED IDEOGRAPH + 0x94F1: 0x975E, //CJK UNIFIED IDEOGRAPH + 0x94F2: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0x94F3: 0x6A0B, //CJK UNIFIED IDEOGRAPH + 0x94F4: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0x94F5: 0x5099, //CJK UNIFIED IDEOGRAPH + 0x94F6: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0x94F7: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0x94F8: 0x6787, //CJK UNIFIED IDEOGRAPH + 0x94F9: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0x94FA: 0x7435, //CJK UNIFIED IDEOGRAPH + 0x94FB: 0x7709, //CJK UNIFIED IDEOGRAPH + 0x94FC: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0x9540: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0x9541: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0x9542: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0x9543: 0x5339, //CJK UNIFIED IDEOGRAPH + 0x9544: 0x758B, //CJK UNIFIED IDEOGRAPH + 0x9545: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0x9546: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0x9547: 0x819D, //CJK UNIFIED IDEOGRAPH + 0x9548: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0x9549: 0x8098, //CJK UNIFIED IDEOGRAPH + 0x954A: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0x954B: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0x954C: 0x7562, //CJK UNIFIED IDEOGRAPH + 0x954D: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0x954E: 0x903C, //CJK UNIFIED IDEOGRAPH + 0x954F: 0x6867, //CJK UNIFIED IDEOGRAPH + 0x9550: 0x59EB, //CJK UNIFIED IDEOGRAPH + 0x9551: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0x9552: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0x9553: 0x767E, //CJK UNIFIED IDEOGRAPH + 0x9554: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0x9555: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0x9556: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0x9557: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0x9558: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0x9559: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0x955A: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0x955B: 0x7968, //CJK UNIFIED IDEOGRAPH + 0x955C: 0x8868, //CJK UNIFIED IDEOGRAPH + 0x955D: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0x955E: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0x955F: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0x9560: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0x9561: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0x9562: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0x9563: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0x9564: 0x9328, //CJK UNIFIED IDEOGRAPH + 0x9565: 0x92F2, //CJK UNIFIED IDEOGRAPH + 0x9566: 0x849C, //CJK UNIFIED IDEOGRAPH + 0x9567: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0x9568: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0x9569: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0x956A: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0x956B: 0x658C, //CJK UNIFIED IDEOGRAPH + 0x956C: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0x956D: 0x7015, //CJK UNIFIED IDEOGRAPH + 0x956E: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0x956F: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0x9570: 0x983B, //CJK UNIFIED IDEOGRAPH + 0x9571: 0x654F, //CJK UNIFIED IDEOGRAPH + 0x9572: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0x9573: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0x9574: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0x9575: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0x9576: 0x592B, //CJK UNIFIED IDEOGRAPH + 0x9577: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0x9578: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0x9579: 0x51A8, //CJK UNIFIED IDEOGRAPH + 0x957A: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0x957B: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0x957C: 0x6016, //CJK UNIFIED IDEOGRAPH + 0x957D: 0x6276, //CJK UNIFIED IDEOGRAPH + 0x957E: 0x6577, //CJK UNIFIED IDEOGRAPH + 0x9580: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0x9581: 0x666E, //CJK UNIFIED IDEOGRAPH + 0x9582: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0x9583: 0x7236, //CJK UNIFIED IDEOGRAPH + 0x9584: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0x9585: 0x8150, //CJK UNIFIED IDEOGRAPH + 0x9586: 0x819A, //CJK UNIFIED IDEOGRAPH + 0x9587: 0x8299, //CJK UNIFIED IDEOGRAPH + 0x9588: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0x9589: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0x958A: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0x958B: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0x958C: 0x961C, //CJK UNIFIED IDEOGRAPH + 0x958D: 0x9644, //CJK UNIFIED IDEOGRAPH + 0x958E: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0x958F: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0x9590: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0x9591: 0x821E, //CJK UNIFIED IDEOGRAPH + 0x9592: 0x8461, //CJK UNIFIED IDEOGRAPH + 0x9593: 0x856A, //CJK UNIFIED IDEOGRAPH + 0x9594: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0x9595: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0x9596: 0x6953, //CJK UNIFIED IDEOGRAPH + 0x9597: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0x9598: 0x847A, //CJK UNIFIED IDEOGRAPH + 0x9599: 0x8557, //CJK UNIFIED IDEOGRAPH + 0x959A: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0x959B: 0x526F, //CJK UNIFIED IDEOGRAPH + 0x959C: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0x959D: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0x959E: 0x670D, //CJK UNIFIED IDEOGRAPH + 0x959F: 0x798F, //CJK UNIFIED IDEOGRAPH + 0x95A0: 0x8179, //CJK UNIFIED IDEOGRAPH + 0x95A1: 0x8907, //CJK UNIFIED IDEOGRAPH + 0x95A2: 0x8986, //CJK UNIFIED IDEOGRAPH + 0x95A3: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0x95A4: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0x95A5: 0x6255, //CJK UNIFIED IDEOGRAPH + 0x95A6: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0x95A7: 0x4ECF, //CJK UNIFIED IDEOGRAPH + 0x95A8: 0x7269, //CJK UNIFIED IDEOGRAPH + 0x95A9: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0x95AA: 0x5206, //CJK UNIFIED IDEOGRAPH + 0x95AB: 0x543B, //CJK UNIFIED IDEOGRAPH + 0x95AC: 0x5674, //CJK UNIFIED IDEOGRAPH + 0x95AD: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0x95AE: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0x95AF: 0x626E, //CJK UNIFIED IDEOGRAPH + 0x95B0: 0x711A, //CJK UNIFIED IDEOGRAPH + 0x95B1: 0x596E, //CJK UNIFIED IDEOGRAPH + 0x95B2: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0x95B3: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0x95B4: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0x95B5: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0x95B6: 0x6587, //CJK UNIFIED IDEOGRAPH + 0x95B7: 0x805E, //CJK UNIFIED IDEOGRAPH + 0x95B8: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0x95B9: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0x95BA: 0x5175, //CJK UNIFIED IDEOGRAPH + 0x95BB: 0x5840, //CJK UNIFIED IDEOGRAPH + 0x95BC: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0x95BD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0x95BE: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0x95BF: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0x95C0: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0x95C1: 0x853D, //CJK UNIFIED IDEOGRAPH + 0x95C2: 0x9589, //CJK UNIFIED IDEOGRAPH + 0x95C3: 0x965B, //CJK UNIFIED IDEOGRAPH + 0x95C4: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0x95C5: 0x9801, //CJK UNIFIED IDEOGRAPH + 0x95C6: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0x95C7: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0x95C8: 0x7656, //CJK UNIFIED IDEOGRAPH + 0x95C9: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0x95CA: 0x5225, //CJK UNIFIED IDEOGRAPH + 0x95CB: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0x95CC: 0x8511, //CJK UNIFIED IDEOGRAPH + 0x95CD: 0x7B86, //CJK UNIFIED IDEOGRAPH + 0x95CE: 0x504F, //CJK UNIFIED IDEOGRAPH + 0x95CF: 0x5909, //CJK UNIFIED IDEOGRAPH + 0x95D0: 0x7247, //CJK UNIFIED IDEOGRAPH + 0x95D1: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0x95D2: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0x95D3: 0x8FBA, //CJK UNIFIED IDEOGRAPH + 0x95D4: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0x95D5: 0x904D, //CJK UNIFIED IDEOGRAPH + 0x95D6: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0x95D7: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0x95D8: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0x95D9: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0x95DA: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0x95DB: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0x95DC: 0x8217, //CJK UNIFIED IDEOGRAPH + 0x95DD: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0x95DE: 0x5703, //CJK UNIFIED IDEOGRAPH + 0x95DF: 0x6355, //CJK UNIFIED IDEOGRAPH + 0x95E0: 0x6B69, //CJK UNIFIED IDEOGRAPH + 0x95E1: 0x752B, //CJK UNIFIED IDEOGRAPH + 0x95E2: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0x95E3: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0x95E4: 0x7A42, //CJK UNIFIED IDEOGRAPH + 0x95E5: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0x95E6: 0x5893, //CJK UNIFIED IDEOGRAPH + 0x95E7: 0x6155, //CJK UNIFIED IDEOGRAPH + 0x95E8: 0x620A, //CJK UNIFIED IDEOGRAPH + 0x95E9: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0x95EA: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0x95EB: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0x95EC: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0x95ED: 0x5023, //CJK UNIFIED IDEOGRAPH + 0x95EE: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0x95EF: 0x5305, //CJK UNIFIED IDEOGRAPH + 0x95F0: 0x5446, //CJK UNIFIED IDEOGRAPH + 0x95F1: 0x5831, //CJK UNIFIED IDEOGRAPH + 0x95F2: 0x5949, //CJK UNIFIED IDEOGRAPH + 0x95F3: 0x5B9D, //CJK UNIFIED IDEOGRAPH + 0x95F4: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0x95F5: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0x95F6: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0x95F7: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0x95F8: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0x95F9: 0x6367, //CJK UNIFIED IDEOGRAPH + 0x95FA: 0x653E, //CJK UNIFIED IDEOGRAPH + 0x95FB: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0x95FC: 0x670B, //CJK UNIFIED IDEOGRAPH + 0x9640: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0x9641: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0x9642: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0x9643: 0x7832, //CJK UNIFIED IDEOGRAPH + 0x9644: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0x9645: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0x9646: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0x9647: 0x840C, //CJK UNIFIED IDEOGRAPH + 0x9648: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0x9649: 0x8702, //CJK UNIFIED IDEOGRAPH + 0x964A: 0x8912, //CJK UNIFIED IDEOGRAPH + 0x964B: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0x964C: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0x964D: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0x964E: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0x964F: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0x9650: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0x9651: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0x9652: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0x9653: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0x9654: 0x508D, //CJK UNIFIED IDEOGRAPH + 0x9655: 0x5256, //CJK UNIFIED IDEOGRAPH + 0x9656: 0x574A, //CJK UNIFIED IDEOGRAPH + 0x9657: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0x9658: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0x9659: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0x965A: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0x965B: 0x623F, //CJK UNIFIED IDEOGRAPH + 0x965C: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0x965D: 0x671B, //CJK UNIFIED IDEOGRAPH + 0x965E: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0x965F: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0x9660: 0x5192, //CJK UNIFIED IDEOGRAPH + 0x9661: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0x9662: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0x9663: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0x9664: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0x9665: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0x9666: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0x9667: 0x927E, //CJK UNIFIED IDEOGRAPH + 0x9668: 0x9632, //CJK UNIFIED IDEOGRAPH + 0x9669: 0x5420, //CJK UNIFIED IDEOGRAPH + 0x966A: 0x982C, //CJK UNIFIED IDEOGRAPH + 0x966B: 0x5317, //CJK UNIFIED IDEOGRAPH + 0x966C: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0x966D: 0x535C, //CJK UNIFIED IDEOGRAPH + 0x966E: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0x966F: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0x9670: 0x6734, //CJK UNIFIED IDEOGRAPH + 0x9671: 0x7267, //CJK UNIFIED IDEOGRAPH + 0x9672: 0x7766, //CJK UNIFIED IDEOGRAPH + 0x9673: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0x9674: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0x9675: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0x9676: 0x6CA1, //CJK UNIFIED IDEOGRAPH + 0x9677: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0x9678: 0x5800, //CJK UNIFIED IDEOGRAPH + 0x9679: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0x967A: 0x5954, //CJK UNIFIED IDEOGRAPH + 0x967B: 0x672C, //CJK UNIFIED IDEOGRAPH + 0x967C: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0x967D: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0x967E: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0x9680: 0x6469, //CJK UNIFIED IDEOGRAPH + 0x9681: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0x9682: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0x9683: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0x9684: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0x9685: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0x9686: 0x6627, //CJK UNIFIED IDEOGRAPH + 0x9687: 0x679A, //CJK UNIFIED IDEOGRAPH + 0x9688: 0x6BCE, //CJK UNIFIED IDEOGRAPH + 0x9689: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0x968A: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0x968B: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0x968C: 0x819C, //CJK UNIFIED IDEOGRAPH + 0x968D: 0x6795, //CJK UNIFIED IDEOGRAPH + 0x968E: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0x968F: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0x9690: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0x9691: 0x685D, //CJK UNIFIED IDEOGRAPH + 0x9692: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0x9693: 0x4FE3, //CJK UNIFIED IDEOGRAPH + 0x9694: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0x9695: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0x9696: 0x672B, //CJK UNIFIED IDEOGRAPH + 0x9697: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0x9698: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0x9699: 0x4FAD, //CJK UNIFIED IDEOGRAPH + 0x969A: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0x969B: 0x9EBF, //CJK UNIFIED IDEOGRAPH + 0x969C: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0x969D: 0x6162, //CJK UNIFIED IDEOGRAPH + 0x969E: 0x6E80, //CJK UNIFIED IDEOGRAPH + 0x969F: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0x96A0: 0x8513, //CJK UNIFIED IDEOGRAPH + 0x96A1: 0x5473, //CJK UNIFIED IDEOGRAPH + 0x96A2: 0x672A, //CJK UNIFIED IDEOGRAPH + 0x96A3: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0x96A4: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0x96A5: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0x96A6: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0x96A7: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0x96A8: 0x871C, //CJK UNIFIED IDEOGRAPH + 0x96A9: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0x96AA: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0x96AB: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0x96AC: 0x8108, //CJK UNIFIED IDEOGRAPH + 0x96AD: 0x5999, //CJK UNIFIED IDEOGRAPH + 0x96AE: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0x96AF: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0x96B0: 0x7720, //CJK UNIFIED IDEOGRAPH + 0x96B1: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0x96B2: 0x5922, //CJK UNIFIED IDEOGRAPH + 0x96B3: 0x7121, //CJK UNIFIED IDEOGRAPH + 0x96B4: 0x725F, //CJK UNIFIED IDEOGRAPH + 0x96B5: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0x96B6: 0x9727, //CJK UNIFIED IDEOGRAPH + 0x96B7: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0x96B8: 0x690B, //CJK UNIFIED IDEOGRAPH + 0x96B9: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0x96BA: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0x96BB: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0x96BC: 0x540D, //CJK UNIFIED IDEOGRAPH + 0x96BD: 0x547D, //CJK UNIFIED IDEOGRAPH + 0x96BE: 0x660E, //CJK UNIFIED IDEOGRAPH + 0x96BF: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0x96C0: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0x96C1: 0x9298, //CJK UNIFIED IDEOGRAPH + 0x96C2: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0x96C3: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0x96C4: 0x725D, //CJK UNIFIED IDEOGRAPH + 0x96C5: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0x96C6: 0x514D, //CJK UNIFIED IDEOGRAPH + 0x96C7: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0x96C8: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0x96C9: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0x96CA: 0x9762, //CJK UNIFIED IDEOGRAPH + 0x96CB: 0x9EBA, //CJK UNIFIED IDEOGRAPH + 0x96CC: 0x6478, //CJK UNIFIED IDEOGRAPH + 0x96CD: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0x96CE: 0x8302, //CJK UNIFIED IDEOGRAPH + 0x96CF: 0x5984, //CJK UNIFIED IDEOGRAPH + 0x96D0: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0x96D1: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0x96D2: 0x731B, //CJK UNIFIED IDEOGRAPH + 0x96D3: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0x96D4: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0x96D5: 0x8017, //CJK UNIFIED IDEOGRAPH + 0x96D6: 0x8499, //CJK UNIFIED IDEOGRAPH + 0x96D7: 0x5132, //CJK UNIFIED IDEOGRAPH + 0x96D8: 0x6728, //CJK UNIFIED IDEOGRAPH + 0x96D9: 0x9ED9, //CJK UNIFIED IDEOGRAPH + 0x96DA: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0x96DB: 0x6762, //CJK UNIFIED IDEOGRAPH + 0x96DC: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0x96DD: 0x9905, //CJK UNIFIED IDEOGRAPH + 0x96DE: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0x96DF: 0x623B, //CJK UNIFIED IDEOGRAPH + 0x96E0: 0x7C7E, //CJK UNIFIED IDEOGRAPH + 0x96E1: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0x96E2: 0x554F, //CJK UNIFIED IDEOGRAPH + 0x96E3: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0x96E4: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0x96E5: 0x9580, //CJK UNIFIED IDEOGRAPH + 0x96E6: 0x5301, //CJK UNIFIED IDEOGRAPH + 0x96E7: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0x96E8: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0x96E9: 0x591C, //CJK UNIFIED IDEOGRAPH + 0x96EA: 0x723A, //CJK UNIFIED IDEOGRAPH + 0x96EB: 0x8036, //CJK UNIFIED IDEOGRAPH + 0x96EC: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0x96ED: 0x5F25, //CJK UNIFIED IDEOGRAPH + 0x96EE: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0x96EF: 0x5384, //CJK UNIFIED IDEOGRAPH + 0x96F0: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0x96F1: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0x96F2: 0x85AC, //CJK UNIFIED IDEOGRAPH + 0x96F3: 0x8A33, //CJK UNIFIED IDEOGRAPH + 0x96F4: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0x96F5: 0x9756, //CJK UNIFIED IDEOGRAPH + 0x96F6: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0x96F7: 0x85AE, //CJK UNIFIED IDEOGRAPH + 0x96F8: 0x9453, //CJK UNIFIED IDEOGRAPH + 0x96F9: 0x6109, //CJK UNIFIED IDEOGRAPH + 0x96FA: 0x6108, //CJK UNIFIED IDEOGRAPH + 0x96FB: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0x96FC: 0x7652, //CJK UNIFIED IDEOGRAPH + 0x9740: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0x9741: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0x9742: 0x552F, //CJK UNIFIED IDEOGRAPH + 0x9743: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0x9744: 0x512A, //CJK UNIFIED IDEOGRAPH + 0x9745: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0x9746: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0x9747: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0x9748: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0x9749: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0x974A: 0x6182, //CJK UNIFIED IDEOGRAPH + 0x974B: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0x974C: 0x6709, //CJK UNIFIED IDEOGRAPH + 0x974D: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0x974E: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0x974F: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0x9750: 0x7336, //CJK UNIFIED IDEOGRAPH + 0x9751: 0x7337, //CJK UNIFIED IDEOGRAPH + 0x9752: 0x7531, //CJK UNIFIED IDEOGRAPH + 0x9753: 0x7950, //CJK UNIFIED IDEOGRAPH + 0x9754: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0x9755: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0x9756: 0x904A, //CJK UNIFIED IDEOGRAPH + 0x9757: 0x9091, //CJK UNIFIED IDEOGRAPH + 0x9758: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0x9759: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0x975A: 0x878D, //CJK UNIFIED IDEOGRAPH + 0x975B: 0x5915, //CJK UNIFIED IDEOGRAPH + 0x975C: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0x975D: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0x975E: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0x975F: 0x8A89, //CJK UNIFIED IDEOGRAPH + 0x9760: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0x9761: 0x9810, //CJK UNIFIED IDEOGRAPH + 0x9762: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0x9763: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0x9764: 0x5996, //CJK UNIFIED IDEOGRAPH + 0x9765: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0x9766: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0x9767: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0x9768: 0x63FA, //CJK UNIFIED IDEOGRAPH + 0x9769: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0x976A: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0x976B: 0x694A, //CJK UNIFIED IDEOGRAPH + 0x976C: 0x69D8, //CJK UNIFIED IDEOGRAPH + 0x976D: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0x976E: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0x976F: 0x7194, //CJK UNIFIED IDEOGRAPH + 0x9770: 0x7528, //CJK UNIFIED IDEOGRAPH + 0x9771: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0x9772: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0x9773: 0x8000, //CJK UNIFIED IDEOGRAPH + 0x9774: 0x8449, //CJK UNIFIED IDEOGRAPH + 0x9775: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0x9776: 0x8981, //CJK UNIFIED IDEOGRAPH + 0x9777: 0x8B21, //CJK UNIFIED IDEOGRAPH + 0x9778: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0x9779: 0x9065, //CJK UNIFIED IDEOGRAPH + 0x977A: 0x967D, //CJK UNIFIED IDEOGRAPH + 0x977B: 0x990A, //CJK UNIFIED IDEOGRAPH + 0x977C: 0x617E, //CJK UNIFIED IDEOGRAPH + 0x977D: 0x6291, //CJK UNIFIED IDEOGRAPH + 0x977E: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0x9780: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0x9781: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0x9782: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0x9783: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0x9784: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0x9785: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0x9786: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0x9787: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0x9788: 0x6765, //CJK UNIFIED IDEOGRAPH + 0x9789: 0x83B1, //CJK UNIFIED IDEOGRAPH + 0x978A: 0x983C, //CJK UNIFIED IDEOGRAPH + 0x978B: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0x978C: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0x978D: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0x978E: 0x843D, //CJK UNIFIED IDEOGRAPH + 0x978F: 0x916A, //CJK UNIFIED IDEOGRAPH + 0x9790: 0x4E71, //CJK UNIFIED IDEOGRAPH + 0x9791: 0x5375, //CJK UNIFIED IDEOGRAPH + 0x9792: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0x9793: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0x9794: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0x9795: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0x9796: 0x862D, //CJK UNIFIED IDEOGRAPH + 0x9797: 0x89A7, //CJK UNIFIED IDEOGRAPH + 0x9798: 0x5229, //CJK UNIFIED IDEOGRAPH + 0x9799: 0x540F, //CJK UNIFIED IDEOGRAPH + 0x979A: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0x979B: 0x674E, //CJK UNIFIED IDEOGRAPH + 0x979C: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0x979D: 0x7406, //CJK UNIFIED IDEOGRAPH + 0x979E: 0x7483, //CJK UNIFIED IDEOGRAPH + 0x979F: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0x97A0: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0x97A1: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0x97A2: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0x97A3: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0x97A4: 0x9678, //CJK UNIFIED IDEOGRAPH + 0x97A5: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0x97A6: 0x7387, //CJK UNIFIED IDEOGRAPH + 0x97A7: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0x97A8: 0x844E, //CJK UNIFIED IDEOGRAPH + 0x97A9: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0x97AA: 0x7565, //CJK UNIFIED IDEOGRAPH + 0x97AB: 0x5289, //CJK UNIFIED IDEOGRAPH + 0x97AC: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0x97AD: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0x97AE: 0x7409, //CJK UNIFIED IDEOGRAPH + 0x97AF: 0x7559, //CJK UNIFIED IDEOGRAPH + 0x97B0: 0x786B, //CJK UNIFIED IDEOGRAPH + 0x97B1: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0x97B2: 0x9686, //CJK UNIFIED IDEOGRAPH + 0x97B3: 0x7ADC, //CJK UNIFIED IDEOGRAPH + 0x97B4: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0x97B5: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0x97B6: 0x616E, //CJK UNIFIED IDEOGRAPH + 0x97B7: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0x97B8: 0x865C, //CJK UNIFIED IDEOGRAPH + 0x97B9: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0x97BA: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0x97BB: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0x97BC: 0x4E21, //CJK UNIFIED IDEOGRAPH + 0x97BD: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0x97BE: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0x97BF: 0x6599, //CJK UNIFIED IDEOGRAPH + 0x97C0: 0x6881, //CJK UNIFIED IDEOGRAPH + 0x97C1: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0x97C2: 0x731F, //CJK UNIFIED IDEOGRAPH + 0x97C3: 0x7642, //CJK UNIFIED IDEOGRAPH + 0x97C4: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0x97C5: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0x97C6: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0x97C7: 0x826F, //CJK UNIFIED IDEOGRAPH + 0x97C8: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0x97C9: 0x907C, //CJK UNIFIED IDEOGRAPH + 0x97CA: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0x97CB: 0x9675, //CJK UNIFIED IDEOGRAPH + 0x97CC: 0x9818, //CJK UNIFIED IDEOGRAPH + 0x97CD: 0x529B, //CJK UNIFIED IDEOGRAPH + 0x97CE: 0x7DD1, //CJK UNIFIED IDEOGRAPH + 0x97CF: 0x502B, //CJK UNIFIED IDEOGRAPH + 0x97D0: 0x5398, //CJK UNIFIED IDEOGRAPH + 0x97D1: 0x6797, //CJK UNIFIED IDEOGRAPH + 0x97D2: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0x97D3: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0x97D4: 0x7433, //CJK UNIFIED IDEOGRAPH + 0x97D5: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0x97D6: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0x97D7: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0x97D8: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0x97D9: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0x97DA: 0x7460, //CJK UNIFIED IDEOGRAPH + 0x97DB: 0x5841, //CJK UNIFIED IDEOGRAPH + 0x97DC: 0x6D99, //CJK UNIFIED IDEOGRAPH + 0x97DD: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0x97DE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0x97DF: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0x97E0: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0x97E1: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0x97E2: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0x97E3: 0x52B1, //CJK UNIFIED IDEOGRAPH + 0x97E4: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0x97E5: 0x601C, //CJK UNIFIED IDEOGRAPH + 0x97E6: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0x97E7: 0x793C, //CJK UNIFIED IDEOGRAPH + 0x97E8: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0x97E9: 0x9234, //CJK UNIFIED IDEOGRAPH + 0x97EA: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0x97EB: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0x97EC: 0x970A, //CJK UNIFIED IDEOGRAPH + 0x97ED: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0x97EE: 0x9F62, //CJK UNIFIED IDEOGRAPH + 0x97EF: 0x66A6, //CJK UNIFIED IDEOGRAPH + 0x97F0: 0x6B74, //CJK UNIFIED IDEOGRAPH + 0x97F1: 0x5217, //CJK UNIFIED IDEOGRAPH + 0x97F2: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0x97F3: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0x97F4: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0x97F5: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0x97F6: 0x604B, //CJK UNIFIED IDEOGRAPH + 0x97F7: 0x6190, //CJK UNIFIED IDEOGRAPH + 0x97F8: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0x97F9: 0x7149, //CJK UNIFIED IDEOGRAPH + 0x97FA: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0x97FB: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0x97FC: 0x806F, //CJK UNIFIED IDEOGRAPH + 0x9840: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0x9841: 0x9023, //CJK UNIFIED IDEOGRAPH + 0x9842: 0x932C, //CJK UNIFIED IDEOGRAPH + 0x9843: 0x5442, //CJK UNIFIED IDEOGRAPH + 0x9844: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0x9845: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0x9846: 0x7089, //CJK UNIFIED IDEOGRAPH + 0x9847: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0x9848: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0x9849: 0x9732, //CJK UNIFIED IDEOGRAPH + 0x984A: 0x52B4, //CJK UNIFIED IDEOGRAPH + 0x984B: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0x984C: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0x984D: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0x984E: 0x6717, //CJK UNIFIED IDEOGRAPH + 0x984F: 0x697C, //CJK UNIFIED IDEOGRAPH + 0x9850: 0x6994, //CJK UNIFIED IDEOGRAPH + 0x9851: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0x9852: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0x9853: 0x7262, //CJK UNIFIED IDEOGRAPH + 0x9854: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0x9855: 0x7BED, //CJK UNIFIED IDEOGRAPH + 0x9856: 0x8001, //CJK UNIFIED IDEOGRAPH + 0x9857: 0x807E, //CJK UNIFIED IDEOGRAPH + 0x9858: 0x874B, //CJK UNIFIED IDEOGRAPH + 0x9859: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0x985A: 0x516D, //CJK UNIFIED IDEOGRAPH + 0x985B: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0x985C: 0x7984, //CJK UNIFIED IDEOGRAPH + 0x985D: 0x808B, //CJK UNIFIED IDEOGRAPH + 0x985E: 0x9332, //CJK UNIFIED IDEOGRAPH + 0x985F: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0x9860: 0x502D, //CJK UNIFIED IDEOGRAPH + 0x9861: 0x548C, //CJK UNIFIED IDEOGRAPH + 0x9862: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0x9863: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0x9864: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0x9865: 0x8107, //CJK UNIFIED IDEOGRAPH + 0x9866: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0x9867: 0x67A0, //CJK UNIFIED IDEOGRAPH + 0x9868: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0x9869: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0x986A: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0x986B: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0x986C: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0x986D: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0x986E: 0x8568, //CJK UNIFIED IDEOGRAPH + 0x986F: 0x6900, //CJK UNIFIED IDEOGRAPH + 0x9870: 0x6E7E, //CJK UNIFIED IDEOGRAPH + 0x9871: 0x7897, //CJK UNIFIED IDEOGRAPH + 0x9872: 0x8155, //CJK UNIFIED IDEOGRAPH + 0x989F: 0x5F0C, //CJK UNIFIED IDEOGRAPH + 0x98A0: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0x98A1: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0x98A2: 0x4E2A, //CJK UNIFIED IDEOGRAPH + 0x98A3: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0x98A4: 0x4E36, //CJK UNIFIED IDEOGRAPH + 0x98A5: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0x98A6: 0x4E3F, //CJK UNIFIED IDEOGRAPH + 0x98A7: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0x98A8: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0x98A9: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0x98AA: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0x98AB: 0x4E85, //CJK UNIFIED IDEOGRAPH + 0x98AC: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0x98AD: 0x4E8A, //CJK UNIFIED IDEOGRAPH + 0x98AE: 0x8212, //CJK UNIFIED IDEOGRAPH + 0x98AF: 0x5F0D, //CJK UNIFIED IDEOGRAPH + 0x98B0: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0x98B1: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0x98B2: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0x98B3: 0x4EA0, //CJK UNIFIED IDEOGRAPH + 0x98B4: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0x98B5: 0x4EB0, //CJK UNIFIED IDEOGRAPH + 0x98B6: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0x98B7: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0x98B8: 0x4ECE, //CJK UNIFIED IDEOGRAPH + 0x98B9: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0x98BA: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0x98BB: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0x98BC: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0x98BD: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0x98BE: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0x98BF: 0x4EED, //CJK UNIFIED IDEOGRAPH + 0x98C0: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0x98C1: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0x98C2: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0x98C3: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0x98C4: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0x98C5: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0x98C6: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0x98C7: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0x98C8: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0x98C9: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0x98CA: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0x98CB: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0x98CC: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0x98CD: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0x98CE: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0x98CF: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0x98D0: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0x98D1: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0x98D2: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0x98D3: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0x98D4: 0x5118, //CJK UNIFIED IDEOGRAPH + 0x98D5: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0x98D6: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0x98D7: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0x98D8: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0x98D9: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0x98DA: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0x98DB: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0x98DC: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0x98DD: 0x4FE4, //CJK UNIFIED IDEOGRAPH + 0x98DE: 0x4FE5, //CJK UNIFIED IDEOGRAPH + 0x98DF: 0x501A, //CJK UNIFIED IDEOGRAPH + 0x98E0: 0x5028, //CJK UNIFIED IDEOGRAPH + 0x98E1: 0x5014, //CJK UNIFIED IDEOGRAPH + 0x98E2: 0x502A, //CJK UNIFIED IDEOGRAPH + 0x98E3: 0x5025, //CJK UNIFIED IDEOGRAPH + 0x98E4: 0x5005, //CJK UNIFIED IDEOGRAPH + 0x98E5: 0x4F1C, //CJK UNIFIED IDEOGRAPH + 0x98E6: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0x98E7: 0x5021, //CJK UNIFIED IDEOGRAPH + 0x98E8: 0x5029, //CJK UNIFIED IDEOGRAPH + 0x98E9: 0x502C, //CJK UNIFIED IDEOGRAPH + 0x98EA: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0x98EB: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0x98EC: 0x5011, //CJK UNIFIED IDEOGRAPH + 0x98ED: 0x5006, //CJK UNIFIED IDEOGRAPH + 0x98EE: 0x5043, //CJK UNIFIED IDEOGRAPH + 0x98EF: 0x5047, //CJK UNIFIED IDEOGRAPH + 0x98F0: 0x6703, //CJK UNIFIED IDEOGRAPH + 0x98F1: 0x5055, //CJK UNIFIED IDEOGRAPH + 0x98F2: 0x5050, //CJK UNIFIED IDEOGRAPH + 0x98F3: 0x5048, //CJK UNIFIED IDEOGRAPH + 0x98F4: 0x505A, //CJK UNIFIED IDEOGRAPH + 0x98F5: 0x5056, //CJK UNIFIED IDEOGRAPH + 0x98F6: 0x506C, //CJK UNIFIED IDEOGRAPH + 0x98F7: 0x5078, //CJK UNIFIED IDEOGRAPH + 0x98F8: 0x5080, //CJK UNIFIED IDEOGRAPH + 0x98F9: 0x509A, //CJK UNIFIED IDEOGRAPH + 0x98FA: 0x5085, //CJK UNIFIED IDEOGRAPH + 0x98FB: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0x98FC: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0x9940: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0x9941: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0x9942: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0x9943: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0x9944: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0x9945: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0x9946: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0x9947: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0x9948: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0x9949: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0x994A: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0x994B: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0x994C: 0x5109, //CJK UNIFIED IDEOGRAPH + 0x994D: 0x5101, //CJK UNIFIED IDEOGRAPH + 0x994E: 0x5102, //CJK UNIFIED IDEOGRAPH + 0x994F: 0x5116, //CJK UNIFIED IDEOGRAPH + 0x9950: 0x5115, //CJK UNIFIED IDEOGRAPH + 0x9951: 0x5114, //CJK UNIFIED IDEOGRAPH + 0x9952: 0x511A, //CJK UNIFIED IDEOGRAPH + 0x9953: 0x5121, //CJK UNIFIED IDEOGRAPH + 0x9954: 0x513A, //CJK UNIFIED IDEOGRAPH + 0x9955: 0x5137, //CJK UNIFIED IDEOGRAPH + 0x9956: 0x513C, //CJK UNIFIED IDEOGRAPH + 0x9957: 0x513B, //CJK UNIFIED IDEOGRAPH + 0x9958: 0x513F, //CJK UNIFIED IDEOGRAPH + 0x9959: 0x5140, //CJK UNIFIED IDEOGRAPH + 0x995A: 0x5152, //CJK UNIFIED IDEOGRAPH + 0x995B: 0x514C, //CJK UNIFIED IDEOGRAPH + 0x995C: 0x5154, //CJK UNIFIED IDEOGRAPH + 0x995D: 0x5162, //CJK UNIFIED IDEOGRAPH + 0x995E: 0x7AF8, //CJK UNIFIED IDEOGRAPH + 0x995F: 0x5169, //CJK UNIFIED IDEOGRAPH + 0x9960: 0x516A, //CJK UNIFIED IDEOGRAPH + 0x9961: 0x516E, //CJK UNIFIED IDEOGRAPH + 0x9962: 0x5180, //CJK UNIFIED IDEOGRAPH + 0x9963: 0x5182, //CJK UNIFIED IDEOGRAPH + 0x9964: 0x56D8, //CJK UNIFIED IDEOGRAPH + 0x9965: 0x518C, //CJK UNIFIED IDEOGRAPH + 0x9966: 0x5189, //CJK UNIFIED IDEOGRAPH + 0x9967: 0x518F, //CJK UNIFIED IDEOGRAPH + 0x9968: 0x5191, //CJK UNIFIED IDEOGRAPH + 0x9969: 0x5193, //CJK UNIFIED IDEOGRAPH + 0x996A: 0x5195, //CJK UNIFIED IDEOGRAPH + 0x996B: 0x5196, //CJK UNIFIED IDEOGRAPH + 0x996C: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0x996D: 0x51A6, //CJK UNIFIED IDEOGRAPH + 0x996E: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0x996F: 0x51A9, //CJK UNIFIED IDEOGRAPH + 0x9970: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0x9971: 0x51AB, //CJK UNIFIED IDEOGRAPH + 0x9972: 0x51B3, //CJK UNIFIED IDEOGRAPH + 0x9973: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0x9974: 0x51B2, //CJK UNIFIED IDEOGRAPH + 0x9975: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0x9976: 0x51B5, //CJK UNIFIED IDEOGRAPH + 0x9977: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0x9978: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0x9979: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0x997A: 0x51DB, //CJK UNIFIED IDEOGRAPH + 0x997B: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0x997C: 0x8655, //CJK UNIFIED IDEOGRAPH + 0x997D: 0x51E9, //CJK UNIFIED IDEOGRAPH + 0x997E: 0x51ED, //CJK UNIFIED IDEOGRAPH + 0x9980: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0x9981: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0x9982: 0x51FE, //CJK UNIFIED IDEOGRAPH + 0x9983: 0x5204, //CJK UNIFIED IDEOGRAPH + 0x9984: 0x520B, //CJK UNIFIED IDEOGRAPH + 0x9985: 0x5214, //CJK UNIFIED IDEOGRAPH + 0x9986: 0x520E, //CJK UNIFIED IDEOGRAPH + 0x9987: 0x5227, //CJK UNIFIED IDEOGRAPH + 0x9988: 0x522A, //CJK UNIFIED IDEOGRAPH + 0x9989: 0x522E, //CJK UNIFIED IDEOGRAPH + 0x998A: 0x5233, //CJK UNIFIED IDEOGRAPH + 0x998B: 0x5239, //CJK UNIFIED IDEOGRAPH + 0x998C: 0x524F, //CJK UNIFIED IDEOGRAPH + 0x998D: 0x5244, //CJK UNIFIED IDEOGRAPH + 0x998E: 0x524B, //CJK UNIFIED IDEOGRAPH + 0x998F: 0x524C, //CJK UNIFIED IDEOGRAPH + 0x9990: 0x525E, //CJK UNIFIED IDEOGRAPH + 0x9991: 0x5254, //CJK UNIFIED IDEOGRAPH + 0x9992: 0x526A, //CJK UNIFIED IDEOGRAPH + 0x9993: 0x5274, //CJK UNIFIED IDEOGRAPH + 0x9994: 0x5269, //CJK UNIFIED IDEOGRAPH + 0x9995: 0x5273, //CJK UNIFIED IDEOGRAPH + 0x9996: 0x527F, //CJK UNIFIED IDEOGRAPH + 0x9997: 0x527D, //CJK UNIFIED IDEOGRAPH + 0x9998: 0x528D, //CJK UNIFIED IDEOGRAPH + 0x9999: 0x5294, //CJK UNIFIED IDEOGRAPH + 0x999A: 0x5292, //CJK UNIFIED IDEOGRAPH + 0x999B: 0x5271, //CJK UNIFIED IDEOGRAPH + 0x999C: 0x5288, //CJK UNIFIED IDEOGRAPH + 0x999D: 0x5291, //CJK UNIFIED IDEOGRAPH + 0x999E: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0x999F: 0x8FA7, //CJK UNIFIED IDEOGRAPH + 0x99A0: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0x99A1: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0x99A2: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0x99A3: 0x52B5, //CJK UNIFIED IDEOGRAPH + 0x99A4: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0x99A5: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0x99A6: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0x99A7: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0x99A8: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0x99A9: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0x99AA: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0x99AB: 0x52E0, //CJK UNIFIED IDEOGRAPH + 0x99AC: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0x99AD: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0x99AE: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0x99AF: 0x52F9, //CJK UNIFIED IDEOGRAPH + 0x99B0: 0x5306, //CJK UNIFIED IDEOGRAPH + 0x99B1: 0x5308, //CJK UNIFIED IDEOGRAPH + 0x99B2: 0x7538, //CJK UNIFIED IDEOGRAPH + 0x99B3: 0x530D, //CJK UNIFIED IDEOGRAPH + 0x99B4: 0x5310, //CJK UNIFIED IDEOGRAPH + 0x99B5: 0x530F, //CJK UNIFIED IDEOGRAPH + 0x99B6: 0x5315, //CJK UNIFIED IDEOGRAPH + 0x99B7: 0x531A, //CJK UNIFIED IDEOGRAPH + 0x99B8: 0x5323, //CJK UNIFIED IDEOGRAPH + 0x99B9: 0x532F, //CJK UNIFIED IDEOGRAPH + 0x99BA: 0x5331, //CJK UNIFIED IDEOGRAPH + 0x99BB: 0x5333, //CJK UNIFIED IDEOGRAPH + 0x99BC: 0x5338, //CJK UNIFIED IDEOGRAPH + 0x99BD: 0x5340, //CJK UNIFIED IDEOGRAPH + 0x99BE: 0x5346, //CJK UNIFIED IDEOGRAPH + 0x99BF: 0x5345, //CJK UNIFIED IDEOGRAPH + 0x99C0: 0x4E17, //CJK UNIFIED IDEOGRAPH + 0x99C1: 0x5349, //CJK UNIFIED IDEOGRAPH + 0x99C2: 0x534D, //CJK UNIFIED IDEOGRAPH + 0x99C3: 0x51D6, //CJK UNIFIED IDEOGRAPH + 0x99C4: 0x535E, //CJK UNIFIED IDEOGRAPH + 0x99C5: 0x5369, //CJK UNIFIED IDEOGRAPH + 0x99C6: 0x536E, //CJK UNIFIED IDEOGRAPH + 0x99C7: 0x5918, //CJK UNIFIED IDEOGRAPH + 0x99C8: 0x537B, //CJK UNIFIED IDEOGRAPH + 0x99C9: 0x5377, //CJK UNIFIED IDEOGRAPH + 0x99CA: 0x5382, //CJK UNIFIED IDEOGRAPH + 0x99CB: 0x5396, //CJK UNIFIED IDEOGRAPH + 0x99CC: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0x99CD: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0x99CE: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0x99CF: 0x53AE, //CJK UNIFIED IDEOGRAPH + 0x99D0: 0x53B0, //CJK UNIFIED IDEOGRAPH + 0x99D1: 0x53B6, //CJK UNIFIED IDEOGRAPH + 0x99D2: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0x99D3: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0x99D4: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0x99D5: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0x99D6: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0x99D7: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0x99D8: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0x99D9: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0x99DA: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0x99DB: 0x53FA, //CJK UNIFIED IDEOGRAPH + 0x99DC: 0x5401, //CJK UNIFIED IDEOGRAPH + 0x99DD: 0x543D, //CJK UNIFIED IDEOGRAPH + 0x99DE: 0x5440, //CJK UNIFIED IDEOGRAPH + 0x99DF: 0x542C, //CJK UNIFIED IDEOGRAPH + 0x99E0: 0x542D, //CJK UNIFIED IDEOGRAPH + 0x99E1: 0x543C, //CJK UNIFIED IDEOGRAPH + 0x99E2: 0x542E, //CJK UNIFIED IDEOGRAPH + 0x99E3: 0x5436, //CJK UNIFIED IDEOGRAPH + 0x99E4: 0x5429, //CJK UNIFIED IDEOGRAPH + 0x99E5: 0x541D, //CJK UNIFIED IDEOGRAPH + 0x99E6: 0x544E, //CJK UNIFIED IDEOGRAPH + 0x99E7: 0x548F, //CJK UNIFIED IDEOGRAPH + 0x99E8: 0x5475, //CJK UNIFIED IDEOGRAPH + 0x99E9: 0x548E, //CJK UNIFIED IDEOGRAPH + 0x99EA: 0x545F, //CJK UNIFIED IDEOGRAPH + 0x99EB: 0x5471, //CJK UNIFIED IDEOGRAPH + 0x99EC: 0x5477, //CJK UNIFIED IDEOGRAPH + 0x99ED: 0x5470, //CJK UNIFIED IDEOGRAPH + 0x99EE: 0x5492, //CJK UNIFIED IDEOGRAPH + 0x99EF: 0x547B, //CJK UNIFIED IDEOGRAPH + 0x99F0: 0x5480, //CJK UNIFIED IDEOGRAPH + 0x99F1: 0x5476, //CJK UNIFIED IDEOGRAPH + 0x99F2: 0x5484, //CJK UNIFIED IDEOGRAPH + 0x99F3: 0x5490, //CJK UNIFIED IDEOGRAPH + 0x99F4: 0x5486, //CJK UNIFIED IDEOGRAPH + 0x99F5: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0x99F6: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0x99F7: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0x99F8: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0x99F9: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0x99FA: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0x99FB: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0x99FC: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0x9A40: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0x9A41: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0x9A42: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0x9A43: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0x9A44: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0x9A45: 0x54D8, //CJK UNIFIED IDEOGRAPH + 0x9A46: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0x9A47: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0x9A48: 0x550F, //CJK UNIFIED IDEOGRAPH + 0x9A49: 0x5514, //CJK UNIFIED IDEOGRAPH + 0x9A4A: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0x9A4B: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0x9A4C: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0x9A4D: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0x9A4E: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0x9A4F: 0x5539, //CJK UNIFIED IDEOGRAPH + 0x9A50: 0x5540, //CJK UNIFIED IDEOGRAPH + 0x9A51: 0x5563, //CJK UNIFIED IDEOGRAPH + 0x9A52: 0x554C, //CJK UNIFIED IDEOGRAPH + 0x9A53: 0x552E, //CJK UNIFIED IDEOGRAPH + 0x9A54: 0x555C, //CJK UNIFIED IDEOGRAPH + 0x9A55: 0x5545, //CJK UNIFIED IDEOGRAPH + 0x9A56: 0x5556, //CJK UNIFIED IDEOGRAPH + 0x9A57: 0x5557, //CJK UNIFIED IDEOGRAPH + 0x9A58: 0x5538, //CJK UNIFIED IDEOGRAPH + 0x9A59: 0x5533, //CJK UNIFIED IDEOGRAPH + 0x9A5A: 0x555D, //CJK UNIFIED IDEOGRAPH + 0x9A5B: 0x5599, //CJK UNIFIED IDEOGRAPH + 0x9A5C: 0x5580, //CJK UNIFIED IDEOGRAPH + 0x9A5D: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0x9A5E: 0x558A, //CJK UNIFIED IDEOGRAPH + 0x9A5F: 0x559F, //CJK UNIFIED IDEOGRAPH + 0x9A60: 0x557B, //CJK UNIFIED IDEOGRAPH + 0x9A61: 0x557E, //CJK UNIFIED IDEOGRAPH + 0x9A62: 0x5598, //CJK UNIFIED IDEOGRAPH + 0x9A63: 0x559E, //CJK UNIFIED IDEOGRAPH + 0x9A64: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0x9A65: 0x557C, //CJK UNIFIED IDEOGRAPH + 0x9A66: 0x5583, //CJK UNIFIED IDEOGRAPH + 0x9A67: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0x9A68: 0x5587, //CJK UNIFIED IDEOGRAPH + 0x9A69: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0x9A6A: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0x9A6B: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0x9A6C: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0x9A6D: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0x9A6E: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0x9A6F: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0x9A70: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0x9A71: 0x5614, //CJK UNIFIED IDEOGRAPH + 0x9A72: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0x9A73: 0x5616, //CJK UNIFIED IDEOGRAPH + 0x9A74: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0x9A75: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0x9A76: 0x561B, //CJK UNIFIED IDEOGRAPH + 0x9A77: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0x9A78: 0x564E, //CJK UNIFIED IDEOGRAPH + 0x9A79: 0x5650, //CJK UNIFIED IDEOGRAPH + 0x9A7A: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0x9A7B: 0x5634, //CJK UNIFIED IDEOGRAPH + 0x9A7C: 0x5636, //CJK UNIFIED IDEOGRAPH + 0x9A7D: 0x5632, //CJK UNIFIED IDEOGRAPH + 0x9A7E: 0x5638, //CJK UNIFIED IDEOGRAPH + 0x9A80: 0x566B, //CJK UNIFIED IDEOGRAPH + 0x9A81: 0x5664, //CJK UNIFIED IDEOGRAPH + 0x9A82: 0x562F, //CJK UNIFIED IDEOGRAPH + 0x9A83: 0x566C, //CJK UNIFIED IDEOGRAPH + 0x9A84: 0x566A, //CJK UNIFIED IDEOGRAPH + 0x9A85: 0x5686, //CJK UNIFIED IDEOGRAPH + 0x9A86: 0x5680, //CJK UNIFIED IDEOGRAPH + 0x9A87: 0x568A, //CJK UNIFIED IDEOGRAPH + 0x9A88: 0x56A0, //CJK UNIFIED IDEOGRAPH + 0x9A89: 0x5694, //CJK UNIFIED IDEOGRAPH + 0x9A8A: 0x568F, //CJK UNIFIED IDEOGRAPH + 0x9A8B: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0x9A8C: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0x9A8D: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0x9A8E: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0x9A8F: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0x9A90: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0x9A91: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0x9A92: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0x9A93: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0x9A94: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0x9A95: 0x56CE, //CJK UNIFIED IDEOGRAPH + 0x9A96: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0x9A97: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0x9A98: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0x9A99: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0x9A9A: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0x9A9B: 0x5700, //CJK UNIFIED IDEOGRAPH + 0x9A9C: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0x9A9D: 0x5704, //CJK UNIFIED IDEOGRAPH + 0x9A9E: 0x5709, //CJK UNIFIED IDEOGRAPH + 0x9A9F: 0x5708, //CJK UNIFIED IDEOGRAPH + 0x9AA0: 0x570B, //CJK UNIFIED IDEOGRAPH + 0x9AA1: 0x570D, //CJK UNIFIED IDEOGRAPH + 0x9AA2: 0x5713, //CJK UNIFIED IDEOGRAPH + 0x9AA3: 0x5718, //CJK UNIFIED IDEOGRAPH + 0x9AA4: 0x5716, //CJK UNIFIED IDEOGRAPH + 0x9AA5: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0x9AA6: 0x571C, //CJK UNIFIED IDEOGRAPH + 0x9AA7: 0x5726, //CJK UNIFIED IDEOGRAPH + 0x9AA8: 0x5737, //CJK UNIFIED IDEOGRAPH + 0x9AA9: 0x5738, //CJK UNIFIED IDEOGRAPH + 0x9AAA: 0x574E, //CJK UNIFIED IDEOGRAPH + 0x9AAB: 0x573B, //CJK UNIFIED IDEOGRAPH + 0x9AAC: 0x5740, //CJK UNIFIED IDEOGRAPH + 0x9AAD: 0x574F, //CJK UNIFIED IDEOGRAPH + 0x9AAE: 0x5769, //CJK UNIFIED IDEOGRAPH + 0x9AAF: 0x57C0, //CJK UNIFIED IDEOGRAPH + 0x9AB0: 0x5788, //CJK UNIFIED IDEOGRAPH + 0x9AB1: 0x5761, //CJK UNIFIED IDEOGRAPH + 0x9AB2: 0x577F, //CJK UNIFIED IDEOGRAPH + 0x9AB3: 0x5789, //CJK UNIFIED IDEOGRAPH + 0x9AB4: 0x5793, //CJK UNIFIED IDEOGRAPH + 0x9AB5: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0x9AB6: 0x57B3, //CJK UNIFIED IDEOGRAPH + 0x9AB7: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0x9AB8: 0x57AA, //CJK UNIFIED IDEOGRAPH + 0x9AB9: 0x57B0, //CJK UNIFIED IDEOGRAPH + 0x9ABA: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0x9ABB: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0x9ABC: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0x9ABD: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0x9ABE: 0x57D3, //CJK UNIFIED IDEOGRAPH + 0x9ABF: 0x580A, //CJK UNIFIED IDEOGRAPH + 0x9AC0: 0x57D6, //CJK UNIFIED IDEOGRAPH + 0x9AC1: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0x9AC2: 0x580B, //CJK UNIFIED IDEOGRAPH + 0x9AC3: 0x5819, //CJK UNIFIED IDEOGRAPH + 0x9AC4: 0x581D, //CJK UNIFIED IDEOGRAPH + 0x9AC5: 0x5872, //CJK UNIFIED IDEOGRAPH + 0x9AC6: 0x5821, //CJK UNIFIED IDEOGRAPH + 0x9AC7: 0x5862, //CJK UNIFIED IDEOGRAPH + 0x9AC8: 0x584B, //CJK UNIFIED IDEOGRAPH + 0x9AC9: 0x5870, //CJK UNIFIED IDEOGRAPH + 0x9ACA: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0x9ACB: 0x5852, //CJK UNIFIED IDEOGRAPH + 0x9ACC: 0x583D, //CJK UNIFIED IDEOGRAPH + 0x9ACD: 0x5879, //CJK UNIFIED IDEOGRAPH + 0x9ACE: 0x5885, //CJK UNIFIED IDEOGRAPH + 0x9ACF: 0x58B9, //CJK UNIFIED IDEOGRAPH + 0x9AD0: 0x589F, //CJK UNIFIED IDEOGRAPH + 0x9AD1: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0x9AD2: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0x9AD3: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0x9AD4: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0x9AD5: 0x58B8, //CJK UNIFIED IDEOGRAPH + 0x9AD6: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0x9AD7: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0x9AD8: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0x9AD9: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0x9ADA: 0x58D7, //CJK UNIFIED IDEOGRAPH + 0x9ADB: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0x9ADC: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0x9ADD: 0x58E5, //CJK UNIFIED IDEOGRAPH + 0x9ADE: 0x58DC, //CJK UNIFIED IDEOGRAPH + 0x9ADF: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0x9AE0: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0x9AE1: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0x9AE2: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0x9AE3: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0x9AE4: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0x9AE5: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0x9AE6: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0x9AE7: 0x5902, //CJK UNIFIED IDEOGRAPH + 0x9AE8: 0x590A, //CJK UNIFIED IDEOGRAPH + 0x9AE9: 0x5910, //CJK UNIFIED IDEOGRAPH + 0x9AEA: 0x591B, //CJK UNIFIED IDEOGRAPH + 0x9AEB: 0x68A6, //CJK UNIFIED IDEOGRAPH + 0x9AEC: 0x5925, //CJK UNIFIED IDEOGRAPH + 0x9AED: 0x592C, //CJK UNIFIED IDEOGRAPH + 0x9AEE: 0x592D, //CJK UNIFIED IDEOGRAPH + 0x9AEF: 0x5932, //CJK UNIFIED IDEOGRAPH + 0x9AF0: 0x5938, //CJK UNIFIED IDEOGRAPH + 0x9AF1: 0x593E, //CJK UNIFIED IDEOGRAPH + 0x9AF2: 0x7AD2, //CJK UNIFIED IDEOGRAPH + 0x9AF3: 0x5955, //CJK UNIFIED IDEOGRAPH + 0x9AF4: 0x5950, //CJK UNIFIED IDEOGRAPH + 0x9AF5: 0x594E, //CJK UNIFIED IDEOGRAPH + 0x9AF6: 0x595A, //CJK UNIFIED IDEOGRAPH + 0x9AF7: 0x5958, //CJK UNIFIED IDEOGRAPH + 0x9AF8: 0x5962, //CJK UNIFIED IDEOGRAPH + 0x9AF9: 0x5960, //CJK UNIFIED IDEOGRAPH + 0x9AFA: 0x5967, //CJK UNIFIED IDEOGRAPH + 0x9AFB: 0x596C, //CJK UNIFIED IDEOGRAPH + 0x9AFC: 0x5969, //CJK UNIFIED IDEOGRAPH + 0x9B40: 0x5978, //CJK UNIFIED IDEOGRAPH + 0x9B41: 0x5981, //CJK UNIFIED IDEOGRAPH + 0x9B42: 0x599D, //CJK UNIFIED IDEOGRAPH + 0x9B43: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0x9B44: 0x4FAB, //CJK UNIFIED IDEOGRAPH + 0x9B45: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0x9B46: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0x9B47: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0x9B48: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0x9B49: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0x9B4A: 0x598D, //CJK UNIFIED IDEOGRAPH + 0x9B4B: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0x9B4C: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0x9B4D: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0x9B4E: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0x9B4F: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0x9B50: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0x9B51: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0x9B52: 0x5A1A, //CJK UNIFIED IDEOGRAPH + 0x9B53: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0x9B54: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0x9B55: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0x9B56: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0x9B57: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0x9B58: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0x9B59: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0x9B5A: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0x9B5B: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0x9B5C: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0x9B5D: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0x9B5E: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0x9B5F: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0x9B60: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0x9B61: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0x9B62: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0x9B63: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0x9B64: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0x9B65: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0x9B66: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0x9B67: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0x9B68: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0x9B69: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0x9B6A: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0x9B6B: 0x5AD0, //CJK UNIFIED IDEOGRAPH + 0x9B6C: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0x9B6D: 0x5B36, //CJK UNIFIED IDEOGRAPH + 0x9B6E: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0x9B6F: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0x9B70: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0x9B71: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0x9B72: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0x9B73: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0x9B74: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0x9B75: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0x9B76: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0x9B77: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0x9B78: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0x9B79: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0x9B7A: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0x9B7B: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0x9B7C: 0x6588, //CJK UNIFIED IDEOGRAPH + 0x9B7D: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0x9B7E: 0x5B80, //CJK UNIFIED IDEOGRAPH + 0x9B80: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0x9B81: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0x9B82: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0x9B83: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0x9B84: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0x9B85: 0x5BC9, //CJK UNIFIED IDEOGRAPH + 0x9B86: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0x9B87: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0x9B88: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0x9B89: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0x9B8A: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0x9B8B: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0x9B8C: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0x9B8D: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0x9B8E: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0x9B8F: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0x9B90: 0x5BF3, //CJK UNIFIED IDEOGRAPH + 0x9B91: 0x5C05, //CJK UNIFIED IDEOGRAPH + 0x9B92: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0x9B93: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0x9B94: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0x9B95: 0x5C13, //CJK UNIFIED IDEOGRAPH + 0x9B96: 0x5C20, //CJK UNIFIED IDEOGRAPH + 0x9B97: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0x9B98: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0x9B99: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0x9B9A: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0x9B9B: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0x9B9C: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0x9B9D: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0x9B9E: 0x5C53, //CJK UNIFIED IDEOGRAPH + 0x9B9F: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0x9BA0: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0x9BA1: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0x9BA2: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0x9BA3: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0x9BA4: 0x4E62, //CJK UNIFIED IDEOGRAPH + 0x9BA5: 0x5C76, //CJK UNIFIED IDEOGRAPH + 0x9BA6: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0x9BA7: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0x9BA8: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0x9BA9: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0x9BAA: 0x599B, //CJK UNIFIED IDEOGRAPH + 0x9BAB: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0x9BAC: 0x5CBB, //CJK UNIFIED IDEOGRAPH + 0x9BAD: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0x9BAE: 0x5CBC, //CJK UNIFIED IDEOGRAPH + 0x9BAF: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0x9BB0: 0x5CC5, //CJK UNIFIED IDEOGRAPH + 0x9BB1: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0x9BB2: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0x9BB3: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0x9BB4: 0x5CE9, //CJK UNIFIED IDEOGRAPH + 0x9BB5: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0x9BB6: 0x5CFA, //CJK UNIFIED IDEOGRAPH + 0x9BB7: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0x9BB8: 0x5D8C, //CJK UNIFIED IDEOGRAPH + 0x9BB9: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0x9BBA: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0x9BBB: 0x5D15, //CJK UNIFIED IDEOGRAPH + 0x9BBC: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0x9BBD: 0x5D5C, //CJK UNIFIED IDEOGRAPH + 0x9BBE: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0x9BBF: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0x9BC0: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0x9BC1: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0x9BC2: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0x9BC3: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0x9BC4: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0x9BC5: 0x5D18, //CJK UNIFIED IDEOGRAPH + 0x9BC6: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0x9BC7: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0x9BC8: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0x9BC9: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0x9BCA: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0x9BCB: 0x5D73, //CJK UNIFIED IDEOGRAPH + 0x9BCC: 0x5D76, //CJK UNIFIED IDEOGRAPH + 0x9BCD: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0x9BCE: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0x9BCF: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0x9BD0: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0x9BD1: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0x9BD2: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0x9BD3: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0x9BD4: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0x9BD5: 0x5D90, //CJK UNIFIED IDEOGRAPH + 0x9BD6: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0x9BD7: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0x9BD8: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0x9BD9: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0x9BDA: 0x5DD3, //CJK UNIFIED IDEOGRAPH + 0x9BDB: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0x9BDC: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0x9BDD: 0x5DDB, //CJK UNIFIED IDEOGRAPH + 0x9BDE: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0x9BDF: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0x9BE0: 0x5DF5, //CJK UNIFIED IDEOGRAPH + 0x9BE1: 0x5E0B, //CJK UNIFIED IDEOGRAPH + 0x9BE2: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0x9BE3: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0x9BE4: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0x9BE5: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0x9BE6: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0x9BE7: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0x9BE8: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0x9BE9: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0x9BEA: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0x9BEB: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0x9BEC: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0x9BED: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0x9BEE: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0x9BEF: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0x9BF0: 0x5E64, //CJK UNIFIED IDEOGRAPH + 0x9BF1: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0x9BF2: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0x9BF3: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0x9BF4: 0x5E7A, //CJK UNIFIED IDEOGRAPH + 0x9BF5: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0x9BF6: 0x5E7F, //CJK UNIFIED IDEOGRAPH + 0x9BF7: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0x9BF8: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0x9BF9: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0x9BFA: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0x9BFB: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0x9BFC: 0x5ECF, //CJK UNIFIED IDEOGRAPH + 0x9C40: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0x9C41: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0x9C42: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0x9C43: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0x9C44: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0x9C45: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0x9C46: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0x9C47: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0x9C48: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0x9C49: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0x9C4A: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0x9C4B: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0x9C4C: 0x5EF0, //CJK UNIFIED IDEOGRAPH + 0x9C4D: 0x5EF4, //CJK UNIFIED IDEOGRAPH + 0x9C4E: 0x5EF8, //CJK UNIFIED IDEOGRAPH + 0x9C4F: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0x9C50: 0x5F03, //CJK UNIFIED IDEOGRAPH + 0x9C51: 0x5F09, //CJK UNIFIED IDEOGRAPH + 0x9C52: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0x9C53: 0x5F5C, //CJK UNIFIED IDEOGRAPH + 0x9C54: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0x9C55: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0x9C56: 0x5F16, //CJK UNIFIED IDEOGRAPH + 0x9C57: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0x9C58: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0x9C59: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0x9C5A: 0x5F41, //CJK UNIFIED IDEOGRAPH + 0x9C5B: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0x9C5C: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0x9C5D: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0x9C5E: 0x5F2F, //CJK UNIFIED IDEOGRAPH + 0x9C5F: 0x5F51, //CJK UNIFIED IDEOGRAPH + 0x9C60: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0x9C61: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0x9C62: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0x9C63: 0x5F61, //CJK UNIFIED IDEOGRAPH + 0x9C64: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0x9C65: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0x9C66: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0x9C67: 0x5F83, //CJK UNIFIED IDEOGRAPH + 0x9C68: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0x9C69: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0x9C6A: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0x9C6B: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0x9C6C: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0x9C6D: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0x9C6E: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0x9C6F: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0x9C70: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0x9C71: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0x9C72: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0x9C73: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0x9C74: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0x9C75: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0x9C76: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0x9C77: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0x9C78: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0x9C79: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0x9C7A: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0x9C7B: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0x9C7C: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0x9C7D: 0x6021, //CJK UNIFIED IDEOGRAPH + 0x9C7E: 0x6060, //CJK UNIFIED IDEOGRAPH + 0x9C80: 0x6019, //CJK UNIFIED IDEOGRAPH + 0x9C81: 0x6010, //CJK UNIFIED IDEOGRAPH + 0x9C82: 0x6029, //CJK UNIFIED IDEOGRAPH + 0x9C83: 0x600E, //CJK UNIFIED IDEOGRAPH + 0x9C84: 0x6031, //CJK UNIFIED IDEOGRAPH + 0x9C85: 0x601B, //CJK UNIFIED IDEOGRAPH + 0x9C86: 0x6015, //CJK UNIFIED IDEOGRAPH + 0x9C87: 0x602B, //CJK UNIFIED IDEOGRAPH + 0x9C88: 0x6026, //CJK UNIFIED IDEOGRAPH + 0x9C89: 0x600F, //CJK UNIFIED IDEOGRAPH + 0x9C8A: 0x603A, //CJK UNIFIED IDEOGRAPH + 0x9C8B: 0x605A, //CJK UNIFIED IDEOGRAPH + 0x9C8C: 0x6041, //CJK UNIFIED IDEOGRAPH + 0x9C8D: 0x606A, //CJK UNIFIED IDEOGRAPH + 0x9C8E: 0x6077, //CJK UNIFIED IDEOGRAPH + 0x9C8F: 0x605F, //CJK UNIFIED IDEOGRAPH + 0x9C90: 0x604A, //CJK UNIFIED IDEOGRAPH + 0x9C91: 0x6046, //CJK UNIFIED IDEOGRAPH + 0x9C92: 0x604D, //CJK UNIFIED IDEOGRAPH + 0x9C93: 0x6063, //CJK UNIFIED IDEOGRAPH + 0x9C94: 0x6043, //CJK UNIFIED IDEOGRAPH + 0x9C95: 0x6064, //CJK UNIFIED IDEOGRAPH + 0x9C96: 0x6042, //CJK UNIFIED IDEOGRAPH + 0x9C97: 0x606C, //CJK UNIFIED IDEOGRAPH + 0x9C98: 0x606B, //CJK UNIFIED IDEOGRAPH + 0x9C99: 0x6059, //CJK UNIFIED IDEOGRAPH + 0x9C9A: 0x6081, //CJK UNIFIED IDEOGRAPH + 0x9C9B: 0x608D, //CJK UNIFIED IDEOGRAPH + 0x9C9C: 0x60E7, //CJK UNIFIED IDEOGRAPH + 0x9C9D: 0x6083, //CJK UNIFIED IDEOGRAPH + 0x9C9E: 0x609A, //CJK UNIFIED IDEOGRAPH + 0x9C9F: 0x6084, //CJK UNIFIED IDEOGRAPH + 0x9CA0: 0x609B, //CJK UNIFIED IDEOGRAPH + 0x9CA1: 0x6096, //CJK UNIFIED IDEOGRAPH + 0x9CA2: 0x6097, //CJK UNIFIED IDEOGRAPH + 0x9CA3: 0x6092, //CJK UNIFIED IDEOGRAPH + 0x9CA4: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0x9CA5: 0x608B, //CJK UNIFIED IDEOGRAPH + 0x9CA6: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0x9CA7: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0x9CA8: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0x9CA9: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0x9CAA: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0x9CAB: 0x5FF0, //CJK UNIFIED IDEOGRAPH + 0x9CAC: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0x9CAD: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0x9CAE: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0x9CAF: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0x9CB0: 0x614D, //CJK UNIFIED IDEOGRAPH + 0x9CB1: 0x6115, //CJK UNIFIED IDEOGRAPH + 0x9CB2: 0x6106, //CJK UNIFIED IDEOGRAPH + 0x9CB3: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0x9CB4: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0x9CB5: 0x6100, //CJK UNIFIED IDEOGRAPH + 0x9CB6: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0x9CB7: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0x9CB8: 0x6103, //CJK UNIFIED IDEOGRAPH + 0x9CB9: 0x6121, //CJK UNIFIED IDEOGRAPH + 0x9CBA: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0x9CBB: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0x9CBC: 0x610D, //CJK UNIFIED IDEOGRAPH + 0x9CBD: 0x610E, //CJK UNIFIED IDEOGRAPH + 0x9CBE: 0x6147, //CJK UNIFIED IDEOGRAPH + 0x9CBF: 0x613E, //CJK UNIFIED IDEOGRAPH + 0x9CC0: 0x6128, //CJK UNIFIED IDEOGRAPH + 0x9CC1: 0x6127, //CJK UNIFIED IDEOGRAPH + 0x9CC2: 0x614A, //CJK UNIFIED IDEOGRAPH + 0x9CC3: 0x613F, //CJK UNIFIED IDEOGRAPH + 0x9CC4: 0x613C, //CJK UNIFIED IDEOGRAPH + 0x9CC5: 0x612C, //CJK UNIFIED IDEOGRAPH + 0x9CC6: 0x6134, //CJK UNIFIED IDEOGRAPH + 0x9CC7: 0x613D, //CJK UNIFIED IDEOGRAPH + 0x9CC8: 0x6142, //CJK UNIFIED IDEOGRAPH + 0x9CC9: 0x6144, //CJK UNIFIED IDEOGRAPH + 0x9CCA: 0x6173, //CJK UNIFIED IDEOGRAPH + 0x9CCB: 0x6177, //CJK UNIFIED IDEOGRAPH + 0x9CCC: 0x6158, //CJK UNIFIED IDEOGRAPH + 0x9CCD: 0x6159, //CJK UNIFIED IDEOGRAPH + 0x9CCE: 0x615A, //CJK UNIFIED IDEOGRAPH + 0x9CCF: 0x616B, //CJK UNIFIED IDEOGRAPH + 0x9CD0: 0x6174, //CJK UNIFIED IDEOGRAPH + 0x9CD1: 0x616F, //CJK UNIFIED IDEOGRAPH + 0x9CD2: 0x6165, //CJK UNIFIED IDEOGRAPH + 0x9CD3: 0x6171, //CJK UNIFIED IDEOGRAPH + 0x9CD4: 0x615F, //CJK UNIFIED IDEOGRAPH + 0x9CD5: 0x615D, //CJK UNIFIED IDEOGRAPH + 0x9CD6: 0x6153, //CJK UNIFIED IDEOGRAPH + 0x9CD7: 0x6175, //CJK UNIFIED IDEOGRAPH + 0x9CD8: 0x6199, //CJK UNIFIED IDEOGRAPH + 0x9CD9: 0x6196, //CJK UNIFIED IDEOGRAPH + 0x9CDA: 0x6187, //CJK UNIFIED IDEOGRAPH + 0x9CDB: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0x9CDC: 0x6194, //CJK UNIFIED IDEOGRAPH + 0x9CDD: 0x619A, //CJK UNIFIED IDEOGRAPH + 0x9CDE: 0x618A, //CJK UNIFIED IDEOGRAPH + 0x9CDF: 0x6191, //CJK UNIFIED IDEOGRAPH + 0x9CE0: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0x9CE1: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0x9CE2: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0x9CE3: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0x9CE4: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0x9CE5: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0x9CE6: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0x9CE7: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0x9CE8: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0x9CE9: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0x9CEA: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0x9CEB: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0x9CEC: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0x9CED: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0x9CEE: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0x9CEF: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0x9CF0: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0x9CF1: 0x61F4, //CJK UNIFIED IDEOGRAPH + 0x9CF2: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0x9CF3: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0x9CF4: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0x9CF5: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0x9CF6: 0x6200, //CJK UNIFIED IDEOGRAPH + 0x9CF7: 0x6208, //CJK UNIFIED IDEOGRAPH + 0x9CF8: 0x6209, //CJK UNIFIED IDEOGRAPH + 0x9CF9: 0x620D, //CJK UNIFIED IDEOGRAPH + 0x9CFA: 0x620C, //CJK UNIFIED IDEOGRAPH + 0x9CFB: 0x6214, //CJK UNIFIED IDEOGRAPH + 0x9CFC: 0x621B, //CJK UNIFIED IDEOGRAPH + 0x9D40: 0x621E, //CJK UNIFIED IDEOGRAPH + 0x9D41: 0x6221, //CJK UNIFIED IDEOGRAPH + 0x9D42: 0x622A, //CJK UNIFIED IDEOGRAPH + 0x9D43: 0x622E, //CJK UNIFIED IDEOGRAPH + 0x9D44: 0x6230, //CJK UNIFIED IDEOGRAPH + 0x9D45: 0x6232, //CJK UNIFIED IDEOGRAPH + 0x9D46: 0x6233, //CJK UNIFIED IDEOGRAPH + 0x9D47: 0x6241, //CJK UNIFIED IDEOGRAPH + 0x9D48: 0x624E, //CJK UNIFIED IDEOGRAPH + 0x9D49: 0x625E, //CJK UNIFIED IDEOGRAPH + 0x9D4A: 0x6263, //CJK UNIFIED IDEOGRAPH + 0x9D4B: 0x625B, //CJK UNIFIED IDEOGRAPH + 0x9D4C: 0x6260, //CJK UNIFIED IDEOGRAPH + 0x9D4D: 0x6268, //CJK UNIFIED IDEOGRAPH + 0x9D4E: 0x627C, //CJK UNIFIED IDEOGRAPH + 0x9D4F: 0x6282, //CJK UNIFIED IDEOGRAPH + 0x9D50: 0x6289, //CJK UNIFIED IDEOGRAPH + 0x9D51: 0x627E, //CJK UNIFIED IDEOGRAPH + 0x9D52: 0x6292, //CJK UNIFIED IDEOGRAPH + 0x9D53: 0x6293, //CJK UNIFIED IDEOGRAPH + 0x9D54: 0x6296, //CJK UNIFIED IDEOGRAPH + 0x9D55: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0x9D56: 0x6283, //CJK UNIFIED IDEOGRAPH + 0x9D57: 0x6294, //CJK UNIFIED IDEOGRAPH + 0x9D58: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0x9D59: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0x9D5A: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0x9D5B: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0x9D5C: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0x9D5D: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0x9D5E: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0x9D5F: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0x9D60: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0x9D61: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0x9D62: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0x9D63: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0x9D64: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0x9D65: 0x629B, //CJK UNIFIED IDEOGRAPH + 0x9D66: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0x9D67: 0x630C, //CJK UNIFIED IDEOGRAPH + 0x9D68: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0x9D69: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0x9D6A: 0x6327, //CJK UNIFIED IDEOGRAPH + 0x9D6B: 0x6302, //CJK UNIFIED IDEOGRAPH + 0x9D6C: 0x6308, //CJK UNIFIED IDEOGRAPH + 0x9D6D: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0x9D6E: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0x9D6F: 0x6350, //CJK UNIFIED IDEOGRAPH + 0x9D70: 0x633E, //CJK UNIFIED IDEOGRAPH + 0x9D71: 0x634D, //CJK UNIFIED IDEOGRAPH + 0x9D72: 0x641C, //CJK UNIFIED IDEOGRAPH + 0x9D73: 0x634F, //CJK UNIFIED IDEOGRAPH + 0x9D74: 0x6396, //CJK UNIFIED IDEOGRAPH + 0x9D75: 0x638E, //CJK UNIFIED IDEOGRAPH + 0x9D76: 0x6380, //CJK UNIFIED IDEOGRAPH + 0x9D77: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0x9D78: 0x6376, //CJK UNIFIED IDEOGRAPH + 0x9D79: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0x9D7A: 0x638F, //CJK UNIFIED IDEOGRAPH + 0x9D7B: 0x6389, //CJK UNIFIED IDEOGRAPH + 0x9D7C: 0x639F, //CJK UNIFIED IDEOGRAPH + 0x9D7D: 0x63B5, //CJK UNIFIED IDEOGRAPH + 0x9D7E: 0x636B, //CJK UNIFIED IDEOGRAPH + 0x9D80: 0x6369, //CJK UNIFIED IDEOGRAPH + 0x9D81: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0x9D82: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0x9D83: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0x9D84: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0x9D85: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0x9D86: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0x9D87: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0x9D88: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0x9D89: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0x9D8A: 0x6416, //CJK UNIFIED IDEOGRAPH + 0x9D8B: 0x6434, //CJK UNIFIED IDEOGRAPH + 0x9D8C: 0x6406, //CJK UNIFIED IDEOGRAPH + 0x9D8D: 0x6413, //CJK UNIFIED IDEOGRAPH + 0x9D8E: 0x6426, //CJK UNIFIED IDEOGRAPH + 0x9D8F: 0x6436, //CJK UNIFIED IDEOGRAPH + 0x9D90: 0x651D, //CJK UNIFIED IDEOGRAPH + 0x9D91: 0x6417, //CJK UNIFIED IDEOGRAPH + 0x9D92: 0x6428, //CJK UNIFIED IDEOGRAPH + 0x9D93: 0x640F, //CJK UNIFIED IDEOGRAPH + 0x9D94: 0x6467, //CJK UNIFIED IDEOGRAPH + 0x9D95: 0x646F, //CJK UNIFIED IDEOGRAPH + 0x9D96: 0x6476, //CJK UNIFIED IDEOGRAPH + 0x9D97: 0x644E, //CJK UNIFIED IDEOGRAPH + 0x9D98: 0x652A, //CJK UNIFIED IDEOGRAPH + 0x9D99: 0x6495, //CJK UNIFIED IDEOGRAPH + 0x9D9A: 0x6493, //CJK UNIFIED IDEOGRAPH + 0x9D9B: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0x9D9C: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0x9D9D: 0x6488, //CJK UNIFIED IDEOGRAPH + 0x9D9E: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0x9D9F: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0x9DA0: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0x9DA1: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0x9DA2: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0x9DA3: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0x9DA4: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0x9DA5: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0x9DA6: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0x9DA7: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0x9DA8: 0x8209, //CJK UNIFIED IDEOGRAPH + 0x9DA9: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0x9DAA: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0x9DAB: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0x9DAC: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0x9DAD: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0x9DAE: 0x652C, //CJK UNIFIED IDEOGRAPH + 0x9DAF: 0x64F6, //CJK UNIFIED IDEOGRAPH + 0x9DB0: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0x9DB1: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0x9DB2: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0x9DB3: 0x6500, //CJK UNIFIED IDEOGRAPH + 0x9DB4: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0x9DB5: 0x6518, //CJK UNIFIED IDEOGRAPH + 0x9DB6: 0x651C, //CJK UNIFIED IDEOGRAPH + 0x9DB7: 0x6505, //CJK UNIFIED IDEOGRAPH + 0x9DB8: 0x6524, //CJK UNIFIED IDEOGRAPH + 0x9DB9: 0x6523, //CJK UNIFIED IDEOGRAPH + 0x9DBA: 0x652B, //CJK UNIFIED IDEOGRAPH + 0x9DBB: 0x6534, //CJK UNIFIED IDEOGRAPH + 0x9DBC: 0x6535, //CJK UNIFIED IDEOGRAPH + 0x9DBD: 0x6537, //CJK UNIFIED IDEOGRAPH + 0x9DBE: 0x6536, //CJK UNIFIED IDEOGRAPH + 0x9DBF: 0x6538, //CJK UNIFIED IDEOGRAPH + 0x9DC0: 0x754B, //CJK UNIFIED IDEOGRAPH + 0x9DC1: 0x6548, //CJK UNIFIED IDEOGRAPH + 0x9DC2: 0x6556, //CJK UNIFIED IDEOGRAPH + 0x9DC3: 0x6555, //CJK UNIFIED IDEOGRAPH + 0x9DC4: 0x654D, //CJK UNIFIED IDEOGRAPH + 0x9DC5: 0x6558, //CJK UNIFIED IDEOGRAPH + 0x9DC6: 0x655E, //CJK UNIFIED IDEOGRAPH + 0x9DC7: 0x655D, //CJK UNIFIED IDEOGRAPH + 0x9DC8: 0x6572, //CJK UNIFIED IDEOGRAPH + 0x9DC9: 0x6578, //CJK UNIFIED IDEOGRAPH + 0x9DCA: 0x6582, //CJK UNIFIED IDEOGRAPH + 0x9DCB: 0x6583, //CJK UNIFIED IDEOGRAPH + 0x9DCC: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0x9DCD: 0x659B, //CJK UNIFIED IDEOGRAPH + 0x9DCE: 0x659F, //CJK UNIFIED IDEOGRAPH + 0x9DCF: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0x9DD0: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0x9DD1: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0x9DD2: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0x9DD3: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0x9DD4: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0x9DD5: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0x9DD6: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0x9DD7: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0x9DD8: 0x65D9, //CJK UNIFIED IDEOGRAPH + 0x9DD9: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0x9DDA: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0x9DDB: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0x9DDC: 0x6772, //CJK UNIFIED IDEOGRAPH + 0x9DDD: 0x660A, //CJK UNIFIED IDEOGRAPH + 0x9DDE: 0x6603, //CJK UNIFIED IDEOGRAPH + 0x9DDF: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0x9DE0: 0x6773, //CJK UNIFIED IDEOGRAPH + 0x9DE1: 0x6635, //CJK UNIFIED IDEOGRAPH + 0x9DE2: 0x6636, //CJK UNIFIED IDEOGRAPH + 0x9DE3: 0x6634, //CJK UNIFIED IDEOGRAPH + 0x9DE4: 0x661C, //CJK UNIFIED IDEOGRAPH + 0x9DE5: 0x664F, //CJK UNIFIED IDEOGRAPH + 0x9DE6: 0x6644, //CJK UNIFIED IDEOGRAPH + 0x9DE7: 0x6649, //CJK UNIFIED IDEOGRAPH + 0x9DE8: 0x6641, //CJK UNIFIED IDEOGRAPH + 0x9DE9: 0x665E, //CJK UNIFIED IDEOGRAPH + 0x9DEA: 0x665D, //CJK UNIFIED IDEOGRAPH + 0x9DEB: 0x6664, //CJK UNIFIED IDEOGRAPH + 0x9DEC: 0x6667, //CJK UNIFIED IDEOGRAPH + 0x9DED: 0x6668, //CJK UNIFIED IDEOGRAPH + 0x9DEE: 0x665F, //CJK UNIFIED IDEOGRAPH + 0x9DEF: 0x6662, //CJK UNIFIED IDEOGRAPH + 0x9DF0: 0x6670, //CJK UNIFIED IDEOGRAPH + 0x9DF1: 0x6683, //CJK UNIFIED IDEOGRAPH + 0x9DF2: 0x6688, //CJK UNIFIED IDEOGRAPH + 0x9DF3: 0x668E, //CJK UNIFIED IDEOGRAPH + 0x9DF4: 0x6689, //CJK UNIFIED IDEOGRAPH + 0x9DF5: 0x6684, //CJK UNIFIED IDEOGRAPH + 0x9DF6: 0x6698, //CJK UNIFIED IDEOGRAPH + 0x9DF7: 0x669D, //CJK UNIFIED IDEOGRAPH + 0x9DF8: 0x66C1, //CJK UNIFIED IDEOGRAPH + 0x9DF9: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0x9DFA: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0x9DFB: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0x9DFC: 0x66BC, //CJK UNIFIED IDEOGRAPH + 0x9E40: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0x9E41: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0x9E42: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0x9E43: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0x9E44: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0x9E45: 0x663F, //CJK UNIFIED IDEOGRAPH + 0x9E46: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0x9E47: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0x9E48: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0x9E49: 0x66F5, //CJK UNIFIED IDEOGRAPH + 0x9E4A: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0x9E4B: 0x670F, //CJK UNIFIED IDEOGRAPH + 0x9E4C: 0x6716, //CJK UNIFIED IDEOGRAPH + 0x9E4D: 0x671E, //CJK UNIFIED IDEOGRAPH + 0x9E4E: 0x6726, //CJK UNIFIED IDEOGRAPH + 0x9E4F: 0x6727, //CJK UNIFIED IDEOGRAPH + 0x9E50: 0x9738, //CJK UNIFIED IDEOGRAPH + 0x9E51: 0x672E, //CJK UNIFIED IDEOGRAPH + 0x9E52: 0x673F, //CJK UNIFIED IDEOGRAPH + 0x9E53: 0x6736, //CJK UNIFIED IDEOGRAPH + 0x9E54: 0x6741, //CJK UNIFIED IDEOGRAPH + 0x9E55: 0x6738, //CJK UNIFIED IDEOGRAPH + 0x9E56: 0x6737, //CJK UNIFIED IDEOGRAPH + 0x9E57: 0x6746, //CJK UNIFIED IDEOGRAPH + 0x9E58: 0x675E, //CJK UNIFIED IDEOGRAPH + 0x9E59: 0x6760, //CJK UNIFIED IDEOGRAPH + 0x9E5A: 0x6759, //CJK UNIFIED IDEOGRAPH + 0x9E5B: 0x6763, //CJK UNIFIED IDEOGRAPH + 0x9E5C: 0x6764, //CJK UNIFIED IDEOGRAPH + 0x9E5D: 0x6789, //CJK UNIFIED IDEOGRAPH + 0x9E5E: 0x6770, //CJK UNIFIED IDEOGRAPH + 0x9E5F: 0x67A9, //CJK UNIFIED IDEOGRAPH + 0x9E60: 0x677C, //CJK UNIFIED IDEOGRAPH + 0x9E61: 0x676A, //CJK UNIFIED IDEOGRAPH + 0x9E62: 0x678C, //CJK UNIFIED IDEOGRAPH + 0x9E63: 0x678B, //CJK UNIFIED IDEOGRAPH + 0x9E64: 0x67A6, //CJK UNIFIED IDEOGRAPH + 0x9E65: 0x67A1, //CJK UNIFIED IDEOGRAPH + 0x9E66: 0x6785, //CJK UNIFIED IDEOGRAPH + 0x9E67: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0x9E68: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0x9E69: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0x9E6A: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0x9E6B: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0x9E6C: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0x9E6D: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0x9E6E: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0x9E6F: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0x9E70: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0x9E71: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0x9E72: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0x9E73: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0x9E74: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0x9E75: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0x9E76: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0x9E77: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0x9E78: 0x681E, //CJK UNIFIED IDEOGRAPH + 0x9E79: 0x6846, //CJK UNIFIED IDEOGRAPH + 0x9E7A: 0x6829, //CJK UNIFIED IDEOGRAPH + 0x9E7B: 0x6840, //CJK UNIFIED IDEOGRAPH + 0x9E7C: 0x684D, //CJK UNIFIED IDEOGRAPH + 0x9E7D: 0x6832, //CJK UNIFIED IDEOGRAPH + 0x9E7E: 0x684E, //CJK UNIFIED IDEOGRAPH + 0x9E80: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0x9E81: 0x682B, //CJK UNIFIED IDEOGRAPH + 0x9E82: 0x6859, //CJK UNIFIED IDEOGRAPH + 0x9E83: 0x6863, //CJK UNIFIED IDEOGRAPH + 0x9E84: 0x6877, //CJK UNIFIED IDEOGRAPH + 0x9E85: 0x687F, //CJK UNIFIED IDEOGRAPH + 0x9E86: 0x689F, //CJK UNIFIED IDEOGRAPH + 0x9E87: 0x688F, //CJK UNIFIED IDEOGRAPH + 0x9E88: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0x9E89: 0x6894, //CJK UNIFIED IDEOGRAPH + 0x9E8A: 0x689D, //CJK UNIFIED IDEOGRAPH + 0x9E8B: 0x689B, //CJK UNIFIED IDEOGRAPH + 0x9E8C: 0x6883, //CJK UNIFIED IDEOGRAPH + 0x9E8D: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0x9E8E: 0x68B9, //CJK UNIFIED IDEOGRAPH + 0x9E8F: 0x6874, //CJK UNIFIED IDEOGRAPH + 0x9E90: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0x9E91: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0x9E92: 0x68BA, //CJK UNIFIED IDEOGRAPH + 0x9E93: 0x690F, //CJK UNIFIED IDEOGRAPH + 0x9E94: 0x688D, //CJK UNIFIED IDEOGRAPH + 0x9E95: 0x687E, //CJK UNIFIED IDEOGRAPH + 0x9E96: 0x6901, //CJK UNIFIED IDEOGRAPH + 0x9E97: 0x68CA, //CJK UNIFIED IDEOGRAPH + 0x9E98: 0x6908, //CJK UNIFIED IDEOGRAPH + 0x9E99: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0x9E9A: 0x6922, //CJK UNIFIED IDEOGRAPH + 0x9E9B: 0x6926, //CJK UNIFIED IDEOGRAPH + 0x9E9C: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0x9E9D: 0x690C, //CJK UNIFIED IDEOGRAPH + 0x9E9E: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0x9E9F: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0x9EA0: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0x9EA1: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0x9EA2: 0x6936, //CJK UNIFIED IDEOGRAPH + 0x9EA3: 0x6912, //CJK UNIFIED IDEOGRAPH + 0x9EA4: 0x6904, //CJK UNIFIED IDEOGRAPH + 0x9EA5: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0x9EA6: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0x9EA7: 0x6925, //CJK UNIFIED IDEOGRAPH + 0x9EA8: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0x9EA9: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0x9EAA: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0x9EAB: 0x6928, //CJK UNIFIED IDEOGRAPH + 0x9EAC: 0x692A, //CJK UNIFIED IDEOGRAPH + 0x9EAD: 0x691A, //CJK UNIFIED IDEOGRAPH + 0x9EAE: 0x6923, //CJK UNIFIED IDEOGRAPH + 0x9EAF: 0x6921, //CJK UNIFIED IDEOGRAPH + 0x9EB0: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0x9EB1: 0x6979, //CJK UNIFIED IDEOGRAPH + 0x9EB2: 0x6977, //CJK UNIFIED IDEOGRAPH + 0x9EB3: 0x695C, //CJK UNIFIED IDEOGRAPH + 0x9EB4: 0x6978, //CJK UNIFIED IDEOGRAPH + 0x9EB5: 0x696B, //CJK UNIFIED IDEOGRAPH + 0x9EB6: 0x6954, //CJK UNIFIED IDEOGRAPH + 0x9EB7: 0x697E, //CJK UNIFIED IDEOGRAPH + 0x9EB8: 0x696E, //CJK UNIFIED IDEOGRAPH + 0x9EB9: 0x6939, //CJK UNIFIED IDEOGRAPH + 0x9EBA: 0x6974, //CJK UNIFIED IDEOGRAPH + 0x9EBB: 0x693D, //CJK UNIFIED IDEOGRAPH + 0x9EBC: 0x6959, //CJK UNIFIED IDEOGRAPH + 0x9EBD: 0x6930, //CJK UNIFIED IDEOGRAPH + 0x9EBE: 0x6961, //CJK UNIFIED IDEOGRAPH + 0x9EBF: 0x695E, //CJK UNIFIED IDEOGRAPH + 0x9EC0: 0x695D, //CJK UNIFIED IDEOGRAPH + 0x9EC1: 0x6981, //CJK UNIFIED IDEOGRAPH + 0x9EC2: 0x696A, //CJK UNIFIED IDEOGRAPH + 0x9EC3: 0x69B2, //CJK UNIFIED IDEOGRAPH + 0x9EC4: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0x9EC5: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0x9EC6: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0x9EC7: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0x9EC8: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0x9EC9: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0x9ECA: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0x9ECB: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0x9ECC: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0x9ECD: 0x69DD, //CJK UNIFIED IDEOGRAPH + 0x9ECE: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0x9ECF: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0x9ED0: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0x9ED1: 0x6A2E, //CJK UNIFIED IDEOGRAPH + 0x9ED2: 0x6991, //CJK UNIFIED IDEOGRAPH + 0x9ED3: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0x9ED4: 0x699C, //CJK UNIFIED IDEOGRAPH + 0x9ED5: 0x6995, //CJK UNIFIED IDEOGRAPH + 0x9ED6: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0x9ED7: 0x69DE, //CJK UNIFIED IDEOGRAPH + 0x9ED8: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0x9ED9: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0x9EDA: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0x9EDB: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0x9EDC: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0x9EDD: 0x69F9, //CJK UNIFIED IDEOGRAPH + 0x9EDE: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0x9EDF: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0x9EE0: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0x9EE1: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0x9EE2: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0x9EE3: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0x9EE4: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0x9EE5: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0x9EE6: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0x9EE7: 0x6A12, //CJK UNIFIED IDEOGRAPH + 0x9EE8: 0x6AC1, //CJK UNIFIED IDEOGRAPH + 0x9EE9: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0x9EEA: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0x9EEB: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0x9EEC: 0x6A0C, //CJK UNIFIED IDEOGRAPH + 0x9EED: 0x6A72, //CJK UNIFIED IDEOGRAPH + 0x9EEE: 0x6A36, //CJK UNIFIED IDEOGRAPH + 0x9EEF: 0x6A78, //CJK UNIFIED IDEOGRAPH + 0x9EF0: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0x9EF1: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0x9EF2: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0x9EF3: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0x9EF4: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0x9EF5: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0x9EF6: 0x6A22, //CJK UNIFIED IDEOGRAPH + 0x9EF7: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0x9EF8: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0x9EF9: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0x9EFA: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0x9EFB: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0x9EFC: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0x9F40: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0x9F41: 0x8617, //CJK UNIFIED IDEOGRAPH + 0x9F42: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0x9F43: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0x9F44: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0x9F45: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0x9F46: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0x9F47: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0x9F48: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0x9F49: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0x9F4A: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0x9F4B: 0x6AAA, //CJK UNIFIED IDEOGRAPH + 0x9F4C: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0x9F4D: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0x9F4E: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0x9F4F: 0x6B05, //CJK UNIFIED IDEOGRAPH + 0x9F50: 0x8616, //CJK UNIFIED IDEOGRAPH + 0x9F51: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0x9F52: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0x9F53: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0x9F54: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0x9F55: 0x6B1F, //CJK UNIFIED IDEOGRAPH + 0x9F56: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0x9F57: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0x9F58: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0x9F59: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0x9F5A: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0x9F5B: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0x9F5C: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0x9F5D: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0x9F5E: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0x9F5F: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0x9F60: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0x9F61: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0x9F62: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0x9F63: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0x9F64: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0x9F65: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0x9F66: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0x9F67: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0x9F68: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0x9F69: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0x9F6A: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0x9F6B: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0x9F6C: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0x9F6D: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0x9F6E: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0x9F6F: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0x9F70: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0x9F71: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0x9F72: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0x9F73: 0x6BB1, //CJK UNIFIED IDEOGRAPH + 0x9F74: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0x9F75: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0x9F76: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0x9F77: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0x9F78: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0x9F79: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0x9F7A: 0x6BDF, //CJK UNIFIED IDEOGRAPH + 0x9F7B: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0x9F7C: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0x9F7D: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0x9F7E: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0x9F80: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0x9F81: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0x9F82: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0x9F83: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0x9F84: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0x9F85: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0x9F86: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0x9F87: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0x9F88: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0x9F89: 0x6C62, //CJK UNIFIED IDEOGRAPH + 0x9F8A: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0x9F8B: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0x9F8C: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0x9F8D: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0x9F8E: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0x9F8F: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0x9F90: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0x9F91: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0x9F92: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0x9F93: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0x9F94: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0x9F95: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0x9F96: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0x9F97: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0x9F98: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0x9F99: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0x9F9A: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0x9F9B: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0x9F9C: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0x9F9D: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0x9F9E: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0x9F9F: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0x9FA0: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0x9FA1: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0x9FA2: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0x9FA3: 0x6CEA, //CJK UNIFIED IDEOGRAPH + 0x9FA4: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0x9FA5: 0x884D, //CJK UNIFIED IDEOGRAPH + 0x9FA6: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0x9FA7: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0x9FA8: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0x9FA9: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0x9FAA: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0x9FAB: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0x9FAC: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0x9FAD: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0x9FAE: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0x9FAF: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0x9FB0: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0x9FB1: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0x9FB2: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0x9FB3: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0x9FB4: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0x9FB5: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0x9FB6: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0x9FB7: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0x9FB8: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0x9FB9: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0x9FBA: 0x6E15, //CJK UNIFIED IDEOGRAPH + 0x9FBB: 0x6E0A, //CJK UNIFIED IDEOGRAPH + 0x9FBC: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0x9FBD: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0x9FBE: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0x9FBF: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0x9FC0: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0x9FC1: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0x9FC2: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0x9FC3: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0x9FC4: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0x9FC5: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0x9FC6: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0x9FC7: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0x9FC8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0x9FC9: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0x9FCA: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0x9FCB: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0x9FCC: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0x9FCD: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0x9FCE: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0x9FCF: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0x9FD0: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0x9FD1: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0x9FD2: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0x9FD3: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0x9FD4: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0x9FD5: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0x9FD6: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0x9FD7: 0x6E76, //CJK UNIFIED IDEOGRAPH + 0x9FD8: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0x9FD9: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0x9FDA: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0x9FDB: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0x9FDC: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0x9FDD: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0x9FDE: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0x9FDF: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0x9FE0: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0x9FE1: 0x6E82, //CJK UNIFIED IDEOGRAPH + 0x9FE2: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0x9FE3: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0x9FE4: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0x9FE5: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0x9FE6: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0x9FE7: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0x9FE8: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0x9FE9: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0x9FEA: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0x9FEB: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0x9FEC: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0x9FED: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0x9FEE: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0x9FEF: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0x9FF0: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0x9FF1: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0x9FF2: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0x9FF3: 0x704C, //CJK UNIFIED IDEOGRAPH + 0x9FF4: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0x9FF5: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0x9FF6: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0x9FF7: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0x9FF8: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0x9FF9: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0x9FFA: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0x9FFB: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0x9FFC: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x6FF3, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x6F91, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x6F74, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x7030, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x7032, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xE080: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xE081: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xE082: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xE083: 0x711C, //CJK UNIFIED IDEOGRAPH + 0xE084: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xE085: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xE086: 0x7155, //CJK UNIFIED IDEOGRAPH + 0xE087: 0x7188, //CJK UNIFIED IDEOGRAPH + 0xE088: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xE089: 0x7162, //CJK UNIFIED IDEOGRAPH + 0xE08A: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xE08B: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xE08C: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xE08D: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xE08E: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xE08F: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xE090: 0x7195, //CJK UNIFIED IDEOGRAPH + 0xE091: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xE092: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xE093: 0x71D7, //CJK UNIFIED IDEOGRAPH + 0xE094: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xE095: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xE096: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xE097: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xE098: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xE099: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xE09A: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xE09B: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xE09C: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xE09D: 0x71F5, //CJK UNIFIED IDEOGRAPH + 0xE09E: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xE09F: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xE0A0: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x723C, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x7282, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x7287, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x72B9, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x72B2, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x72E2, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x732F, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x734F, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x73CE, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x74A2, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x7476, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x73F1, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x74E7, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x74F2, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x74F0, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x74F1, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x74F8, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x7505, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x750E, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x751E, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x753C, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x7544, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x754D, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x754A, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x7549, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x7546, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x7569, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x7567, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x756D, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x7574, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x7589, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x7582, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x75C3, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xE180: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xE181: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xE182: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xE183: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xE184: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xE185: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xE186: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xE187: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xE188: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xE189: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xE18A: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xE18B: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xE18C: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xE18D: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xE18E: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xE18F: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xE190: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xE191: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xE192: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xE193: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xE194: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xE195: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xE196: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xE197: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xE198: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xE199: 0x7668, //CJK UNIFIED IDEOGRAPH + 0xE19A: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xE19B: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xE19C: 0x7667, //CJK UNIFIED IDEOGRAPH + 0xE19D: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xE19E: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xE19F: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xE1A0: 0x7676, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x7680, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x7683, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x76B9, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x862F, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x7724, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x7726, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x77B9, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x7874, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x78B5, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x78AF, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x78C6, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x7907, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x799D, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x79E1, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x7980, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x7A3E, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x7A43, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x9F9D, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x7AC8, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x7AB0, //CJK UNIFIED IDEOGRAPH + 0xE280: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xE281: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xE282: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xE283: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xE284: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE285: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xE286: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xE287: 0x7ACD, //CJK UNIFIED IDEOGRAPH + 0xE288: 0x7ACF, //CJK UNIFIED IDEOGRAPH + 0xE289: 0x7AD5, //CJK UNIFIED IDEOGRAPH + 0xE28A: 0x7AD3, //CJK UNIFIED IDEOGRAPH + 0xE28B: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xE28C: 0x7ADA, //CJK UNIFIED IDEOGRAPH + 0xE28D: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xE28E: 0x7AE1, //CJK UNIFIED IDEOGRAPH + 0xE28F: 0x7AE2, //CJK UNIFIED IDEOGRAPH + 0xE290: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xE291: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xE292: 0x7AF0, //CJK UNIFIED IDEOGRAPH + 0xE293: 0x7B02, //CJK UNIFIED IDEOGRAPH + 0xE294: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xE295: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xE296: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xE297: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xE298: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xE299: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xE29A: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xE29B: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xE29C: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xE29D: 0x7B36, //CJK UNIFIED IDEOGRAPH + 0xE29E: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xE29F: 0x7B7A, //CJK UNIFIED IDEOGRAPH + 0xE2A0: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x7B0B, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7B9F, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x7B92, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x7B5D, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x7BCF, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x7C14, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x7C13, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x7C17, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x7BF6, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x7C4F, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7C58, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x7C56, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x7C90, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x7CA4, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x7CAD, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x7CAB, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x7CC0, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x7CC2, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x7CD8, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x7CFA, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x7D4B, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x7D89, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x7D9B, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x7DAB, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x7DDC, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x7DE4, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x7E05, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x7E66, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xE380: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xE381: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xE382: 0x7E67, //CJK UNIFIED IDEOGRAPH + 0xE383: 0x7E5D, //CJK UNIFIED IDEOGRAPH + 0xE384: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xE385: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xE386: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xE387: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xE388: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xE389: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xE38A: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xE38B: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xE38C: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xE38D: 0x7E83, //CJK UNIFIED IDEOGRAPH + 0xE38E: 0x7DD5, //CJK UNIFIED IDEOGRAPH + 0xE38F: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xE390: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xE391: 0x7E7F, //CJK UNIFIED IDEOGRAPH + 0xE392: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xE393: 0x7E89, //CJK UNIFIED IDEOGRAPH + 0xE394: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xE395: 0x7E92, //CJK UNIFIED IDEOGRAPH + 0xE396: 0x7E90, //CJK UNIFIED IDEOGRAPH + 0xE397: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xE398: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xE399: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xE39A: 0x7E8E, //CJK UNIFIED IDEOGRAPH + 0xE39B: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xE39C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xE39D: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xE39E: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xE39F: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xE3A0: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x7F4E, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x7F78, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x7F82, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x7FA3, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x7FAE, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x8B71, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x7FC6, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x803B, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x805F, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8062, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x8068, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x5190, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x80AC, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x8109, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x81A4, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x815F, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x8193, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x81B8, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x81C8, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x8229, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x825D, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xE480: 0x8262, //CJK UNIFIED IDEOGRAPH + 0xE481: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xE482: 0x826A, //CJK UNIFIED IDEOGRAPH + 0xE483: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xE484: 0x822E, //CJK UNIFIED IDEOGRAPH + 0xE485: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xE486: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xE487: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xE488: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xE489: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xE48A: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xE48B: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xE48C: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xE48D: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xE48E: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xE48F: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xE490: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xE491: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xE492: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xE493: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xE494: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xE495: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xE496: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xE497: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xE498: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xE499: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xE49A: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xE49B: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xE49C: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xE49D: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xE49E: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xE49F: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xE4A0: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x8318, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x8385, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x839F, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x8323, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x83B5, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x83F7, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x8422, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x8420, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x842A, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x855A, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x8484, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x84AD, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x8462, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x84D9, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x854B, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x8613, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x8630, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x4E55, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x86AB, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xE580: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xE581: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xE582: 0x86EF, //CJK UNIFIED IDEOGRAPH + 0xE583: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xE584: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xE585: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xE586: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xE587: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xE588: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xE589: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xE58A: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xE58B: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xE58C: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xE58D: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xE58E: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xE58F: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xE590: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xE591: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xE592: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xE593: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xE594: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xE595: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xE596: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xE597: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xE598: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xE599: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xE59A: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xE59B: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xE59C: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xE59D: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xE59E: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xE59F: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xE5A0: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x87D0, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x87C7, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x880F, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x880E, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x8827, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x8842, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x885E, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x88B5, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x88AE, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x88B0, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x88BF, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x88C3, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x88C4, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x8904, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x8943, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x891D, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x8977, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x898A, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x89E7, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x8ADA, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xE680: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xE681: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xE682: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xE683: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xE684: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xE685: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xE686: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xE687: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xE688: 0x8B0C, //CJK UNIFIED IDEOGRAPH + 0xE689: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xE68A: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xE68B: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xE68C: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xE68D: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xE68E: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xE68F: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xE690: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xE691: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xE692: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xE693: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xE694: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xE695: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xE696: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xE697: 0x8B4C, //CJK UNIFIED IDEOGRAPH + 0xE698: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xE699: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xE69A: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xE69B: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xE69C: 0x8B5B, //CJK UNIFIED IDEOGRAPH + 0xE69D: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xE69E: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xE69F: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xE6A0: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x8C3A, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x8C8E, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x8C7C, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x621D, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x8CAD, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x8CAE, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x8CCD, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x8D71, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x8E08, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x8E99, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x8EB0, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x8EC6, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x8EB1, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x8EBE, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x8EC5, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x8EC8, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x8EE3, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x8F19, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x8F0C, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x8F4C, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x8F5C, //CJK UNIFIED IDEOGRAPH + 0xE780: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xE781: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xE782: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xE783: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xE784: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xE785: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xE786: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xE787: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xE788: 0x8FB7, //CJK UNIFIED IDEOGRAPH + 0xE789: 0x8FDA, //CJK UNIFIED IDEOGRAPH + 0xE78A: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xE78B: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xE78C: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xE78D: 0x8FEF, //CJK UNIFIED IDEOGRAPH + 0xE78E: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xE78F: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xE790: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xE791: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xE792: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xE793: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xE794: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xE795: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xE796: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE797: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xE798: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xE799: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xE79A: 0x9027, //CJK UNIFIED IDEOGRAPH + 0xE79B: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xE79C: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xE79D: 0x9039, //CJK UNIFIED IDEOGRAPH + 0xE79E: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xE79F: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xE7A0: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x900E, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x9056, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x9089, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x91D6, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x91DF, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x91E1, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x91DB, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x91FC, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x91F6, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x922C, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x9344, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x933A, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x933B, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x93B9, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x93E5, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x941A, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x9421, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x9441, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x9229, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x945A, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x9587, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x958A, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x9596, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x9599, //CJK UNIFIED IDEOGRAPH + 0xE880: 0x95A0, //CJK UNIFIED IDEOGRAPH + 0xE881: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xE882: 0x95A7, //CJK UNIFIED IDEOGRAPH + 0xE883: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xE884: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE885: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE886: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xE887: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xE888: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xE889: 0x6FF6, //CJK UNIFIED IDEOGRAPH + 0xE88A: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xE88B: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xE88C: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xE88D: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xE88E: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xE88F: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xE890: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xE891: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xE892: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xE893: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xE894: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xE895: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xE896: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xE897: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xE898: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xE899: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xE89A: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xE89B: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xE89C: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xE89D: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xE89E: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xE89F: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xE8A0: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x9666, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x96B2, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x96B6, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x894D, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x9764, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x976B, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x9771, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x9779, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x9786, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x9790, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x97B4, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x97C8, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x97F2, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x97F5, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x983D, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x984B, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x98AA, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x98C3, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x991D, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x9942, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x99BC, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x99F2, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xE980: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xE981: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xE982: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xE983: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xE984: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xE985: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xE986: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xE987: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xE988: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xE989: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xE98A: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xE98B: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xE98C: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xE98D: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xE98E: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xE98F: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xE990: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xE991: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xE992: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xE993: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xE994: 0x9ADE, //CJK UNIFIED IDEOGRAPH + 0xE995: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xE996: 0x9AE2, //CJK UNIFIED IDEOGRAPH + 0xE997: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xE998: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xE999: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xE99A: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xE99B: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xE99C: 0x9AF4, //CJK UNIFIED IDEOGRAPH + 0xE99D: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xE99E: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xE99F: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xE9A0: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x9B83, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x9B96, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x9B97, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x9BB4, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x9BCF, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x9BD1, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x9BD2, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x9BE3, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x9C3A, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x9BF2, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x9BF1, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x9C0C, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x9C0A, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x9C04, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x9C2E, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x9C1B, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x9C30, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x9C5A, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x9C76, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x9CEC, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x9CF0, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x9CEB, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x9D2A, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x9D44, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x9D46, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x9D48, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x9D5E, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x9D64, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x9D50, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x9DAB, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x9D7A, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x9DC6, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x9E81, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x9E95, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x9EB8, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x9EAA, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xEA80: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xEA81: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xEA82: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xEA83: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xEA84: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEA85: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xEA86: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xEA87: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xEA88: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xEA89: 0x76B7, //CJK UNIFIED IDEOGRAPH + 0xEA8A: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xEA8B: 0x9F21, //CJK UNIFIED IDEOGRAPH + 0xEA8C: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xEA8D: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xEA8E: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xEA8F: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xEA90: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xEA91: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xEA92: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xEA93: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xEA94: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xEA95: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xEA96: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xEA97: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xEA98: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xEA99: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xEA9A: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xEA9B: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xEA9C: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xEA9D: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xEA9E: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xEA9F: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xEAA0: 0x69C7, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x5042, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x514A, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x5164, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x519D, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x5215, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x529C, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x5307, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x5324, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0xED73: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xED74: 0x549C, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x548A, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x5759, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x5765, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xED80: 0xFA10, //CJK COMPATIBILITY IDEOGRAPH + 0xED81: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xED82: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0xED83: 0x590B, //CJK UNIFIED IDEOGRAPH + 0xED84: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xED85: 0x595B, //CJK UNIFIED IDEOGRAPH + 0xED86: 0x595D, //CJK UNIFIED IDEOGRAPH + 0xED87: 0x5963, //CJK UNIFIED IDEOGRAPH + 0xED88: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xED89: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xED8A: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xED8B: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xED8C: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xED8D: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xED8E: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xED8F: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0xED90: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xED91: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xED92: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0xED93: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xED94: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0xED95: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xED96: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xED97: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0xED98: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xED99: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0xED9A: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0xED9B: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0xED9C: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0xED9D: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xED9E: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xED9F: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xEDA0: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x6111, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x6213, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0xFA12, //CJK COMPATIBILITY IDEOGRAPH + 0xEDBD: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x670E, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xEDC5: 0x6766, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x6852, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x6801, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xEDCD: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xEDCF: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x710F, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0xFA15, //CJK COMPATIBILITY IDEOGRAPH + 0xEDFA: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0xFA16, //CJK COMPATIBILITY IDEOGRAPH + 0xEE43: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0xFA17, //CJK COMPATIBILITY IDEOGRAPH + 0xEE5A: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xEE62: 0xFA19, //CJK COMPATIBILITY IDEOGRAPH + 0xEE63: 0xFA1A, //CJK COMPATIBILITY IDEOGRAPH + 0xEE64: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0xFA1B, //CJK COMPATIBILITY IDEOGRAPH + 0xEE66: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0xFA1C, //CJK COMPATIBILITY IDEOGRAPH + 0xEE6A: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0xFA1D, //CJK COMPATIBILITY IDEOGRAPH + 0xEE6D: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0xFA1E, //CJK COMPATIBILITY IDEOGRAPH + 0xEE76: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xEE80: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xEE81: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xEE82: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xEE83: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xEE84: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xEE85: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xEE86: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xEE87: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xEE88: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xEE89: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xEE8A: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xEE8B: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xEE8C: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xEE8D: 0xFA22, //CJK COMPATIBILITY IDEOGRAPH + 0xEE8E: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xEE8F: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xEE90: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xEE91: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xEE92: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xEE93: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xEE94: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xEE95: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xEE96: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xEE97: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xEE98: 0xFA25, //CJK COMPATIBILITY IDEOGRAPH + 0xEE99: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xEE9A: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xEE9B: 0xFA26, //CJK COMPATIBILITY IDEOGRAPH + 0xEE9C: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xEE9D: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xEE9E: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xEE9F: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xEEA0: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xEEB8: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xEEBF: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xEECE: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + 0xEECF: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0xFA2A, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDB: 0xFA2B, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDC: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0xFA2C, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDE: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0xFA2D, //CJK COMPATIBILITY IDEOGRAPH + 0xEEEB: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xEEF0: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xEEF1: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xEEF2: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xEEF3: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xEEF4: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xEEF5: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xEEF6: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xEEF7: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xEEF8: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xEEF9: 0xFFE2, //FULLWIDTH NOT SIGN + 0xEEFA: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xEEFB: 0xFF07, //FULLWIDTH APOSTROPHE + 0xEEFC: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xFA40: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xFA41: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xFA42: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xFA43: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xFA44: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xFA45: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xFA46: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xFA47: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xFA48: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xFA49: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xFA4A: 0x2160, //ROMAN NUMERAL ONE + 0xFA4B: 0x2161, //ROMAN NUMERAL TWO + 0xFA4C: 0x2162, //ROMAN NUMERAL THREE + 0xFA4D: 0x2163, //ROMAN NUMERAL FOUR + 0xFA4E: 0x2164, //ROMAN NUMERAL FIVE + 0xFA4F: 0x2165, //ROMAN NUMERAL SIX + 0xFA50: 0x2166, //ROMAN NUMERAL SEVEN + 0xFA51: 0x2167, //ROMAN NUMERAL EIGHT + 0xFA52: 0x2168, //ROMAN NUMERAL NINE + 0xFA53: 0x2169, //ROMAN NUMERAL TEN + 0xFA54: 0xFFE2, //FULLWIDTH NOT SIGN + 0xFA55: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xFA56: 0xFF07, //FULLWIDTH APOSTROPHE + 0xFA57: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xFA58: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0xFA59: 0x2116, //NUMERO SIGN + 0xFA5A: 0x2121, //TELEPHONE SIGN + 0xFA5B: 0x2235, //BECAUSE + 0xFA5C: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xFA5D: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xFA5E: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xFA5F: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xFA60: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xFA61: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xFA62: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xFA63: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xFA64: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xFA65: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xFA66: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0xFA67: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0xFA68: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xFA69: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xFA6A: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0xFA6B: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xFA6C: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0xFA6D: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0xFA6E: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xFA6F: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xFA70: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xFA71: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xFA72: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xFA73: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xFA74: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xFA75: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xFA76: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0xFA77: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xFA78: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xFA79: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xFA7A: 0x5042, //CJK UNIFIED IDEOGRAPH + 0xFA7B: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xFA7C: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0xFA7D: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0xFA7E: 0x514A, //CJK UNIFIED IDEOGRAPH + 0xFA80: 0x5164, //CJK UNIFIED IDEOGRAPH + 0xFA81: 0x519D, //CJK UNIFIED IDEOGRAPH + 0xFA82: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xFA83: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0xFA84: 0x5215, //CJK UNIFIED IDEOGRAPH + 0xFA85: 0x529C, //CJK UNIFIED IDEOGRAPH + 0xFA86: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xFA87: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xFA88: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xFA89: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xFA8A: 0x5307, //CJK UNIFIED IDEOGRAPH + 0xFA8B: 0x5324, //CJK UNIFIED IDEOGRAPH + 0xFA8C: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xFA8D: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xFA8E: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xFA8F: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0xFA90: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xFA91: 0x549C, //CJK UNIFIED IDEOGRAPH + 0xFA92: 0x548A, //CJK UNIFIED IDEOGRAPH + 0xFA93: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xFA94: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xFA95: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xFA96: 0x5759, //CJK UNIFIED IDEOGRAPH + 0xFA97: 0x5765, //CJK UNIFIED IDEOGRAPH + 0xFA98: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0xFA99: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xFA9A: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xFA9B: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xFA9C: 0xFA10, //CJK COMPATIBILITY IDEOGRAPH + 0xFA9D: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xFA9E: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0xFA9F: 0x590B, //CJK UNIFIED IDEOGRAPH + 0xFAA0: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xFAA1: 0x595B, //CJK UNIFIED IDEOGRAPH + 0xFAA2: 0x595D, //CJK UNIFIED IDEOGRAPH + 0xFAA3: 0x5963, //CJK UNIFIED IDEOGRAPH + 0xFAA4: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xFAA5: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xFAA6: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xFAA7: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xFAA8: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xFAA9: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xFAAA: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xFAAB: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0xFAAC: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xFAAD: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xFAAE: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0xFAAF: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xFAB0: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0xFAB1: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xFAB2: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xFAB3: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0xFAB4: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xFAB5: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0xFAB6: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0xFAB7: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0xFAB8: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0xFAB9: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xFABA: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xFABB: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xFABC: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xFABD: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xFABE: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xFABF: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0xFAC0: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xFAC1: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xFAC2: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xFAC3: 0x6111, //CJK UNIFIED IDEOGRAPH + 0xFAC4: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xFAC5: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xFAC6: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xFAC7: 0x6213, //CJK UNIFIED IDEOGRAPH + 0xFAC8: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0xFAC9: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xFACA: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xFACB: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xFACC: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xFACD: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xFACE: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xFACF: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xFAD0: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xFAD1: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xFAD2: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xFAD3: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xFAD4: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xFAD5: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xFAD6: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xFAD7: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xFAD8: 0xFA12, //CJK COMPATIBILITY IDEOGRAPH + 0xFAD9: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xFADA: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xFADB: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xFADC: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xFADD: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0xFADE: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xFADF: 0x670E, //CJK UNIFIED IDEOGRAPH + 0xFAE0: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE1: 0x6766, //CJK UNIFIED IDEOGRAPH + 0xFAE2: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xFAE3: 0x6852, //CJK UNIFIED IDEOGRAPH + 0xFAE4: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xFAE5: 0x6801, //CJK UNIFIED IDEOGRAPH + 0xFAE6: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xFAE7: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0xFAE8: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE9: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xFAEA: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xFAEB: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xFAEC: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xFAED: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0xFAEE: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xFAEF: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xFAF0: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0xFAF1: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xFAF2: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0xFAF3: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0xFAF4: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xFAF5: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xFAF6: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xFAF7: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xFAF8: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xFAF9: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xFAFA: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xFAFB: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xFAFC: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xFB40: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0xFB41: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xFB42: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xFB43: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xFB44: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xFB45: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xFB46: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xFB47: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xFB48: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xFB49: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xFB4A: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xFB4B: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xFB4C: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0xFB4D: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0xFB4E: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xFB4F: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xFB50: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xFB51: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xFB52: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xFB53: 0x710F, //CJK UNIFIED IDEOGRAPH + 0xFB54: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xFB55: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xFB56: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xFB57: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xFB58: 0xFA15, //CJK COMPATIBILITY IDEOGRAPH + 0xFB59: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xFB5A: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xFB5B: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xFB5C: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xFB5D: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xFB5E: 0xFA16, //CJK COMPATIBILITY IDEOGRAPH + 0xFB5F: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xFB60: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xFB61: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xFB62: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xFB63: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xFB64: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xFB65: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xFB66: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xFB67: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xFB68: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xFB69: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xFB6A: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xFB6B: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xFB6C: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xFB6D: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xFB6E: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xFB6F: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xFB70: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xFB71: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xFB72: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xFB73: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xFB74: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xFB75: 0xFA17, //CJK COMPATIBILITY IDEOGRAPH + 0xFB76: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xFB77: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0xFB78: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xFB79: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xFB7A: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xFB7B: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xFB7C: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xFB7D: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xFB7E: 0xFA19, //CJK COMPATIBILITY IDEOGRAPH + 0xFB80: 0xFA1A, //CJK COMPATIBILITY IDEOGRAPH + 0xFB81: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xFB82: 0xFA1B, //CJK COMPATIBILITY IDEOGRAPH + 0xFB83: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xFB84: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xFB85: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xFB86: 0xFA1C, //CJK COMPATIBILITY IDEOGRAPH + 0xFB87: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xFB88: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xFB89: 0xFA1D, //CJK COMPATIBILITY IDEOGRAPH + 0xFB8A: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xFB8B: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xFB8C: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xFB8D: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xFB8E: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xFB8F: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xFB90: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xFB91: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xFB92: 0xFA1E, //CJK COMPATIBILITY IDEOGRAPH + 0xFB93: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xFB94: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xFB95: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xFB96: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xFB97: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xFB98: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xFB99: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xFB9A: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xFB9B: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xFB9C: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xFB9D: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xFB9E: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xFB9F: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xFBA0: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xFBA1: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xFBA2: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xFBA3: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xFBA4: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xFBA5: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xFBA6: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xFBA7: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xFBA8: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xFBA9: 0xFA22, //CJK COMPATIBILITY IDEOGRAPH + 0xFBAA: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xFBAB: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xFBAC: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xFBAD: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xFBAE: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xFBAF: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xFBB0: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xFBB1: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB2: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xFBB3: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB4: 0xFA25, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB5: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xFBB6: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xFBB7: 0xFA26, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB8: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xFBB9: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xFBBA: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xFBBB: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xFBBC: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xFBBD: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xFBBE: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xFBBF: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xFBC0: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xFBC1: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xFBC2: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xFBC3: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xFBC4: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xFBC5: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xFBC6: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xFBC7: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xFBC8: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xFBC9: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xFBCA: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xFBCB: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xFBCC: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xFBCD: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xFBCE: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xFBCF: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xFBD0: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xFBD1: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xFBD2: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xFBD3: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xFBD4: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xFBD5: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xFBD6: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xFBD7: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xFBD8: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xFBD9: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xFBDA: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xFBDB: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xFBDC: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xFBDD: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xFBDE: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xFBDF: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xFBE0: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xFBE1: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xFBE2: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xFBE3: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xFBE4: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xFBE5: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xFBE6: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xFBE7: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xFBE8: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xFBE9: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xFBEA: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + 0xFBEB: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xFBEC: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xFBED: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xFBEE: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xFBEF: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xFBF0: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xFBF1: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xFBF2: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xFBF3: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xFBF4: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xFBF5: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xFBF6: 0xFA2A, //CJK COMPATIBILITY IDEOGRAPH + 0xFBF7: 0xFA2B, //CJK COMPATIBILITY IDEOGRAPH + 0xFBF8: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xFBF9: 0xFA2C, //CJK COMPATIBILITY IDEOGRAPH + 0xFBFA: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xFBFB: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xFBFC: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xFC40: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xFC41: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xFC42: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xFC43: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xFC44: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xFC45: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xFC46: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xFC47: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xFC48: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xFC49: 0xFA2D, //CJK COMPATIBILITY IDEOGRAPH + 0xFC4A: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xFC4B: 0x9ED1, //CJK UNIFIED IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go new file mode 100644 index 0000000..d1fac12 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go @@ -0,0 +1,22055 @@ +package cp + +var cp936 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8140: 0x4E02, //CJK UNIFIED IDEOGRAPH + 0x8141: 0x4E04, //CJK UNIFIED IDEOGRAPH + 0x8142: 0x4E05, //CJK UNIFIED IDEOGRAPH + 0x8143: 0x4E06, //CJK UNIFIED IDEOGRAPH + 0x8144: 0x4E0F, //CJK UNIFIED IDEOGRAPH + 0x8145: 0x4E12, //CJK UNIFIED IDEOGRAPH + 0x8146: 0x4E17, //CJK UNIFIED IDEOGRAPH + 0x8147: 0x4E1F, //CJK UNIFIED IDEOGRAPH + 0x8148: 0x4E20, //CJK UNIFIED IDEOGRAPH + 0x8149: 0x4E21, //CJK UNIFIED IDEOGRAPH + 0x814A: 0x4E23, //CJK UNIFIED IDEOGRAPH + 0x814B: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0x814C: 0x4E29, //CJK UNIFIED IDEOGRAPH + 0x814D: 0x4E2E, //CJK UNIFIED IDEOGRAPH + 0x814E: 0x4E2F, //CJK UNIFIED IDEOGRAPH + 0x814F: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0x8150: 0x4E33, //CJK UNIFIED IDEOGRAPH + 0x8151: 0x4E35, //CJK UNIFIED IDEOGRAPH + 0x8152: 0x4E37, //CJK UNIFIED IDEOGRAPH + 0x8153: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0x8154: 0x4E40, //CJK UNIFIED IDEOGRAPH + 0x8155: 0x4E41, //CJK UNIFIED IDEOGRAPH + 0x8156: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0x8157: 0x4E44, //CJK UNIFIED IDEOGRAPH + 0x8158: 0x4E46, //CJK UNIFIED IDEOGRAPH + 0x8159: 0x4E4A, //CJK UNIFIED IDEOGRAPH + 0x815A: 0x4E51, //CJK UNIFIED IDEOGRAPH + 0x815B: 0x4E55, //CJK UNIFIED IDEOGRAPH + 0x815C: 0x4E57, //CJK UNIFIED IDEOGRAPH + 0x815D: 0x4E5A, //CJK UNIFIED IDEOGRAPH + 0x815E: 0x4E5B, //CJK UNIFIED IDEOGRAPH + 0x815F: 0x4E62, //CJK UNIFIED IDEOGRAPH + 0x8160: 0x4E63, //CJK UNIFIED IDEOGRAPH + 0x8161: 0x4E64, //CJK UNIFIED IDEOGRAPH + 0x8162: 0x4E65, //CJK UNIFIED IDEOGRAPH + 0x8163: 0x4E67, //CJK UNIFIED IDEOGRAPH + 0x8164: 0x4E68, //CJK UNIFIED IDEOGRAPH + 0x8165: 0x4E6A, //CJK UNIFIED IDEOGRAPH + 0x8166: 0x4E6B, //CJK UNIFIED IDEOGRAPH + 0x8167: 0x4E6C, //CJK UNIFIED IDEOGRAPH + 0x8168: 0x4E6D, //CJK UNIFIED IDEOGRAPH + 0x8169: 0x4E6E, //CJK UNIFIED IDEOGRAPH + 0x816A: 0x4E6F, //CJK UNIFIED IDEOGRAPH + 0x816B: 0x4E72, //CJK UNIFIED IDEOGRAPH + 0x816C: 0x4E74, //CJK UNIFIED IDEOGRAPH + 0x816D: 0x4E75, //CJK UNIFIED IDEOGRAPH + 0x816E: 0x4E76, //CJK UNIFIED IDEOGRAPH + 0x816F: 0x4E77, //CJK UNIFIED IDEOGRAPH + 0x8170: 0x4E78, //CJK UNIFIED IDEOGRAPH + 0x8171: 0x4E79, //CJK UNIFIED IDEOGRAPH + 0x8172: 0x4E7A, //CJK UNIFIED IDEOGRAPH + 0x8173: 0x4E7B, //CJK UNIFIED IDEOGRAPH + 0x8174: 0x4E7C, //CJK UNIFIED IDEOGRAPH + 0x8175: 0x4E7D, //CJK UNIFIED IDEOGRAPH + 0x8176: 0x4E7F, //CJK UNIFIED IDEOGRAPH + 0x8177: 0x4E80, //CJK UNIFIED IDEOGRAPH + 0x8178: 0x4E81, //CJK UNIFIED IDEOGRAPH + 0x8179: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0x817A: 0x4E83, //CJK UNIFIED IDEOGRAPH + 0x817B: 0x4E84, //CJK UNIFIED IDEOGRAPH + 0x817C: 0x4E85, //CJK UNIFIED IDEOGRAPH + 0x817D: 0x4E87, //CJK UNIFIED IDEOGRAPH + 0x817E: 0x4E8A, //CJK UNIFIED IDEOGRAPH + 0x8180: 0x4E90, //CJK UNIFIED IDEOGRAPH + 0x8181: 0x4E96, //CJK UNIFIED IDEOGRAPH + 0x8182: 0x4E97, //CJK UNIFIED IDEOGRAPH + 0x8183: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0x8184: 0x4E9C, //CJK UNIFIED IDEOGRAPH + 0x8185: 0x4E9D, //CJK UNIFIED IDEOGRAPH + 0x8186: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0x8187: 0x4EA3, //CJK UNIFIED IDEOGRAPH + 0x8188: 0x4EAA, //CJK UNIFIED IDEOGRAPH + 0x8189: 0x4EAF, //CJK UNIFIED IDEOGRAPH + 0x818A: 0x4EB0, //CJK UNIFIED IDEOGRAPH + 0x818B: 0x4EB1, //CJK UNIFIED IDEOGRAPH + 0x818C: 0x4EB4, //CJK UNIFIED IDEOGRAPH + 0x818D: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0x818E: 0x4EB7, //CJK UNIFIED IDEOGRAPH + 0x818F: 0x4EB8, //CJK UNIFIED IDEOGRAPH + 0x8190: 0x4EB9, //CJK UNIFIED IDEOGRAPH + 0x8191: 0x4EBC, //CJK UNIFIED IDEOGRAPH + 0x8192: 0x4EBD, //CJK UNIFIED IDEOGRAPH + 0x8193: 0x4EBE, //CJK UNIFIED IDEOGRAPH + 0x8194: 0x4EC8, //CJK UNIFIED IDEOGRAPH + 0x8195: 0x4ECC, //CJK UNIFIED IDEOGRAPH + 0x8196: 0x4ECF, //CJK UNIFIED IDEOGRAPH + 0x8197: 0x4ED0, //CJK UNIFIED IDEOGRAPH + 0x8198: 0x4ED2, //CJK UNIFIED IDEOGRAPH + 0x8199: 0x4EDA, //CJK UNIFIED IDEOGRAPH + 0x819A: 0x4EDB, //CJK UNIFIED IDEOGRAPH + 0x819B: 0x4EDC, //CJK UNIFIED IDEOGRAPH + 0x819C: 0x4EE0, //CJK UNIFIED IDEOGRAPH + 0x819D: 0x4EE2, //CJK UNIFIED IDEOGRAPH + 0x819E: 0x4EE6, //CJK UNIFIED IDEOGRAPH + 0x819F: 0x4EE7, //CJK UNIFIED IDEOGRAPH + 0x81A0: 0x4EE9, //CJK UNIFIED IDEOGRAPH + 0x81A1: 0x4EED, //CJK UNIFIED IDEOGRAPH + 0x81A2: 0x4EEE, //CJK UNIFIED IDEOGRAPH + 0x81A3: 0x4EEF, //CJK UNIFIED IDEOGRAPH + 0x81A4: 0x4EF1, //CJK UNIFIED IDEOGRAPH + 0x81A5: 0x4EF4, //CJK UNIFIED IDEOGRAPH + 0x81A6: 0x4EF8, //CJK UNIFIED IDEOGRAPH + 0x81A7: 0x4EF9, //CJK UNIFIED IDEOGRAPH + 0x81A8: 0x4EFA, //CJK UNIFIED IDEOGRAPH + 0x81A9: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0x81AA: 0x4EFE, //CJK UNIFIED IDEOGRAPH + 0x81AB: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0x81AC: 0x4F02, //CJK UNIFIED IDEOGRAPH + 0x81AD: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0x81AE: 0x4F04, //CJK UNIFIED IDEOGRAPH + 0x81AF: 0x4F05, //CJK UNIFIED IDEOGRAPH + 0x81B0: 0x4F06, //CJK UNIFIED IDEOGRAPH + 0x81B1: 0x4F07, //CJK UNIFIED IDEOGRAPH + 0x81B2: 0x4F08, //CJK UNIFIED IDEOGRAPH + 0x81B3: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0x81B4: 0x4F0C, //CJK UNIFIED IDEOGRAPH + 0x81B5: 0x4F12, //CJK UNIFIED IDEOGRAPH + 0x81B6: 0x4F13, //CJK UNIFIED IDEOGRAPH + 0x81B7: 0x4F14, //CJK UNIFIED IDEOGRAPH + 0x81B8: 0x4F15, //CJK UNIFIED IDEOGRAPH + 0x81B9: 0x4F16, //CJK UNIFIED IDEOGRAPH + 0x81BA: 0x4F1C, //CJK UNIFIED IDEOGRAPH + 0x81BB: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0x81BC: 0x4F21, //CJK UNIFIED IDEOGRAPH + 0x81BD: 0x4F23, //CJK UNIFIED IDEOGRAPH + 0x81BE: 0x4F28, //CJK UNIFIED IDEOGRAPH + 0x81BF: 0x4F29, //CJK UNIFIED IDEOGRAPH + 0x81C0: 0x4F2C, //CJK UNIFIED IDEOGRAPH + 0x81C1: 0x4F2D, //CJK UNIFIED IDEOGRAPH + 0x81C2: 0x4F2E, //CJK UNIFIED IDEOGRAPH + 0x81C3: 0x4F31, //CJK UNIFIED IDEOGRAPH + 0x81C4: 0x4F33, //CJK UNIFIED IDEOGRAPH + 0x81C5: 0x4F35, //CJK UNIFIED IDEOGRAPH + 0x81C6: 0x4F37, //CJK UNIFIED IDEOGRAPH + 0x81C7: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0x81C8: 0x4F3B, //CJK UNIFIED IDEOGRAPH + 0x81C9: 0x4F3E, //CJK UNIFIED IDEOGRAPH + 0x81CA: 0x4F3F, //CJK UNIFIED IDEOGRAPH + 0x81CB: 0x4F40, //CJK UNIFIED IDEOGRAPH + 0x81CC: 0x4F41, //CJK UNIFIED IDEOGRAPH + 0x81CD: 0x4F42, //CJK UNIFIED IDEOGRAPH + 0x81CE: 0x4F44, //CJK UNIFIED IDEOGRAPH + 0x81CF: 0x4F45, //CJK UNIFIED IDEOGRAPH + 0x81D0: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0x81D1: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0x81D2: 0x4F49, //CJK UNIFIED IDEOGRAPH + 0x81D3: 0x4F4A, //CJK UNIFIED IDEOGRAPH + 0x81D4: 0x4F4B, //CJK UNIFIED IDEOGRAPH + 0x81D5: 0x4F4C, //CJK UNIFIED IDEOGRAPH + 0x81D6: 0x4F52, //CJK UNIFIED IDEOGRAPH + 0x81D7: 0x4F54, //CJK UNIFIED IDEOGRAPH + 0x81D8: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0x81D9: 0x4F61, //CJK UNIFIED IDEOGRAPH + 0x81DA: 0x4F62, //CJK UNIFIED IDEOGRAPH + 0x81DB: 0x4F66, //CJK UNIFIED IDEOGRAPH + 0x81DC: 0x4F68, //CJK UNIFIED IDEOGRAPH + 0x81DD: 0x4F6A, //CJK UNIFIED IDEOGRAPH + 0x81DE: 0x4F6B, //CJK UNIFIED IDEOGRAPH + 0x81DF: 0x4F6D, //CJK UNIFIED IDEOGRAPH + 0x81E0: 0x4F6E, //CJK UNIFIED IDEOGRAPH + 0x81E1: 0x4F71, //CJK UNIFIED IDEOGRAPH + 0x81E2: 0x4F72, //CJK UNIFIED IDEOGRAPH + 0x81E3: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0x81E4: 0x4F77, //CJK UNIFIED IDEOGRAPH + 0x81E5: 0x4F78, //CJK UNIFIED IDEOGRAPH + 0x81E6: 0x4F79, //CJK UNIFIED IDEOGRAPH + 0x81E7: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0x81E8: 0x4F7D, //CJK UNIFIED IDEOGRAPH + 0x81E9: 0x4F80, //CJK UNIFIED IDEOGRAPH + 0x81EA: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0x81EB: 0x4F82, //CJK UNIFIED IDEOGRAPH + 0x81EC: 0x4F85, //CJK UNIFIED IDEOGRAPH + 0x81ED: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0x81EE: 0x4F87, //CJK UNIFIED IDEOGRAPH + 0x81EF: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0x81F0: 0x4F8C, //CJK UNIFIED IDEOGRAPH + 0x81F1: 0x4F8E, //CJK UNIFIED IDEOGRAPH + 0x81F2: 0x4F90, //CJK UNIFIED IDEOGRAPH + 0x81F3: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0x81F4: 0x4F93, //CJK UNIFIED IDEOGRAPH + 0x81F5: 0x4F95, //CJK UNIFIED IDEOGRAPH + 0x81F6: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0x81F7: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0x81F8: 0x4F99, //CJK UNIFIED IDEOGRAPH + 0x81F9: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0x81FA: 0x4F9C, //CJK UNIFIED IDEOGRAPH + 0x81FB: 0x4F9E, //CJK UNIFIED IDEOGRAPH + 0x81FC: 0x4F9F, //CJK UNIFIED IDEOGRAPH + 0x81FD: 0x4FA1, //CJK UNIFIED IDEOGRAPH + 0x81FE: 0x4FA2, //CJK UNIFIED IDEOGRAPH + 0x8240: 0x4FA4, //CJK UNIFIED IDEOGRAPH + 0x8241: 0x4FAB, //CJK UNIFIED IDEOGRAPH + 0x8242: 0x4FAD, //CJK UNIFIED IDEOGRAPH + 0x8243: 0x4FB0, //CJK UNIFIED IDEOGRAPH + 0x8244: 0x4FB1, //CJK UNIFIED IDEOGRAPH + 0x8245: 0x4FB2, //CJK UNIFIED IDEOGRAPH + 0x8246: 0x4FB3, //CJK UNIFIED IDEOGRAPH + 0x8247: 0x4FB4, //CJK UNIFIED IDEOGRAPH + 0x8248: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0x8249: 0x4FB7, //CJK UNIFIED IDEOGRAPH + 0x824A: 0x4FB8, //CJK UNIFIED IDEOGRAPH + 0x824B: 0x4FB9, //CJK UNIFIED IDEOGRAPH + 0x824C: 0x4FBA, //CJK UNIFIED IDEOGRAPH + 0x824D: 0x4FBB, //CJK UNIFIED IDEOGRAPH + 0x824E: 0x4FBC, //CJK UNIFIED IDEOGRAPH + 0x824F: 0x4FBD, //CJK UNIFIED IDEOGRAPH + 0x8250: 0x4FBE, //CJK UNIFIED IDEOGRAPH + 0x8251: 0x4FC0, //CJK UNIFIED IDEOGRAPH + 0x8252: 0x4FC1, //CJK UNIFIED IDEOGRAPH + 0x8253: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0x8254: 0x4FC6, //CJK UNIFIED IDEOGRAPH + 0x8255: 0x4FC7, //CJK UNIFIED IDEOGRAPH + 0x8256: 0x4FC8, //CJK UNIFIED IDEOGRAPH + 0x8257: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0x8258: 0x4FCB, //CJK UNIFIED IDEOGRAPH + 0x8259: 0x4FCC, //CJK UNIFIED IDEOGRAPH + 0x825A: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0x825B: 0x4FD2, //CJK UNIFIED IDEOGRAPH + 0x825C: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0x825D: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0x825E: 0x4FD5, //CJK UNIFIED IDEOGRAPH + 0x825F: 0x4FD6, //CJK UNIFIED IDEOGRAPH + 0x8260: 0x4FD9, //CJK UNIFIED IDEOGRAPH + 0x8261: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0x8262: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0x8263: 0x4FE2, //CJK UNIFIED IDEOGRAPH + 0x8264: 0x4FE4, //CJK UNIFIED IDEOGRAPH + 0x8265: 0x4FE5, //CJK UNIFIED IDEOGRAPH + 0x8266: 0x4FE7, //CJK UNIFIED IDEOGRAPH + 0x8267: 0x4FEB, //CJK UNIFIED IDEOGRAPH + 0x8268: 0x4FEC, //CJK UNIFIED IDEOGRAPH + 0x8269: 0x4FF0, //CJK UNIFIED IDEOGRAPH + 0x826A: 0x4FF2, //CJK UNIFIED IDEOGRAPH + 0x826B: 0x4FF4, //CJK UNIFIED IDEOGRAPH + 0x826C: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0x826D: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0x826E: 0x4FF7, //CJK UNIFIED IDEOGRAPH + 0x826F: 0x4FF9, //CJK UNIFIED IDEOGRAPH + 0x8270: 0x4FFB, //CJK UNIFIED IDEOGRAPH + 0x8271: 0x4FFC, //CJK UNIFIED IDEOGRAPH + 0x8272: 0x4FFD, //CJK UNIFIED IDEOGRAPH + 0x8273: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0x8274: 0x5000, //CJK UNIFIED IDEOGRAPH + 0x8275: 0x5001, //CJK UNIFIED IDEOGRAPH + 0x8276: 0x5002, //CJK UNIFIED IDEOGRAPH + 0x8277: 0x5003, //CJK UNIFIED IDEOGRAPH + 0x8278: 0x5004, //CJK UNIFIED IDEOGRAPH + 0x8279: 0x5005, //CJK UNIFIED IDEOGRAPH + 0x827A: 0x5006, //CJK UNIFIED IDEOGRAPH + 0x827B: 0x5007, //CJK UNIFIED IDEOGRAPH + 0x827C: 0x5008, //CJK UNIFIED IDEOGRAPH + 0x827D: 0x5009, //CJK UNIFIED IDEOGRAPH + 0x827E: 0x500A, //CJK UNIFIED IDEOGRAPH + 0x8280: 0x500B, //CJK UNIFIED IDEOGRAPH + 0x8281: 0x500E, //CJK UNIFIED IDEOGRAPH + 0x8282: 0x5010, //CJK UNIFIED IDEOGRAPH + 0x8283: 0x5011, //CJK UNIFIED IDEOGRAPH + 0x8284: 0x5013, //CJK UNIFIED IDEOGRAPH + 0x8285: 0x5015, //CJK UNIFIED IDEOGRAPH + 0x8286: 0x5016, //CJK UNIFIED IDEOGRAPH + 0x8287: 0x5017, //CJK UNIFIED IDEOGRAPH + 0x8288: 0x501B, //CJK UNIFIED IDEOGRAPH + 0x8289: 0x501D, //CJK UNIFIED IDEOGRAPH + 0x828A: 0x501E, //CJK UNIFIED IDEOGRAPH + 0x828B: 0x5020, //CJK UNIFIED IDEOGRAPH + 0x828C: 0x5022, //CJK UNIFIED IDEOGRAPH + 0x828D: 0x5023, //CJK UNIFIED IDEOGRAPH + 0x828E: 0x5024, //CJK UNIFIED IDEOGRAPH + 0x828F: 0x5027, //CJK UNIFIED IDEOGRAPH + 0x8290: 0x502B, //CJK UNIFIED IDEOGRAPH + 0x8291: 0x502F, //CJK UNIFIED IDEOGRAPH + 0x8292: 0x5030, //CJK UNIFIED IDEOGRAPH + 0x8293: 0x5031, //CJK UNIFIED IDEOGRAPH + 0x8294: 0x5032, //CJK UNIFIED IDEOGRAPH + 0x8295: 0x5033, //CJK UNIFIED IDEOGRAPH + 0x8296: 0x5034, //CJK UNIFIED IDEOGRAPH + 0x8297: 0x5035, //CJK UNIFIED IDEOGRAPH + 0x8298: 0x5036, //CJK UNIFIED IDEOGRAPH + 0x8299: 0x5037, //CJK UNIFIED IDEOGRAPH + 0x829A: 0x5038, //CJK UNIFIED IDEOGRAPH + 0x829B: 0x5039, //CJK UNIFIED IDEOGRAPH + 0x829C: 0x503B, //CJK UNIFIED IDEOGRAPH + 0x829D: 0x503D, //CJK UNIFIED IDEOGRAPH + 0x829E: 0x503F, //CJK UNIFIED IDEOGRAPH + 0x829F: 0x5040, //CJK UNIFIED IDEOGRAPH + 0x82A0: 0x5041, //CJK UNIFIED IDEOGRAPH + 0x82A1: 0x5042, //CJK UNIFIED IDEOGRAPH + 0x82A2: 0x5044, //CJK UNIFIED IDEOGRAPH + 0x82A3: 0x5045, //CJK UNIFIED IDEOGRAPH + 0x82A4: 0x5046, //CJK UNIFIED IDEOGRAPH + 0x82A5: 0x5049, //CJK UNIFIED IDEOGRAPH + 0x82A6: 0x504A, //CJK UNIFIED IDEOGRAPH + 0x82A7: 0x504B, //CJK UNIFIED IDEOGRAPH + 0x82A8: 0x504D, //CJK UNIFIED IDEOGRAPH + 0x82A9: 0x5050, //CJK UNIFIED IDEOGRAPH + 0x82AA: 0x5051, //CJK UNIFIED IDEOGRAPH + 0x82AB: 0x5052, //CJK UNIFIED IDEOGRAPH + 0x82AC: 0x5053, //CJK UNIFIED IDEOGRAPH + 0x82AD: 0x5054, //CJK UNIFIED IDEOGRAPH + 0x82AE: 0x5056, //CJK UNIFIED IDEOGRAPH + 0x82AF: 0x5057, //CJK UNIFIED IDEOGRAPH + 0x82B0: 0x5058, //CJK UNIFIED IDEOGRAPH + 0x82B1: 0x5059, //CJK UNIFIED IDEOGRAPH + 0x82B2: 0x505B, //CJK UNIFIED IDEOGRAPH + 0x82B3: 0x505D, //CJK UNIFIED IDEOGRAPH + 0x82B4: 0x505E, //CJK UNIFIED IDEOGRAPH + 0x82B5: 0x505F, //CJK UNIFIED IDEOGRAPH + 0x82B6: 0x5060, //CJK UNIFIED IDEOGRAPH + 0x82B7: 0x5061, //CJK UNIFIED IDEOGRAPH + 0x82B8: 0x5062, //CJK UNIFIED IDEOGRAPH + 0x82B9: 0x5063, //CJK UNIFIED IDEOGRAPH + 0x82BA: 0x5064, //CJK UNIFIED IDEOGRAPH + 0x82BB: 0x5066, //CJK UNIFIED IDEOGRAPH + 0x82BC: 0x5067, //CJK UNIFIED IDEOGRAPH + 0x82BD: 0x5068, //CJK UNIFIED IDEOGRAPH + 0x82BE: 0x5069, //CJK UNIFIED IDEOGRAPH + 0x82BF: 0x506A, //CJK UNIFIED IDEOGRAPH + 0x82C0: 0x506B, //CJK UNIFIED IDEOGRAPH + 0x82C1: 0x506D, //CJK UNIFIED IDEOGRAPH + 0x82C2: 0x506E, //CJK UNIFIED IDEOGRAPH + 0x82C3: 0x506F, //CJK UNIFIED IDEOGRAPH + 0x82C4: 0x5070, //CJK UNIFIED IDEOGRAPH + 0x82C5: 0x5071, //CJK UNIFIED IDEOGRAPH + 0x82C6: 0x5072, //CJK UNIFIED IDEOGRAPH + 0x82C7: 0x5073, //CJK UNIFIED IDEOGRAPH + 0x82C8: 0x5074, //CJK UNIFIED IDEOGRAPH + 0x82C9: 0x5075, //CJK UNIFIED IDEOGRAPH + 0x82CA: 0x5078, //CJK UNIFIED IDEOGRAPH + 0x82CB: 0x5079, //CJK UNIFIED IDEOGRAPH + 0x82CC: 0x507A, //CJK UNIFIED IDEOGRAPH + 0x82CD: 0x507C, //CJK UNIFIED IDEOGRAPH + 0x82CE: 0x507D, //CJK UNIFIED IDEOGRAPH + 0x82CF: 0x5081, //CJK UNIFIED IDEOGRAPH + 0x82D0: 0x5082, //CJK UNIFIED IDEOGRAPH + 0x82D1: 0x5083, //CJK UNIFIED IDEOGRAPH + 0x82D2: 0x5084, //CJK UNIFIED IDEOGRAPH + 0x82D3: 0x5086, //CJK UNIFIED IDEOGRAPH + 0x82D4: 0x5087, //CJK UNIFIED IDEOGRAPH + 0x82D5: 0x5089, //CJK UNIFIED IDEOGRAPH + 0x82D6: 0x508A, //CJK UNIFIED IDEOGRAPH + 0x82D7: 0x508B, //CJK UNIFIED IDEOGRAPH + 0x82D8: 0x508C, //CJK UNIFIED IDEOGRAPH + 0x82D9: 0x508E, //CJK UNIFIED IDEOGRAPH + 0x82DA: 0x508F, //CJK UNIFIED IDEOGRAPH + 0x82DB: 0x5090, //CJK UNIFIED IDEOGRAPH + 0x82DC: 0x5091, //CJK UNIFIED IDEOGRAPH + 0x82DD: 0x5092, //CJK UNIFIED IDEOGRAPH + 0x82DE: 0x5093, //CJK UNIFIED IDEOGRAPH + 0x82DF: 0x5094, //CJK UNIFIED IDEOGRAPH + 0x82E0: 0x5095, //CJK UNIFIED IDEOGRAPH + 0x82E1: 0x5096, //CJK UNIFIED IDEOGRAPH + 0x82E2: 0x5097, //CJK UNIFIED IDEOGRAPH + 0x82E3: 0x5098, //CJK UNIFIED IDEOGRAPH + 0x82E4: 0x5099, //CJK UNIFIED IDEOGRAPH + 0x82E5: 0x509A, //CJK UNIFIED IDEOGRAPH + 0x82E6: 0x509B, //CJK UNIFIED IDEOGRAPH + 0x82E7: 0x509C, //CJK UNIFIED IDEOGRAPH + 0x82E8: 0x509D, //CJK UNIFIED IDEOGRAPH + 0x82E9: 0x509E, //CJK UNIFIED IDEOGRAPH + 0x82EA: 0x509F, //CJK UNIFIED IDEOGRAPH + 0x82EB: 0x50A0, //CJK UNIFIED IDEOGRAPH + 0x82EC: 0x50A1, //CJK UNIFIED IDEOGRAPH + 0x82ED: 0x50A2, //CJK UNIFIED IDEOGRAPH + 0x82EE: 0x50A4, //CJK UNIFIED IDEOGRAPH + 0x82EF: 0x50A6, //CJK UNIFIED IDEOGRAPH + 0x82F0: 0x50AA, //CJK UNIFIED IDEOGRAPH + 0x82F1: 0x50AB, //CJK UNIFIED IDEOGRAPH + 0x82F2: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0x82F3: 0x50AE, //CJK UNIFIED IDEOGRAPH + 0x82F4: 0x50AF, //CJK UNIFIED IDEOGRAPH + 0x82F5: 0x50B0, //CJK UNIFIED IDEOGRAPH + 0x82F6: 0x50B1, //CJK UNIFIED IDEOGRAPH + 0x82F7: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0x82F8: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0x82F9: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0x82FA: 0x50B6, //CJK UNIFIED IDEOGRAPH + 0x82FB: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0x82FC: 0x50B8, //CJK UNIFIED IDEOGRAPH + 0x82FD: 0x50B9, //CJK UNIFIED IDEOGRAPH + 0x82FE: 0x50BC, //CJK UNIFIED IDEOGRAPH + 0x8340: 0x50BD, //CJK UNIFIED IDEOGRAPH + 0x8341: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0x8342: 0x50BF, //CJK UNIFIED IDEOGRAPH + 0x8343: 0x50C0, //CJK UNIFIED IDEOGRAPH + 0x8344: 0x50C1, //CJK UNIFIED IDEOGRAPH + 0x8345: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0x8346: 0x50C3, //CJK UNIFIED IDEOGRAPH + 0x8347: 0x50C4, //CJK UNIFIED IDEOGRAPH + 0x8348: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0x8349: 0x50C6, //CJK UNIFIED IDEOGRAPH + 0x834A: 0x50C7, //CJK UNIFIED IDEOGRAPH + 0x834B: 0x50C8, //CJK UNIFIED IDEOGRAPH + 0x834C: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0x834D: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0x834E: 0x50CB, //CJK UNIFIED IDEOGRAPH + 0x834F: 0x50CC, //CJK UNIFIED IDEOGRAPH + 0x8350: 0x50CD, //CJK UNIFIED IDEOGRAPH + 0x8351: 0x50CE, //CJK UNIFIED IDEOGRAPH + 0x8352: 0x50D0, //CJK UNIFIED IDEOGRAPH + 0x8353: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0x8354: 0x50D2, //CJK UNIFIED IDEOGRAPH + 0x8355: 0x50D3, //CJK UNIFIED IDEOGRAPH + 0x8356: 0x50D4, //CJK UNIFIED IDEOGRAPH + 0x8357: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0x8358: 0x50D7, //CJK UNIFIED IDEOGRAPH + 0x8359: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0x835A: 0x50D9, //CJK UNIFIED IDEOGRAPH + 0x835B: 0x50DB, //CJK UNIFIED IDEOGRAPH + 0x835C: 0x50DC, //CJK UNIFIED IDEOGRAPH + 0x835D: 0x50DD, //CJK UNIFIED IDEOGRAPH + 0x835E: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0x835F: 0x50DF, //CJK UNIFIED IDEOGRAPH + 0x8360: 0x50E0, //CJK UNIFIED IDEOGRAPH + 0x8361: 0x50E1, //CJK UNIFIED IDEOGRAPH + 0x8362: 0x50E2, //CJK UNIFIED IDEOGRAPH + 0x8363: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0x8364: 0x50E4, //CJK UNIFIED IDEOGRAPH + 0x8365: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0x8366: 0x50E8, //CJK UNIFIED IDEOGRAPH + 0x8367: 0x50E9, //CJK UNIFIED IDEOGRAPH + 0x8368: 0x50EA, //CJK UNIFIED IDEOGRAPH + 0x8369: 0x50EB, //CJK UNIFIED IDEOGRAPH + 0x836A: 0x50EF, //CJK UNIFIED IDEOGRAPH + 0x836B: 0x50F0, //CJK UNIFIED IDEOGRAPH + 0x836C: 0x50F1, //CJK UNIFIED IDEOGRAPH + 0x836D: 0x50F2, //CJK UNIFIED IDEOGRAPH + 0x836E: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0x836F: 0x50F6, //CJK UNIFIED IDEOGRAPH + 0x8370: 0x50F7, //CJK UNIFIED IDEOGRAPH + 0x8371: 0x50F8, //CJK UNIFIED IDEOGRAPH + 0x8372: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0x8373: 0x50FA, //CJK UNIFIED IDEOGRAPH + 0x8374: 0x50FC, //CJK UNIFIED IDEOGRAPH + 0x8375: 0x50FD, //CJK UNIFIED IDEOGRAPH + 0x8376: 0x50FE, //CJK UNIFIED IDEOGRAPH + 0x8377: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0x8378: 0x5100, //CJK UNIFIED IDEOGRAPH + 0x8379: 0x5101, //CJK UNIFIED IDEOGRAPH + 0x837A: 0x5102, //CJK UNIFIED IDEOGRAPH + 0x837B: 0x5103, //CJK UNIFIED IDEOGRAPH + 0x837C: 0x5104, //CJK UNIFIED IDEOGRAPH + 0x837D: 0x5105, //CJK UNIFIED IDEOGRAPH + 0x837E: 0x5108, //CJK UNIFIED IDEOGRAPH + 0x8380: 0x5109, //CJK UNIFIED IDEOGRAPH + 0x8381: 0x510A, //CJK UNIFIED IDEOGRAPH + 0x8382: 0x510C, //CJK UNIFIED IDEOGRAPH + 0x8383: 0x510D, //CJK UNIFIED IDEOGRAPH + 0x8384: 0x510E, //CJK UNIFIED IDEOGRAPH + 0x8385: 0x510F, //CJK UNIFIED IDEOGRAPH + 0x8386: 0x5110, //CJK UNIFIED IDEOGRAPH + 0x8387: 0x5111, //CJK UNIFIED IDEOGRAPH + 0x8388: 0x5113, //CJK UNIFIED IDEOGRAPH + 0x8389: 0x5114, //CJK UNIFIED IDEOGRAPH + 0x838A: 0x5115, //CJK UNIFIED IDEOGRAPH + 0x838B: 0x5116, //CJK UNIFIED IDEOGRAPH + 0x838C: 0x5117, //CJK UNIFIED IDEOGRAPH + 0x838D: 0x5118, //CJK UNIFIED IDEOGRAPH + 0x838E: 0x5119, //CJK UNIFIED IDEOGRAPH + 0x838F: 0x511A, //CJK UNIFIED IDEOGRAPH + 0x8390: 0x511B, //CJK UNIFIED IDEOGRAPH + 0x8391: 0x511C, //CJK UNIFIED IDEOGRAPH + 0x8392: 0x511D, //CJK UNIFIED IDEOGRAPH + 0x8393: 0x511E, //CJK UNIFIED IDEOGRAPH + 0x8394: 0x511F, //CJK UNIFIED IDEOGRAPH + 0x8395: 0x5120, //CJK UNIFIED IDEOGRAPH + 0x8396: 0x5122, //CJK UNIFIED IDEOGRAPH + 0x8397: 0x5123, //CJK UNIFIED IDEOGRAPH + 0x8398: 0x5124, //CJK UNIFIED IDEOGRAPH + 0x8399: 0x5125, //CJK UNIFIED IDEOGRAPH + 0x839A: 0x5126, //CJK UNIFIED IDEOGRAPH + 0x839B: 0x5127, //CJK UNIFIED IDEOGRAPH + 0x839C: 0x5128, //CJK UNIFIED IDEOGRAPH + 0x839D: 0x5129, //CJK UNIFIED IDEOGRAPH + 0x839E: 0x512A, //CJK UNIFIED IDEOGRAPH + 0x839F: 0x512B, //CJK UNIFIED IDEOGRAPH + 0x83A0: 0x512C, //CJK UNIFIED IDEOGRAPH + 0x83A1: 0x512D, //CJK UNIFIED IDEOGRAPH + 0x83A2: 0x512E, //CJK UNIFIED IDEOGRAPH + 0x83A3: 0x512F, //CJK UNIFIED IDEOGRAPH + 0x83A4: 0x5130, //CJK UNIFIED IDEOGRAPH + 0x83A5: 0x5131, //CJK UNIFIED IDEOGRAPH + 0x83A6: 0x5132, //CJK UNIFIED IDEOGRAPH + 0x83A7: 0x5133, //CJK UNIFIED IDEOGRAPH + 0x83A8: 0x5134, //CJK UNIFIED IDEOGRAPH + 0x83A9: 0x5135, //CJK UNIFIED IDEOGRAPH + 0x83AA: 0x5136, //CJK UNIFIED IDEOGRAPH + 0x83AB: 0x5137, //CJK UNIFIED IDEOGRAPH + 0x83AC: 0x5138, //CJK UNIFIED IDEOGRAPH + 0x83AD: 0x5139, //CJK UNIFIED IDEOGRAPH + 0x83AE: 0x513A, //CJK UNIFIED IDEOGRAPH + 0x83AF: 0x513B, //CJK UNIFIED IDEOGRAPH + 0x83B0: 0x513C, //CJK UNIFIED IDEOGRAPH + 0x83B1: 0x513D, //CJK UNIFIED IDEOGRAPH + 0x83B2: 0x513E, //CJK UNIFIED IDEOGRAPH + 0x83B3: 0x5142, //CJK UNIFIED IDEOGRAPH + 0x83B4: 0x5147, //CJK UNIFIED IDEOGRAPH + 0x83B5: 0x514A, //CJK UNIFIED IDEOGRAPH + 0x83B6: 0x514C, //CJK UNIFIED IDEOGRAPH + 0x83B7: 0x514E, //CJK UNIFIED IDEOGRAPH + 0x83B8: 0x514F, //CJK UNIFIED IDEOGRAPH + 0x83B9: 0x5150, //CJK UNIFIED IDEOGRAPH + 0x83BA: 0x5152, //CJK UNIFIED IDEOGRAPH + 0x83BB: 0x5153, //CJK UNIFIED IDEOGRAPH + 0x83BC: 0x5157, //CJK UNIFIED IDEOGRAPH + 0x83BD: 0x5158, //CJK UNIFIED IDEOGRAPH + 0x83BE: 0x5159, //CJK UNIFIED IDEOGRAPH + 0x83BF: 0x515B, //CJK UNIFIED IDEOGRAPH + 0x83C0: 0x515D, //CJK UNIFIED IDEOGRAPH + 0x83C1: 0x515E, //CJK UNIFIED IDEOGRAPH + 0x83C2: 0x515F, //CJK UNIFIED IDEOGRAPH + 0x83C3: 0x5160, //CJK UNIFIED IDEOGRAPH + 0x83C4: 0x5161, //CJK UNIFIED IDEOGRAPH + 0x83C5: 0x5163, //CJK UNIFIED IDEOGRAPH + 0x83C6: 0x5164, //CJK UNIFIED IDEOGRAPH + 0x83C7: 0x5166, //CJK UNIFIED IDEOGRAPH + 0x83C8: 0x5167, //CJK UNIFIED IDEOGRAPH + 0x83C9: 0x5169, //CJK UNIFIED IDEOGRAPH + 0x83CA: 0x516A, //CJK UNIFIED IDEOGRAPH + 0x83CB: 0x516F, //CJK UNIFIED IDEOGRAPH + 0x83CC: 0x5172, //CJK UNIFIED IDEOGRAPH + 0x83CD: 0x517A, //CJK UNIFIED IDEOGRAPH + 0x83CE: 0x517E, //CJK UNIFIED IDEOGRAPH + 0x83CF: 0x517F, //CJK UNIFIED IDEOGRAPH + 0x83D0: 0x5183, //CJK UNIFIED IDEOGRAPH + 0x83D1: 0x5184, //CJK UNIFIED IDEOGRAPH + 0x83D2: 0x5186, //CJK UNIFIED IDEOGRAPH + 0x83D3: 0x5187, //CJK UNIFIED IDEOGRAPH + 0x83D4: 0x518A, //CJK UNIFIED IDEOGRAPH + 0x83D5: 0x518B, //CJK UNIFIED IDEOGRAPH + 0x83D6: 0x518E, //CJK UNIFIED IDEOGRAPH + 0x83D7: 0x518F, //CJK UNIFIED IDEOGRAPH + 0x83D8: 0x5190, //CJK UNIFIED IDEOGRAPH + 0x83D9: 0x5191, //CJK UNIFIED IDEOGRAPH + 0x83DA: 0x5193, //CJK UNIFIED IDEOGRAPH + 0x83DB: 0x5194, //CJK UNIFIED IDEOGRAPH + 0x83DC: 0x5198, //CJK UNIFIED IDEOGRAPH + 0x83DD: 0x519A, //CJK UNIFIED IDEOGRAPH + 0x83DE: 0x519D, //CJK UNIFIED IDEOGRAPH + 0x83DF: 0x519E, //CJK UNIFIED IDEOGRAPH + 0x83E0: 0x519F, //CJK UNIFIED IDEOGRAPH + 0x83E1: 0x51A1, //CJK UNIFIED IDEOGRAPH + 0x83E2: 0x51A3, //CJK UNIFIED IDEOGRAPH + 0x83E3: 0x51A6, //CJK UNIFIED IDEOGRAPH + 0x83E4: 0x51A7, //CJK UNIFIED IDEOGRAPH + 0x83E5: 0x51A8, //CJK UNIFIED IDEOGRAPH + 0x83E6: 0x51A9, //CJK UNIFIED IDEOGRAPH + 0x83E7: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0x83E8: 0x51AD, //CJK UNIFIED IDEOGRAPH + 0x83E9: 0x51AE, //CJK UNIFIED IDEOGRAPH + 0x83EA: 0x51B4, //CJK UNIFIED IDEOGRAPH + 0x83EB: 0x51B8, //CJK UNIFIED IDEOGRAPH + 0x83EC: 0x51B9, //CJK UNIFIED IDEOGRAPH + 0x83ED: 0x51BA, //CJK UNIFIED IDEOGRAPH + 0x83EE: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0x83EF: 0x51BF, //CJK UNIFIED IDEOGRAPH + 0x83F0: 0x51C1, //CJK UNIFIED IDEOGRAPH + 0x83F1: 0x51C2, //CJK UNIFIED IDEOGRAPH + 0x83F2: 0x51C3, //CJK UNIFIED IDEOGRAPH + 0x83F3: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0x83F4: 0x51C8, //CJK UNIFIED IDEOGRAPH + 0x83F5: 0x51CA, //CJK UNIFIED IDEOGRAPH + 0x83F6: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0x83F7: 0x51CE, //CJK UNIFIED IDEOGRAPH + 0x83F8: 0x51D0, //CJK UNIFIED IDEOGRAPH + 0x83F9: 0x51D2, //CJK UNIFIED IDEOGRAPH + 0x83FA: 0x51D3, //CJK UNIFIED IDEOGRAPH + 0x83FB: 0x51D4, //CJK UNIFIED IDEOGRAPH + 0x83FC: 0x51D5, //CJK UNIFIED IDEOGRAPH + 0x83FD: 0x51D6, //CJK UNIFIED IDEOGRAPH + 0x83FE: 0x51D7, //CJK UNIFIED IDEOGRAPH + 0x8440: 0x51D8, //CJK UNIFIED IDEOGRAPH + 0x8441: 0x51D9, //CJK UNIFIED IDEOGRAPH + 0x8442: 0x51DA, //CJK UNIFIED IDEOGRAPH + 0x8443: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0x8444: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0x8445: 0x51DF, //CJK UNIFIED IDEOGRAPH + 0x8446: 0x51E2, //CJK UNIFIED IDEOGRAPH + 0x8447: 0x51E3, //CJK UNIFIED IDEOGRAPH + 0x8448: 0x51E5, //CJK UNIFIED IDEOGRAPH + 0x8449: 0x51E6, //CJK UNIFIED IDEOGRAPH + 0x844A: 0x51E7, //CJK UNIFIED IDEOGRAPH + 0x844B: 0x51E8, //CJK UNIFIED IDEOGRAPH + 0x844C: 0x51E9, //CJK UNIFIED IDEOGRAPH + 0x844D: 0x51EA, //CJK UNIFIED IDEOGRAPH + 0x844E: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0x844F: 0x51EE, //CJK UNIFIED IDEOGRAPH + 0x8450: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0x8451: 0x51F2, //CJK UNIFIED IDEOGRAPH + 0x8452: 0x51F4, //CJK UNIFIED IDEOGRAPH + 0x8453: 0x51F7, //CJK UNIFIED IDEOGRAPH + 0x8454: 0x51FE, //CJK UNIFIED IDEOGRAPH + 0x8455: 0x5204, //CJK UNIFIED IDEOGRAPH + 0x8456: 0x5205, //CJK UNIFIED IDEOGRAPH + 0x8457: 0x5209, //CJK UNIFIED IDEOGRAPH + 0x8458: 0x520B, //CJK UNIFIED IDEOGRAPH + 0x8459: 0x520C, //CJK UNIFIED IDEOGRAPH + 0x845A: 0x520F, //CJK UNIFIED IDEOGRAPH + 0x845B: 0x5210, //CJK UNIFIED IDEOGRAPH + 0x845C: 0x5213, //CJK UNIFIED IDEOGRAPH + 0x845D: 0x5214, //CJK UNIFIED IDEOGRAPH + 0x845E: 0x5215, //CJK UNIFIED IDEOGRAPH + 0x845F: 0x521C, //CJK UNIFIED IDEOGRAPH + 0x8460: 0x521E, //CJK UNIFIED IDEOGRAPH + 0x8461: 0x521F, //CJK UNIFIED IDEOGRAPH + 0x8462: 0x5221, //CJK UNIFIED IDEOGRAPH + 0x8463: 0x5222, //CJK UNIFIED IDEOGRAPH + 0x8464: 0x5223, //CJK UNIFIED IDEOGRAPH + 0x8465: 0x5225, //CJK UNIFIED IDEOGRAPH + 0x8466: 0x5226, //CJK UNIFIED IDEOGRAPH + 0x8467: 0x5227, //CJK UNIFIED IDEOGRAPH + 0x8468: 0x522A, //CJK UNIFIED IDEOGRAPH + 0x8469: 0x522C, //CJK UNIFIED IDEOGRAPH + 0x846A: 0x522F, //CJK UNIFIED IDEOGRAPH + 0x846B: 0x5231, //CJK UNIFIED IDEOGRAPH + 0x846C: 0x5232, //CJK UNIFIED IDEOGRAPH + 0x846D: 0x5234, //CJK UNIFIED IDEOGRAPH + 0x846E: 0x5235, //CJK UNIFIED IDEOGRAPH + 0x846F: 0x523C, //CJK UNIFIED IDEOGRAPH + 0x8470: 0x523E, //CJK UNIFIED IDEOGRAPH + 0x8471: 0x5244, //CJK UNIFIED IDEOGRAPH + 0x8472: 0x5245, //CJK UNIFIED IDEOGRAPH + 0x8473: 0x5246, //CJK UNIFIED IDEOGRAPH + 0x8474: 0x5247, //CJK UNIFIED IDEOGRAPH + 0x8475: 0x5248, //CJK UNIFIED IDEOGRAPH + 0x8476: 0x5249, //CJK UNIFIED IDEOGRAPH + 0x8477: 0x524B, //CJK UNIFIED IDEOGRAPH + 0x8478: 0x524E, //CJK UNIFIED IDEOGRAPH + 0x8479: 0x524F, //CJK UNIFIED IDEOGRAPH + 0x847A: 0x5252, //CJK UNIFIED IDEOGRAPH + 0x847B: 0x5253, //CJK UNIFIED IDEOGRAPH + 0x847C: 0x5255, //CJK UNIFIED IDEOGRAPH + 0x847D: 0x5257, //CJK UNIFIED IDEOGRAPH + 0x847E: 0x5258, //CJK UNIFIED IDEOGRAPH + 0x8480: 0x5259, //CJK UNIFIED IDEOGRAPH + 0x8481: 0x525A, //CJK UNIFIED IDEOGRAPH + 0x8482: 0x525B, //CJK UNIFIED IDEOGRAPH + 0x8483: 0x525D, //CJK UNIFIED IDEOGRAPH + 0x8484: 0x525F, //CJK UNIFIED IDEOGRAPH + 0x8485: 0x5260, //CJK UNIFIED IDEOGRAPH + 0x8486: 0x5262, //CJK UNIFIED IDEOGRAPH + 0x8487: 0x5263, //CJK UNIFIED IDEOGRAPH + 0x8488: 0x5264, //CJK UNIFIED IDEOGRAPH + 0x8489: 0x5266, //CJK UNIFIED IDEOGRAPH + 0x848A: 0x5268, //CJK UNIFIED IDEOGRAPH + 0x848B: 0x526B, //CJK UNIFIED IDEOGRAPH + 0x848C: 0x526C, //CJK UNIFIED IDEOGRAPH + 0x848D: 0x526D, //CJK UNIFIED IDEOGRAPH + 0x848E: 0x526E, //CJK UNIFIED IDEOGRAPH + 0x848F: 0x5270, //CJK UNIFIED IDEOGRAPH + 0x8490: 0x5271, //CJK UNIFIED IDEOGRAPH + 0x8491: 0x5273, //CJK UNIFIED IDEOGRAPH + 0x8492: 0x5274, //CJK UNIFIED IDEOGRAPH + 0x8493: 0x5275, //CJK UNIFIED IDEOGRAPH + 0x8494: 0x5276, //CJK UNIFIED IDEOGRAPH + 0x8495: 0x5277, //CJK UNIFIED IDEOGRAPH + 0x8496: 0x5278, //CJK UNIFIED IDEOGRAPH + 0x8497: 0x5279, //CJK UNIFIED IDEOGRAPH + 0x8498: 0x527A, //CJK UNIFIED IDEOGRAPH + 0x8499: 0x527B, //CJK UNIFIED IDEOGRAPH + 0x849A: 0x527C, //CJK UNIFIED IDEOGRAPH + 0x849B: 0x527E, //CJK UNIFIED IDEOGRAPH + 0x849C: 0x5280, //CJK UNIFIED IDEOGRAPH + 0x849D: 0x5283, //CJK UNIFIED IDEOGRAPH + 0x849E: 0x5284, //CJK UNIFIED IDEOGRAPH + 0x849F: 0x5285, //CJK UNIFIED IDEOGRAPH + 0x84A0: 0x5286, //CJK UNIFIED IDEOGRAPH + 0x84A1: 0x5287, //CJK UNIFIED IDEOGRAPH + 0x84A2: 0x5289, //CJK UNIFIED IDEOGRAPH + 0x84A3: 0x528A, //CJK UNIFIED IDEOGRAPH + 0x84A4: 0x528B, //CJK UNIFIED IDEOGRAPH + 0x84A5: 0x528C, //CJK UNIFIED IDEOGRAPH + 0x84A6: 0x528D, //CJK UNIFIED IDEOGRAPH + 0x84A7: 0x528E, //CJK UNIFIED IDEOGRAPH + 0x84A8: 0x528F, //CJK UNIFIED IDEOGRAPH + 0x84A9: 0x5291, //CJK UNIFIED IDEOGRAPH + 0x84AA: 0x5292, //CJK UNIFIED IDEOGRAPH + 0x84AB: 0x5294, //CJK UNIFIED IDEOGRAPH + 0x84AC: 0x5295, //CJK UNIFIED IDEOGRAPH + 0x84AD: 0x5296, //CJK UNIFIED IDEOGRAPH + 0x84AE: 0x5297, //CJK UNIFIED IDEOGRAPH + 0x84AF: 0x5298, //CJK UNIFIED IDEOGRAPH + 0x84B0: 0x5299, //CJK UNIFIED IDEOGRAPH + 0x84B1: 0x529A, //CJK UNIFIED IDEOGRAPH + 0x84B2: 0x529C, //CJK UNIFIED IDEOGRAPH + 0x84B3: 0x52A4, //CJK UNIFIED IDEOGRAPH + 0x84B4: 0x52A5, //CJK UNIFIED IDEOGRAPH + 0x84B5: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0x84B6: 0x52A7, //CJK UNIFIED IDEOGRAPH + 0x84B7: 0x52AE, //CJK UNIFIED IDEOGRAPH + 0x84B8: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0x84B9: 0x52B0, //CJK UNIFIED IDEOGRAPH + 0x84BA: 0x52B4, //CJK UNIFIED IDEOGRAPH + 0x84BB: 0x52B5, //CJK UNIFIED IDEOGRAPH + 0x84BC: 0x52B6, //CJK UNIFIED IDEOGRAPH + 0x84BD: 0x52B7, //CJK UNIFIED IDEOGRAPH + 0x84BE: 0x52B8, //CJK UNIFIED IDEOGRAPH + 0x84BF: 0x52B9, //CJK UNIFIED IDEOGRAPH + 0x84C0: 0x52BA, //CJK UNIFIED IDEOGRAPH + 0x84C1: 0x52BB, //CJK UNIFIED IDEOGRAPH + 0x84C2: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0x84C3: 0x52BD, //CJK UNIFIED IDEOGRAPH + 0x84C4: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0x84C5: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0x84C6: 0x52C2, //CJK UNIFIED IDEOGRAPH + 0x84C7: 0x52C4, //CJK UNIFIED IDEOGRAPH + 0x84C8: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0x84C9: 0x52C6, //CJK UNIFIED IDEOGRAPH + 0x84CA: 0x52C8, //CJK UNIFIED IDEOGRAPH + 0x84CB: 0x52CA, //CJK UNIFIED IDEOGRAPH + 0x84CC: 0x52CC, //CJK UNIFIED IDEOGRAPH + 0x84CD: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0x84CE: 0x52CE, //CJK UNIFIED IDEOGRAPH + 0x84CF: 0x52CF, //CJK UNIFIED IDEOGRAPH + 0x84D0: 0x52D1, //CJK UNIFIED IDEOGRAPH + 0x84D1: 0x52D3, //CJK UNIFIED IDEOGRAPH + 0x84D2: 0x52D4, //CJK UNIFIED IDEOGRAPH + 0x84D3: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0x84D4: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0x84D5: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0x84D6: 0x52DA, //CJK UNIFIED IDEOGRAPH + 0x84D7: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0x84D8: 0x52DC, //CJK UNIFIED IDEOGRAPH + 0x84D9: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0x84DA: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0x84DB: 0x52E0, //CJK UNIFIED IDEOGRAPH + 0x84DC: 0x52E1, //CJK UNIFIED IDEOGRAPH + 0x84DD: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0x84DE: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0x84DF: 0x52E5, //CJK UNIFIED IDEOGRAPH + 0x84E0: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0x84E1: 0x52E7, //CJK UNIFIED IDEOGRAPH + 0x84E2: 0x52E8, //CJK UNIFIED IDEOGRAPH + 0x84E3: 0x52E9, //CJK UNIFIED IDEOGRAPH + 0x84E4: 0x52EA, //CJK UNIFIED IDEOGRAPH + 0x84E5: 0x52EB, //CJK UNIFIED IDEOGRAPH + 0x84E6: 0x52EC, //CJK UNIFIED IDEOGRAPH + 0x84E7: 0x52ED, //CJK UNIFIED IDEOGRAPH + 0x84E8: 0x52EE, //CJK UNIFIED IDEOGRAPH + 0x84E9: 0x52EF, //CJK UNIFIED IDEOGRAPH + 0x84EA: 0x52F1, //CJK UNIFIED IDEOGRAPH + 0x84EB: 0x52F2, //CJK UNIFIED IDEOGRAPH + 0x84EC: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0x84ED: 0x52F4, //CJK UNIFIED IDEOGRAPH + 0x84EE: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0x84EF: 0x52F6, //CJK UNIFIED IDEOGRAPH + 0x84F0: 0x52F7, //CJK UNIFIED IDEOGRAPH + 0x84F1: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0x84F2: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0x84F3: 0x52FC, //CJK UNIFIED IDEOGRAPH + 0x84F4: 0x52FD, //CJK UNIFIED IDEOGRAPH + 0x84F5: 0x5301, //CJK UNIFIED IDEOGRAPH + 0x84F6: 0x5302, //CJK UNIFIED IDEOGRAPH + 0x84F7: 0x5303, //CJK UNIFIED IDEOGRAPH + 0x84F8: 0x5304, //CJK UNIFIED IDEOGRAPH + 0x84F9: 0x5307, //CJK UNIFIED IDEOGRAPH + 0x84FA: 0x5309, //CJK UNIFIED IDEOGRAPH + 0x84FB: 0x530A, //CJK UNIFIED IDEOGRAPH + 0x84FC: 0x530B, //CJK UNIFIED IDEOGRAPH + 0x84FD: 0x530C, //CJK UNIFIED IDEOGRAPH + 0x84FE: 0x530E, //CJK UNIFIED IDEOGRAPH + 0x8540: 0x5311, //CJK UNIFIED IDEOGRAPH + 0x8541: 0x5312, //CJK UNIFIED IDEOGRAPH + 0x8542: 0x5313, //CJK UNIFIED IDEOGRAPH + 0x8543: 0x5314, //CJK UNIFIED IDEOGRAPH + 0x8544: 0x5318, //CJK UNIFIED IDEOGRAPH + 0x8545: 0x531B, //CJK UNIFIED IDEOGRAPH + 0x8546: 0x531C, //CJK UNIFIED IDEOGRAPH + 0x8547: 0x531E, //CJK UNIFIED IDEOGRAPH + 0x8548: 0x531F, //CJK UNIFIED IDEOGRAPH + 0x8549: 0x5322, //CJK UNIFIED IDEOGRAPH + 0x854A: 0x5324, //CJK UNIFIED IDEOGRAPH + 0x854B: 0x5325, //CJK UNIFIED IDEOGRAPH + 0x854C: 0x5327, //CJK UNIFIED IDEOGRAPH + 0x854D: 0x5328, //CJK UNIFIED IDEOGRAPH + 0x854E: 0x5329, //CJK UNIFIED IDEOGRAPH + 0x854F: 0x532B, //CJK UNIFIED IDEOGRAPH + 0x8550: 0x532C, //CJK UNIFIED IDEOGRAPH + 0x8551: 0x532D, //CJK UNIFIED IDEOGRAPH + 0x8552: 0x532F, //CJK UNIFIED IDEOGRAPH + 0x8553: 0x5330, //CJK UNIFIED IDEOGRAPH + 0x8554: 0x5331, //CJK UNIFIED IDEOGRAPH + 0x8555: 0x5332, //CJK UNIFIED IDEOGRAPH + 0x8556: 0x5333, //CJK UNIFIED IDEOGRAPH + 0x8557: 0x5334, //CJK UNIFIED IDEOGRAPH + 0x8558: 0x5335, //CJK UNIFIED IDEOGRAPH + 0x8559: 0x5336, //CJK UNIFIED IDEOGRAPH + 0x855A: 0x5337, //CJK UNIFIED IDEOGRAPH + 0x855B: 0x5338, //CJK UNIFIED IDEOGRAPH + 0x855C: 0x533C, //CJK UNIFIED IDEOGRAPH + 0x855D: 0x533D, //CJK UNIFIED IDEOGRAPH + 0x855E: 0x5340, //CJK UNIFIED IDEOGRAPH + 0x855F: 0x5342, //CJK UNIFIED IDEOGRAPH + 0x8560: 0x5344, //CJK UNIFIED IDEOGRAPH + 0x8561: 0x5346, //CJK UNIFIED IDEOGRAPH + 0x8562: 0x534B, //CJK UNIFIED IDEOGRAPH + 0x8563: 0x534C, //CJK UNIFIED IDEOGRAPH + 0x8564: 0x534D, //CJK UNIFIED IDEOGRAPH + 0x8565: 0x5350, //CJK UNIFIED IDEOGRAPH + 0x8566: 0x5354, //CJK UNIFIED IDEOGRAPH + 0x8567: 0x5358, //CJK UNIFIED IDEOGRAPH + 0x8568: 0x5359, //CJK UNIFIED IDEOGRAPH + 0x8569: 0x535B, //CJK UNIFIED IDEOGRAPH + 0x856A: 0x535D, //CJK UNIFIED IDEOGRAPH + 0x856B: 0x5365, //CJK UNIFIED IDEOGRAPH + 0x856C: 0x5368, //CJK UNIFIED IDEOGRAPH + 0x856D: 0x536A, //CJK UNIFIED IDEOGRAPH + 0x856E: 0x536C, //CJK UNIFIED IDEOGRAPH + 0x856F: 0x536D, //CJK UNIFIED IDEOGRAPH + 0x8570: 0x5372, //CJK UNIFIED IDEOGRAPH + 0x8571: 0x5376, //CJK UNIFIED IDEOGRAPH + 0x8572: 0x5379, //CJK UNIFIED IDEOGRAPH + 0x8573: 0x537B, //CJK UNIFIED IDEOGRAPH + 0x8574: 0x537C, //CJK UNIFIED IDEOGRAPH + 0x8575: 0x537D, //CJK UNIFIED IDEOGRAPH + 0x8576: 0x537E, //CJK UNIFIED IDEOGRAPH + 0x8577: 0x5380, //CJK UNIFIED IDEOGRAPH + 0x8578: 0x5381, //CJK UNIFIED IDEOGRAPH + 0x8579: 0x5383, //CJK UNIFIED IDEOGRAPH + 0x857A: 0x5387, //CJK UNIFIED IDEOGRAPH + 0x857B: 0x5388, //CJK UNIFIED IDEOGRAPH + 0x857C: 0x538A, //CJK UNIFIED IDEOGRAPH + 0x857D: 0x538E, //CJK UNIFIED IDEOGRAPH + 0x857E: 0x538F, //CJK UNIFIED IDEOGRAPH + 0x8580: 0x5390, //CJK UNIFIED IDEOGRAPH + 0x8581: 0x5391, //CJK UNIFIED IDEOGRAPH + 0x8582: 0x5392, //CJK UNIFIED IDEOGRAPH + 0x8583: 0x5393, //CJK UNIFIED IDEOGRAPH + 0x8584: 0x5394, //CJK UNIFIED IDEOGRAPH + 0x8585: 0x5396, //CJK UNIFIED IDEOGRAPH + 0x8586: 0x5397, //CJK UNIFIED IDEOGRAPH + 0x8587: 0x5399, //CJK UNIFIED IDEOGRAPH + 0x8588: 0x539B, //CJK UNIFIED IDEOGRAPH + 0x8589: 0x539C, //CJK UNIFIED IDEOGRAPH + 0x858A: 0x539E, //CJK UNIFIED IDEOGRAPH + 0x858B: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0x858C: 0x53A1, //CJK UNIFIED IDEOGRAPH + 0x858D: 0x53A4, //CJK UNIFIED IDEOGRAPH + 0x858E: 0x53A7, //CJK UNIFIED IDEOGRAPH + 0x858F: 0x53AA, //CJK UNIFIED IDEOGRAPH + 0x8590: 0x53AB, //CJK UNIFIED IDEOGRAPH + 0x8591: 0x53AC, //CJK UNIFIED IDEOGRAPH + 0x8592: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0x8593: 0x53AF, //CJK UNIFIED IDEOGRAPH + 0x8594: 0x53B0, //CJK UNIFIED IDEOGRAPH + 0x8595: 0x53B1, //CJK UNIFIED IDEOGRAPH + 0x8596: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0x8597: 0x53B3, //CJK UNIFIED IDEOGRAPH + 0x8598: 0x53B4, //CJK UNIFIED IDEOGRAPH + 0x8599: 0x53B5, //CJK UNIFIED IDEOGRAPH + 0x859A: 0x53B7, //CJK UNIFIED IDEOGRAPH + 0x859B: 0x53B8, //CJK UNIFIED IDEOGRAPH + 0x859C: 0x53B9, //CJK UNIFIED IDEOGRAPH + 0x859D: 0x53BA, //CJK UNIFIED IDEOGRAPH + 0x859E: 0x53BC, //CJK UNIFIED IDEOGRAPH + 0x859F: 0x53BD, //CJK UNIFIED IDEOGRAPH + 0x85A0: 0x53BE, //CJK UNIFIED IDEOGRAPH + 0x85A1: 0x53C0, //CJK UNIFIED IDEOGRAPH + 0x85A2: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0x85A3: 0x53C4, //CJK UNIFIED IDEOGRAPH + 0x85A4: 0x53C5, //CJK UNIFIED IDEOGRAPH + 0x85A5: 0x53C6, //CJK UNIFIED IDEOGRAPH + 0x85A6: 0x53C7, //CJK UNIFIED IDEOGRAPH + 0x85A7: 0x53CE, //CJK UNIFIED IDEOGRAPH + 0x85A8: 0x53CF, //CJK UNIFIED IDEOGRAPH + 0x85A9: 0x53D0, //CJK UNIFIED IDEOGRAPH + 0x85AA: 0x53D2, //CJK UNIFIED IDEOGRAPH + 0x85AB: 0x53D3, //CJK UNIFIED IDEOGRAPH + 0x85AC: 0x53D5, //CJK UNIFIED IDEOGRAPH + 0x85AD: 0x53DA, //CJK UNIFIED IDEOGRAPH + 0x85AE: 0x53DC, //CJK UNIFIED IDEOGRAPH + 0x85AF: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0x85B0: 0x53DE, //CJK UNIFIED IDEOGRAPH + 0x85B1: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0x85B2: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0x85B3: 0x53E7, //CJK UNIFIED IDEOGRAPH + 0x85B4: 0x53F4, //CJK UNIFIED IDEOGRAPH + 0x85B5: 0x53FA, //CJK UNIFIED IDEOGRAPH + 0x85B6: 0x53FE, //CJK UNIFIED IDEOGRAPH + 0x85B7: 0x53FF, //CJK UNIFIED IDEOGRAPH + 0x85B8: 0x5400, //CJK UNIFIED IDEOGRAPH + 0x85B9: 0x5402, //CJK UNIFIED IDEOGRAPH + 0x85BA: 0x5405, //CJK UNIFIED IDEOGRAPH + 0x85BB: 0x5407, //CJK UNIFIED IDEOGRAPH + 0x85BC: 0x540B, //CJK UNIFIED IDEOGRAPH + 0x85BD: 0x5414, //CJK UNIFIED IDEOGRAPH + 0x85BE: 0x5418, //CJK UNIFIED IDEOGRAPH + 0x85BF: 0x5419, //CJK UNIFIED IDEOGRAPH + 0x85C0: 0x541A, //CJK UNIFIED IDEOGRAPH + 0x85C1: 0x541C, //CJK UNIFIED IDEOGRAPH + 0x85C2: 0x5422, //CJK UNIFIED IDEOGRAPH + 0x85C3: 0x5424, //CJK UNIFIED IDEOGRAPH + 0x85C4: 0x5425, //CJK UNIFIED IDEOGRAPH + 0x85C5: 0x542A, //CJK UNIFIED IDEOGRAPH + 0x85C6: 0x5430, //CJK UNIFIED IDEOGRAPH + 0x85C7: 0x5433, //CJK UNIFIED IDEOGRAPH + 0x85C8: 0x5436, //CJK UNIFIED IDEOGRAPH + 0x85C9: 0x5437, //CJK UNIFIED IDEOGRAPH + 0x85CA: 0x543A, //CJK UNIFIED IDEOGRAPH + 0x85CB: 0x543D, //CJK UNIFIED IDEOGRAPH + 0x85CC: 0x543F, //CJK UNIFIED IDEOGRAPH + 0x85CD: 0x5441, //CJK UNIFIED IDEOGRAPH + 0x85CE: 0x5442, //CJK UNIFIED IDEOGRAPH + 0x85CF: 0x5444, //CJK UNIFIED IDEOGRAPH + 0x85D0: 0x5445, //CJK UNIFIED IDEOGRAPH + 0x85D1: 0x5447, //CJK UNIFIED IDEOGRAPH + 0x85D2: 0x5449, //CJK UNIFIED IDEOGRAPH + 0x85D3: 0x544C, //CJK UNIFIED IDEOGRAPH + 0x85D4: 0x544D, //CJK UNIFIED IDEOGRAPH + 0x85D5: 0x544E, //CJK UNIFIED IDEOGRAPH + 0x85D6: 0x544F, //CJK UNIFIED IDEOGRAPH + 0x85D7: 0x5451, //CJK UNIFIED IDEOGRAPH + 0x85D8: 0x545A, //CJK UNIFIED IDEOGRAPH + 0x85D9: 0x545D, //CJK UNIFIED IDEOGRAPH + 0x85DA: 0x545E, //CJK UNIFIED IDEOGRAPH + 0x85DB: 0x545F, //CJK UNIFIED IDEOGRAPH + 0x85DC: 0x5460, //CJK UNIFIED IDEOGRAPH + 0x85DD: 0x5461, //CJK UNIFIED IDEOGRAPH + 0x85DE: 0x5463, //CJK UNIFIED IDEOGRAPH + 0x85DF: 0x5465, //CJK UNIFIED IDEOGRAPH + 0x85E0: 0x5467, //CJK UNIFIED IDEOGRAPH + 0x85E1: 0x5469, //CJK UNIFIED IDEOGRAPH + 0x85E2: 0x546A, //CJK UNIFIED IDEOGRAPH + 0x85E3: 0x546B, //CJK UNIFIED IDEOGRAPH + 0x85E4: 0x546C, //CJK UNIFIED IDEOGRAPH + 0x85E5: 0x546D, //CJK UNIFIED IDEOGRAPH + 0x85E6: 0x546E, //CJK UNIFIED IDEOGRAPH + 0x85E7: 0x546F, //CJK UNIFIED IDEOGRAPH + 0x85E8: 0x5470, //CJK UNIFIED IDEOGRAPH + 0x85E9: 0x5474, //CJK UNIFIED IDEOGRAPH + 0x85EA: 0x5479, //CJK UNIFIED IDEOGRAPH + 0x85EB: 0x547A, //CJK UNIFIED IDEOGRAPH + 0x85EC: 0x547E, //CJK UNIFIED IDEOGRAPH + 0x85ED: 0x547F, //CJK UNIFIED IDEOGRAPH + 0x85EE: 0x5481, //CJK UNIFIED IDEOGRAPH + 0x85EF: 0x5483, //CJK UNIFIED IDEOGRAPH + 0x85F0: 0x5485, //CJK UNIFIED IDEOGRAPH + 0x85F1: 0x5487, //CJK UNIFIED IDEOGRAPH + 0x85F2: 0x5488, //CJK UNIFIED IDEOGRAPH + 0x85F3: 0x5489, //CJK UNIFIED IDEOGRAPH + 0x85F4: 0x548A, //CJK UNIFIED IDEOGRAPH + 0x85F5: 0x548D, //CJK UNIFIED IDEOGRAPH + 0x85F6: 0x5491, //CJK UNIFIED IDEOGRAPH + 0x85F7: 0x5493, //CJK UNIFIED IDEOGRAPH + 0x85F8: 0x5497, //CJK UNIFIED IDEOGRAPH + 0x85F9: 0x5498, //CJK UNIFIED IDEOGRAPH + 0x85FA: 0x549C, //CJK UNIFIED IDEOGRAPH + 0x85FB: 0x549E, //CJK UNIFIED IDEOGRAPH + 0x85FC: 0x549F, //CJK UNIFIED IDEOGRAPH + 0x85FD: 0x54A0, //CJK UNIFIED IDEOGRAPH + 0x85FE: 0x54A1, //CJK UNIFIED IDEOGRAPH + 0x8640: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0x8641: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0x8642: 0x54AE, //CJK UNIFIED IDEOGRAPH + 0x8643: 0x54B0, //CJK UNIFIED IDEOGRAPH + 0x8644: 0x54B2, //CJK UNIFIED IDEOGRAPH + 0x8645: 0x54B5, //CJK UNIFIED IDEOGRAPH + 0x8646: 0x54B6, //CJK UNIFIED IDEOGRAPH + 0x8647: 0x54B7, //CJK UNIFIED IDEOGRAPH + 0x8648: 0x54B9, //CJK UNIFIED IDEOGRAPH + 0x8649: 0x54BA, //CJK UNIFIED IDEOGRAPH + 0x864A: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0x864B: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0x864C: 0x54C3, //CJK UNIFIED IDEOGRAPH + 0x864D: 0x54C5, //CJK UNIFIED IDEOGRAPH + 0x864E: 0x54CA, //CJK UNIFIED IDEOGRAPH + 0x864F: 0x54CB, //CJK UNIFIED IDEOGRAPH + 0x8650: 0x54D6, //CJK UNIFIED IDEOGRAPH + 0x8651: 0x54D8, //CJK UNIFIED IDEOGRAPH + 0x8652: 0x54DB, //CJK UNIFIED IDEOGRAPH + 0x8653: 0x54E0, //CJK UNIFIED IDEOGRAPH + 0x8654: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0x8655: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0x8656: 0x54E3, //CJK UNIFIED IDEOGRAPH + 0x8657: 0x54E4, //CJK UNIFIED IDEOGRAPH + 0x8658: 0x54EB, //CJK UNIFIED IDEOGRAPH + 0x8659: 0x54EC, //CJK UNIFIED IDEOGRAPH + 0x865A: 0x54EF, //CJK UNIFIED IDEOGRAPH + 0x865B: 0x54F0, //CJK UNIFIED IDEOGRAPH + 0x865C: 0x54F1, //CJK UNIFIED IDEOGRAPH + 0x865D: 0x54F4, //CJK UNIFIED IDEOGRAPH + 0x865E: 0x54F5, //CJK UNIFIED IDEOGRAPH + 0x865F: 0x54F6, //CJK UNIFIED IDEOGRAPH + 0x8660: 0x54F7, //CJK UNIFIED IDEOGRAPH + 0x8661: 0x54F8, //CJK UNIFIED IDEOGRAPH + 0x8662: 0x54F9, //CJK UNIFIED IDEOGRAPH + 0x8663: 0x54FB, //CJK UNIFIED IDEOGRAPH + 0x8664: 0x54FE, //CJK UNIFIED IDEOGRAPH + 0x8665: 0x5500, //CJK UNIFIED IDEOGRAPH + 0x8666: 0x5502, //CJK UNIFIED IDEOGRAPH + 0x8667: 0x5503, //CJK UNIFIED IDEOGRAPH + 0x8668: 0x5504, //CJK UNIFIED IDEOGRAPH + 0x8669: 0x5505, //CJK UNIFIED IDEOGRAPH + 0x866A: 0x5508, //CJK UNIFIED IDEOGRAPH + 0x866B: 0x550A, //CJK UNIFIED IDEOGRAPH + 0x866C: 0x550B, //CJK UNIFIED IDEOGRAPH + 0x866D: 0x550C, //CJK UNIFIED IDEOGRAPH + 0x866E: 0x550D, //CJK UNIFIED IDEOGRAPH + 0x866F: 0x550E, //CJK UNIFIED IDEOGRAPH + 0x8670: 0x5512, //CJK UNIFIED IDEOGRAPH + 0x8671: 0x5513, //CJK UNIFIED IDEOGRAPH + 0x8672: 0x5515, //CJK UNIFIED IDEOGRAPH + 0x8673: 0x5516, //CJK UNIFIED IDEOGRAPH + 0x8674: 0x5517, //CJK UNIFIED IDEOGRAPH + 0x8675: 0x5518, //CJK UNIFIED IDEOGRAPH + 0x8676: 0x5519, //CJK UNIFIED IDEOGRAPH + 0x8677: 0x551A, //CJK UNIFIED IDEOGRAPH + 0x8678: 0x551C, //CJK UNIFIED IDEOGRAPH + 0x8679: 0x551D, //CJK UNIFIED IDEOGRAPH + 0x867A: 0x551E, //CJK UNIFIED IDEOGRAPH + 0x867B: 0x551F, //CJK UNIFIED IDEOGRAPH + 0x867C: 0x5521, //CJK UNIFIED IDEOGRAPH + 0x867D: 0x5525, //CJK UNIFIED IDEOGRAPH + 0x867E: 0x5526, //CJK UNIFIED IDEOGRAPH + 0x8680: 0x5528, //CJK UNIFIED IDEOGRAPH + 0x8681: 0x5529, //CJK UNIFIED IDEOGRAPH + 0x8682: 0x552B, //CJK UNIFIED IDEOGRAPH + 0x8683: 0x552D, //CJK UNIFIED IDEOGRAPH + 0x8684: 0x5532, //CJK UNIFIED IDEOGRAPH + 0x8685: 0x5534, //CJK UNIFIED IDEOGRAPH + 0x8686: 0x5535, //CJK UNIFIED IDEOGRAPH + 0x8687: 0x5536, //CJK UNIFIED IDEOGRAPH + 0x8688: 0x5538, //CJK UNIFIED IDEOGRAPH + 0x8689: 0x5539, //CJK UNIFIED IDEOGRAPH + 0x868A: 0x553A, //CJK UNIFIED IDEOGRAPH + 0x868B: 0x553B, //CJK UNIFIED IDEOGRAPH + 0x868C: 0x553D, //CJK UNIFIED IDEOGRAPH + 0x868D: 0x5540, //CJK UNIFIED IDEOGRAPH + 0x868E: 0x5542, //CJK UNIFIED IDEOGRAPH + 0x868F: 0x5545, //CJK UNIFIED IDEOGRAPH + 0x8690: 0x5547, //CJK UNIFIED IDEOGRAPH + 0x8691: 0x5548, //CJK UNIFIED IDEOGRAPH + 0x8692: 0x554B, //CJK UNIFIED IDEOGRAPH + 0x8693: 0x554C, //CJK UNIFIED IDEOGRAPH + 0x8694: 0x554D, //CJK UNIFIED IDEOGRAPH + 0x8695: 0x554E, //CJK UNIFIED IDEOGRAPH + 0x8696: 0x554F, //CJK UNIFIED IDEOGRAPH + 0x8697: 0x5551, //CJK UNIFIED IDEOGRAPH + 0x8698: 0x5552, //CJK UNIFIED IDEOGRAPH + 0x8699: 0x5553, //CJK UNIFIED IDEOGRAPH + 0x869A: 0x5554, //CJK UNIFIED IDEOGRAPH + 0x869B: 0x5557, //CJK UNIFIED IDEOGRAPH + 0x869C: 0x5558, //CJK UNIFIED IDEOGRAPH + 0x869D: 0x5559, //CJK UNIFIED IDEOGRAPH + 0x869E: 0x555A, //CJK UNIFIED IDEOGRAPH + 0x869F: 0x555B, //CJK UNIFIED IDEOGRAPH + 0x86A0: 0x555D, //CJK UNIFIED IDEOGRAPH + 0x86A1: 0x555E, //CJK UNIFIED IDEOGRAPH + 0x86A2: 0x555F, //CJK UNIFIED IDEOGRAPH + 0x86A3: 0x5560, //CJK UNIFIED IDEOGRAPH + 0x86A4: 0x5562, //CJK UNIFIED IDEOGRAPH + 0x86A5: 0x5563, //CJK UNIFIED IDEOGRAPH + 0x86A6: 0x5568, //CJK UNIFIED IDEOGRAPH + 0x86A7: 0x5569, //CJK UNIFIED IDEOGRAPH + 0x86A8: 0x556B, //CJK UNIFIED IDEOGRAPH + 0x86A9: 0x556F, //CJK UNIFIED IDEOGRAPH + 0x86AA: 0x5570, //CJK UNIFIED IDEOGRAPH + 0x86AB: 0x5571, //CJK UNIFIED IDEOGRAPH + 0x86AC: 0x5572, //CJK UNIFIED IDEOGRAPH + 0x86AD: 0x5573, //CJK UNIFIED IDEOGRAPH + 0x86AE: 0x5574, //CJK UNIFIED IDEOGRAPH + 0x86AF: 0x5579, //CJK UNIFIED IDEOGRAPH + 0x86B0: 0x557A, //CJK UNIFIED IDEOGRAPH + 0x86B1: 0x557D, //CJK UNIFIED IDEOGRAPH + 0x86B2: 0x557F, //CJK UNIFIED IDEOGRAPH + 0x86B3: 0x5585, //CJK UNIFIED IDEOGRAPH + 0x86B4: 0x5586, //CJK UNIFIED IDEOGRAPH + 0x86B5: 0x558C, //CJK UNIFIED IDEOGRAPH + 0x86B6: 0x558D, //CJK UNIFIED IDEOGRAPH + 0x86B7: 0x558E, //CJK UNIFIED IDEOGRAPH + 0x86B8: 0x5590, //CJK UNIFIED IDEOGRAPH + 0x86B9: 0x5592, //CJK UNIFIED IDEOGRAPH + 0x86BA: 0x5593, //CJK UNIFIED IDEOGRAPH + 0x86BB: 0x5595, //CJK UNIFIED IDEOGRAPH + 0x86BC: 0x5596, //CJK UNIFIED IDEOGRAPH + 0x86BD: 0x5597, //CJK UNIFIED IDEOGRAPH + 0x86BE: 0x559A, //CJK UNIFIED IDEOGRAPH + 0x86BF: 0x559B, //CJK UNIFIED IDEOGRAPH + 0x86C0: 0x559E, //CJK UNIFIED IDEOGRAPH + 0x86C1: 0x55A0, //CJK UNIFIED IDEOGRAPH + 0x86C2: 0x55A1, //CJK UNIFIED IDEOGRAPH + 0x86C3: 0x55A2, //CJK UNIFIED IDEOGRAPH + 0x86C4: 0x55A3, //CJK UNIFIED IDEOGRAPH + 0x86C5: 0x55A4, //CJK UNIFIED IDEOGRAPH + 0x86C6: 0x55A5, //CJK UNIFIED IDEOGRAPH + 0x86C7: 0x55A6, //CJK UNIFIED IDEOGRAPH + 0x86C8: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0x86C9: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0x86CA: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0x86CB: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0x86CC: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0x86CD: 0x55AD, //CJK UNIFIED IDEOGRAPH + 0x86CE: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0x86CF: 0x55AF, //CJK UNIFIED IDEOGRAPH + 0x86D0: 0x55B0, //CJK UNIFIED IDEOGRAPH + 0x86D1: 0x55B2, //CJK UNIFIED IDEOGRAPH + 0x86D2: 0x55B4, //CJK UNIFIED IDEOGRAPH + 0x86D3: 0x55B6, //CJK UNIFIED IDEOGRAPH + 0x86D4: 0x55B8, //CJK UNIFIED IDEOGRAPH + 0x86D5: 0x55BA, //CJK UNIFIED IDEOGRAPH + 0x86D6: 0x55BC, //CJK UNIFIED IDEOGRAPH + 0x86D7: 0x55BF, //CJK UNIFIED IDEOGRAPH + 0x86D8: 0x55C0, //CJK UNIFIED IDEOGRAPH + 0x86D9: 0x55C1, //CJK UNIFIED IDEOGRAPH + 0x86DA: 0x55C2, //CJK UNIFIED IDEOGRAPH + 0x86DB: 0x55C3, //CJK UNIFIED IDEOGRAPH + 0x86DC: 0x55C6, //CJK UNIFIED IDEOGRAPH + 0x86DD: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0x86DE: 0x55C8, //CJK UNIFIED IDEOGRAPH + 0x86DF: 0x55CA, //CJK UNIFIED IDEOGRAPH + 0x86E0: 0x55CB, //CJK UNIFIED IDEOGRAPH + 0x86E1: 0x55CE, //CJK UNIFIED IDEOGRAPH + 0x86E2: 0x55CF, //CJK UNIFIED IDEOGRAPH + 0x86E3: 0x55D0, //CJK UNIFIED IDEOGRAPH + 0x86E4: 0x55D5, //CJK UNIFIED IDEOGRAPH + 0x86E5: 0x55D7, //CJK UNIFIED IDEOGRAPH + 0x86E6: 0x55D8, //CJK UNIFIED IDEOGRAPH + 0x86E7: 0x55D9, //CJK UNIFIED IDEOGRAPH + 0x86E8: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0x86E9: 0x55DB, //CJK UNIFIED IDEOGRAPH + 0x86EA: 0x55DE, //CJK UNIFIED IDEOGRAPH + 0x86EB: 0x55E0, //CJK UNIFIED IDEOGRAPH + 0x86EC: 0x55E2, //CJK UNIFIED IDEOGRAPH + 0x86ED: 0x55E7, //CJK UNIFIED IDEOGRAPH + 0x86EE: 0x55E9, //CJK UNIFIED IDEOGRAPH + 0x86EF: 0x55ED, //CJK UNIFIED IDEOGRAPH + 0x86F0: 0x55EE, //CJK UNIFIED IDEOGRAPH + 0x86F1: 0x55F0, //CJK UNIFIED IDEOGRAPH + 0x86F2: 0x55F1, //CJK UNIFIED IDEOGRAPH + 0x86F3: 0x55F4, //CJK UNIFIED IDEOGRAPH + 0x86F4: 0x55F6, //CJK UNIFIED IDEOGRAPH + 0x86F5: 0x55F8, //CJK UNIFIED IDEOGRAPH + 0x86F6: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0x86F7: 0x55FA, //CJK UNIFIED IDEOGRAPH + 0x86F8: 0x55FB, //CJK UNIFIED IDEOGRAPH + 0x86F9: 0x55FC, //CJK UNIFIED IDEOGRAPH + 0x86FA: 0x55FF, //CJK UNIFIED IDEOGRAPH + 0x86FB: 0x5602, //CJK UNIFIED IDEOGRAPH + 0x86FC: 0x5603, //CJK UNIFIED IDEOGRAPH + 0x86FD: 0x5604, //CJK UNIFIED IDEOGRAPH + 0x86FE: 0x5605, //CJK UNIFIED IDEOGRAPH + 0x8740: 0x5606, //CJK UNIFIED IDEOGRAPH + 0x8741: 0x5607, //CJK UNIFIED IDEOGRAPH + 0x8742: 0x560A, //CJK UNIFIED IDEOGRAPH + 0x8743: 0x560B, //CJK UNIFIED IDEOGRAPH + 0x8744: 0x560D, //CJK UNIFIED IDEOGRAPH + 0x8745: 0x5610, //CJK UNIFIED IDEOGRAPH + 0x8746: 0x5611, //CJK UNIFIED IDEOGRAPH + 0x8747: 0x5612, //CJK UNIFIED IDEOGRAPH + 0x8748: 0x5613, //CJK UNIFIED IDEOGRAPH + 0x8749: 0x5614, //CJK UNIFIED IDEOGRAPH + 0x874A: 0x5615, //CJK UNIFIED IDEOGRAPH + 0x874B: 0x5616, //CJK UNIFIED IDEOGRAPH + 0x874C: 0x5617, //CJK UNIFIED IDEOGRAPH + 0x874D: 0x5619, //CJK UNIFIED IDEOGRAPH + 0x874E: 0x561A, //CJK UNIFIED IDEOGRAPH + 0x874F: 0x561C, //CJK UNIFIED IDEOGRAPH + 0x8750: 0x561D, //CJK UNIFIED IDEOGRAPH + 0x8751: 0x5620, //CJK UNIFIED IDEOGRAPH + 0x8752: 0x5621, //CJK UNIFIED IDEOGRAPH + 0x8753: 0x5622, //CJK UNIFIED IDEOGRAPH + 0x8754: 0x5625, //CJK UNIFIED IDEOGRAPH + 0x8755: 0x5626, //CJK UNIFIED IDEOGRAPH + 0x8756: 0x5628, //CJK UNIFIED IDEOGRAPH + 0x8757: 0x5629, //CJK UNIFIED IDEOGRAPH + 0x8758: 0x562A, //CJK UNIFIED IDEOGRAPH + 0x8759: 0x562B, //CJK UNIFIED IDEOGRAPH + 0x875A: 0x562E, //CJK UNIFIED IDEOGRAPH + 0x875B: 0x562F, //CJK UNIFIED IDEOGRAPH + 0x875C: 0x5630, //CJK UNIFIED IDEOGRAPH + 0x875D: 0x5633, //CJK UNIFIED IDEOGRAPH + 0x875E: 0x5635, //CJK UNIFIED IDEOGRAPH + 0x875F: 0x5637, //CJK UNIFIED IDEOGRAPH + 0x8760: 0x5638, //CJK UNIFIED IDEOGRAPH + 0x8761: 0x563A, //CJK UNIFIED IDEOGRAPH + 0x8762: 0x563C, //CJK UNIFIED IDEOGRAPH + 0x8763: 0x563D, //CJK UNIFIED IDEOGRAPH + 0x8764: 0x563E, //CJK UNIFIED IDEOGRAPH + 0x8765: 0x5640, //CJK UNIFIED IDEOGRAPH + 0x8766: 0x5641, //CJK UNIFIED IDEOGRAPH + 0x8767: 0x5642, //CJK UNIFIED IDEOGRAPH + 0x8768: 0x5643, //CJK UNIFIED IDEOGRAPH + 0x8769: 0x5644, //CJK UNIFIED IDEOGRAPH + 0x876A: 0x5645, //CJK UNIFIED IDEOGRAPH + 0x876B: 0x5646, //CJK UNIFIED IDEOGRAPH + 0x876C: 0x5647, //CJK UNIFIED IDEOGRAPH + 0x876D: 0x5648, //CJK UNIFIED IDEOGRAPH + 0x876E: 0x5649, //CJK UNIFIED IDEOGRAPH + 0x876F: 0x564A, //CJK UNIFIED IDEOGRAPH + 0x8770: 0x564B, //CJK UNIFIED IDEOGRAPH + 0x8771: 0x564F, //CJK UNIFIED IDEOGRAPH + 0x8772: 0x5650, //CJK UNIFIED IDEOGRAPH + 0x8773: 0x5651, //CJK UNIFIED IDEOGRAPH + 0x8774: 0x5652, //CJK UNIFIED IDEOGRAPH + 0x8775: 0x5653, //CJK UNIFIED IDEOGRAPH + 0x8776: 0x5655, //CJK UNIFIED IDEOGRAPH + 0x8777: 0x5656, //CJK UNIFIED IDEOGRAPH + 0x8778: 0x565A, //CJK UNIFIED IDEOGRAPH + 0x8779: 0x565B, //CJK UNIFIED IDEOGRAPH + 0x877A: 0x565D, //CJK UNIFIED IDEOGRAPH + 0x877B: 0x565E, //CJK UNIFIED IDEOGRAPH + 0x877C: 0x565F, //CJK UNIFIED IDEOGRAPH + 0x877D: 0x5660, //CJK UNIFIED IDEOGRAPH + 0x877E: 0x5661, //CJK UNIFIED IDEOGRAPH + 0x8780: 0x5663, //CJK UNIFIED IDEOGRAPH + 0x8781: 0x5665, //CJK UNIFIED IDEOGRAPH + 0x8782: 0x5666, //CJK UNIFIED IDEOGRAPH + 0x8783: 0x5667, //CJK UNIFIED IDEOGRAPH + 0x8784: 0x566D, //CJK UNIFIED IDEOGRAPH + 0x8785: 0x566E, //CJK UNIFIED IDEOGRAPH + 0x8786: 0x566F, //CJK UNIFIED IDEOGRAPH + 0x8787: 0x5670, //CJK UNIFIED IDEOGRAPH + 0x8788: 0x5672, //CJK UNIFIED IDEOGRAPH + 0x8789: 0x5673, //CJK UNIFIED IDEOGRAPH + 0x878A: 0x5674, //CJK UNIFIED IDEOGRAPH + 0x878B: 0x5675, //CJK UNIFIED IDEOGRAPH + 0x878C: 0x5677, //CJK UNIFIED IDEOGRAPH + 0x878D: 0x5678, //CJK UNIFIED IDEOGRAPH + 0x878E: 0x5679, //CJK UNIFIED IDEOGRAPH + 0x878F: 0x567A, //CJK UNIFIED IDEOGRAPH + 0x8790: 0x567D, //CJK UNIFIED IDEOGRAPH + 0x8791: 0x567E, //CJK UNIFIED IDEOGRAPH + 0x8792: 0x567F, //CJK UNIFIED IDEOGRAPH + 0x8793: 0x5680, //CJK UNIFIED IDEOGRAPH + 0x8794: 0x5681, //CJK UNIFIED IDEOGRAPH + 0x8795: 0x5682, //CJK UNIFIED IDEOGRAPH + 0x8796: 0x5683, //CJK UNIFIED IDEOGRAPH + 0x8797: 0x5684, //CJK UNIFIED IDEOGRAPH + 0x8798: 0x5687, //CJK UNIFIED IDEOGRAPH + 0x8799: 0x5688, //CJK UNIFIED IDEOGRAPH + 0x879A: 0x5689, //CJK UNIFIED IDEOGRAPH + 0x879B: 0x568A, //CJK UNIFIED IDEOGRAPH + 0x879C: 0x568B, //CJK UNIFIED IDEOGRAPH + 0x879D: 0x568C, //CJK UNIFIED IDEOGRAPH + 0x879E: 0x568D, //CJK UNIFIED IDEOGRAPH + 0x879F: 0x5690, //CJK UNIFIED IDEOGRAPH + 0x87A0: 0x5691, //CJK UNIFIED IDEOGRAPH + 0x87A1: 0x5692, //CJK UNIFIED IDEOGRAPH + 0x87A2: 0x5694, //CJK UNIFIED IDEOGRAPH + 0x87A3: 0x5695, //CJK UNIFIED IDEOGRAPH + 0x87A4: 0x5696, //CJK UNIFIED IDEOGRAPH + 0x87A5: 0x5697, //CJK UNIFIED IDEOGRAPH + 0x87A6: 0x5698, //CJK UNIFIED IDEOGRAPH + 0x87A7: 0x5699, //CJK UNIFIED IDEOGRAPH + 0x87A8: 0x569A, //CJK UNIFIED IDEOGRAPH + 0x87A9: 0x569B, //CJK UNIFIED IDEOGRAPH + 0x87AA: 0x569C, //CJK UNIFIED IDEOGRAPH + 0x87AB: 0x569D, //CJK UNIFIED IDEOGRAPH + 0x87AC: 0x569E, //CJK UNIFIED IDEOGRAPH + 0x87AD: 0x569F, //CJK UNIFIED IDEOGRAPH + 0x87AE: 0x56A0, //CJK UNIFIED IDEOGRAPH + 0x87AF: 0x56A1, //CJK UNIFIED IDEOGRAPH + 0x87B0: 0x56A2, //CJK UNIFIED IDEOGRAPH + 0x87B1: 0x56A4, //CJK UNIFIED IDEOGRAPH + 0x87B2: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0x87B3: 0x56A6, //CJK UNIFIED IDEOGRAPH + 0x87B4: 0x56A7, //CJK UNIFIED IDEOGRAPH + 0x87B5: 0x56A8, //CJK UNIFIED IDEOGRAPH + 0x87B6: 0x56A9, //CJK UNIFIED IDEOGRAPH + 0x87B7: 0x56AA, //CJK UNIFIED IDEOGRAPH + 0x87B8: 0x56AB, //CJK UNIFIED IDEOGRAPH + 0x87B9: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0x87BA: 0x56AD, //CJK UNIFIED IDEOGRAPH + 0x87BB: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0x87BC: 0x56B0, //CJK UNIFIED IDEOGRAPH + 0x87BD: 0x56B1, //CJK UNIFIED IDEOGRAPH + 0x87BE: 0x56B2, //CJK UNIFIED IDEOGRAPH + 0x87BF: 0x56B3, //CJK UNIFIED IDEOGRAPH + 0x87C0: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0x87C1: 0x56B5, //CJK UNIFIED IDEOGRAPH + 0x87C2: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0x87C3: 0x56B8, //CJK UNIFIED IDEOGRAPH + 0x87C4: 0x56B9, //CJK UNIFIED IDEOGRAPH + 0x87C5: 0x56BA, //CJK UNIFIED IDEOGRAPH + 0x87C6: 0x56BB, //CJK UNIFIED IDEOGRAPH + 0x87C7: 0x56BD, //CJK UNIFIED IDEOGRAPH + 0x87C8: 0x56BE, //CJK UNIFIED IDEOGRAPH + 0x87C9: 0x56BF, //CJK UNIFIED IDEOGRAPH + 0x87CA: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0x87CB: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0x87CC: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0x87CD: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0x87CE: 0x56C4, //CJK UNIFIED IDEOGRAPH + 0x87CF: 0x56C5, //CJK UNIFIED IDEOGRAPH + 0x87D0: 0x56C6, //CJK UNIFIED IDEOGRAPH + 0x87D1: 0x56C7, //CJK UNIFIED IDEOGRAPH + 0x87D2: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0x87D3: 0x56C9, //CJK UNIFIED IDEOGRAPH + 0x87D4: 0x56CB, //CJK UNIFIED IDEOGRAPH + 0x87D5: 0x56CC, //CJK UNIFIED IDEOGRAPH + 0x87D6: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0x87D7: 0x56CE, //CJK UNIFIED IDEOGRAPH + 0x87D8: 0x56CF, //CJK UNIFIED IDEOGRAPH + 0x87D9: 0x56D0, //CJK UNIFIED IDEOGRAPH + 0x87DA: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0x87DB: 0x56D2, //CJK UNIFIED IDEOGRAPH + 0x87DC: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0x87DD: 0x56D5, //CJK UNIFIED IDEOGRAPH + 0x87DE: 0x56D6, //CJK UNIFIED IDEOGRAPH + 0x87DF: 0x56D8, //CJK UNIFIED IDEOGRAPH + 0x87E0: 0x56D9, //CJK UNIFIED IDEOGRAPH + 0x87E1: 0x56DC, //CJK UNIFIED IDEOGRAPH + 0x87E2: 0x56E3, //CJK UNIFIED IDEOGRAPH + 0x87E3: 0x56E5, //CJK UNIFIED IDEOGRAPH + 0x87E4: 0x56E6, //CJK UNIFIED IDEOGRAPH + 0x87E5: 0x56E7, //CJK UNIFIED IDEOGRAPH + 0x87E6: 0x56E8, //CJK UNIFIED IDEOGRAPH + 0x87E7: 0x56E9, //CJK UNIFIED IDEOGRAPH + 0x87E8: 0x56EA, //CJK UNIFIED IDEOGRAPH + 0x87E9: 0x56EC, //CJK UNIFIED IDEOGRAPH + 0x87EA: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0x87EB: 0x56EF, //CJK UNIFIED IDEOGRAPH + 0x87EC: 0x56F2, //CJK UNIFIED IDEOGRAPH + 0x87ED: 0x56F3, //CJK UNIFIED IDEOGRAPH + 0x87EE: 0x56F6, //CJK UNIFIED IDEOGRAPH + 0x87EF: 0x56F7, //CJK UNIFIED IDEOGRAPH + 0x87F0: 0x56F8, //CJK UNIFIED IDEOGRAPH + 0x87F1: 0x56FB, //CJK UNIFIED IDEOGRAPH + 0x87F2: 0x56FC, //CJK UNIFIED IDEOGRAPH + 0x87F3: 0x5700, //CJK UNIFIED IDEOGRAPH + 0x87F4: 0x5701, //CJK UNIFIED IDEOGRAPH + 0x87F5: 0x5702, //CJK UNIFIED IDEOGRAPH + 0x87F6: 0x5705, //CJK UNIFIED IDEOGRAPH + 0x87F7: 0x5707, //CJK UNIFIED IDEOGRAPH + 0x87F8: 0x570B, //CJK UNIFIED IDEOGRAPH + 0x87F9: 0x570C, //CJK UNIFIED IDEOGRAPH + 0x87FA: 0x570D, //CJK UNIFIED IDEOGRAPH + 0x87FB: 0x570E, //CJK UNIFIED IDEOGRAPH + 0x87FC: 0x570F, //CJK UNIFIED IDEOGRAPH + 0x87FD: 0x5710, //CJK UNIFIED IDEOGRAPH + 0x87FE: 0x5711, //CJK UNIFIED IDEOGRAPH + 0x8840: 0x5712, //CJK UNIFIED IDEOGRAPH + 0x8841: 0x5713, //CJK UNIFIED IDEOGRAPH + 0x8842: 0x5714, //CJK UNIFIED IDEOGRAPH + 0x8843: 0x5715, //CJK UNIFIED IDEOGRAPH + 0x8844: 0x5716, //CJK UNIFIED IDEOGRAPH + 0x8845: 0x5717, //CJK UNIFIED IDEOGRAPH + 0x8846: 0x5718, //CJK UNIFIED IDEOGRAPH + 0x8847: 0x5719, //CJK UNIFIED IDEOGRAPH + 0x8848: 0x571A, //CJK UNIFIED IDEOGRAPH + 0x8849: 0x571B, //CJK UNIFIED IDEOGRAPH + 0x884A: 0x571D, //CJK UNIFIED IDEOGRAPH + 0x884B: 0x571E, //CJK UNIFIED IDEOGRAPH + 0x884C: 0x5720, //CJK UNIFIED IDEOGRAPH + 0x884D: 0x5721, //CJK UNIFIED IDEOGRAPH + 0x884E: 0x5722, //CJK UNIFIED IDEOGRAPH + 0x884F: 0x5724, //CJK UNIFIED IDEOGRAPH + 0x8850: 0x5725, //CJK UNIFIED IDEOGRAPH + 0x8851: 0x5726, //CJK UNIFIED IDEOGRAPH + 0x8852: 0x5727, //CJK UNIFIED IDEOGRAPH + 0x8853: 0x572B, //CJK UNIFIED IDEOGRAPH + 0x8854: 0x5731, //CJK UNIFIED IDEOGRAPH + 0x8855: 0x5732, //CJK UNIFIED IDEOGRAPH + 0x8856: 0x5734, //CJK UNIFIED IDEOGRAPH + 0x8857: 0x5735, //CJK UNIFIED IDEOGRAPH + 0x8858: 0x5736, //CJK UNIFIED IDEOGRAPH + 0x8859: 0x5737, //CJK UNIFIED IDEOGRAPH + 0x885A: 0x5738, //CJK UNIFIED IDEOGRAPH + 0x885B: 0x573C, //CJK UNIFIED IDEOGRAPH + 0x885C: 0x573D, //CJK UNIFIED IDEOGRAPH + 0x885D: 0x573F, //CJK UNIFIED IDEOGRAPH + 0x885E: 0x5741, //CJK UNIFIED IDEOGRAPH + 0x885F: 0x5743, //CJK UNIFIED IDEOGRAPH + 0x8860: 0x5744, //CJK UNIFIED IDEOGRAPH + 0x8861: 0x5745, //CJK UNIFIED IDEOGRAPH + 0x8862: 0x5746, //CJK UNIFIED IDEOGRAPH + 0x8863: 0x5748, //CJK UNIFIED IDEOGRAPH + 0x8864: 0x5749, //CJK UNIFIED IDEOGRAPH + 0x8865: 0x574B, //CJK UNIFIED IDEOGRAPH + 0x8866: 0x5752, //CJK UNIFIED IDEOGRAPH + 0x8867: 0x5753, //CJK UNIFIED IDEOGRAPH + 0x8868: 0x5754, //CJK UNIFIED IDEOGRAPH + 0x8869: 0x5755, //CJK UNIFIED IDEOGRAPH + 0x886A: 0x5756, //CJK UNIFIED IDEOGRAPH + 0x886B: 0x5758, //CJK UNIFIED IDEOGRAPH + 0x886C: 0x5759, //CJK UNIFIED IDEOGRAPH + 0x886D: 0x5762, //CJK UNIFIED IDEOGRAPH + 0x886E: 0x5763, //CJK UNIFIED IDEOGRAPH + 0x886F: 0x5765, //CJK UNIFIED IDEOGRAPH + 0x8870: 0x5767, //CJK UNIFIED IDEOGRAPH + 0x8871: 0x576C, //CJK UNIFIED IDEOGRAPH + 0x8872: 0x576E, //CJK UNIFIED IDEOGRAPH + 0x8873: 0x5770, //CJK UNIFIED IDEOGRAPH + 0x8874: 0x5771, //CJK UNIFIED IDEOGRAPH + 0x8875: 0x5772, //CJK UNIFIED IDEOGRAPH + 0x8876: 0x5774, //CJK UNIFIED IDEOGRAPH + 0x8877: 0x5775, //CJK UNIFIED IDEOGRAPH + 0x8878: 0x5778, //CJK UNIFIED IDEOGRAPH + 0x8879: 0x5779, //CJK UNIFIED IDEOGRAPH + 0x887A: 0x577A, //CJK UNIFIED IDEOGRAPH + 0x887B: 0x577D, //CJK UNIFIED IDEOGRAPH + 0x887C: 0x577E, //CJK UNIFIED IDEOGRAPH + 0x887D: 0x577F, //CJK UNIFIED IDEOGRAPH + 0x887E: 0x5780, //CJK UNIFIED IDEOGRAPH + 0x8880: 0x5781, //CJK UNIFIED IDEOGRAPH + 0x8881: 0x5787, //CJK UNIFIED IDEOGRAPH + 0x8882: 0x5788, //CJK UNIFIED IDEOGRAPH + 0x8883: 0x5789, //CJK UNIFIED IDEOGRAPH + 0x8884: 0x578A, //CJK UNIFIED IDEOGRAPH + 0x8885: 0x578D, //CJK UNIFIED IDEOGRAPH + 0x8886: 0x578E, //CJK UNIFIED IDEOGRAPH + 0x8887: 0x578F, //CJK UNIFIED IDEOGRAPH + 0x8888: 0x5790, //CJK UNIFIED IDEOGRAPH + 0x8889: 0x5791, //CJK UNIFIED IDEOGRAPH + 0x888A: 0x5794, //CJK UNIFIED IDEOGRAPH + 0x888B: 0x5795, //CJK UNIFIED IDEOGRAPH + 0x888C: 0x5796, //CJK UNIFIED IDEOGRAPH + 0x888D: 0x5797, //CJK UNIFIED IDEOGRAPH + 0x888E: 0x5798, //CJK UNIFIED IDEOGRAPH + 0x888F: 0x5799, //CJK UNIFIED IDEOGRAPH + 0x8890: 0x579A, //CJK UNIFIED IDEOGRAPH + 0x8891: 0x579C, //CJK UNIFIED IDEOGRAPH + 0x8892: 0x579D, //CJK UNIFIED IDEOGRAPH + 0x8893: 0x579E, //CJK UNIFIED IDEOGRAPH + 0x8894: 0x579F, //CJK UNIFIED IDEOGRAPH + 0x8895: 0x57A5, //CJK UNIFIED IDEOGRAPH + 0x8896: 0x57A8, //CJK UNIFIED IDEOGRAPH + 0x8897: 0x57AA, //CJK UNIFIED IDEOGRAPH + 0x8898: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0x8899: 0x57AF, //CJK UNIFIED IDEOGRAPH + 0x889A: 0x57B0, //CJK UNIFIED IDEOGRAPH + 0x889B: 0x57B1, //CJK UNIFIED IDEOGRAPH + 0x889C: 0x57B3, //CJK UNIFIED IDEOGRAPH + 0x889D: 0x57B5, //CJK UNIFIED IDEOGRAPH + 0x889E: 0x57B6, //CJK UNIFIED IDEOGRAPH + 0x889F: 0x57B7, //CJK UNIFIED IDEOGRAPH + 0x88A0: 0x57B9, //CJK UNIFIED IDEOGRAPH + 0x88A1: 0x57BA, //CJK UNIFIED IDEOGRAPH + 0x88A2: 0x57BB, //CJK UNIFIED IDEOGRAPH + 0x88A3: 0x57BC, //CJK UNIFIED IDEOGRAPH + 0x88A4: 0x57BD, //CJK UNIFIED IDEOGRAPH + 0x88A5: 0x57BE, //CJK UNIFIED IDEOGRAPH + 0x88A6: 0x57BF, //CJK UNIFIED IDEOGRAPH + 0x88A7: 0x57C0, //CJK UNIFIED IDEOGRAPH + 0x88A8: 0x57C1, //CJK UNIFIED IDEOGRAPH + 0x88A9: 0x57C4, //CJK UNIFIED IDEOGRAPH + 0x88AA: 0x57C5, //CJK UNIFIED IDEOGRAPH + 0x88AB: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0x88AC: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0x88AD: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0x88AE: 0x57C9, //CJK UNIFIED IDEOGRAPH + 0x88AF: 0x57CA, //CJK UNIFIED IDEOGRAPH + 0x88B0: 0x57CC, //CJK UNIFIED IDEOGRAPH + 0x88B1: 0x57CD, //CJK UNIFIED IDEOGRAPH + 0x88B2: 0x57D0, //CJK UNIFIED IDEOGRAPH + 0x88B3: 0x57D1, //CJK UNIFIED IDEOGRAPH + 0x88B4: 0x57D3, //CJK UNIFIED IDEOGRAPH + 0x88B5: 0x57D6, //CJK UNIFIED IDEOGRAPH + 0x88B6: 0x57D7, //CJK UNIFIED IDEOGRAPH + 0x88B7: 0x57DB, //CJK UNIFIED IDEOGRAPH + 0x88B8: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0x88B9: 0x57DE, //CJK UNIFIED IDEOGRAPH + 0x88BA: 0x57E1, //CJK UNIFIED IDEOGRAPH + 0x88BB: 0x57E2, //CJK UNIFIED IDEOGRAPH + 0x88BC: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0x88BD: 0x57E5, //CJK UNIFIED IDEOGRAPH + 0x88BE: 0x57E6, //CJK UNIFIED IDEOGRAPH + 0x88BF: 0x57E7, //CJK UNIFIED IDEOGRAPH + 0x88C0: 0x57E8, //CJK UNIFIED IDEOGRAPH + 0x88C1: 0x57E9, //CJK UNIFIED IDEOGRAPH + 0x88C2: 0x57EA, //CJK UNIFIED IDEOGRAPH + 0x88C3: 0x57EB, //CJK UNIFIED IDEOGRAPH + 0x88C4: 0x57EC, //CJK UNIFIED IDEOGRAPH + 0x88C5: 0x57EE, //CJK UNIFIED IDEOGRAPH + 0x88C6: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0x88C7: 0x57F1, //CJK UNIFIED IDEOGRAPH + 0x88C8: 0x57F2, //CJK UNIFIED IDEOGRAPH + 0x88C9: 0x57F3, //CJK UNIFIED IDEOGRAPH + 0x88CA: 0x57F5, //CJK UNIFIED IDEOGRAPH + 0x88CB: 0x57F6, //CJK UNIFIED IDEOGRAPH + 0x88CC: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0x88CD: 0x57FB, //CJK UNIFIED IDEOGRAPH + 0x88CE: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0x88CF: 0x57FE, //CJK UNIFIED IDEOGRAPH + 0x88D0: 0x57FF, //CJK UNIFIED IDEOGRAPH + 0x88D1: 0x5801, //CJK UNIFIED IDEOGRAPH + 0x88D2: 0x5803, //CJK UNIFIED IDEOGRAPH + 0x88D3: 0x5804, //CJK UNIFIED IDEOGRAPH + 0x88D4: 0x5805, //CJK UNIFIED IDEOGRAPH + 0x88D5: 0x5808, //CJK UNIFIED IDEOGRAPH + 0x88D6: 0x5809, //CJK UNIFIED IDEOGRAPH + 0x88D7: 0x580A, //CJK UNIFIED IDEOGRAPH + 0x88D8: 0x580C, //CJK UNIFIED IDEOGRAPH + 0x88D9: 0x580E, //CJK UNIFIED IDEOGRAPH + 0x88DA: 0x580F, //CJK UNIFIED IDEOGRAPH + 0x88DB: 0x5810, //CJK UNIFIED IDEOGRAPH + 0x88DC: 0x5812, //CJK UNIFIED IDEOGRAPH + 0x88DD: 0x5813, //CJK UNIFIED IDEOGRAPH + 0x88DE: 0x5814, //CJK UNIFIED IDEOGRAPH + 0x88DF: 0x5816, //CJK UNIFIED IDEOGRAPH + 0x88E0: 0x5817, //CJK UNIFIED IDEOGRAPH + 0x88E1: 0x5818, //CJK UNIFIED IDEOGRAPH + 0x88E2: 0x581A, //CJK UNIFIED IDEOGRAPH + 0x88E3: 0x581B, //CJK UNIFIED IDEOGRAPH + 0x88E4: 0x581C, //CJK UNIFIED IDEOGRAPH + 0x88E5: 0x581D, //CJK UNIFIED IDEOGRAPH + 0x88E6: 0x581F, //CJK UNIFIED IDEOGRAPH + 0x88E7: 0x5822, //CJK UNIFIED IDEOGRAPH + 0x88E8: 0x5823, //CJK UNIFIED IDEOGRAPH + 0x88E9: 0x5825, //CJK UNIFIED IDEOGRAPH + 0x88EA: 0x5826, //CJK UNIFIED IDEOGRAPH + 0x88EB: 0x5827, //CJK UNIFIED IDEOGRAPH + 0x88EC: 0x5828, //CJK UNIFIED IDEOGRAPH + 0x88ED: 0x5829, //CJK UNIFIED IDEOGRAPH + 0x88EE: 0x582B, //CJK UNIFIED IDEOGRAPH + 0x88EF: 0x582C, //CJK UNIFIED IDEOGRAPH + 0x88F0: 0x582D, //CJK UNIFIED IDEOGRAPH + 0x88F1: 0x582E, //CJK UNIFIED IDEOGRAPH + 0x88F2: 0x582F, //CJK UNIFIED IDEOGRAPH + 0x88F3: 0x5831, //CJK UNIFIED IDEOGRAPH + 0x88F4: 0x5832, //CJK UNIFIED IDEOGRAPH + 0x88F5: 0x5833, //CJK UNIFIED IDEOGRAPH + 0x88F6: 0x5834, //CJK UNIFIED IDEOGRAPH + 0x88F7: 0x5836, //CJK UNIFIED IDEOGRAPH + 0x88F8: 0x5837, //CJK UNIFIED IDEOGRAPH + 0x88F9: 0x5838, //CJK UNIFIED IDEOGRAPH + 0x88FA: 0x5839, //CJK UNIFIED IDEOGRAPH + 0x88FB: 0x583A, //CJK UNIFIED IDEOGRAPH + 0x88FC: 0x583B, //CJK UNIFIED IDEOGRAPH + 0x88FD: 0x583C, //CJK UNIFIED IDEOGRAPH + 0x88FE: 0x583D, //CJK UNIFIED IDEOGRAPH + 0x8940: 0x583E, //CJK UNIFIED IDEOGRAPH + 0x8941: 0x583F, //CJK UNIFIED IDEOGRAPH + 0x8942: 0x5840, //CJK UNIFIED IDEOGRAPH + 0x8943: 0x5841, //CJK UNIFIED IDEOGRAPH + 0x8944: 0x5842, //CJK UNIFIED IDEOGRAPH + 0x8945: 0x5843, //CJK UNIFIED IDEOGRAPH + 0x8946: 0x5845, //CJK UNIFIED IDEOGRAPH + 0x8947: 0x5846, //CJK UNIFIED IDEOGRAPH + 0x8948: 0x5847, //CJK UNIFIED IDEOGRAPH + 0x8949: 0x5848, //CJK UNIFIED IDEOGRAPH + 0x894A: 0x5849, //CJK UNIFIED IDEOGRAPH + 0x894B: 0x584A, //CJK UNIFIED IDEOGRAPH + 0x894C: 0x584B, //CJK UNIFIED IDEOGRAPH + 0x894D: 0x584E, //CJK UNIFIED IDEOGRAPH + 0x894E: 0x584F, //CJK UNIFIED IDEOGRAPH + 0x894F: 0x5850, //CJK UNIFIED IDEOGRAPH + 0x8950: 0x5852, //CJK UNIFIED IDEOGRAPH + 0x8951: 0x5853, //CJK UNIFIED IDEOGRAPH + 0x8952: 0x5855, //CJK UNIFIED IDEOGRAPH + 0x8953: 0x5856, //CJK UNIFIED IDEOGRAPH + 0x8954: 0x5857, //CJK UNIFIED IDEOGRAPH + 0x8955: 0x5859, //CJK UNIFIED IDEOGRAPH + 0x8956: 0x585A, //CJK UNIFIED IDEOGRAPH + 0x8957: 0x585B, //CJK UNIFIED IDEOGRAPH + 0x8958: 0x585C, //CJK UNIFIED IDEOGRAPH + 0x8959: 0x585D, //CJK UNIFIED IDEOGRAPH + 0x895A: 0x585F, //CJK UNIFIED IDEOGRAPH + 0x895B: 0x5860, //CJK UNIFIED IDEOGRAPH + 0x895C: 0x5861, //CJK UNIFIED IDEOGRAPH + 0x895D: 0x5862, //CJK UNIFIED IDEOGRAPH + 0x895E: 0x5863, //CJK UNIFIED IDEOGRAPH + 0x895F: 0x5864, //CJK UNIFIED IDEOGRAPH + 0x8960: 0x5866, //CJK UNIFIED IDEOGRAPH + 0x8961: 0x5867, //CJK UNIFIED IDEOGRAPH + 0x8962: 0x5868, //CJK UNIFIED IDEOGRAPH + 0x8963: 0x5869, //CJK UNIFIED IDEOGRAPH + 0x8964: 0x586A, //CJK UNIFIED IDEOGRAPH + 0x8965: 0x586D, //CJK UNIFIED IDEOGRAPH + 0x8966: 0x586E, //CJK UNIFIED IDEOGRAPH + 0x8967: 0x586F, //CJK UNIFIED IDEOGRAPH + 0x8968: 0x5870, //CJK UNIFIED IDEOGRAPH + 0x8969: 0x5871, //CJK UNIFIED IDEOGRAPH + 0x896A: 0x5872, //CJK UNIFIED IDEOGRAPH + 0x896B: 0x5873, //CJK UNIFIED IDEOGRAPH + 0x896C: 0x5874, //CJK UNIFIED IDEOGRAPH + 0x896D: 0x5875, //CJK UNIFIED IDEOGRAPH + 0x896E: 0x5876, //CJK UNIFIED IDEOGRAPH + 0x896F: 0x5877, //CJK UNIFIED IDEOGRAPH + 0x8970: 0x5878, //CJK UNIFIED IDEOGRAPH + 0x8971: 0x5879, //CJK UNIFIED IDEOGRAPH + 0x8972: 0x587A, //CJK UNIFIED IDEOGRAPH + 0x8973: 0x587B, //CJK UNIFIED IDEOGRAPH + 0x8974: 0x587C, //CJK UNIFIED IDEOGRAPH + 0x8975: 0x587D, //CJK UNIFIED IDEOGRAPH + 0x8976: 0x587F, //CJK UNIFIED IDEOGRAPH + 0x8977: 0x5882, //CJK UNIFIED IDEOGRAPH + 0x8978: 0x5884, //CJK UNIFIED IDEOGRAPH + 0x8979: 0x5886, //CJK UNIFIED IDEOGRAPH + 0x897A: 0x5887, //CJK UNIFIED IDEOGRAPH + 0x897B: 0x5888, //CJK UNIFIED IDEOGRAPH + 0x897C: 0x588A, //CJK UNIFIED IDEOGRAPH + 0x897D: 0x588B, //CJK UNIFIED IDEOGRAPH + 0x897E: 0x588C, //CJK UNIFIED IDEOGRAPH + 0x8980: 0x588D, //CJK UNIFIED IDEOGRAPH + 0x8981: 0x588E, //CJK UNIFIED IDEOGRAPH + 0x8982: 0x588F, //CJK UNIFIED IDEOGRAPH + 0x8983: 0x5890, //CJK UNIFIED IDEOGRAPH + 0x8984: 0x5891, //CJK UNIFIED IDEOGRAPH + 0x8985: 0x5894, //CJK UNIFIED IDEOGRAPH + 0x8986: 0x5895, //CJK UNIFIED IDEOGRAPH + 0x8987: 0x5896, //CJK UNIFIED IDEOGRAPH + 0x8988: 0x5897, //CJK UNIFIED IDEOGRAPH + 0x8989: 0x5898, //CJK UNIFIED IDEOGRAPH + 0x898A: 0x589B, //CJK UNIFIED IDEOGRAPH + 0x898B: 0x589C, //CJK UNIFIED IDEOGRAPH + 0x898C: 0x589D, //CJK UNIFIED IDEOGRAPH + 0x898D: 0x58A0, //CJK UNIFIED IDEOGRAPH + 0x898E: 0x58A1, //CJK UNIFIED IDEOGRAPH + 0x898F: 0x58A2, //CJK UNIFIED IDEOGRAPH + 0x8990: 0x58A3, //CJK UNIFIED IDEOGRAPH + 0x8991: 0x58A4, //CJK UNIFIED IDEOGRAPH + 0x8992: 0x58A5, //CJK UNIFIED IDEOGRAPH + 0x8993: 0x58A6, //CJK UNIFIED IDEOGRAPH + 0x8994: 0x58A7, //CJK UNIFIED IDEOGRAPH + 0x8995: 0x58AA, //CJK UNIFIED IDEOGRAPH + 0x8996: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0x8997: 0x58AC, //CJK UNIFIED IDEOGRAPH + 0x8998: 0x58AD, //CJK UNIFIED IDEOGRAPH + 0x8999: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0x899A: 0x58AF, //CJK UNIFIED IDEOGRAPH + 0x899B: 0x58B0, //CJK UNIFIED IDEOGRAPH + 0x899C: 0x58B1, //CJK UNIFIED IDEOGRAPH + 0x899D: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0x899E: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0x899F: 0x58B4, //CJK UNIFIED IDEOGRAPH + 0x89A0: 0x58B5, //CJK UNIFIED IDEOGRAPH + 0x89A1: 0x58B6, //CJK UNIFIED IDEOGRAPH + 0x89A2: 0x58B7, //CJK UNIFIED IDEOGRAPH + 0x89A3: 0x58B8, //CJK UNIFIED IDEOGRAPH + 0x89A4: 0x58B9, //CJK UNIFIED IDEOGRAPH + 0x89A5: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0x89A6: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0x89A7: 0x58BD, //CJK UNIFIED IDEOGRAPH + 0x89A8: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0x89A9: 0x58BF, //CJK UNIFIED IDEOGRAPH + 0x89AA: 0x58C0, //CJK UNIFIED IDEOGRAPH + 0x89AB: 0x58C2, //CJK UNIFIED IDEOGRAPH + 0x89AC: 0x58C3, //CJK UNIFIED IDEOGRAPH + 0x89AD: 0x58C4, //CJK UNIFIED IDEOGRAPH + 0x89AE: 0x58C6, //CJK UNIFIED IDEOGRAPH + 0x89AF: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0x89B0: 0x58C8, //CJK UNIFIED IDEOGRAPH + 0x89B1: 0x58C9, //CJK UNIFIED IDEOGRAPH + 0x89B2: 0x58CA, //CJK UNIFIED IDEOGRAPH + 0x89B3: 0x58CB, //CJK UNIFIED IDEOGRAPH + 0x89B4: 0x58CC, //CJK UNIFIED IDEOGRAPH + 0x89B5: 0x58CD, //CJK UNIFIED IDEOGRAPH + 0x89B6: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0x89B7: 0x58CF, //CJK UNIFIED IDEOGRAPH + 0x89B8: 0x58D0, //CJK UNIFIED IDEOGRAPH + 0x89B9: 0x58D2, //CJK UNIFIED IDEOGRAPH + 0x89BA: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0x89BB: 0x58D4, //CJK UNIFIED IDEOGRAPH + 0x89BC: 0x58D6, //CJK UNIFIED IDEOGRAPH + 0x89BD: 0x58D7, //CJK UNIFIED IDEOGRAPH + 0x89BE: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0x89BF: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0x89C0: 0x58DA, //CJK UNIFIED IDEOGRAPH + 0x89C1: 0x58DB, //CJK UNIFIED IDEOGRAPH + 0x89C2: 0x58DC, //CJK UNIFIED IDEOGRAPH + 0x89C3: 0x58DD, //CJK UNIFIED IDEOGRAPH + 0x89C4: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0x89C5: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0x89C6: 0x58E0, //CJK UNIFIED IDEOGRAPH + 0x89C7: 0x58E1, //CJK UNIFIED IDEOGRAPH + 0x89C8: 0x58E2, //CJK UNIFIED IDEOGRAPH + 0x89C9: 0x58E3, //CJK UNIFIED IDEOGRAPH + 0x89CA: 0x58E5, //CJK UNIFIED IDEOGRAPH + 0x89CB: 0x58E6, //CJK UNIFIED IDEOGRAPH + 0x89CC: 0x58E7, //CJK UNIFIED IDEOGRAPH + 0x89CD: 0x58E8, //CJK UNIFIED IDEOGRAPH + 0x89CE: 0x58E9, //CJK UNIFIED IDEOGRAPH + 0x89CF: 0x58EA, //CJK UNIFIED IDEOGRAPH + 0x89D0: 0x58ED, //CJK UNIFIED IDEOGRAPH + 0x89D1: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0x89D2: 0x58F1, //CJK UNIFIED IDEOGRAPH + 0x89D3: 0x58F2, //CJK UNIFIED IDEOGRAPH + 0x89D4: 0x58F4, //CJK UNIFIED IDEOGRAPH + 0x89D5: 0x58F5, //CJK UNIFIED IDEOGRAPH + 0x89D6: 0x58F7, //CJK UNIFIED IDEOGRAPH + 0x89D7: 0x58F8, //CJK UNIFIED IDEOGRAPH + 0x89D8: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0x89D9: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0x89DA: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0x89DB: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0x89DC: 0x58FE, //CJK UNIFIED IDEOGRAPH + 0x89DD: 0x58FF, //CJK UNIFIED IDEOGRAPH + 0x89DE: 0x5900, //CJK UNIFIED IDEOGRAPH + 0x89DF: 0x5901, //CJK UNIFIED IDEOGRAPH + 0x89E0: 0x5903, //CJK UNIFIED IDEOGRAPH + 0x89E1: 0x5905, //CJK UNIFIED IDEOGRAPH + 0x89E2: 0x5906, //CJK UNIFIED IDEOGRAPH + 0x89E3: 0x5908, //CJK UNIFIED IDEOGRAPH + 0x89E4: 0x5909, //CJK UNIFIED IDEOGRAPH + 0x89E5: 0x590A, //CJK UNIFIED IDEOGRAPH + 0x89E6: 0x590B, //CJK UNIFIED IDEOGRAPH + 0x89E7: 0x590C, //CJK UNIFIED IDEOGRAPH + 0x89E8: 0x590E, //CJK UNIFIED IDEOGRAPH + 0x89E9: 0x5910, //CJK UNIFIED IDEOGRAPH + 0x89EA: 0x5911, //CJK UNIFIED IDEOGRAPH + 0x89EB: 0x5912, //CJK UNIFIED IDEOGRAPH + 0x89EC: 0x5913, //CJK UNIFIED IDEOGRAPH + 0x89ED: 0x5917, //CJK UNIFIED IDEOGRAPH + 0x89EE: 0x5918, //CJK UNIFIED IDEOGRAPH + 0x89EF: 0x591B, //CJK UNIFIED IDEOGRAPH + 0x89F0: 0x591D, //CJK UNIFIED IDEOGRAPH + 0x89F1: 0x591E, //CJK UNIFIED IDEOGRAPH + 0x89F2: 0x5920, //CJK UNIFIED IDEOGRAPH + 0x89F3: 0x5921, //CJK UNIFIED IDEOGRAPH + 0x89F4: 0x5922, //CJK UNIFIED IDEOGRAPH + 0x89F5: 0x5923, //CJK UNIFIED IDEOGRAPH + 0x89F6: 0x5926, //CJK UNIFIED IDEOGRAPH + 0x89F7: 0x5928, //CJK UNIFIED IDEOGRAPH + 0x89F8: 0x592C, //CJK UNIFIED IDEOGRAPH + 0x89F9: 0x5930, //CJK UNIFIED IDEOGRAPH + 0x89FA: 0x5932, //CJK UNIFIED IDEOGRAPH + 0x89FB: 0x5933, //CJK UNIFIED IDEOGRAPH + 0x89FC: 0x5935, //CJK UNIFIED IDEOGRAPH + 0x89FD: 0x5936, //CJK UNIFIED IDEOGRAPH + 0x89FE: 0x593B, //CJK UNIFIED IDEOGRAPH + 0x8A40: 0x593D, //CJK UNIFIED IDEOGRAPH + 0x8A41: 0x593E, //CJK UNIFIED IDEOGRAPH + 0x8A42: 0x593F, //CJK UNIFIED IDEOGRAPH + 0x8A43: 0x5940, //CJK UNIFIED IDEOGRAPH + 0x8A44: 0x5943, //CJK UNIFIED IDEOGRAPH + 0x8A45: 0x5945, //CJK UNIFIED IDEOGRAPH + 0x8A46: 0x5946, //CJK UNIFIED IDEOGRAPH + 0x8A47: 0x594A, //CJK UNIFIED IDEOGRAPH + 0x8A48: 0x594C, //CJK UNIFIED IDEOGRAPH + 0x8A49: 0x594D, //CJK UNIFIED IDEOGRAPH + 0x8A4A: 0x5950, //CJK UNIFIED IDEOGRAPH + 0x8A4B: 0x5952, //CJK UNIFIED IDEOGRAPH + 0x8A4C: 0x5953, //CJK UNIFIED IDEOGRAPH + 0x8A4D: 0x5959, //CJK UNIFIED IDEOGRAPH + 0x8A4E: 0x595B, //CJK UNIFIED IDEOGRAPH + 0x8A4F: 0x595C, //CJK UNIFIED IDEOGRAPH + 0x8A50: 0x595D, //CJK UNIFIED IDEOGRAPH + 0x8A51: 0x595E, //CJK UNIFIED IDEOGRAPH + 0x8A52: 0x595F, //CJK UNIFIED IDEOGRAPH + 0x8A53: 0x5961, //CJK UNIFIED IDEOGRAPH + 0x8A54: 0x5963, //CJK UNIFIED IDEOGRAPH + 0x8A55: 0x5964, //CJK UNIFIED IDEOGRAPH + 0x8A56: 0x5966, //CJK UNIFIED IDEOGRAPH + 0x8A57: 0x5967, //CJK UNIFIED IDEOGRAPH + 0x8A58: 0x5968, //CJK UNIFIED IDEOGRAPH + 0x8A59: 0x5969, //CJK UNIFIED IDEOGRAPH + 0x8A5A: 0x596A, //CJK UNIFIED IDEOGRAPH + 0x8A5B: 0x596B, //CJK UNIFIED IDEOGRAPH + 0x8A5C: 0x596C, //CJK UNIFIED IDEOGRAPH + 0x8A5D: 0x596D, //CJK UNIFIED IDEOGRAPH + 0x8A5E: 0x596E, //CJK UNIFIED IDEOGRAPH + 0x8A5F: 0x596F, //CJK UNIFIED IDEOGRAPH + 0x8A60: 0x5970, //CJK UNIFIED IDEOGRAPH + 0x8A61: 0x5971, //CJK UNIFIED IDEOGRAPH + 0x8A62: 0x5972, //CJK UNIFIED IDEOGRAPH + 0x8A63: 0x5975, //CJK UNIFIED IDEOGRAPH + 0x8A64: 0x5977, //CJK UNIFIED IDEOGRAPH + 0x8A65: 0x597A, //CJK UNIFIED IDEOGRAPH + 0x8A66: 0x597B, //CJK UNIFIED IDEOGRAPH + 0x8A67: 0x597C, //CJK UNIFIED IDEOGRAPH + 0x8A68: 0x597E, //CJK UNIFIED IDEOGRAPH + 0x8A69: 0x597F, //CJK UNIFIED IDEOGRAPH + 0x8A6A: 0x5980, //CJK UNIFIED IDEOGRAPH + 0x8A6B: 0x5985, //CJK UNIFIED IDEOGRAPH + 0x8A6C: 0x5989, //CJK UNIFIED IDEOGRAPH + 0x8A6D: 0x598B, //CJK UNIFIED IDEOGRAPH + 0x8A6E: 0x598C, //CJK UNIFIED IDEOGRAPH + 0x8A6F: 0x598E, //CJK UNIFIED IDEOGRAPH + 0x8A70: 0x598F, //CJK UNIFIED IDEOGRAPH + 0x8A71: 0x5990, //CJK UNIFIED IDEOGRAPH + 0x8A72: 0x5991, //CJK UNIFIED IDEOGRAPH + 0x8A73: 0x5994, //CJK UNIFIED IDEOGRAPH + 0x8A74: 0x5995, //CJK UNIFIED IDEOGRAPH + 0x8A75: 0x5998, //CJK UNIFIED IDEOGRAPH + 0x8A76: 0x599A, //CJK UNIFIED IDEOGRAPH + 0x8A77: 0x599B, //CJK UNIFIED IDEOGRAPH + 0x8A78: 0x599C, //CJK UNIFIED IDEOGRAPH + 0x8A79: 0x599D, //CJK UNIFIED IDEOGRAPH + 0x8A7A: 0x599F, //CJK UNIFIED IDEOGRAPH + 0x8A7B: 0x59A0, //CJK UNIFIED IDEOGRAPH + 0x8A7C: 0x59A1, //CJK UNIFIED IDEOGRAPH + 0x8A7D: 0x59A2, //CJK UNIFIED IDEOGRAPH + 0x8A7E: 0x59A6, //CJK UNIFIED IDEOGRAPH + 0x8A80: 0x59A7, //CJK UNIFIED IDEOGRAPH + 0x8A81: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0x8A82: 0x59AD, //CJK UNIFIED IDEOGRAPH + 0x8A83: 0x59B0, //CJK UNIFIED IDEOGRAPH + 0x8A84: 0x59B1, //CJK UNIFIED IDEOGRAPH + 0x8A85: 0x59B3, //CJK UNIFIED IDEOGRAPH + 0x8A86: 0x59B4, //CJK UNIFIED IDEOGRAPH + 0x8A87: 0x59B5, //CJK UNIFIED IDEOGRAPH + 0x8A88: 0x59B6, //CJK UNIFIED IDEOGRAPH + 0x8A89: 0x59B7, //CJK UNIFIED IDEOGRAPH + 0x8A8A: 0x59B8, //CJK UNIFIED IDEOGRAPH + 0x8A8B: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0x8A8C: 0x59BC, //CJK UNIFIED IDEOGRAPH + 0x8A8D: 0x59BD, //CJK UNIFIED IDEOGRAPH + 0x8A8E: 0x59BF, //CJK UNIFIED IDEOGRAPH + 0x8A8F: 0x59C0, //CJK UNIFIED IDEOGRAPH + 0x8A90: 0x59C1, //CJK UNIFIED IDEOGRAPH + 0x8A91: 0x59C2, //CJK UNIFIED IDEOGRAPH + 0x8A92: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0x8A93: 0x59C4, //CJK UNIFIED IDEOGRAPH + 0x8A94: 0x59C5, //CJK UNIFIED IDEOGRAPH + 0x8A95: 0x59C7, //CJK UNIFIED IDEOGRAPH + 0x8A96: 0x59C8, //CJK UNIFIED IDEOGRAPH + 0x8A97: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0x8A98: 0x59CC, //CJK UNIFIED IDEOGRAPH + 0x8A99: 0x59CD, //CJK UNIFIED IDEOGRAPH + 0x8A9A: 0x59CE, //CJK UNIFIED IDEOGRAPH + 0x8A9B: 0x59CF, //CJK UNIFIED IDEOGRAPH + 0x8A9C: 0x59D5, //CJK UNIFIED IDEOGRAPH + 0x8A9D: 0x59D6, //CJK UNIFIED IDEOGRAPH + 0x8A9E: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0x8A9F: 0x59DB, //CJK UNIFIED IDEOGRAPH + 0x8AA0: 0x59DE, //CJK UNIFIED IDEOGRAPH + 0x8AA1: 0x59DF, //CJK UNIFIED IDEOGRAPH + 0x8AA2: 0x59E0, //CJK UNIFIED IDEOGRAPH + 0x8AA3: 0x59E1, //CJK UNIFIED IDEOGRAPH + 0x8AA4: 0x59E2, //CJK UNIFIED IDEOGRAPH + 0x8AA5: 0x59E4, //CJK UNIFIED IDEOGRAPH + 0x8AA6: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0x8AA7: 0x59E7, //CJK UNIFIED IDEOGRAPH + 0x8AA8: 0x59E9, //CJK UNIFIED IDEOGRAPH + 0x8AA9: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0x8AAA: 0x59EB, //CJK UNIFIED IDEOGRAPH + 0x8AAB: 0x59ED, //CJK UNIFIED IDEOGRAPH + 0x8AAC: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0x8AAD: 0x59EF, //CJK UNIFIED IDEOGRAPH + 0x8AAE: 0x59F0, //CJK UNIFIED IDEOGRAPH + 0x8AAF: 0x59F1, //CJK UNIFIED IDEOGRAPH + 0x8AB0: 0x59F2, //CJK UNIFIED IDEOGRAPH + 0x8AB1: 0x59F3, //CJK UNIFIED IDEOGRAPH + 0x8AB2: 0x59F4, //CJK UNIFIED IDEOGRAPH + 0x8AB3: 0x59F5, //CJK UNIFIED IDEOGRAPH + 0x8AB4: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0x8AB5: 0x59F7, //CJK UNIFIED IDEOGRAPH + 0x8AB6: 0x59F8, //CJK UNIFIED IDEOGRAPH + 0x8AB7: 0x59FA, //CJK UNIFIED IDEOGRAPH + 0x8AB8: 0x59FC, //CJK UNIFIED IDEOGRAPH + 0x8AB9: 0x59FD, //CJK UNIFIED IDEOGRAPH + 0x8ABA: 0x59FE, //CJK UNIFIED IDEOGRAPH + 0x8ABB: 0x5A00, //CJK UNIFIED IDEOGRAPH + 0x8ABC: 0x5A02, //CJK UNIFIED IDEOGRAPH + 0x8ABD: 0x5A0A, //CJK UNIFIED IDEOGRAPH + 0x8ABE: 0x5A0B, //CJK UNIFIED IDEOGRAPH + 0x8ABF: 0x5A0D, //CJK UNIFIED IDEOGRAPH + 0x8AC0: 0x5A0E, //CJK UNIFIED IDEOGRAPH + 0x8AC1: 0x5A0F, //CJK UNIFIED IDEOGRAPH + 0x8AC2: 0x5A10, //CJK UNIFIED IDEOGRAPH + 0x8AC3: 0x5A12, //CJK UNIFIED IDEOGRAPH + 0x8AC4: 0x5A14, //CJK UNIFIED IDEOGRAPH + 0x8AC5: 0x5A15, //CJK UNIFIED IDEOGRAPH + 0x8AC6: 0x5A16, //CJK UNIFIED IDEOGRAPH + 0x8AC7: 0x5A17, //CJK UNIFIED IDEOGRAPH + 0x8AC8: 0x5A19, //CJK UNIFIED IDEOGRAPH + 0x8AC9: 0x5A1A, //CJK UNIFIED IDEOGRAPH + 0x8ACA: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0x8ACB: 0x5A1D, //CJK UNIFIED IDEOGRAPH + 0x8ACC: 0x5A1E, //CJK UNIFIED IDEOGRAPH + 0x8ACD: 0x5A21, //CJK UNIFIED IDEOGRAPH + 0x8ACE: 0x5A22, //CJK UNIFIED IDEOGRAPH + 0x8ACF: 0x5A24, //CJK UNIFIED IDEOGRAPH + 0x8AD0: 0x5A26, //CJK UNIFIED IDEOGRAPH + 0x8AD1: 0x5A27, //CJK UNIFIED IDEOGRAPH + 0x8AD2: 0x5A28, //CJK UNIFIED IDEOGRAPH + 0x8AD3: 0x5A2A, //CJK UNIFIED IDEOGRAPH + 0x8AD4: 0x5A2B, //CJK UNIFIED IDEOGRAPH + 0x8AD5: 0x5A2C, //CJK UNIFIED IDEOGRAPH + 0x8AD6: 0x5A2D, //CJK UNIFIED IDEOGRAPH + 0x8AD7: 0x5A2E, //CJK UNIFIED IDEOGRAPH + 0x8AD8: 0x5A2F, //CJK UNIFIED IDEOGRAPH + 0x8AD9: 0x5A30, //CJK UNIFIED IDEOGRAPH + 0x8ADA: 0x5A33, //CJK UNIFIED IDEOGRAPH + 0x8ADB: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0x8ADC: 0x5A37, //CJK UNIFIED IDEOGRAPH + 0x8ADD: 0x5A38, //CJK UNIFIED IDEOGRAPH + 0x8ADE: 0x5A39, //CJK UNIFIED IDEOGRAPH + 0x8ADF: 0x5A3A, //CJK UNIFIED IDEOGRAPH + 0x8AE0: 0x5A3B, //CJK UNIFIED IDEOGRAPH + 0x8AE1: 0x5A3D, //CJK UNIFIED IDEOGRAPH + 0x8AE2: 0x5A3E, //CJK UNIFIED IDEOGRAPH + 0x8AE3: 0x5A3F, //CJK UNIFIED IDEOGRAPH + 0x8AE4: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0x8AE5: 0x5A42, //CJK UNIFIED IDEOGRAPH + 0x8AE6: 0x5A43, //CJK UNIFIED IDEOGRAPH + 0x8AE7: 0x5A44, //CJK UNIFIED IDEOGRAPH + 0x8AE8: 0x5A45, //CJK UNIFIED IDEOGRAPH + 0x8AE9: 0x5A47, //CJK UNIFIED IDEOGRAPH + 0x8AEA: 0x5A48, //CJK UNIFIED IDEOGRAPH + 0x8AEB: 0x5A4B, //CJK UNIFIED IDEOGRAPH + 0x8AEC: 0x5A4C, //CJK UNIFIED IDEOGRAPH + 0x8AED: 0x5A4D, //CJK UNIFIED IDEOGRAPH + 0x8AEE: 0x5A4E, //CJK UNIFIED IDEOGRAPH + 0x8AEF: 0x5A4F, //CJK UNIFIED IDEOGRAPH + 0x8AF0: 0x5A50, //CJK UNIFIED IDEOGRAPH + 0x8AF1: 0x5A51, //CJK UNIFIED IDEOGRAPH + 0x8AF2: 0x5A52, //CJK UNIFIED IDEOGRAPH + 0x8AF3: 0x5A53, //CJK UNIFIED IDEOGRAPH + 0x8AF4: 0x5A54, //CJK UNIFIED IDEOGRAPH + 0x8AF5: 0x5A56, //CJK UNIFIED IDEOGRAPH + 0x8AF6: 0x5A57, //CJK UNIFIED IDEOGRAPH + 0x8AF7: 0x5A58, //CJK UNIFIED IDEOGRAPH + 0x8AF8: 0x5A59, //CJK UNIFIED IDEOGRAPH + 0x8AF9: 0x5A5B, //CJK UNIFIED IDEOGRAPH + 0x8AFA: 0x5A5C, //CJK UNIFIED IDEOGRAPH + 0x8AFB: 0x5A5D, //CJK UNIFIED IDEOGRAPH + 0x8AFC: 0x5A5E, //CJK UNIFIED IDEOGRAPH + 0x8AFD: 0x5A5F, //CJK UNIFIED IDEOGRAPH + 0x8AFE: 0x5A60, //CJK UNIFIED IDEOGRAPH + 0x8B40: 0x5A61, //CJK UNIFIED IDEOGRAPH + 0x8B41: 0x5A63, //CJK UNIFIED IDEOGRAPH + 0x8B42: 0x5A64, //CJK UNIFIED IDEOGRAPH + 0x8B43: 0x5A65, //CJK UNIFIED IDEOGRAPH + 0x8B44: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0x8B45: 0x5A68, //CJK UNIFIED IDEOGRAPH + 0x8B46: 0x5A69, //CJK UNIFIED IDEOGRAPH + 0x8B47: 0x5A6B, //CJK UNIFIED IDEOGRAPH + 0x8B48: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0x8B49: 0x5A6D, //CJK UNIFIED IDEOGRAPH + 0x8B4A: 0x5A6E, //CJK UNIFIED IDEOGRAPH + 0x8B4B: 0x5A6F, //CJK UNIFIED IDEOGRAPH + 0x8B4C: 0x5A70, //CJK UNIFIED IDEOGRAPH + 0x8B4D: 0x5A71, //CJK UNIFIED IDEOGRAPH + 0x8B4E: 0x5A72, //CJK UNIFIED IDEOGRAPH + 0x8B4F: 0x5A73, //CJK UNIFIED IDEOGRAPH + 0x8B50: 0x5A78, //CJK UNIFIED IDEOGRAPH + 0x8B51: 0x5A79, //CJK UNIFIED IDEOGRAPH + 0x8B52: 0x5A7B, //CJK UNIFIED IDEOGRAPH + 0x8B53: 0x5A7C, //CJK UNIFIED IDEOGRAPH + 0x8B54: 0x5A7D, //CJK UNIFIED IDEOGRAPH + 0x8B55: 0x5A7E, //CJK UNIFIED IDEOGRAPH + 0x8B56: 0x5A80, //CJK UNIFIED IDEOGRAPH + 0x8B57: 0x5A81, //CJK UNIFIED IDEOGRAPH + 0x8B58: 0x5A82, //CJK UNIFIED IDEOGRAPH + 0x8B59: 0x5A83, //CJK UNIFIED IDEOGRAPH + 0x8B5A: 0x5A84, //CJK UNIFIED IDEOGRAPH + 0x8B5B: 0x5A85, //CJK UNIFIED IDEOGRAPH + 0x8B5C: 0x5A86, //CJK UNIFIED IDEOGRAPH + 0x8B5D: 0x5A87, //CJK UNIFIED IDEOGRAPH + 0x8B5E: 0x5A88, //CJK UNIFIED IDEOGRAPH + 0x8B5F: 0x5A89, //CJK UNIFIED IDEOGRAPH + 0x8B60: 0x5A8A, //CJK UNIFIED IDEOGRAPH + 0x8B61: 0x5A8B, //CJK UNIFIED IDEOGRAPH + 0x8B62: 0x5A8C, //CJK UNIFIED IDEOGRAPH + 0x8B63: 0x5A8D, //CJK UNIFIED IDEOGRAPH + 0x8B64: 0x5A8E, //CJK UNIFIED IDEOGRAPH + 0x8B65: 0x5A8F, //CJK UNIFIED IDEOGRAPH + 0x8B66: 0x5A90, //CJK UNIFIED IDEOGRAPH + 0x8B67: 0x5A91, //CJK UNIFIED IDEOGRAPH + 0x8B68: 0x5A93, //CJK UNIFIED IDEOGRAPH + 0x8B69: 0x5A94, //CJK UNIFIED IDEOGRAPH + 0x8B6A: 0x5A95, //CJK UNIFIED IDEOGRAPH + 0x8B6B: 0x5A96, //CJK UNIFIED IDEOGRAPH + 0x8B6C: 0x5A97, //CJK UNIFIED IDEOGRAPH + 0x8B6D: 0x5A98, //CJK UNIFIED IDEOGRAPH + 0x8B6E: 0x5A99, //CJK UNIFIED IDEOGRAPH + 0x8B6F: 0x5A9C, //CJK UNIFIED IDEOGRAPH + 0x8B70: 0x5A9D, //CJK UNIFIED IDEOGRAPH + 0x8B71: 0x5A9E, //CJK UNIFIED IDEOGRAPH + 0x8B72: 0x5A9F, //CJK UNIFIED IDEOGRAPH + 0x8B73: 0x5AA0, //CJK UNIFIED IDEOGRAPH + 0x8B74: 0x5AA1, //CJK UNIFIED IDEOGRAPH + 0x8B75: 0x5AA2, //CJK UNIFIED IDEOGRAPH + 0x8B76: 0x5AA3, //CJK UNIFIED IDEOGRAPH + 0x8B77: 0x5AA4, //CJK UNIFIED IDEOGRAPH + 0x8B78: 0x5AA5, //CJK UNIFIED IDEOGRAPH + 0x8B79: 0x5AA6, //CJK UNIFIED IDEOGRAPH + 0x8B7A: 0x5AA7, //CJK UNIFIED IDEOGRAPH + 0x8B7B: 0x5AA8, //CJK UNIFIED IDEOGRAPH + 0x8B7C: 0x5AA9, //CJK UNIFIED IDEOGRAPH + 0x8B7D: 0x5AAB, //CJK UNIFIED IDEOGRAPH + 0x8B7E: 0x5AAC, //CJK UNIFIED IDEOGRAPH + 0x8B80: 0x5AAD, //CJK UNIFIED IDEOGRAPH + 0x8B81: 0x5AAE, //CJK UNIFIED IDEOGRAPH + 0x8B82: 0x5AAF, //CJK UNIFIED IDEOGRAPH + 0x8B83: 0x5AB0, //CJK UNIFIED IDEOGRAPH + 0x8B84: 0x5AB1, //CJK UNIFIED IDEOGRAPH + 0x8B85: 0x5AB4, //CJK UNIFIED IDEOGRAPH + 0x8B86: 0x5AB6, //CJK UNIFIED IDEOGRAPH + 0x8B87: 0x5AB7, //CJK UNIFIED IDEOGRAPH + 0x8B88: 0x5AB9, //CJK UNIFIED IDEOGRAPH + 0x8B89: 0x5ABA, //CJK UNIFIED IDEOGRAPH + 0x8B8A: 0x5ABB, //CJK UNIFIED IDEOGRAPH + 0x8B8B: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0x8B8C: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0x8B8D: 0x5ABF, //CJK UNIFIED IDEOGRAPH + 0x8B8E: 0x5AC0, //CJK UNIFIED IDEOGRAPH + 0x8B8F: 0x5AC3, //CJK UNIFIED IDEOGRAPH + 0x8B90: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0x8B91: 0x5AC5, //CJK UNIFIED IDEOGRAPH + 0x8B92: 0x5AC6, //CJK UNIFIED IDEOGRAPH + 0x8B93: 0x5AC7, //CJK UNIFIED IDEOGRAPH + 0x8B94: 0x5AC8, //CJK UNIFIED IDEOGRAPH + 0x8B95: 0x5ACA, //CJK UNIFIED IDEOGRAPH + 0x8B96: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0x8B97: 0x5ACD, //CJK UNIFIED IDEOGRAPH + 0x8B98: 0x5ACE, //CJK UNIFIED IDEOGRAPH + 0x8B99: 0x5ACF, //CJK UNIFIED IDEOGRAPH + 0x8B9A: 0x5AD0, //CJK UNIFIED IDEOGRAPH + 0x8B9B: 0x5AD1, //CJK UNIFIED IDEOGRAPH + 0x8B9C: 0x5AD3, //CJK UNIFIED IDEOGRAPH + 0x8B9D: 0x5AD5, //CJK UNIFIED IDEOGRAPH + 0x8B9E: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0x8B9F: 0x5AD9, //CJK UNIFIED IDEOGRAPH + 0x8BA0: 0x5ADA, //CJK UNIFIED IDEOGRAPH + 0x8BA1: 0x5ADB, //CJK UNIFIED IDEOGRAPH + 0x8BA2: 0x5ADD, //CJK UNIFIED IDEOGRAPH + 0x8BA3: 0x5ADE, //CJK UNIFIED IDEOGRAPH + 0x8BA4: 0x5ADF, //CJK UNIFIED IDEOGRAPH + 0x8BA5: 0x5AE2, //CJK UNIFIED IDEOGRAPH + 0x8BA6: 0x5AE4, //CJK UNIFIED IDEOGRAPH + 0x8BA7: 0x5AE5, //CJK UNIFIED IDEOGRAPH + 0x8BA8: 0x5AE7, //CJK UNIFIED IDEOGRAPH + 0x8BA9: 0x5AE8, //CJK UNIFIED IDEOGRAPH + 0x8BAA: 0x5AEA, //CJK UNIFIED IDEOGRAPH + 0x8BAB: 0x5AEC, //CJK UNIFIED IDEOGRAPH + 0x8BAC: 0x5AED, //CJK UNIFIED IDEOGRAPH + 0x8BAD: 0x5AEE, //CJK UNIFIED IDEOGRAPH + 0x8BAE: 0x5AEF, //CJK UNIFIED IDEOGRAPH + 0x8BAF: 0x5AF0, //CJK UNIFIED IDEOGRAPH + 0x8BB0: 0x5AF2, //CJK UNIFIED IDEOGRAPH + 0x8BB1: 0x5AF3, //CJK UNIFIED IDEOGRAPH + 0x8BB2: 0x5AF4, //CJK UNIFIED IDEOGRAPH + 0x8BB3: 0x5AF5, //CJK UNIFIED IDEOGRAPH + 0x8BB4: 0x5AF6, //CJK UNIFIED IDEOGRAPH + 0x8BB5: 0x5AF7, //CJK UNIFIED IDEOGRAPH + 0x8BB6: 0x5AF8, //CJK UNIFIED IDEOGRAPH + 0x8BB7: 0x5AF9, //CJK UNIFIED IDEOGRAPH + 0x8BB8: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0x8BB9: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0x8BBA: 0x5AFC, //CJK UNIFIED IDEOGRAPH + 0x8BBB: 0x5AFD, //CJK UNIFIED IDEOGRAPH + 0x8BBC: 0x5AFE, //CJK UNIFIED IDEOGRAPH + 0x8BBD: 0x5AFF, //CJK UNIFIED IDEOGRAPH + 0x8BBE: 0x5B00, //CJK UNIFIED IDEOGRAPH + 0x8BBF: 0x5B01, //CJK UNIFIED IDEOGRAPH + 0x8BC0: 0x5B02, //CJK UNIFIED IDEOGRAPH + 0x8BC1: 0x5B03, //CJK UNIFIED IDEOGRAPH + 0x8BC2: 0x5B04, //CJK UNIFIED IDEOGRAPH + 0x8BC3: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0x8BC4: 0x5B06, //CJK UNIFIED IDEOGRAPH + 0x8BC5: 0x5B07, //CJK UNIFIED IDEOGRAPH + 0x8BC6: 0x5B08, //CJK UNIFIED IDEOGRAPH + 0x8BC7: 0x5B0A, //CJK UNIFIED IDEOGRAPH + 0x8BC8: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0x8BC9: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0x8BCA: 0x5B0D, //CJK UNIFIED IDEOGRAPH + 0x8BCB: 0x5B0E, //CJK UNIFIED IDEOGRAPH + 0x8BCC: 0x5B0F, //CJK UNIFIED IDEOGRAPH + 0x8BCD: 0x5B10, //CJK UNIFIED IDEOGRAPH + 0x8BCE: 0x5B11, //CJK UNIFIED IDEOGRAPH + 0x8BCF: 0x5B12, //CJK UNIFIED IDEOGRAPH + 0x8BD0: 0x5B13, //CJK UNIFIED IDEOGRAPH + 0x8BD1: 0x5B14, //CJK UNIFIED IDEOGRAPH + 0x8BD2: 0x5B15, //CJK UNIFIED IDEOGRAPH + 0x8BD3: 0x5B18, //CJK UNIFIED IDEOGRAPH + 0x8BD4: 0x5B19, //CJK UNIFIED IDEOGRAPH + 0x8BD5: 0x5B1A, //CJK UNIFIED IDEOGRAPH + 0x8BD6: 0x5B1B, //CJK UNIFIED IDEOGRAPH + 0x8BD7: 0x5B1C, //CJK UNIFIED IDEOGRAPH + 0x8BD8: 0x5B1D, //CJK UNIFIED IDEOGRAPH + 0x8BD9: 0x5B1E, //CJK UNIFIED IDEOGRAPH + 0x8BDA: 0x5B1F, //CJK UNIFIED IDEOGRAPH + 0x8BDB: 0x5B20, //CJK UNIFIED IDEOGRAPH + 0x8BDC: 0x5B21, //CJK UNIFIED IDEOGRAPH + 0x8BDD: 0x5B22, //CJK UNIFIED IDEOGRAPH + 0x8BDE: 0x5B23, //CJK UNIFIED IDEOGRAPH + 0x8BDF: 0x5B24, //CJK UNIFIED IDEOGRAPH + 0x8BE0: 0x5B25, //CJK UNIFIED IDEOGRAPH + 0x8BE1: 0x5B26, //CJK UNIFIED IDEOGRAPH + 0x8BE2: 0x5B27, //CJK UNIFIED IDEOGRAPH + 0x8BE3: 0x5B28, //CJK UNIFIED IDEOGRAPH + 0x8BE4: 0x5B29, //CJK UNIFIED IDEOGRAPH + 0x8BE5: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0x8BE6: 0x5B2B, //CJK UNIFIED IDEOGRAPH + 0x8BE7: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0x8BE8: 0x5B2D, //CJK UNIFIED IDEOGRAPH + 0x8BE9: 0x5B2E, //CJK UNIFIED IDEOGRAPH + 0x8BEA: 0x5B2F, //CJK UNIFIED IDEOGRAPH + 0x8BEB: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0x8BEC: 0x5B31, //CJK UNIFIED IDEOGRAPH + 0x8BED: 0x5B33, //CJK UNIFIED IDEOGRAPH + 0x8BEE: 0x5B35, //CJK UNIFIED IDEOGRAPH + 0x8BEF: 0x5B36, //CJK UNIFIED IDEOGRAPH + 0x8BF0: 0x5B38, //CJK UNIFIED IDEOGRAPH + 0x8BF1: 0x5B39, //CJK UNIFIED IDEOGRAPH + 0x8BF2: 0x5B3A, //CJK UNIFIED IDEOGRAPH + 0x8BF3: 0x5B3B, //CJK UNIFIED IDEOGRAPH + 0x8BF4: 0x5B3C, //CJK UNIFIED IDEOGRAPH + 0x8BF5: 0x5B3D, //CJK UNIFIED IDEOGRAPH + 0x8BF6: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0x8BF7: 0x5B3F, //CJK UNIFIED IDEOGRAPH + 0x8BF8: 0x5B41, //CJK UNIFIED IDEOGRAPH + 0x8BF9: 0x5B42, //CJK UNIFIED IDEOGRAPH + 0x8BFA: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0x8BFB: 0x5B44, //CJK UNIFIED IDEOGRAPH + 0x8BFC: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0x8BFD: 0x5B46, //CJK UNIFIED IDEOGRAPH + 0x8BFE: 0x5B47, //CJK UNIFIED IDEOGRAPH + 0x8C40: 0x5B48, //CJK UNIFIED IDEOGRAPH + 0x8C41: 0x5B49, //CJK UNIFIED IDEOGRAPH + 0x8C42: 0x5B4A, //CJK UNIFIED IDEOGRAPH + 0x8C43: 0x5B4B, //CJK UNIFIED IDEOGRAPH + 0x8C44: 0x5B4C, //CJK UNIFIED IDEOGRAPH + 0x8C45: 0x5B4D, //CJK UNIFIED IDEOGRAPH + 0x8C46: 0x5B4E, //CJK UNIFIED IDEOGRAPH + 0x8C47: 0x5B4F, //CJK UNIFIED IDEOGRAPH + 0x8C48: 0x5B52, //CJK UNIFIED IDEOGRAPH + 0x8C49: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0x8C4A: 0x5B5E, //CJK UNIFIED IDEOGRAPH + 0x8C4B: 0x5B60, //CJK UNIFIED IDEOGRAPH + 0x8C4C: 0x5B61, //CJK UNIFIED IDEOGRAPH + 0x8C4D: 0x5B67, //CJK UNIFIED IDEOGRAPH + 0x8C4E: 0x5B68, //CJK UNIFIED IDEOGRAPH + 0x8C4F: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0x8C50: 0x5B6D, //CJK UNIFIED IDEOGRAPH + 0x8C51: 0x5B6E, //CJK UNIFIED IDEOGRAPH + 0x8C52: 0x5B6F, //CJK UNIFIED IDEOGRAPH + 0x8C53: 0x5B72, //CJK UNIFIED IDEOGRAPH + 0x8C54: 0x5B74, //CJK UNIFIED IDEOGRAPH + 0x8C55: 0x5B76, //CJK UNIFIED IDEOGRAPH + 0x8C56: 0x5B77, //CJK UNIFIED IDEOGRAPH + 0x8C57: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0x8C58: 0x5B79, //CJK UNIFIED IDEOGRAPH + 0x8C59: 0x5B7B, //CJK UNIFIED IDEOGRAPH + 0x8C5A: 0x5B7C, //CJK UNIFIED IDEOGRAPH + 0x8C5B: 0x5B7E, //CJK UNIFIED IDEOGRAPH + 0x8C5C: 0x5B7F, //CJK UNIFIED IDEOGRAPH + 0x8C5D: 0x5B82, //CJK UNIFIED IDEOGRAPH + 0x8C5E: 0x5B86, //CJK UNIFIED IDEOGRAPH + 0x8C5F: 0x5B8A, //CJK UNIFIED IDEOGRAPH + 0x8C60: 0x5B8D, //CJK UNIFIED IDEOGRAPH + 0x8C61: 0x5B8E, //CJK UNIFIED IDEOGRAPH + 0x8C62: 0x5B90, //CJK UNIFIED IDEOGRAPH + 0x8C63: 0x5B91, //CJK UNIFIED IDEOGRAPH + 0x8C64: 0x5B92, //CJK UNIFIED IDEOGRAPH + 0x8C65: 0x5B94, //CJK UNIFIED IDEOGRAPH + 0x8C66: 0x5B96, //CJK UNIFIED IDEOGRAPH + 0x8C67: 0x5B9F, //CJK UNIFIED IDEOGRAPH + 0x8C68: 0x5BA7, //CJK UNIFIED IDEOGRAPH + 0x8C69: 0x5BA8, //CJK UNIFIED IDEOGRAPH + 0x8C6A: 0x5BA9, //CJK UNIFIED IDEOGRAPH + 0x8C6B: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0x8C6C: 0x5BAD, //CJK UNIFIED IDEOGRAPH + 0x8C6D: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0x8C6E: 0x5BAF, //CJK UNIFIED IDEOGRAPH + 0x8C6F: 0x5BB1, //CJK UNIFIED IDEOGRAPH + 0x8C70: 0x5BB2, //CJK UNIFIED IDEOGRAPH + 0x8C71: 0x5BB7, //CJK UNIFIED IDEOGRAPH + 0x8C72: 0x5BBA, //CJK UNIFIED IDEOGRAPH + 0x8C73: 0x5BBB, //CJK UNIFIED IDEOGRAPH + 0x8C74: 0x5BBC, //CJK UNIFIED IDEOGRAPH + 0x8C75: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0x8C76: 0x5BC1, //CJK UNIFIED IDEOGRAPH + 0x8C77: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0x8C78: 0x5BC8, //CJK UNIFIED IDEOGRAPH + 0x8C79: 0x5BC9, //CJK UNIFIED IDEOGRAPH + 0x8C7A: 0x5BCA, //CJK UNIFIED IDEOGRAPH + 0x8C7B: 0x5BCB, //CJK UNIFIED IDEOGRAPH + 0x8C7C: 0x5BCD, //CJK UNIFIED IDEOGRAPH + 0x8C7D: 0x5BCE, //CJK UNIFIED IDEOGRAPH + 0x8C7E: 0x5BCF, //CJK UNIFIED IDEOGRAPH + 0x8C80: 0x5BD1, //CJK UNIFIED IDEOGRAPH + 0x8C81: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0x8C82: 0x5BD5, //CJK UNIFIED IDEOGRAPH + 0x8C83: 0x5BD6, //CJK UNIFIED IDEOGRAPH + 0x8C84: 0x5BD7, //CJK UNIFIED IDEOGRAPH + 0x8C85: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0x8C86: 0x5BD9, //CJK UNIFIED IDEOGRAPH + 0x8C87: 0x5BDA, //CJK UNIFIED IDEOGRAPH + 0x8C88: 0x5BDB, //CJK UNIFIED IDEOGRAPH + 0x8C89: 0x5BDC, //CJK UNIFIED IDEOGRAPH + 0x8C8A: 0x5BE0, //CJK UNIFIED IDEOGRAPH + 0x8C8B: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0x8C8C: 0x5BE3, //CJK UNIFIED IDEOGRAPH + 0x8C8D: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0x8C8E: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0x8C8F: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0x8C90: 0x5BEA, //CJK UNIFIED IDEOGRAPH + 0x8C91: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0x8C92: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0x8C93: 0x5BED, //CJK UNIFIED IDEOGRAPH + 0x8C94: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0x8C95: 0x5BF1, //CJK UNIFIED IDEOGRAPH + 0x8C96: 0x5BF2, //CJK UNIFIED IDEOGRAPH + 0x8C97: 0x5BF3, //CJK UNIFIED IDEOGRAPH + 0x8C98: 0x5BF4, //CJK UNIFIED IDEOGRAPH + 0x8C99: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0x8C9A: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0x8C9B: 0x5BF7, //CJK UNIFIED IDEOGRAPH + 0x8C9C: 0x5BFD, //CJK UNIFIED IDEOGRAPH + 0x8C9D: 0x5BFE, //CJK UNIFIED IDEOGRAPH + 0x8C9E: 0x5C00, //CJK UNIFIED IDEOGRAPH + 0x8C9F: 0x5C02, //CJK UNIFIED IDEOGRAPH + 0x8CA0: 0x5C03, //CJK UNIFIED IDEOGRAPH + 0x8CA1: 0x5C05, //CJK UNIFIED IDEOGRAPH + 0x8CA2: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0x8CA3: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0x8CA4: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0x8CA5: 0x5C0C, //CJK UNIFIED IDEOGRAPH + 0x8CA6: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0x8CA7: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0x8CA8: 0x5C10, //CJK UNIFIED IDEOGRAPH + 0x8CA9: 0x5C12, //CJK UNIFIED IDEOGRAPH + 0x8CAA: 0x5C13, //CJK UNIFIED IDEOGRAPH + 0x8CAB: 0x5C17, //CJK UNIFIED IDEOGRAPH + 0x8CAC: 0x5C19, //CJK UNIFIED IDEOGRAPH + 0x8CAD: 0x5C1B, //CJK UNIFIED IDEOGRAPH + 0x8CAE: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0x8CAF: 0x5C1F, //CJK UNIFIED IDEOGRAPH + 0x8CB0: 0x5C20, //CJK UNIFIED IDEOGRAPH + 0x8CB1: 0x5C21, //CJK UNIFIED IDEOGRAPH + 0x8CB2: 0x5C23, //CJK UNIFIED IDEOGRAPH + 0x8CB3: 0x5C26, //CJK UNIFIED IDEOGRAPH + 0x8CB4: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0x8CB5: 0x5C29, //CJK UNIFIED IDEOGRAPH + 0x8CB6: 0x5C2A, //CJK UNIFIED IDEOGRAPH + 0x8CB7: 0x5C2B, //CJK UNIFIED IDEOGRAPH + 0x8CB8: 0x5C2D, //CJK UNIFIED IDEOGRAPH + 0x8CB9: 0x5C2E, //CJK UNIFIED IDEOGRAPH + 0x8CBA: 0x5C2F, //CJK UNIFIED IDEOGRAPH + 0x8CBB: 0x5C30, //CJK UNIFIED IDEOGRAPH + 0x8CBC: 0x5C32, //CJK UNIFIED IDEOGRAPH + 0x8CBD: 0x5C33, //CJK UNIFIED IDEOGRAPH + 0x8CBE: 0x5C35, //CJK UNIFIED IDEOGRAPH + 0x8CBF: 0x5C36, //CJK UNIFIED IDEOGRAPH + 0x8CC0: 0x5C37, //CJK UNIFIED IDEOGRAPH + 0x8CC1: 0x5C43, //CJK UNIFIED IDEOGRAPH + 0x8CC2: 0x5C44, //CJK UNIFIED IDEOGRAPH + 0x8CC3: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0x8CC4: 0x5C47, //CJK UNIFIED IDEOGRAPH + 0x8CC5: 0x5C4C, //CJK UNIFIED IDEOGRAPH + 0x8CC6: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0x8CC7: 0x5C52, //CJK UNIFIED IDEOGRAPH + 0x8CC8: 0x5C53, //CJK UNIFIED IDEOGRAPH + 0x8CC9: 0x5C54, //CJK UNIFIED IDEOGRAPH + 0x8CCA: 0x5C56, //CJK UNIFIED IDEOGRAPH + 0x8CCB: 0x5C57, //CJK UNIFIED IDEOGRAPH + 0x8CCC: 0x5C58, //CJK UNIFIED IDEOGRAPH + 0x8CCD: 0x5C5A, //CJK UNIFIED IDEOGRAPH + 0x8CCE: 0x5C5B, //CJK UNIFIED IDEOGRAPH + 0x8CCF: 0x5C5C, //CJK UNIFIED IDEOGRAPH + 0x8CD0: 0x5C5D, //CJK UNIFIED IDEOGRAPH + 0x8CD1: 0x5C5F, //CJK UNIFIED IDEOGRAPH + 0x8CD2: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0x8CD3: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0x8CD4: 0x5C67, //CJK UNIFIED IDEOGRAPH + 0x8CD5: 0x5C68, //CJK UNIFIED IDEOGRAPH + 0x8CD6: 0x5C69, //CJK UNIFIED IDEOGRAPH + 0x8CD7: 0x5C6A, //CJK UNIFIED IDEOGRAPH + 0x8CD8: 0x5C6B, //CJK UNIFIED IDEOGRAPH + 0x8CD9: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0x8CDA: 0x5C6D, //CJK UNIFIED IDEOGRAPH + 0x8CDB: 0x5C70, //CJK UNIFIED IDEOGRAPH + 0x8CDC: 0x5C72, //CJK UNIFIED IDEOGRAPH + 0x8CDD: 0x5C73, //CJK UNIFIED IDEOGRAPH + 0x8CDE: 0x5C74, //CJK UNIFIED IDEOGRAPH + 0x8CDF: 0x5C75, //CJK UNIFIED IDEOGRAPH + 0x8CE0: 0x5C76, //CJK UNIFIED IDEOGRAPH + 0x8CE1: 0x5C77, //CJK UNIFIED IDEOGRAPH + 0x8CE2: 0x5C78, //CJK UNIFIED IDEOGRAPH + 0x8CE3: 0x5C7B, //CJK UNIFIED IDEOGRAPH + 0x8CE4: 0x5C7C, //CJK UNIFIED IDEOGRAPH + 0x8CE5: 0x5C7D, //CJK UNIFIED IDEOGRAPH + 0x8CE6: 0x5C7E, //CJK UNIFIED IDEOGRAPH + 0x8CE7: 0x5C80, //CJK UNIFIED IDEOGRAPH + 0x8CE8: 0x5C83, //CJK UNIFIED IDEOGRAPH + 0x8CE9: 0x5C84, //CJK UNIFIED IDEOGRAPH + 0x8CEA: 0x5C85, //CJK UNIFIED IDEOGRAPH + 0x8CEB: 0x5C86, //CJK UNIFIED IDEOGRAPH + 0x8CEC: 0x5C87, //CJK UNIFIED IDEOGRAPH + 0x8CED: 0x5C89, //CJK UNIFIED IDEOGRAPH + 0x8CEE: 0x5C8A, //CJK UNIFIED IDEOGRAPH + 0x8CEF: 0x5C8B, //CJK UNIFIED IDEOGRAPH + 0x8CF0: 0x5C8E, //CJK UNIFIED IDEOGRAPH + 0x8CF1: 0x5C8F, //CJK UNIFIED IDEOGRAPH + 0x8CF2: 0x5C92, //CJK UNIFIED IDEOGRAPH + 0x8CF3: 0x5C93, //CJK UNIFIED IDEOGRAPH + 0x8CF4: 0x5C95, //CJK UNIFIED IDEOGRAPH + 0x8CF5: 0x5C9D, //CJK UNIFIED IDEOGRAPH + 0x8CF6: 0x5C9E, //CJK UNIFIED IDEOGRAPH + 0x8CF7: 0x5C9F, //CJK UNIFIED IDEOGRAPH + 0x8CF8: 0x5CA0, //CJK UNIFIED IDEOGRAPH + 0x8CF9: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0x8CFA: 0x5CA4, //CJK UNIFIED IDEOGRAPH + 0x8CFB: 0x5CA5, //CJK UNIFIED IDEOGRAPH + 0x8CFC: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0x8CFD: 0x5CA7, //CJK UNIFIED IDEOGRAPH + 0x8CFE: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0x8D40: 0x5CAA, //CJK UNIFIED IDEOGRAPH + 0x8D41: 0x5CAE, //CJK UNIFIED IDEOGRAPH + 0x8D42: 0x5CAF, //CJK UNIFIED IDEOGRAPH + 0x8D43: 0x5CB0, //CJK UNIFIED IDEOGRAPH + 0x8D44: 0x5CB2, //CJK UNIFIED IDEOGRAPH + 0x8D45: 0x5CB4, //CJK UNIFIED IDEOGRAPH + 0x8D46: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0x8D47: 0x5CB9, //CJK UNIFIED IDEOGRAPH + 0x8D48: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0x8D49: 0x5CBB, //CJK UNIFIED IDEOGRAPH + 0x8D4A: 0x5CBC, //CJK UNIFIED IDEOGRAPH + 0x8D4B: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0x8D4C: 0x5CC0, //CJK UNIFIED IDEOGRAPH + 0x8D4D: 0x5CC2, //CJK UNIFIED IDEOGRAPH + 0x8D4E: 0x5CC3, //CJK UNIFIED IDEOGRAPH + 0x8D4F: 0x5CC5, //CJK UNIFIED IDEOGRAPH + 0x8D50: 0x5CC6, //CJK UNIFIED IDEOGRAPH + 0x8D51: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0x8D52: 0x5CC8, //CJK UNIFIED IDEOGRAPH + 0x8D53: 0x5CC9, //CJK UNIFIED IDEOGRAPH + 0x8D54: 0x5CCA, //CJK UNIFIED IDEOGRAPH + 0x8D55: 0x5CCC, //CJK UNIFIED IDEOGRAPH + 0x8D56: 0x5CCD, //CJK UNIFIED IDEOGRAPH + 0x8D57: 0x5CCE, //CJK UNIFIED IDEOGRAPH + 0x8D58: 0x5CCF, //CJK UNIFIED IDEOGRAPH + 0x8D59: 0x5CD0, //CJK UNIFIED IDEOGRAPH + 0x8D5A: 0x5CD1, //CJK UNIFIED IDEOGRAPH + 0x8D5B: 0x5CD3, //CJK UNIFIED IDEOGRAPH + 0x8D5C: 0x5CD4, //CJK UNIFIED IDEOGRAPH + 0x8D5D: 0x5CD5, //CJK UNIFIED IDEOGRAPH + 0x8D5E: 0x5CD6, //CJK UNIFIED IDEOGRAPH + 0x8D5F: 0x5CD7, //CJK UNIFIED IDEOGRAPH + 0x8D60: 0x5CD8, //CJK UNIFIED IDEOGRAPH + 0x8D61: 0x5CDA, //CJK UNIFIED IDEOGRAPH + 0x8D62: 0x5CDB, //CJK UNIFIED IDEOGRAPH + 0x8D63: 0x5CDC, //CJK UNIFIED IDEOGRAPH + 0x8D64: 0x5CDD, //CJK UNIFIED IDEOGRAPH + 0x8D65: 0x5CDE, //CJK UNIFIED IDEOGRAPH + 0x8D66: 0x5CDF, //CJK UNIFIED IDEOGRAPH + 0x8D67: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0x8D68: 0x5CE2, //CJK UNIFIED IDEOGRAPH + 0x8D69: 0x5CE3, //CJK UNIFIED IDEOGRAPH + 0x8D6A: 0x5CE7, //CJK UNIFIED IDEOGRAPH + 0x8D6B: 0x5CE9, //CJK UNIFIED IDEOGRAPH + 0x8D6C: 0x5CEB, //CJK UNIFIED IDEOGRAPH + 0x8D6D: 0x5CEC, //CJK UNIFIED IDEOGRAPH + 0x8D6E: 0x5CEE, //CJK UNIFIED IDEOGRAPH + 0x8D6F: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0x8D70: 0x5CF1, //CJK UNIFIED IDEOGRAPH + 0x8D71: 0x5CF2, //CJK UNIFIED IDEOGRAPH + 0x8D72: 0x5CF3, //CJK UNIFIED IDEOGRAPH + 0x8D73: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0x8D74: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0x8D75: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0x8D76: 0x5CF7, //CJK UNIFIED IDEOGRAPH + 0x8D77: 0x5CF8, //CJK UNIFIED IDEOGRAPH + 0x8D78: 0x5CF9, //CJK UNIFIED IDEOGRAPH + 0x8D79: 0x5CFA, //CJK UNIFIED IDEOGRAPH + 0x8D7A: 0x5CFC, //CJK UNIFIED IDEOGRAPH + 0x8D7B: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0x8D7C: 0x5CFE, //CJK UNIFIED IDEOGRAPH + 0x8D7D: 0x5CFF, //CJK UNIFIED IDEOGRAPH + 0x8D7E: 0x5D00, //CJK UNIFIED IDEOGRAPH + 0x8D80: 0x5D01, //CJK UNIFIED IDEOGRAPH + 0x8D81: 0x5D04, //CJK UNIFIED IDEOGRAPH + 0x8D82: 0x5D05, //CJK UNIFIED IDEOGRAPH + 0x8D83: 0x5D08, //CJK UNIFIED IDEOGRAPH + 0x8D84: 0x5D09, //CJK UNIFIED IDEOGRAPH + 0x8D85: 0x5D0A, //CJK UNIFIED IDEOGRAPH + 0x8D86: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0x8D87: 0x5D0C, //CJK UNIFIED IDEOGRAPH + 0x8D88: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0x8D89: 0x5D0F, //CJK UNIFIED IDEOGRAPH + 0x8D8A: 0x5D10, //CJK UNIFIED IDEOGRAPH + 0x8D8B: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0x8D8C: 0x5D12, //CJK UNIFIED IDEOGRAPH + 0x8D8D: 0x5D13, //CJK UNIFIED IDEOGRAPH + 0x8D8E: 0x5D15, //CJK UNIFIED IDEOGRAPH + 0x8D8F: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0x8D90: 0x5D18, //CJK UNIFIED IDEOGRAPH + 0x8D91: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0x8D92: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0x8D93: 0x5D1C, //CJK UNIFIED IDEOGRAPH + 0x8D94: 0x5D1D, //CJK UNIFIED IDEOGRAPH + 0x8D95: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0x8D96: 0x5D20, //CJK UNIFIED IDEOGRAPH + 0x8D97: 0x5D21, //CJK UNIFIED IDEOGRAPH + 0x8D98: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0x8D99: 0x5D23, //CJK UNIFIED IDEOGRAPH + 0x8D9A: 0x5D25, //CJK UNIFIED IDEOGRAPH + 0x8D9B: 0x5D28, //CJK UNIFIED IDEOGRAPH + 0x8D9C: 0x5D2A, //CJK UNIFIED IDEOGRAPH + 0x8D9D: 0x5D2B, //CJK UNIFIED IDEOGRAPH + 0x8D9E: 0x5D2C, //CJK UNIFIED IDEOGRAPH + 0x8D9F: 0x5D2F, //CJK UNIFIED IDEOGRAPH + 0x8DA0: 0x5D30, //CJK UNIFIED IDEOGRAPH + 0x8DA1: 0x5D31, //CJK UNIFIED IDEOGRAPH + 0x8DA2: 0x5D32, //CJK UNIFIED IDEOGRAPH + 0x8DA3: 0x5D33, //CJK UNIFIED IDEOGRAPH + 0x8DA4: 0x5D35, //CJK UNIFIED IDEOGRAPH + 0x8DA5: 0x5D36, //CJK UNIFIED IDEOGRAPH + 0x8DA6: 0x5D37, //CJK UNIFIED IDEOGRAPH + 0x8DA7: 0x5D38, //CJK UNIFIED IDEOGRAPH + 0x8DA8: 0x5D39, //CJK UNIFIED IDEOGRAPH + 0x8DA9: 0x5D3A, //CJK UNIFIED IDEOGRAPH + 0x8DAA: 0x5D3B, //CJK UNIFIED IDEOGRAPH + 0x8DAB: 0x5D3C, //CJK UNIFIED IDEOGRAPH + 0x8DAC: 0x5D3F, //CJK UNIFIED IDEOGRAPH + 0x8DAD: 0x5D40, //CJK UNIFIED IDEOGRAPH + 0x8DAE: 0x5D41, //CJK UNIFIED IDEOGRAPH + 0x8DAF: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0x8DB0: 0x5D43, //CJK UNIFIED IDEOGRAPH + 0x8DB1: 0x5D44, //CJK UNIFIED IDEOGRAPH + 0x8DB2: 0x5D45, //CJK UNIFIED IDEOGRAPH + 0x8DB3: 0x5D46, //CJK UNIFIED IDEOGRAPH + 0x8DB4: 0x5D48, //CJK UNIFIED IDEOGRAPH + 0x8DB5: 0x5D49, //CJK UNIFIED IDEOGRAPH + 0x8DB6: 0x5D4D, //CJK UNIFIED IDEOGRAPH + 0x8DB7: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0x8DB8: 0x5D4F, //CJK UNIFIED IDEOGRAPH + 0x8DB9: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0x8DBA: 0x5D51, //CJK UNIFIED IDEOGRAPH + 0x8DBB: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0x8DBC: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0x8DBD: 0x5D54, //CJK UNIFIED IDEOGRAPH + 0x8DBE: 0x5D55, //CJK UNIFIED IDEOGRAPH + 0x8DBF: 0x5D56, //CJK UNIFIED IDEOGRAPH + 0x8DC0: 0x5D57, //CJK UNIFIED IDEOGRAPH + 0x8DC1: 0x5D59, //CJK UNIFIED IDEOGRAPH + 0x8DC2: 0x5D5A, //CJK UNIFIED IDEOGRAPH + 0x8DC3: 0x5D5C, //CJK UNIFIED IDEOGRAPH + 0x8DC4: 0x5D5E, //CJK UNIFIED IDEOGRAPH + 0x8DC5: 0x5D5F, //CJK UNIFIED IDEOGRAPH + 0x8DC6: 0x5D60, //CJK UNIFIED IDEOGRAPH + 0x8DC7: 0x5D61, //CJK UNIFIED IDEOGRAPH + 0x8DC8: 0x5D62, //CJK UNIFIED IDEOGRAPH + 0x8DC9: 0x5D63, //CJK UNIFIED IDEOGRAPH + 0x8DCA: 0x5D64, //CJK UNIFIED IDEOGRAPH + 0x8DCB: 0x5D65, //CJK UNIFIED IDEOGRAPH + 0x8DCC: 0x5D66, //CJK UNIFIED IDEOGRAPH + 0x8DCD: 0x5D67, //CJK UNIFIED IDEOGRAPH + 0x8DCE: 0x5D68, //CJK UNIFIED IDEOGRAPH + 0x8DCF: 0x5D6A, //CJK UNIFIED IDEOGRAPH + 0x8DD0: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0x8DD1: 0x5D6E, //CJK UNIFIED IDEOGRAPH + 0x8DD2: 0x5D70, //CJK UNIFIED IDEOGRAPH + 0x8DD3: 0x5D71, //CJK UNIFIED IDEOGRAPH + 0x8DD4: 0x5D72, //CJK UNIFIED IDEOGRAPH + 0x8DD5: 0x5D73, //CJK UNIFIED IDEOGRAPH + 0x8DD6: 0x5D75, //CJK UNIFIED IDEOGRAPH + 0x8DD7: 0x5D76, //CJK UNIFIED IDEOGRAPH + 0x8DD8: 0x5D77, //CJK UNIFIED IDEOGRAPH + 0x8DD9: 0x5D78, //CJK UNIFIED IDEOGRAPH + 0x8DDA: 0x5D79, //CJK UNIFIED IDEOGRAPH + 0x8DDB: 0x5D7A, //CJK UNIFIED IDEOGRAPH + 0x8DDC: 0x5D7B, //CJK UNIFIED IDEOGRAPH + 0x8DDD: 0x5D7C, //CJK UNIFIED IDEOGRAPH + 0x8DDE: 0x5D7D, //CJK UNIFIED IDEOGRAPH + 0x8DDF: 0x5D7E, //CJK UNIFIED IDEOGRAPH + 0x8DE0: 0x5D7F, //CJK UNIFIED IDEOGRAPH + 0x8DE1: 0x5D80, //CJK UNIFIED IDEOGRAPH + 0x8DE2: 0x5D81, //CJK UNIFIED IDEOGRAPH + 0x8DE3: 0x5D83, //CJK UNIFIED IDEOGRAPH + 0x8DE4: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0x8DE5: 0x5D85, //CJK UNIFIED IDEOGRAPH + 0x8DE6: 0x5D86, //CJK UNIFIED IDEOGRAPH + 0x8DE7: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0x8DE8: 0x5D88, //CJK UNIFIED IDEOGRAPH + 0x8DE9: 0x5D89, //CJK UNIFIED IDEOGRAPH + 0x8DEA: 0x5D8A, //CJK UNIFIED IDEOGRAPH + 0x8DEB: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0x8DEC: 0x5D8C, //CJK UNIFIED IDEOGRAPH + 0x8DED: 0x5D8D, //CJK UNIFIED IDEOGRAPH + 0x8DEE: 0x5D8E, //CJK UNIFIED IDEOGRAPH + 0x8DEF: 0x5D8F, //CJK UNIFIED IDEOGRAPH + 0x8DF0: 0x5D90, //CJK UNIFIED IDEOGRAPH + 0x8DF1: 0x5D91, //CJK UNIFIED IDEOGRAPH + 0x8DF2: 0x5D92, //CJK UNIFIED IDEOGRAPH + 0x8DF3: 0x5D93, //CJK UNIFIED IDEOGRAPH + 0x8DF4: 0x5D94, //CJK UNIFIED IDEOGRAPH + 0x8DF5: 0x5D95, //CJK UNIFIED IDEOGRAPH + 0x8DF6: 0x5D96, //CJK UNIFIED IDEOGRAPH + 0x8DF7: 0x5D97, //CJK UNIFIED IDEOGRAPH + 0x8DF8: 0x5D98, //CJK UNIFIED IDEOGRAPH + 0x8DF9: 0x5D9A, //CJK UNIFIED IDEOGRAPH + 0x8DFA: 0x5D9B, //CJK UNIFIED IDEOGRAPH + 0x8DFB: 0x5D9C, //CJK UNIFIED IDEOGRAPH + 0x8DFC: 0x5D9E, //CJK UNIFIED IDEOGRAPH + 0x8DFD: 0x5D9F, //CJK UNIFIED IDEOGRAPH + 0x8DFE: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0x8E40: 0x5DA1, //CJK UNIFIED IDEOGRAPH + 0x8E41: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0x8E42: 0x5DA3, //CJK UNIFIED IDEOGRAPH + 0x8E43: 0x5DA4, //CJK UNIFIED IDEOGRAPH + 0x8E44: 0x5DA5, //CJK UNIFIED IDEOGRAPH + 0x8E45: 0x5DA6, //CJK UNIFIED IDEOGRAPH + 0x8E46: 0x5DA7, //CJK UNIFIED IDEOGRAPH + 0x8E47: 0x5DA8, //CJK UNIFIED IDEOGRAPH + 0x8E48: 0x5DA9, //CJK UNIFIED IDEOGRAPH + 0x8E49: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0x8E4A: 0x5DAB, //CJK UNIFIED IDEOGRAPH + 0x8E4B: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0x8E4C: 0x5DAD, //CJK UNIFIED IDEOGRAPH + 0x8E4D: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0x8E4E: 0x5DAF, //CJK UNIFIED IDEOGRAPH + 0x8E4F: 0x5DB0, //CJK UNIFIED IDEOGRAPH + 0x8E50: 0x5DB1, //CJK UNIFIED IDEOGRAPH + 0x8E51: 0x5DB2, //CJK UNIFIED IDEOGRAPH + 0x8E52: 0x5DB3, //CJK UNIFIED IDEOGRAPH + 0x8E53: 0x5DB4, //CJK UNIFIED IDEOGRAPH + 0x8E54: 0x5DB5, //CJK UNIFIED IDEOGRAPH + 0x8E55: 0x5DB6, //CJK UNIFIED IDEOGRAPH + 0x8E56: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0x8E57: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0x8E58: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0x8E59: 0x5DBB, //CJK UNIFIED IDEOGRAPH + 0x8E5A: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0x8E5B: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0x8E5C: 0x5DBE, //CJK UNIFIED IDEOGRAPH + 0x8E5D: 0x5DBF, //CJK UNIFIED IDEOGRAPH + 0x8E5E: 0x5DC0, //CJK UNIFIED IDEOGRAPH + 0x8E5F: 0x5DC1, //CJK UNIFIED IDEOGRAPH + 0x8E60: 0x5DC2, //CJK UNIFIED IDEOGRAPH + 0x8E61: 0x5DC3, //CJK UNIFIED IDEOGRAPH + 0x8E62: 0x5DC4, //CJK UNIFIED IDEOGRAPH + 0x8E63: 0x5DC6, //CJK UNIFIED IDEOGRAPH + 0x8E64: 0x5DC7, //CJK UNIFIED IDEOGRAPH + 0x8E65: 0x5DC8, //CJK UNIFIED IDEOGRAPH + 0x8E66: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0x8E67: 0x5DCA, //CJK UNIFIED IDEOGRAPH + 0x8E68: 0x5DCB, //CJK UNIFIED IDEOGRAPH + 0x8E69: 0x5DCC, //CJK UNIFIED IDEOGRAPH + 0x8E6A: 0x5DCE, //CJK UNIFIED IDEOGRAPH + 0x8E6B: 0x5DCF, //CJK UNIFIED IDEOGRAPH + 0x8E6C: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0x8E6D: 0x5DD1, //CJK UNIFIED IDEOGRAPH + 0x8E6E: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0x8E6F: 0x5DD3, //CJK UNIFIED IDEOGRAPH + 0x8E70: 0x5DD4, //CJK UNIFIED IDEOGRAPH + 0x8E71: 0x5DD5, //CJK UNIFIED IDEOGRAPH + 0x8E72: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0x8E73: 0x5DD7, //CJK UNIFIED IDEOGRAPH + 0x8E74: 0x5DD8, //CJK UNIFIED IDEOGRAPH + 0x8E75: 0x5DD9, //CJK UNIFIED IDEOGRAPH + 0x8E76: 0x5DDA, //CJK UNIFIED IDEOGRAPH + 0x8E77: 0x5DDC, //CJK UNIFIED IDEOGRAPH + 0x8E78: 0x5DDF, //CJK UNIFIED IDEOGRAPH + 0x8E79: 0x5DE0, //CJK UNIFIED IDEOGRAPH + 0x8E7A: 0x5DE3, //CJK UNIFIED IDEOGRAPH + 0x8E7B: 0x5DE4, //CJK UNIFIED IDEOGRAPH + 0x8E7C: 0x5DEA, //CJK UNIFIED IDEOGRAPH + 0x8E7D: 0x5DEC, //CJK UNIFIED IDEOGRAPH + 0x8E7E: 0x5DED, //CJK UNIFIED IDEOGRAPH + 0x8E80: 0x5DF0, //CJK UNIFIED IDEOGRAPH + 0x8E81: 0x5DF5, //CJK UNIFIED IDEOGRAPH + 0x8E82: 0x5DF6, //CJK UNIFIED IDEOGRAPH + 0x8E83: 0x5DF8, //CJK UNIFIED IDEOGRAPH + 0x8E84: 0x5DF9, //CJK UNIFIED IDEOGRAPH + 0x8E85: 0x5DFA, //CJK UNIFIED IDEOGRAPH + 0x8E86: 0x5DFB, //CJK UNIFIED IDEOGRAPH + 0x8E87: 0x5DFC, //CJK UNIFIED IDEOGRAPH + 0x8E88: 0x5DFF, //CJK UNIFIED IDEOGRAPH + 0x8E89: 0x5E00, //CJK UNIFIED IDEOGRAPH + 0x8E8A: 0x5E04, //CJK UNIFIED IDEOGRAPH + 0x8E8B: 0x5E07, //CJK UNIFIED IDEOGRAPH + 0x8E8C: 0x5E09, //CJK UNIFIED IDEOGRAPH + 0x8E8D: 0x5E0A, //CJK UNIFIED IDEOGRAPH + 0x8E8E: 0x5E0B, //CJK UNIFIED IDEOGRAPH + 0x8E8F: 0x5E0D, //CJK UNIFIED IDEOGRAPH + 0x8E90: 0x5E0E, //CJK UNIFIED IDEOGRAPH + 0x8E91: 0x5E12, //CJK UNIFIED IDEOGRAPH + 0x8E92: 0x5E13, //CJK UNIFIED IDEOGRAPH + 0x8E93: 0x5E17, //CJK UNIFIED IDEOGRAPH + 0x8E94: 0x5E1E, //CJK UNIFIED IDEOGRAPH + 0x8E95: 0x5E1F, //CJK UNIFIED IDEOGRAPH + 0x8E96: 0x5E20, //CJK UNIFIED IDEOGRAPH + 0x8E97: 0x5E21, //CJK UNIFIED IDEOGRAPH + 0x8E98: 0x5E22, //CJK UNIFIED IDEOGRAPH + 0x8E99: 0x5E23, //CJK UNIFIED IDEOGRAPH + 0x8E9A: 0x5E24, //CJK UNIFIED IDEOGRAPH + 0x8E9B: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0x8E9C: 0x5E28, //CJK UNIFIED IDEOGRAPH + 0x8E9D: 0x5E29, //CJK UNIFIED IDEOGRAPH + 0x8E9E: 0x5E2A, //CJK UNIFIED IDEOGRAPH + 0x8E9F: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0x8EA0: 0x5E2C, //CJK UNIFIED IDEOGRAPH + 0x8EA1: 0x5E2F, //CJK UNIFIED IDEOGRAPH + 0x8EA2: 0x5E30, //CJK UNIFIED IDEOGRAPH + 0x8EA3: 0x5E32, //CJK UNIFIED IDEOGRAPH + 0x8EA4: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0x8EA5: 0x5E34, //CJK UNIFIED IDEOGRAPH + 0x8EA6: 0x5E35, //CJK UNIFIED IDEOGRAPH + 0x8EA7: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0x8EA8: 0x5E39, //CJK UNIFIED IDEOGRAPH + 0x8EA9: 0x5E3A, //CJK UNIFIED IDEOGRAPH + 0x8EAA: 0x5E3E, //CJK UNIFIED IDEOGRAPH + 0x8EAB: 0x5E3F, //CJK UNIFIED IDEOGRAPH + 0x8EAC: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0x8EAD: 0x5E41, //CJK UNIFIED IDEOGRAPH + 0x8EAE: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0x8EAF: 0x5E46, //CJK UNIFIED IDEOGRAPH + 0x8EB0: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0x8EB1: 0x5E48, //CJK UNIFIED IDEOGRAPH + 0x8EB2: 0x5E49, //CJK UNIFIED IDEOGRAPH + 0x8EB3: 0x5E4A, //CJK UNIFIED IDEOGRAPH + 0x8EB4: 0x5E4B, //CJK UNIFIED IDEOGRAPH + 0x8EB5: 0x5E4D, //CJK UNIFIED IDEOGRAPH + 0x8EB6: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0x8EB7: 0x5E4F, //CJK UNIFIED IDEOGRAPH + 0x8EB8: 0x5E50, //CJK UNIFIED IDEOGRAPH + 0x8EB9: 0x5E51, //CJK UNIFIED IDEOGRAPH + 0x8EBA: 0x5E52, //CJK UNIFIED IDEOGRAPH + 0x8EBB: 0x5E53, //CJK UNIFIED IDEOGRAPH + 0x8EBC: 0x5E56, //CJK UNIFIED IDEOGRAPH + 0x8EBD: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0x8EBE: 0x5E58, //CJK UNIFIED IDEOGRAPH + 0x8EBF: 0x5E59, //CJK UNIFIED IDEOGRAPH + 0x8EC0: 0x5E5A, //CJK UNIFIED IDEOGRAPH + 0x8EC1: 0x5E5C, //CJK UNIFIED IDEOGRAPH + 0x8EC2: 0x5E5D, //CJK UNIFIED IDEOGRAPH + 0x8EC3: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0x8EC4: 0x5E60, //CJK UNIFIED IDEOGRAPH + 0x8EC5: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0x8EC6: 0x5E64, //CJK UNIFIED IDEOGRAPH + 0x8EC7: 0x5E65, //CJK UNIFIED IDEOGRAPH + 0x8EC8: 0x5E66, //CJK UNIFIED IDEOGRAPH + 0x8EC9: 0x5E67, //CJK UNIFIED IDEOGRAPH + 0x8ECA: 0x5E68, //CJK UNIFIED IDEOGRAPH + 0x8ECB: 0x5E69, //CJK UNIFIED IDEOGRAPH + 0x8ECC: 0x5E6A, //CJK UNIFIED IDEOGRAPH + 0x8ECD: 0x5E6B, //CJK UNIFIED IDEOGRAPH + 0x8ECE: 0x5E6C, //CJK UNIFIED IDEOGRAPH + 0x8ECF: 0x5E6D, //CJK UNIFIED IDEOGRAPH + 0x8ED0: 0x5E6E, //CJK UNIFIED IDEOGRAPH + 0x8ED1: 0x5E6F, //CJK UNIFIED IDEOGRAPH + 0x8ED2: 0x5E70, //CJK UNIFIED IDEOGRAPH + 0x8ED3: 0x5E71, //CJK UNIFIED IDEOGRAPH + 0x8ED4: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0x8ED5: 0x5E77, //CJK UNIFIED IDEOGRAPH + 0x8ED6: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0x8ED7: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0x8ED8: 0x5E81, //CJK UNIFIED IDEOGRAPH + 0x8ED9: 0x5E82, //CJK UNIFIED IDEOGRAPH + 0x8EDA: 0x5E83, //CJK UNIFIED IDEOGRAPH + 0x8EDB: 0x5E85, //CJK UNIFIED IDEOGRAPH + 0x8EDC: 0x5E88, //CJK UNIFIED IDEOGRAPH + 0x8EDD: 0x5E89, //CJK UNIFIED IDEOGRAPH + 0x8EDE: 0x5E8C, //CJK UNIFIED IDEOGRAPH + 0x8EDF: 0x5E8D, //CJK UNIFIED IDEOGRAPH + 0x8EE0: 0x5E8E, //CJK UNIFIED IDEOGRAPH + 0x8EE1: 0x5E92, //CJK UNIFIED IDEOGRAPH + 0x8EE2: 0x5E98, //CJK UNIFIED IDEOGRAPH + 0x8EE3: 0x5E9B, //CJK UNIFIED IDEOGRAPH + 0x8EE4: 0x5E9D, //CJK UNIFIED IDEOGRAPH + 0x8EE5: 0x5EA1, //CJK UNIFIED IDEOGRAPH + 0x8EE6: 0x5EA2, //CJK UNIFIED IDEOGRAPH + 0x8EE7: 0x5EA3, //CJK UNIFIED IDEOGRAPH + 0x8EE8: 0x5EA4, //CJK UNIFIED IDEOGRAPH + 0x8EE9: 0x5EA8, //CJK UNIFIED IDEOGRAPH + 0x8EEA: 0x5EA9, //CJK UNIFIED IDEOGRAPH + 0x8EEB: 0x5EAA, //CJK UNIFIED IDEOGRAPH + 0x8EEC: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0x8EED: 0x5EAC, //CJK UNIFIED IDEOGRAPH + 0x8EEE: 0x5EAE, //CJK UNIFIED IDEOGRAPH + 0x8EEF: 0x5EAF, //CJK UNIFIED IDEOGRAPH + 0x8EF0: 0x5EB0, //CJK UNIFIED IDEOGRAPH + 0x8EF1: 0x5EB1, //CJK UNIFIED IDEOGRAPH + 0x8EF2: 0x5EB2, //CJK UNIFIED IDEOGRAPH + 0x8EF3: 0x5EB4, //CJK UNIFIED IDEOGRAPH + 0x8EF4: 0x5EBA, //CJK UNIFIED IDEOGRAPH + 0x8EF5: 0x5EBB, //CJK UNIFIED IDEOGRAPH + 0x8EF6: 0x5EBC, //CJK UNIFIED IDEOGRAPH + 0x8EF7: 0x5EBD, //CJK UNIFIED IDEOGRAPH + 0x8EF8: 0x5EBF, //CJK UNIFIED IDEOGRAPH + 0x8EF9: 0x5EC0, //CJK UNIFIED IDEOGRAPH + 0x8EFA: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0x8EFB: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0x8EFC: 0x5EC3, //CJK UNIFIED IDEOGRAPH + 0x8EFD: 0x5EC4, //CJK UNIFIED IDEOGRAPH + 0x8EFE: 0x5EC5, //CJK UNIFIED IDEOGRAPH + 0x8F40: 0x5EC6, //CJK UNIFIED IDEOGRAPH + 0x8F41: 0x5EC7, //CJK UNIFIED IDEOGRAPH + 0x8F42: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0x8F43: 0x5ECB, //CJK UNIFIED IDEOGRAPH + 0x8F44: 0x5ECC, //CJK UNIFIED IDEOGRAPH + 0x8F45: 0x5ECD, //CJK UNIFIED IDEOGRAPH + 0x8F46: 0x5ECE, //CJK UNIFIED IDEOGRAPH + 0x8F47: 0x5ECF, //CJK UNIFIED IDEOGRAPH + 0x8F48: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0x8F49: 0x5ED4, //CJK UNIFIED IDEOGRAPH + 0x8F4A: 0x5ED5, //CJK UNIFIED IDEOGRAPH + 0x8F4B: 0x5ED7, //CJK UNIFIED IDEOGRAPH + 0x8F4C: 0x5ED8, //CJK UNIFIED IDEOGRAPH + 0x8F4D: 0x5ED9, //CJK UNIFIED IDEOGRAPH + 0x8F4E: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0x8F4F: 0x5EDC, //CJK UNIFIED IDEOGRAPH + 0x8F50: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0x8F51: 0x5EDE, //CJK UNIFIED IDEOGRAPH + 0x8F52: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0x8F53: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0x8F54: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0x8F55: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0x8F56: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0x8F57: 0x5EE4, //CJK UNIFIED IDEOGRAPH + 0x8F58: 0x5EE5, //CJK UNIFIED IDEOGRAPH + 0x8F59: 0x5EE6, //CJK UNIFIED IDEOGRAPH + 0x8F5A: 0x5EE7, //CJK UNIFIED IDEOGRAPH + 0x8F5B: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0x8F5C: 0x5EEB, //CJK UNIFIED IDEOGRAPH + 0x8F5D: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0x8F5E: 0x5EED, //CJK UNIFIED IDEOGRAPH + 0x8F5F: 0x5EEE, //CJK UNIFIED IDEOGRAPH + 0x8F60: 0x5EEF, //CJK UNIFIED IDEOGRAPH + 0x8F61: 0x5EF0, //CJK UNIFIED IDEOGRAPH + 0x8F62: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0x8F63: 0x5EF2, //CJK UNIFIED IDEOGRAPH + 0x8F64: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0x8F65: 0x5EF5, //CJK UNIFIED IDEOGRAPH + 0x8F66: 0x5EF8, //CJK UNIFIED IDEOGRAPH + 0x8F67: 0x5EF9, //CJK UNIFIED IDEOGRAPH + 0x8F68: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0x8F69: 0x5EFC, //CJK UNIFIED IDEOGRAPH + 0x8F6A: 0x5EFD, //CJK UNIFIED IDEOGRAPH + 0x8F6B: 0x5F05, //CJK UNIFIED IDEOGRAPH + 0x8F6C: 0x5F06, //CJK UNIFIED IDEOGRAPH + 0x8F6D: 0x5F07, //CJK UNIFIED IDEOGRAPH + 0x8F6E: 0x5F09, //CJK UNIFIED IDEOGRAPH + 0x8F6F: 0x5F0C, //CJK UNIFIED IDEOGRAPH + 0x8F70: 0x5F0D, //CJK UNIFIED IDEOGRAPH + 0x8F71: 0x5F0E, //CJK UNIFIED IDEOGRAPH + 0x8F72: 0x5F10, //CJK UNIFIED IDEOGRAPH + 0x8F73: 0x5F12, //CJK UNIFIED IDEOGRAPH + 0x8F74: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0x8F75: 0x5F16, //CJK UNIFIED IDEOGRAPH + 0x8F76: 0x5F19, //CJK UNIFIED IDEOGRAPH + 0x8F77: 0x5F1A, //CJK UNIFIED IDEOGRAPH + 0x8F78: 0x5F1C, //CJK UNIFIED IDEOGRAPH + 0x8F79: 0x5F1D, //CJK UNIFIED IDEOGRAPH + 0x8F7A: 0x5F1E, //CJK UNIFIED IDEOGRAPH + 0x8F7B: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0x8F7C: 0x5F22, //CJK UNIFIED IDEOGRAPH + 0x8F7D: 0x5F23, //CJK UNIFIED IDEOGRAPH + 0x8F7E: 0x5F24, //CJK UNIFIED IDEOGRAPH + 0x8F80: 0x5F28, //CJK UNIFIED IDEOGRAPH + 0x8F81: 0x5F2B, //CJK UNIFIED IDEOGRAPH + 0x8F82: 0x5F2C, //CJK UNIFIED IDEOGRAPH + 0x8F83: 0x5F2E, //CJK UNIFIED IDEOGRAPH + 0x8F84: 0x5F30, //CJK UNIFIED IDEOGRAPH + 0x8F85: 0x5F32, //CJK UNIFIED IDEOGRAPH + 0x8F86: 0x5F33, //CJK UNIFIED IDEOGRAPH + 0x8F87: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0x8F88: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0x8F89: 0x5F36, //CJK UNIFIED IDEOGRAPH + 0x8F8A: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0x8F8B: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0x8F8C: 0x5F3B, //CJK UNIFIED IDEOGRAPH + 0x8F8D: 0x5F3D, //CJK UNIFIED IDEOGRAPH + 0x8F8E: 0x5F3E, //CJK UNIFIED IDEOGRAPH + 0x8F8F: 0x5F3F, //CJK UNIFIED IDEOGRAPH + 0x8F90: 0x5F41, //CJK UNIFIED IDEOGRAPH + 0x8F91: 0x5F42, //CJK UNIFIED IDEOGRAPH + 0x8F92: 0x5F43, //CJK UNIFIED IDEOGRAPH + 0x8F93: 0x5F44, //CJK UNIFIED IDEOGRAPH + 0x8F94: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0x8F95: 0x5F46, //CJK UNIFIED IDEOGRAPH + 0x8F96: 0x5F47, //CJK UNIFIED IDEOGRAPH + 0x8F97: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0x8F98: 0x5F49, //CJK UNIFIED IDEOGRAPH + 0x8F99: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0x8F9A: 0x5F4B, //CJK UNIFIED IDEOGRAPH + 0x8F9B: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0x8F9C: 0x5F4D, //CJK UNIFIED IDEOGRAPH + 0x8F9D: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0x8F9E: 0x5F4F, //CJK UNIFIED IDEOGRAPH + 0x8F9F: 0x5F51, //CJK UNIFIED IDEOGRAPH + 0x8FA0: 0x5F54, //CJK UNIFIED IDEOGRAPH + 0x8FA1: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0x8FA2: 0x5F5A, //CJK UNIFIED IDEOGRAPH + 0x8FA3: 0x5F5B, //CJK UNIFIED IDEOGRAPH + 0x8FA4: 0x5F5C, //CJK UNIFIED IDEOGRAPH + 0x8FA5: 0x5F5E, //CJK UNIFIED IDEOGRAPH + 0x8FA6: 0x5F5F, //CJK UNIFIED IDEOGRAPH + 0x8FA7: 0x5F60, //CJK UNIFIED IDEOGRAPH + 0x8FA8: 0x5F63, //CJK UNIFIED IDEOGRAPH + 0x8FA9: 0x5F65, //CJK UNIFIED IDEOGRAPH + 0x8FAA: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0x8FAB: 0x5F68, //CJK UNIFIED IDEOGRAPH + 0x8FAC: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0x8FAD: 0x5F6E, //CJK UNIFIED IDEOGRAPH + 0x8FAE: 0x5F6F, //CJK UNIFIED IDEOGRAPH + 0x8FAF: 0x5F72, //CJK UNIFIED IDEOGRAPH + 0x8FB0: 0x5F74, //CJK UNIFIED IDEOGRAPH + 0x8FB1: 0x5F75, //CJK UNIFIED IDEOGRAPH + 0x8FB2: 0x5F76, //CJK UNIFIED IDEOGRAPH + 0x8FB3: 0x5F78, //CJK UNIFIED IDEOGRAPH + 0x8FB4: 0x5F7A, //CJK UNIFIED IDEOGRAPH + 0x8FB5: 0x5F7D, //CJK UNIFIED IDEOGRAPH + 0x8FB6: 0x5F7E, //CJK UNIFIED IDEOGRAPH + 0x8FB7: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0x8FB8: 0x5F83, //CJK UNIFIED IDEOGRAPH + 0x8FB9: 0x5F86, //CJK UNIFIED IDEOGRAPH + 0x8FBA: 0x5F8D, //CJK UNIFIED IDEOGRAPH + 0x8FBB: 0x5F8E, //CJK UNIFIED IDEOGRAPH + 0x8FBC: 0x5F8F, //CJK UNIFIED IDEOGRAPH + 0x8FBD: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0x8FBE: 0x5F93, //CJK UNIFIED IDEOGRAPH + 0x8FBF: 0x5F94, //CJK UNIFIED IDEOGRAPH + 0x8FC0: 0x5F96, //CJK UNIFIED IDEOGRAPH + 0x8FC1: 0x5F9A, //CJK UNIFIED IDEOGRAPH + 0x8FC2: 0x5F9B, //CJK UNIFIED IDEOGRAPH + 0x8FC3: 0x5F9D, //CJK UNIFIED IDEOGRAPH + 0x8FC4: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0x8FC5: 0x5F9F, //CJK UNIFIED IDEOGRAPH + 0x8FC6: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0x8FC7: 0x5FA2, //CJK UNIFIED IDEOGRAPH + 0x8FC8: 0x5FA3, //CJK UNIFIED IDEOGRAPH + 0x8FC9: 0x5FA4, //CJK UNIFIED IDEOGRAPH + 0x8FCA: 0x5FA5, //CJK UNIFIED IDEOGRAPH + 0x8FCB: 0x5FA6, //CJK UNIFIED IDEOGRAPH + 0x8FCC: 0x5FA7, //CJK UNIFIED IDEOGRAPH + 0x8FCD: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0x8FCE: 0x5FAB, //CJK UNIFIED IDEOGRAPH + 0x8FCF: 0x5FAC, //CJK UNIFIED IDEOGRAPH + 0x8FD0: 0x5FAF, //CJK UNIFIED IDEOGRAPH + 0x8FD1: 0x5FB0, //CJK UNIFIED IDEOGRAPH + 0x8FD2: 0x5FB1, //CJK UNIFIED IDEOGRAPH + 0x8FD3: 0x5FB2, //CJK UNIFIED IDEOGRAPH + 0x8FD4: 0x5FB3, //CJK UNIFIED IDEOGRAPH + 0x8FD5: 0x5FB4, //CJK UNIFIED IDEOGRAPH + 0x8FD6: 0x5FB6, //CJK UNIFIED IDEOGRAPH + 0x8FD7: 0x5FB8, //CJK UNIFIED IDEOGRAPH + 0x8FD8: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0x8FD9: 0x5FBA, //CJK UNIFIED IDEOGRAPH + 0x8FDA: 0x5FBB, //CJK UNIFIED IDEOGRAPH + 0x8FDB: 0x5FBE, //CJK UNIFIED IDEOGRAPH + 0x8FDC: 0x5FBF, //CJK UNIFIED IDEOGRAPH + 0x8FDD: 0x5FC0, //CJK UNIFIED IDEOGRAPH + 0x8FDE: 0x5FC1, //CJK UNIFIED IDEOGRAPH + 0x8FDF: 0x5FC2, //CJK UNIFIED IDEOGRAPH + 0x8FE0: 0x5FC7, //CJK UNIFIED IDEOGRAPH + 0x8FE1: 0x5FC8, //CJK UNIFIED IDEOGRAPH + 0x8FE2: 0x5FCA, //CJK UNIFIED IDEOGRAPH + 0x8FE3: 0x5FCB, //CJK UNIFIED IDEOGRAPH + 0x8FE4: 0x5FCE, //CJK UNIFIED IDEOGRAPH + 0x8FE5: 0x5FD3, //CJK UNIFIED IDEOGRAPH + 0x8FE6: 0x5FD4, //CJK UNIFIED IDEOGRAPH + 0x8FE7: 0x5FD5, //CJK UNIFIED IDEOGRAPH + 0x8FE8: 0x5FDA, //CJK UNIFIED IDEOGRAPH + 0x8FE9: 0x5FDB, //CJK UNIFIED IDEOGRAPH + 0x8FEA: 0x5FDC, //CJK UNIFIED IDEOGRAPH + 0x8FEB: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0x8FEC: 0x5FDF, //CJK UNIFIED IDEOGRAPH + 0x8FED: 0x5FE2, //CJK UNIFIED IDEOGRAPH + 0x8FEE: 0x5FE3, //CJK UNIFIED IDEOGRAPH + 0x8FEF: 0x5FE5, //CJK UNIFIED IDEOGRAPH + 0x8FF0: 0x5FE6, //CJK UNIFIED IDEOGRAPH + 0x8FF1: 0x5FE8, //CJK UNIFIED IDEOGRAPH + 0x8FF2: 0x5FE9, //CJK UNIFIED IDEOGRAPH + 0x8FF3: 0x5FEC, //CJK UNIFIED IDEOGRAPH + 0x8FF4: 0x5FEF, //CJK UNIFIED IDEOGRAPH + 0x8FF5: 0x5FF0, //CJK UNIFIED IDEOGRAPH + 0x8FF6: 0x5FF2, //CJK UNIFIED IDEOGRAPH + 0x8FF7: 0x5FF3, //CJK UNIFIED IDEOGRAPH + 0x8FF8: 0x5FF4, //CJK UNIFIED IDEOGRAPH + 0x8FF9: 0x5FF6, //CJK UNIFIED IDEOGRAPH + 0x8FFA: 0x5FF7, //CJK UNIFIED IDEOGRAPH + 0x8FFB: 0x5FF9, //CJK UNIFIED IDEOGRAPH + 0x8FFC: 0x5FFA, //CJK UNIFIED IDEOGRAPH + 0x8FFD: 0x5FFC, //CJK UNIFIED IDEOGRAPH + 0x8FFE: 0x6007, //CJK UNIFIED IDEOGRAPH + 0x9040: 0x6008, //CJK UNIFIED IDEOGRAPH + 0x9041: 0x6009, //CJK UNIFIED IDEOGRAPH + 0x9042: 0x600B, //CJK UNIFIED IDEOGRAPH + 0x9043: 0x600C, //CJK UNIFIED IDEOGRAPH + 0x9044: 0x6010, //CJK UNIFIED IDEOGRAPH + 0x9045: 0x6011, //CJK UNIFIED IDEOGRAPH + 0x9046: 0x6013, //CJK UNIFIED IDEOGRAPH + 0x9047: 0x6017, //CJK UNIFIED IDEOGRAPH + 0x9048: 0x6018, //CJK UNIFIED IDEOGRAPH + 0x9049: 0x601A, //CJK UNIFIED IDEOGRAPH + 0x904A: 0x601E, //CJK UNIFIED IDEOGRAPH + 0x904B: 0x601F, //CJK UNIFIED IDEOGRAPH + 0x904C: 0x6022, //CJK UNIFIED IDEOGRAPH + 0x904D: 0x6023, //CJK UNIFIED IDEOGRAPH + 0x904E: 0x6024, //CJK UNIFIED IDEOGRAPH + 0x904F: 0x602C, //CJK UNIFIED IDEOGRAPH + 0x9050: 0x602D, //CJK UNIFIED IDEOGRAPH + 0x9051: 0x602E, //CJK UNIFIED IDEOGRAPH + 0x9052: 0x6030, //CJK UNIFIED IDEOGRAPH + 0x9053: 0x6031, //CJK UNIFIED IDEOGRAPH + 0x9054: 0x6032, //CJK UNIFIED IDEOGRAPH + 0x9055: 0x6033, //CJK UNIFIED IDEOGRAPH + 0x9056: 0x6034, //CJK UNIFIED IDEOGRAPH + 0x9057: 0x6036, //CJK UNIFIED IDEOGRAPH + 0x9058: 0x6037, //CJK UNIFIED IDEOGRAPH + 0x9059: 0x6038, //CJK UNIFIED IDEOGRAPH + 0x905A: 0x6039, //CJK UNIFIED IDEOGRAPH + 0x905B: 0x603A, //CJK UNIFIED IDEOGRAPH + 0x905C: 0x603D, //CJK UNIFIED IDEOGRAPH + 0x905D: 0x603E, //CJK UNIFIED IDEOGRAPH + 0x905E: 0x6040, //CJK UNIFIED IDEOGRAPH + 0x905F: 0x6044, //CJK UNIFIED IDEOGRAPH + 0x9060: 0x6045, //CJK UNIFIED IDEOGRAPH + 0x9061: 0x6046, //CJK UNIFIED IDEOGRAPH + 0x9062: 0x6047, //CJK UNIFIED IDEOGRAPH + 0x9063: 0x6048, //CJK UNIFIED IDEOGRAPH + 0x9064: 0x6049, //CJK UNIFIED IDEOGRAPH + 0x9065: 0x604A, //CJK UNIFIED IDEOGRAPH + 0x9066: 0x604C, //CJK UNIFIED IDEOGRAPH + 0x9067: 0x604E, //CJK UNIFIED IDEOGRAPH + 0x9068: 0x604F, //CJK UNIFIED IDEOGRAPH + 0x9069: 0x6051, //CJK UNIFIED IDEOGRAPH + 0x906A: 0x6053, //CJK UNIFIED IDEOGRAPH + 0x906B: 0x6054, //CJK UNIFIED IDEOGRAPH + 0x906C: 0x6056, //CJK UNIFIED IDEOGRAPH + 0x906D: 0x6057, //CJK UNIFIED IDEOGRAPH + 0x906E: 0x6058, //CJK UNIFIED IDEOGRAPH + 0x906F: 0x605B, //CJK UNIFIED IDEOGRAPH + 0x9070: 0x605C, //CJK UNIFIED IDEOGRAPH + 0x9071: 0x605E, //CJK UNIFIED IDEOGRAPH + 0x9072: 0x605F, //CJK UNIFIED IDEOGRAPH + 0x9073: 0x6060, //CJK UNIFIED IDEOGRAPH + 0x9074: 0x6061, //CJK UNIFIED IDEOGRAPH + 0x9075: 0x6065, //CJK UNIFIED IDEOGRAPH + 0x9076: 0x6066, //CJK UNIFIED IDEOGRAPH + 0x9077: 0x606E, //CJK UNIFIED IDEOGRAPH + 0x9078: 0x6071, //CJK UNIFIED IDEOGRAPH + 0x9079: 0x6072, //CJK UNIFIED IDEOGRAPH + 0x907A: 0x6074, //CJK UNIFIED IDEOGRAPH + 0x907B: 0x6075, //CJK UNIFIED IDEOGRAPH + 0x907C: 0x6077, //CJK UNIFIED IDEOGRAPH + 0x907D: 0x607E, //CJK UNIFIED IDEOGRAPH + 0x907E: 0x6080, //CJK UNIFIED IDEOGRAPH + 0x9080: 0x6081, //CJK UNIFIED IDEOGRAPH + 0x9081: 0x6082, //CJK UNIFIED IDEOGRAPH + 0x9082: 0x6085, //CJK UNIFIED IDEOGRAPH + 0x9083: 0x6086, //CJK UNIFIED IDEOGRAPH + 0x9084: 0x6087, //CJK UNIFIED IDEOGRAPH + 0x9085: 0x6088, //CJK UNIFIED IDEOGRAPH + 0x9086: 0x608A, //CJK UNIFIED IDEOGRAPH + 0x9087: 0x608B, //CJK UNIFIED IDEOGRAPH + 0x9088: 0x608E, //CJK UNIFIED IDEOGRAPH + 0x9089: 0x608F, //CJK UNIFIED IDEOGRAPH + 0x908A: 0x6090, //CJK UNIFIED IDEOGRAPH + 0x908B: 0x6091, //CJK UNIFIED IDEOGRAPH + 0x908C: 0x6093, //CJK UNIFIED IDEOGRAPH + 0x908D: 0x6095, //CJK UNIFIED IDEOGRAPH + 0x908E: 0x6097, //CJK UNIFIED IDEOGRAPH + 0x908F: 0x6098, //CJK UNIFIED IDEOGRAPH + 0x9090: 0x6099, //CJK UNIFIED IDEOGRAPH + 0x9091: 0x609C, //CJK UNIFIED IDEOGRAPH + 0x9092: 0x609E, //CJK UNIFIED IDEOGRAPH + 0x9093: 0x60A1, //CJK UNIFIED IDEOGRAPH + 0x9094: 0x60A2, //CJK UNIFIED IDEOGRAPH + 0x9095: 0x60A4, //CJK UNIFIED IDEOGRAPH + 0x9096: 0x60A5, //CJK UNIFIED IDEOGRAPH + 0x9097: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0x9098: 0x60A9, //CJK UNIFIED IDEOGRAPH + 0x9099: 0x60AA, //CJK UNIFIED IDEOGRAPH + 0x909A: 0x60AE, //CJK UNIFIED IDEOGRAPH + 0x909B: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0x909C: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0x909D: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0x909E: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0x909F: 0x60B7, //CJK UNIFIED IDEOGRAPH + 0x90A0: 0x60B9, //CJK UNIFIED IDEOGRAPH + 0x90A1: 0x60BA, //CJK UNIFIED IDEOGRAPH + 0x90A2: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0x90A3: 0x60BE, //CJK UNIFIED IDEOGRAPH + 0x90A4: 0x60BF, //CJK UNIFIED IDEOGRAPH + 0x90A5: 0x60C0, //CJK UNIFIED IDEOGRAPH + 0x90A6: 0x60C1, //CJK UNIFIED IDEOGRAPH + 0x90A7: 0x60C2, //CJK UNIFIED IDEOGRAPH + 0x90A8: 0x60C3, //CJK UNIFIED IDEOGRAPH + 0x90A9: 0x60C4, //CJK UNIFIED IDEOGRAPH + 0x90AA: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0x90AB: 0x60C8, //CJK UNIFIED IDEOGRAPH + 0x90AC: 0x60C9, //CJK UNIFIED IDEOGRAPH + 0x90AD: 0x60CC, //CJK UNIFIED IDEOGRAPH + 0x90AE: 0x60CD, //CJK UNIFIED IDEOGRAPH + 0x90AF: 0x60CE, //CJK UNIFIED IDEOGRAPH + 0x90B0: 0x60CF, //CJK UNIFIED IDEOGRAPH + 0x90B1: 0x60D0, //CJK UNIFIED IDEOGRAPH + 0x90B2: 0x60D2, //CJK UNIFIED IDEOGRAPH + 0x90B3: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0x90B4: 0x60D4, //CJK UNIFIED IDEOGRAPH + 0x90B5: 0x60D6, //CJK UNIFIED IDEOGRAPH + 0x90B6: 0x60D7, //CJK UNIFIED IDEOGRAPH + 0x90B7: 0x60D9, //CJK UNIFIED IDEOGRAPH + 0x90B8: 0x60DB, //CJK UNIFIED IDEOGRAPH + 0x90B9: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0x90BA: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0x90BB: 0x60E2, //CJK UNIFIED IDEOGRAPH + 0x90BC: 0x60E3, //CJK UNIFIED IDEOGRAPH + 0x90BD: 0x60E4, //CJK UNIFIED IDEOGRAPH + 0x90BE: 0x60E5, //CJK UNIFIED IDEOGRAPH + 0x90BF: 0x60EA, //CJK UNIFIED IDEOGRAPH + 0x90C0: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0x90C1: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0x90C2: 0x60F5, //CJK UNIFIED IDEOGRAPH + 0x90C3: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0x90C4: 0x60F8, //CJK UNIFIED IDEOGRAPH + 0x90C5: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0x90C6: 0x60FC, //CJK UNIFIED IDEOGRAPH + 0x90C7: 0x60FD, //CJK UNIFIED IDEOGRAPH + 0x90C8: 0x60FE, //CJK UNIFIED IDEOGRAPH + 0x90C9: 0x60FF, //CJK UNIFIED IDEOGRAPH + 0x90CA: 0x6102, //CJK UNIFIED IDEOGRAPH + 0x90CB: 0x6103, //CJK UNIFIED IDEOGRAPH + 0x90CC: 0x6104, //CJK UNIFIED IDEOGRAPH + 0x90CD: 0x6105, //CJK UNIFIED IDEOGRAPH + 0x90CE: 0x6107, //CJK UNIFIED IDEOGRAPH + 0x90CF: 0x610A, //CJK UNIFIED IDEOGRAPH + 0x90D0: 0x610B, //CJK UNIFIED IDEOGRAPH + 0x90D1: 0x610C, //CJK UNIFIED IDEOGRAPH + 0x90D2: 0x6110, //CJK UNIFIED IDEOGRAPH + 0x90D3: 0x6111, //CJK UNIFIED IDEOGRAPH + 0x90D4: 0x6112, //CJK UNIFIED IDEOGRAPH + 0x90D5: 0x6113, //CJK UNIFIED IDEOGRAPH + 0x90D6: 0x6114, //CJK UNIFIED IDEOGRAPH + 0x90D7: 0x6116, //CJK UNIFIED IDEOGRAPH + 0x90D8: 0x6117, //CJK UNIFIED IDEOGRAPH + 0x90D9: 0x6118, //CJK UNIFIED IDEOGRAPH + 0x90DA: 0x6119, //CJK UNIFIED IDEOGRAPH + 0x90DB: 0x611B, //CJK UNIFIED IDEOGRAPH + 0x90DC: 0x611C, //CJK UNIFIED IDEOGRAPH + 0x90DD: 0x611D, //CJK UNIFIED IDEOGRAPH + 0x90DE: 0x611E, //CJK UNIFIED IDEOGRAPH + 0x90DF: 0x6121, //CJK UNIFIED IDEOGRAPH + 0x90E0: 0x6122, //CJK UNIFIED IDEOGRAPH + 0x90E1: 0x6125, //CJK UNIFIED IDEOGRAPH + 0x90E2: 0x6128, //CJK UNIFIED IDEOGRAPH + 0x90E3: 0x6129, //CJK UNIFIED IDEOGRAPH + 0x90E4: 0x612A, //CJK UNIFIED IDEOGRAPH + 0x90E5: 0x612C, //CJK UNIFIED IDEOGRAPH + 0x90E6: 0x612D, //CJK UNIFIED IDEOGRAPH + 0x90E7: 0x612E, //CJK UNIFIED IDEOGRAPH + 0x90E8: 0x612F, //CJK UNIFIED IDEOGRAPH + 0x90E9: 0x6130, //CJK UNIFIED IDEOGRAPH + 0x90EA: 0x6131, //CJK UNIFIED IDEOGRAPH + 0x90EB: 0x6132, //CJK UNIFIED IDEOGRAPH + 0x90EC: 0x6133, //CJK UNIFIED IDEOGRAPH + 0x90ED: 0x6134, //CJK UNIFIED IDEOGRAPH + 0x90EE: 0x6135, //CJK UNIFIED IDEOGRAPH + 0x90EF: 0x6136, //CJK UNIFIED IDEOGRAPH + 0x90F0: 0x6137, //CJK UNIFIED IDEOGRAPH + 0x90F1: 0x6138, //CJK UNIFIED IDEOGRAPH + 0x90F2: 0x6139, //CJK UNIFIED IDEOGRAPH + 0x90F3: 0x613A, //CJK UNIFIED IDEOGRAPH + 0x90F4: 0x613B, //CJK UNIFIED IDEOGRAPH + 0x90F5: 0x613C, //CJK UNIFIED IDEOGRAPH + 0x90F6: 0x613D, //CJK UNIFIED IDEOGRAPH + 0x90F7: 0x613E, //CJK UNIFIED IDEOGRAPH + 0x90F8: 0x6140, //CJK UNIFIED IDEOGRAPH + 0x90F9: 0x6141, //CJK UNIFIED IDEOGRAPH + 0x90FA: 0x6142, //CJK UNIFIED IDEOGRAPH + 0x90FB: 0x6143, //CJK UNIFIED IDEOGRAPH + 0x90FC: 0x6144, //CJK UNIFIED IDEOGRAPH + 0x90FD: 0x6145, //CJK UNIFIED IDEOGRAPH + 0x90FE: 0x6146, //CJK UNIFIED IDEOGRAPH + 0x9140: 0x6147, //CJK UNIFIED IDEOGRAPH + 0x9141: 0x6149, //CJK UNIFIED IDEOGRAPH + 0x9142: 0x614B, //CJK UNIFIED IDEOGRAPH + 0x9143: 0x614D, //CJK UNIFIED IDEOGRAPH + 0x9144: 0x614F, //CJK UNIFIED IDEOGRAPH + 0x9145: 0x6150, //CJK UNIFIED IDEOGRAPH + 0x9146: 0x6152, //CJK UNIFIED IDEOGRAPH + 0x9147: 0x6153, //CJK UNIFIED IDEOGRAPH + 0x9148: 0x6154, //CJK UNIFIED IDEOGRAPH + 0x9149: 0x6156, //CJK UNIFIED IDEOGRAPH + 0x914A: 0x6157, //CJK UNIFIED IDEOGRAPH + 0x914B: 0x6158, //CJK UNIFIED IDEOGRAPH + 0x914C: 0x6159, //CJK UNIFIED IDEOGRAPH + 0x914D: 0x615A, //CJK UNIFIED IDEOGRAPH + 0x914E: 0x615B, //CJK UNIFIED IDEOGRAPH + 0x914F: 0x615C, //CJK UNIFIED IDEOGRAPH + 0x9150: 0x615E, //CJK UNIFIED IDEOGRAPH + 0x9151: 0x615F, //CJK UNIFIED IDEOGRAPH + 0x9152: 0x6160, //CJK UNIFIED IDEOGRAPH + 0x9153: 0x6161, //CJK UNIFIED IDEOGRAPH + 0x9154: 0x6163, //CJK UNIFIED IDEOGRAPH + 0x9155: 0x6164, //CJK UNIFIED IDEOGRAPH + 0x9156: 0x6165, //CJK UNIFIED IDEOGRAPH + 0x9157: 0x6166, //CJK UNIFIED IDEOGRAPH + 0x9158: 0x6169, //CJK UNIFIED IDEOGRAPH + 0x9159: 0x616A, //CJK UNIFIED IDEOGRAPH + 0x915A: 0x616B, //CJK UNIFIED IDEOGRAPH + 0x915B: 0x616C, //CJK UNIFIED IDEOGRAPH + 0x915C: 0x616D, //CJK UNIFIED IDEOGRAPH + 0x915D: 0x616E, //CJK UNIFIED IDEOGRAPH + 0x915E: 0x616F, //CJK UNIFIED IDEOGRAPH + 0x915F: 0x6171, //CJK UNIFIED IDEOGRAPH + 0x9160: 0x6172, //CJK UNIFIED IDEOGRAPH + 0x9161: 0x6173, //CJK UNIFIED IDEOGRAPH + 0x9162: 0x6174, //CJK UNIFIED IDEOGRAPH + 0x9163: 0x6176, //CJK UNIFIED IDEOGRAPH + 0x9164: 0x6178, //CJK UNIFIED IDEOGRAPH + 0x9165: 0x6179, //CJK UNIFIED IDEOGRAPH + 0x9166: 0x617A, //CJK UNIFIED IDEOGRAPH + 0x9167: 0x617B, //CJK UNIFIED IDEOGRAPH + 0x9168: 0x617C, //CJK UNIFIED IDEOGRAPH + 0x9169: 0x617D, //CJK UNIFIED IDEOGRAPH + 0x916A: 0x617E, //CJK UNIFIED IDEOGRAPH + 0x916B: 0x617F, //CJK UNIFIED IDEOGRAPH + 0x916C: 0x6180, //CJK UNIFIED IDEOGRAPH + 0x916D: 0x6181, //CJK UNIFIED IDEOGRAPH + 0x916E: 0x6182, //CJK UNIFIED IDEOGRAPH + 0x916F: 0x6183, //CJK UNIFIED IDEOGRAPH + 0x9170: 0x6184, //CJK UNIFIED IDEOGRAPH + 0x9171: 0x6185, //CJK UNIFIED IDEOGRAPH + 0x9172: 0x6186, //CJK UNIFIED IDEOGRAPH + 0x9173: 0x6187, //CJK UNIFIED IDEOGRAPH + 0x9174: 0x6188, //CJK UNIFIED IDEOGRAPH + 0x9175: 0x6189, //CJK UNIFIED IDEOGRAPH + 0x9176: 0x618A, //CJK UNIFIED IDEOGRAPH + 0x9177: 0x618C, //CJK UNIFIED IDEOGRAPH + 0x9178: 0x618D, //CJK UNIFIED IDEOGRAPH + 0x9179: 0x618F, //CJK UNIFIED IDEOGRAPH + 0x917A: 0x6190, //CJK UNIFIED IDEOGRAPH + 0x917B: 0x6191, //CJK UNIFIED IDEOGRAPH + 0x917C: 0x6192, //CJK UNIFIED IDEOGRAPH + 0x917D: 0x6193, //CJK UNIFIED IDEOGRAPH + 0x917E: 0x6195, //CJK UNIFIED IDEOGRAPH + 0x9180: 0x6196, //CJK UNIFIED IDEOGRAPH + 0x9181: 0x6197, //CJK UNIFIED IDEOGRAPH + 0x9182: 0x6198, //CJK UNIFIED IDEOGRAPH + 0x9183: 0x6199, //CJK UNIFIED IDEOGRAPH + 0x9184: 0x619A, //CJK UNIFIED IDEOGRAPH + 0x9185: 0x619B, //CJK UNIFIED IDEOGRAPH + 0x9186: 0x619C, //CJK UNIFIED IDEOGRAPH + 0x9187: 0x619E, //CJK UNIFIED IDEOGRAPH + 0x9188: 0x619F, //CJK UNIFIED IDEOGRAPH + 0x9189: 0x61A0, //CJK UNIFIED IDEOGRAPH + 0x918A: 0x61A1, //CJK UNIFIED IDEOGRAPH + 0x918B: 0x61A2, //CJK UNIFIED IDEOGRAPH + 0x918C: 0x61A3, //CJK UNIFIED IDEOGRAPH + 0x918D: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0x918E: 0x61A5, //CJK UNIFIED IDEOGRAPH + 0x918F: 0x61A6, //CJK UNIFIED IDEOGRAPH + 0x9190: 0x61AA, //CJK UNIFIED IDEOGRAPH + 0x9191: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0x9192: 0x61AD, //CJK UNIFIED IDEOGRAPH + 0x9193: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0x9194: 0x61AF, //CJK UNIFIED IDEOGRAPH + 0x9195: 0x61B0, //CJK UNIFIED IDEOGRAPH + 0x9196: 0x61B1, //CJK UNIFIED IDEOGRAPH + 0x9197: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0x9198: 0x61B3, //CJK UNIFIED IDEOGRAPH + 0x9199: 0x61B4, //CJK UNIFIED IDEOGRAPH + 0x919A: 0x61B5, //CJK UNIFIED IDEOGRAPH + 0x919B: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0x919C: 0x61B8, //CJK UNIFIED IDEOGRAPH + 0x919D: 0x61B9, //CJK UNIFIED IDEOGRAPH + 0x919E: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0x919F: 0x61BB, //CJK UNIFIED IDEOGRAPH + 0x91A0: 0x61BC, //CJK UNIFIED IDEOGRAPH + 0x91A1: 0x61BD, //CJK UNIFIED IDEOGRAPH + 0x91A2: 0x61BF, //CJK UNIFIED IDEOGRAPH + 0x91A3: 0x61C0, //CJK UNIFIED IDEOGRAPH + 0x91A4: 0x61C1, //CJK UNIFIED IDEOGRAPH + 0x91A5: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0x91A6: 0x61C4, //CJK UNIFIED IDEOGRAPH + 0x91A7: 0x61C5, //CJK UNIFIED IDEOGRAPH + 0x91A8: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0x91A9: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0x91AA: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0x91AB: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0x91AC: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0x91AD: 0x61CE, //CJK UNIFIED IDEOGRAPH + 0x91AE: 0x61CF, //CJK UNIFIED IDEOGRAPH + 0x91AF: 0x61D0, //CJK UNIFIED IDEOGRAPH + 0x91B0: 0x61D3, //CJK UNIFIED IDEOGRAPH + 0x91B1: 0x61D5, //CJK UNIFIED IDEOGRAPH + 0x91B2: 0x61D6, //CJK UNIFIED IDEOGRAPH + 0x91B3: 0x61D7, //CJK UNIFIED IDEOGRAPH + 0x91B4: 0x61D8, //CJK UNIFIED IDEOGRAPH + 0x91B5: 0x61D9, //CJK UNIFIED IDEOGRAPH + 0x91B6: 0x61DA, //CJK UNIFIED IDEOGRAPH + 0x91B7: 0x61DB, //CJK UNIFIED IDEOGRAPH + 0x91B8: 0x61DC, //CJK UNIFIED IDEOGRAPH + 0x91B9: 0x61DD, //CJK UNIFIED IDEOGRAPH + 0x91BA: 0x61DE, //CJK UNIFIED IDEOGRAPH + 0x91BB: 0x61DF, //CJK UNIFIED IDEOGRAPH + 0x91BC: 0x61E0, //CJK UNIFIED IDEOGRAPH + 0x91BD: 0x61E1, //CJK UNIFIED IDEOGRAPH + 0x91BE: 0x61E2, //CJK UNIFIED IDEOGRAPH + 0x91BF: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0x91C0: 0x61E4, //CJK UNIFIED IDEOGRAPH + 0x91C1: 0x61E5, //CJK UNIFIED IDEOGRAPH + 0x91C2: 0x61E7, //CJK UNIFIED IDEOGRAPH + 0x91C3: 0x61E8, //CJK UNIFIED IDEOGRAPH + 0x91C4: 0x61E9, //CJK UNIFIED IDEOGRAPH + 0x91C5: 0x61EA, //CJK UNIFIED IDEOGRAPH + 0x91C6: 0x61EB, //CJK UNIFIED IDEOGRAPH + 0x91C7: 0x61EC, //CJK UNIFIED IDEOGRAPH + 0x91C8: 0x61ED, //CJK UNIFIED IDEOGRAPH + 0x91C9: 0x61EE, //CJK UNIFIED IDEOGRAPH + 0x91CA: 0x61EF, //CJK UNIFIED IDEOGRAPH + 0x91CB: 0x61F0, //CJK UNIFIED IDEOGRAPH + 0x91CC: 0x61F1, //CJK UNIFIED IDEOGRAPH + 0x91CD: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0x91CE: 0x61F3, //CJK UNIFIED IDEOGRAPH + 0x91CF: 0x61F4, //CJK UNIFIED IDEOGRAPH + 0x91D0: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0x91D1: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0x91D2: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0x91D3: 0x61F9, //CJK UNIFIED IDEOGRAPH + 0x91D4: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0x91D5: 0x61FB, //CJK UNIFIED IDEOGRAPH + 0x91D6: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0x91D7: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0x91D8: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0x91D9: 0x6200, //CJK UNIFIED IDEOGRAPH + 0x91DA: 0x6201, //CJK UNIFIED IDEOGRAPH + 0x91DB: 0x6202, //CJK UNIFIED IDEOGRAPH + 0x91DC: 0x6203, //CJK UNIFIED IDEOGRAPH + 0x91DD: 0x6204, //CJK UNIFIED IDEOGRAPH + 0x91DE: 0x6205, //CJK UNIFIED IDEOGRAPH + 0x91DF: 0x6207, //CJK UNIFIED IDEOGRAPH + 0x91E0: 0x6209, //CJK UNIFIED IDEOGRAPH + 0x91E1: 0x6213, //CJK UNIFIED IDEOGRAPH + 0x91E2: 0x6214, //CJK UNIFIED IDEOGRAPH + 0x91E3: 0x6219, //CJK UNIFIED IDEOGRAPH + 0x91E4: 0x621C, //CJK UNIFIED IDEOGRAPH + 0x91E5: 0x621D, //CJK UNIFIED IDEOGRAPH + 0x91E6: 0x621E, //CJK UNIFIED IDEOGRAPH + 0x91E7: 0x6220, //CJK UNIFIED IDEOGRAPH + 0x91E8: 0x6223, //CJK UNIFIED IDEOGRAPH + 0x91E9: 0x6226, //CJK UNIFIED IDEOGRAPH + 0x91EA: 0x6227, //CJK UNIFIED IDEOGRAPH + 0x91EB: 0x6228, //CJK UNIFIED IDEOGRAPH + 0x91EC: 0x6229, //CJK UNIFIED IDEOGRAPH + 0x91ED: 0x622B, //CJK UNIFIED IDEOGRAPH + 0x91EE: 0x622D, //CJK UNIFIED IDEOGRAPH + 0x91EF: 0x622F, //CJK UNIFIED IDEOGRAPH + 0x91F0: 0x6230, //CJK UNIFIED IDEOGRAPH + 0x91F1: 0x6231, //CJK UNIFIED IDEOGRAPH + 0x91F2: 0x6232, //CJK UNIFIED IDEOGRAPH + 0x91F3: 0x6235, //CJK UNIFIED IDEOGRAPH + 0x91F4: 0x6236, //CJK UNIFIED IDEOGRAPH + 0x91F5: 0x6238, //CJK UNIFIED IDEOGRAPH + 0x91F6: 0x6239, //CJK UNIFIED IDEOGRAPH + 0x91F7: 0x623A, //CJK UNIFIED IDEOGRAPH + 0x91F8: 0x623B, //CJK UNIFIED IDEOGRAPH + 0x91F9: 0x623C, //CJK UNIFIED IDEOGRAPH + 0x91FA: 0x6242, //CJK UNIFIED IDEOGRAPH + 0x91FB: 0x6244, //CJK UNIFIED IDEOGRAPH + 0x91FC: 0x6245, //CJK UNIFIED IDEOGRAPH + 0x91FD: 0x6246, //CJK UNIFIED IDEOGRAPH + 0x91FE: 0x624A, //CJK UNIFIED IDEOGRAPH + 0x9240: 0x624F, //CJK UNIFIED IDEOGRAPH + 0x9241: 0x6250, //CJK UNIFIED IDEOGRAPH + 0x9242: 0x6255, //CJK UNIFIED IDEOGRAPH + 0x9243: 0x6256, //CJK UNIFIED IDEOGRAPH + 0x9244: 0x6257, //CJK UNIFIED IDEOGRAPH + 0x9245: 0x6259, //CJK UNIFIED IDEOGRAPH + 0x9246: 0x625A, //CJK UNIFIED IDEOGRAPH + 0x9247: 0x625C, //CJK UNIFIED IDEOGRAPH + 0x9248: 0x625D, //CJK UNIFIED IDEOGRAPH + 0x9249: 0x625E, //CJK UNIFIED IDEOGRAPH + 0x924A: 0x625F, //CJK UNIFIED IDEOGRAPH + 0x924B: 0x6260, //CJK UNIFIED IDEOGRAPH + 0x924C: 0x6261, //CJK UNIFIED IDEOGRAPH + 0x924D: 0x6262, //CJK UNIFIED IDEOGRAPH + 0x924E: 0x6264, //CJK UNIFIED IDEOGRAPH + 0x924F: 0x6265, //CJK UNIFIED IDEOGRAPH + 0x9250: 0x6268, //CJK UNIFIED IDEOGRAPH + 0x9251: 0x6271, //CJK UNIFIED IDEOGRAPH + 0x9252: 0x6272, //CJK UNIFIED IDEOGRAPH + 0x9253: 0x6274, //CJK UNIFIED IDEOGRAPH + 0x9254: 0x6275, //CJK UNIFIED IDEOGRAPH + 0x9255: 0x6277, //CJK UNIFIED IDEOGRAPH + 0x9256: 0x6278, //CJK UNIFIED IDEOGRAPH + 0x9257: 0x627A, //CJK UNIFIED IDEOGRAPH + 0x9258: 0x627B, //CJK UNIFIED IDEOGRAPH + 0x9259: 0x627D, //CJK UNIFIED IDEOGRAPH + 0x925A: 0x6281, //CJK UNIFIED IDEOGRAPH + 0x925B: 0x6282, //CJK UNIFIED IDEOGRAPH + 0x925C: 0x6283, //CJK UNIFIED IDEOGRAPH + 0x925D: 0x6285, //CJK UNIFIED IDEOGRAPH + 0x925E: 0x6286, //CJK UNIFIED IDEOGRAPH + 0x925F: 0x6287, //CJK UNIFIED IDEOGRAPH + 0x9260: 0x6288, //CJK UNIFIED IDEOGRAPH + 0x9261: 0x628B, //CJK UNIFIED IDEOGRAPH + 0x9262: 0x628C, //CJK UNIFIED IDEOGRAPH + 0x9263: 0x628D, //CJK UNIFIED IDEOGRAPH + 0x9264: 0x628E, //CJK UNIFIED IDEOGRAPH + 0x9265: 0x628F, //CJK UNIFIED IDEOGRAPH + 0x9266: 0x6290, //CJK UNIFIED IDEOGRAPH + 0x9267: 0x6294, //CJK UNIFIED IDEOGRAPH + 0x9268: 0x6299, //CJK UNIFIED IDEOGRAPH + 0x9269: 0x629C, //CJK UNIFIED IDEOGRAPH + 0x926A: 0x629D, //CJK UNIFIED IDEOGRAPH + 0x926B: 0x629E, //CJK UNIFIED IDEOGRAPH + 0x926C: 0x62A3, //CJK UNIFIED IDEOGRAPH + 0x926D: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0x926E: 0x62A7, //CJK UNIFIED IDEOGRAPH + 0x926F: 0x62A9, //CJK UNIFIED IDEOGRAPH + 0x9270: 0x62AA, //CJK UNIFIED IDEOGRAPH + 0x9271: 0x62AD, //CJK UNIFIED IDEOGRAPH + 0x9272: 0x62AE, //CJK UNIFIED IDEOGRAPH + 0x9273: 0x62AF, //CJK UNIFIED IDEOGRAPH + 0x9274: 0x62B0, //CJK UNIFIED IDEOGRAPH + 0x9275: 0x62B2, //CJK UNIFIED IDEOGRAPH + 0x9276: 0x62B3, //CJK UNIFIED IDEOGRAPH + 0x9277: 0x62B4, //CJK UNIFIED IDEOGRAPH + 0x9278: 0x62B6, //CJK UNIFIED IDEOGRAPH + 0x9279: 0x62B7, //CJK UNIFIED IDEOGRAPH + 0x927A: 0x62B8, //CJK UNIFIED IDEOGRAPH + 0x927B: 0x62BA, //CJK UNIFIED IDEOGRAPH + 0x927C: 0x62BE, //CJK UNIFIED IDEOGRAPH + 0x927D: 0x62C0, //CJK UNIFIED IDEOGRAPH + 0x927E: 0x62C1, //CJK UNIFIED IDEOGRAPH + 0x9280: 0x62C3, //CJK UNIFIED IDEOGRAPH + 0x9281: 0x62CB, //CJK UNIFIED IDEOGRAPH + 0x9282: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0x9283: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0x9284: 0x62D5, //CJK UNIFIED IDEOGRAPH + 0x9285: 0x62DD, //CJK UNIFIED IDEOGRAPH + 0x9286: 0x62DE, //CJK UNIFIED IDEOGRAPH + 0x9287: 0x62E0, //CJK UNIFIED IDEOGRAPH + 0x9288: 0x62E1, //CJK UNIFIED IDEOGRAPH + 0x9289: 0x62E4, //CJK UNIFIED IDEOGRAPH + 0x928A: 0x62EA, //CJK UNIFIED IDEOGRAPH + 0x928B: 0x62EB, //CJK UNIFIED IDEOGRAPH + 0x928C: 0x62F0, //CJK UNIFIED IDEOGRAPH + 0x928D: 0x62F2, //CJK UNIFIED IDEOGRAPH + 0x928E: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0x928F: 0x62F8, //CJK UNIFIED IDEOGRAPH + 0x9290: 0x62F9, //CJK UNIFIED IDEOGRAPH + 0x9291: 0x62FA, //CJK UNIFIED IDEOGRAPH + 0x9292: 0x62FB, //CJK UNIFIED IDEOGRAPH + 0x9293: 0x6300, //CJK UNIFIED IDEOGRAPH + 0x9294: 0x6303, //CJK UNIFIED IDEOGRAPH + 0x9295: 0x6304, //CJK UNIFIED IDEOGRAPH + 0x9296: 0x6305, //CJK UNIFIED IDEOGRAPH + 0x9297: 0x6306, //CJK UNIFIED IDEOGRAPH + 0x9298: 0x630A, //CJK UNIFIED IDEOGRAPH + 0x9299: 0x630B, //CJK UNIFIED IDEOGRAPH + 0x929A: 0x630C, //CJK UNIFIED IDEOGRAPH + 0x929B: 0x630D, //CJK UNIFIED IDEOGRAPH + 0x929C: 0x630F, //CJK UNIFIED IDEOGRAPH + 0x929D: 0x6310, //CJK UNIFIED IDEOGRAPH + 0x929E: 0x6312, //CJK UNIFIED IDEOGRAPH + 0x929F: 0x6313, //CJK UNIFIED IDEOGRAPH + 0x92A0: 0x6314, //CJK UNIFIED IDEOGRAPH + 0x92A1: 0x6315, //CJK UNIFIED IDEOGRAPH + 0x92A2: 0x6317, //CJK UNIFIED IDEOGRAPH + 0x92A3: 0x6318, //CJK UNIFIED IDEOGRAPH + 0x92A4: 0x6319, //CJK UNIFIED IDEOGRAPH + 0x92A5: 0x631C, //CJK UNIFIED IDEOGRAPH + 0x92A6: 0x6326, //CJK UNIFIED IDEOGRAPH + 0x92A7: 0x6327, //CJK UNIFIED IDEOGRAPH + 0x92A8: 0x6329, //CJK UNIFIED IDEOGRAPH + 0x92A9: 0x632C, //CJK UNIFIED IDEOGRAPH + 0x92AA: 0x632D, //CJK UNIFIED IDEOGRAPH + 0x92AB: 0x632E, //CJK UNIFIED IDEOGRAPH + 0x92AC: 0x6330, //CJK UNIFIED IDEOGRAPH + 0x92AD: 0x6331, //CJK UNIFIED IDEOGRAPH + 0x92AE: 0x6333, //CJK UNIFIED IDEOGRAPH + 0x92AF: 0x6334, //CJK UNIFIED IDEOGRAPH + 0x92B0: 0x6335, //CJK UNIFIED IDEOGRAPH + 0x92B1: 0x6336, //CJK UNIFIED IDEOGRAPH + 0x92B2: 0x6337, //CJK UNIFIED IDEOGRAPH + 0x92B3: 0x6338, //CJK UNIFIED IDEOGRAPH + 0x92B4: 0x633B, //CJK UNIFIED IDEOGRAPH + 0x92B5: 0x633C, //CJK UNIFIED IDEOGRAPH + 0x92B6: 0x633E, //CJK UNIFIED IDEOGRAPH + 0x92B7: 0x633F, //CJK UNIFIED IDEOGRAPH + 0x92B8: 0x6340, //CJK UNIFIED IDEOGRAPH + 0x92B9: 0x6341, //CJK UNIFIED IDEOGRAPH + 0x92BA: 0x6344, //CJK UNIFIED IDEOGRAPH + 0x92BB: 0x6347, //CJK UNIFIED IDEOGRAPH + 0x92BC: 0x6348, //CJK UNIFIED IDEOGRAPH + 0x92BD: 0x634A, //CJK UNIFIED IDEOGRAPH + 0x92BE: 0x6351, //CJK UNIFIED IDEOGRAPH + 0x92BF: 0x6352, //CJK UNIFIED IDEOGRAPH + 0x92C0: 0x6353, //CJK UNIFIED IDEOGRAPH + 0x92C1: 0x6354, //CJK UNIFIED IDEOGRAPH + 0x92C2: 0x6356, //CJK UNIFIED IDEOGRAPH + 0x92C3: 0x6357, //CJK UNIFIED IDEOGRAPH + 0x92C4: 0x6358, //CJK UNIFIED IDEOGRAPH + 0x92C5: 0x6359, //CJK UNIFIED IDEOGRAPH + 0x92C6: 0x635A, //CJK UNIFIED IDEOGRAPH + 0x92C7: 0x635B, //CJK UNIFIED IDEOGRAPH + 0x92C8: 0x635C, //CJK UNIFIED IDEOGRAPH + 0x92C9: 0x635D, //CJK UNIFIED IDEOGRAPH + 0x92CA: 0x6360, //CJK UNIFIED IDEOGRAPH + 0x92CB: 0x6364, //CJK UNIFIED IDEOGRAPH + 0x92CC: 0x6365, //CJK UNIFIED IDEOGRAPH + 0x92CD: 0x6366, //CJK UNIFIED IDEOGRAPH + 0x92CE: 0x6368, //CJK UNIFIED IDEOGRAPH + 0x92CF: 0x636A, //CJK UNIFIED IDEOGRAPH + 0x92D0: 0x636B, //CJK UNIFIED IDEOGRAPH + 0x92D1: 0x636C, //CJK UNIFIED IDEOGRAPH + 0x92D2: 0x636F, //CJK UNIFIED IDEOGRAPH + 0x92D3: 0x6370, //CJK UNIFIED IDEOGRAPH + 0x92D4: 0x6372, //CJK UNIFIED IDEOGRAPH + 0x92D5: 0x6373, //CJK UNIFIED IDEOGRAPH + 0x92D6: 0x6374, //CJK UNIFIED IDEOGRAPH + 0x92D7: 0x6375, //CJK UNIFIED IDEOGRAPH + 0x92D8: 0x6378, //CJK UNIFIED IDEOGRAPH + 0x92D9: 0x6379, //CJK UNIFIED IDEOGRAPH + 0x92DA: 0x637C, //CJK UNIFIED IDEOGRAPH + 0x92DB: 0x637D, //CJK UNIFIED IDEOGRAPH + 0x92DC: 0x637E, //CJK UNIFIED IDEOGRAPH + 0x92DD: 0x637F, //CJK UNIFIED IDEOGRAPH + 0x92DE: 0x6381, //CJK UNIFIED IDEOGRAPH + 0x92DF: 0x6383, //CJK UNIFIED IDEOGRAPH + 0x92E0: 0x6384, //CJK UNIFIED IDEOGRAPH + 0x92E1: 0x6385, //CJK UNIFIED IDEOGRAPH + 0x92E2: 0x6386, //CJK UNIFIED IDEOGRAPH + 0x92E3: 0x638B, //CJK UNIFIED IDEOGRAPH + 0x92E4: 0x638D, //CJK UNIFIED IDEOGRAPH + 0x92E5: 0x6391, //CJK UNIFIED IDEOGRAPH + 0x92E6: 0x6393, //CJK UNIFIED IDEOGRAPH + 0x92E7: 0x6394, //CJK UNIFIED IDEOGRAPH + 0x92E8: 0x6395, //CJK UNIFIED IDEOGRAPH + 0x92E9: 0x6397, //CJK UNIFIED IDEOGRAPH + 0x92EA: 0x6399, //CJK UNIFIED IDEOGRAPH + 0x92EB: 0x639A, //CJK UNIFIED IDEOGRAPH + 0x92EC: 0x639B, //CJK UNIFIED IDEOGRAPH + 0x92ED: 0x639C, //CJK UNIFIED IDEOGRAPH + 0x92EE: 0x639D, //CJK UNIFIED IDEOGRAPH + 0x92EF: 0x639E, //CJK UNIFIED IDEOGRAPH + 0x92F0: 0x639F, //CJK UNIFIED IDEOGRAPH + 0x92F1: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0x92F2: 0x63A4, //CJK UNIFIED IDEOGRAPH + 0x92F3: 0x63A6, //CJK UNIFIED IDEOGRAPH + 0x92F4: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0x92F5: 0x63AF, //CJK UNIFIED IDEOGRAPH + 0x92F6: 0x63B1, //CJK UNIFIED IDEOGRAPH + 0x92F7: 0x63B2, //CJK UNIFIED IDEOGRAPH + 0x92F8: 0x63B5, //CJK UNIFIED IDEOGRAPH + 0x92F9: 0x63B6, //CJK UNIFIED IDEOGRAPH + 0x92FA: 0x63B9, //CJK UNIFIED IDEOGRAPH + 0x92FB: 0x63BB, //CJK UNIFIED IDEOGRAPH + 0x92FC: 0x63BD, //CJK UNIFIED IDEOGRAPH + 0x92FD: 0x63BF, //CJK UNIFIED IDEOGRAPH + 0x92FE: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0x9340: 0x63C1, //CJK UNIFIED IDEOGRAPH + 0x9341: 0x63C2, //CJK UNIFIED IDEOGRAPH + 0x9342: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0x9343: 0x63C5, //CJK UNIFIED IDEOGRAPH + 0x9344: 0x63C7, //CJK UNIFIED IDEOGRAPH + 0x9345: 0x63C8, //CJK UNIFIED IDEOGRAPH + 0x9346: 0x63CA, //CJK UNIFIED IDEOGRAPH + 0x9347: 0x63CB, //CJK UNIFIED IDEOGRAPH + 0x9348: 0x63CC, //CJK UNIFIED IDEOGRAPH + 0x9349: 0x63D1, //CJK UNIFIED IDEOGRAPH + 0x934A: 0x63D3, //CJK UNIFIED IDEOGRAPH + 0x934B: 0x63D4, //CJK UNIFIED IDEOGRAPH + 0x934C: 0x63D5, //CJK UNIFIED IDEOGRAPH + 0x934D: 0x63D7, //CJK UNIFIED IDEOGRAPH + 0x934E: 0x63D8, //CJK UNIFIED IDEOGRAPH + 0x934F: 0x63D9, //CJK UNIFIED IDEOGRAPH + 0x9350: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0x9351: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0x9352: 0x63DC, //CJK UNIFIED IDEOGRAPH + 0x9353: 0x63DD, //CJK UNIFIED IDEOGRAPH + 0x9354: 0x63DF, //CJK UNIFIED IDEOGRAPH + 0x9355: 0x63E2, //CJK UNIFIED IDEOGRAPH + 0x9356: 0x63E4, //CJK UNIFIED IDEOGRAPH + 0x9357: 0x63E5, //CJK UNIFIED IDEOGRAPH + 0x9358: 0x63E6, //CJK UNIFIED IDEOGRAPH + 0x9359: 0x63E7, //CJK UNIFIED IDEOGRAPH + 0x935A: 0x63E8, //CJK UNIFIED IDEOGRAPH + 0x935B: 0x63EB, //CJK UNIFIED IDEOGRAPH + 0x935C: 0x63EC, //CJK UNIFIED IDEOGRAPH + 0x935D: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0x935E: 0x63EF, //CJK UNIFIED IDEOGRAPH + 0x935F: 0x63F0, //CJK UNIFIED IDEOGRAPH + 0x9360: 0x63F1, //CJK UNIFIED IDEOGRAPH + 0x9361: 0x63F3, //CJK UNIFIED IDEOGRAPH + 0x9362: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0x9363: 0x63F7, //CJK UNIFIED IDEOGRAPH + 0x9364: 0x63F9, //CJK UNIFIED IDEOGRAPH + 0x9365: 0x63FA, //CJK UNIFIED IDEOGRAPH + 0x9366: 0x63FB, //CJK UNIFIED IDEOGRAPH + 0x9367: 0x63FC, //CJK UNIFIED IDEOGRAPH + 0x9368: 0x63FE, //CJK UNIFIED IDEOGRAPH + 0x9369: 0x6403, //CJK UNIFIED IDEOGRAPH + 0x936A: 0x6404, //CJK UNIFIED IDEOGRAPH + 0x936B: 0x6406, //CJK UNIFIED IDEOGRAPH + 0x936C: 0x6407, //CJK UNIFIED IDEOGRAPH + 0x936D: 0x6408, //CJK UNIFIED IDEOGRAPH + 0x936E: 0x6409, //CJK UNIFIED IDEOGRAPH + 0x936F: 0x640A, //CJK UNIFIED IDEOGRAPH + 0x9370: 0x640D, //CJK UNIFIED IDEOGRAPH + 0x9371: 0x640E, //CJK UNIFIED IDEOGRAPH + 0x9372: 0x6411, //CJK UNIFIED IDEOGRAPH + 0x9373: 0x6412, //CJK UNIFIED IDEOGRAPH + 0x9374: 0x6415, //CJK UNIFIED IDEOGRAPH + 0x9375: 0x6416, //CJK UNIFIED IDEOGRAPH + 0x9376: 0x6417, //CJK UNIFIED IDEOGRAPH + 0x9377: 0x6418, //CJK UNIFIED IDEOGRAPH + 0x9378: 0x6419, //CJK UNIFIED IDEOGRAPH + 0x9379: 0x641A, //CJK UNIFIED IDEOGRAPH + 0x937A: 0x641D, //CJK UNIFIED IDEOGRAPH + 0x937B: 0x641F, //CJK UNIFIED IDEOGRAPH + 0x937C: 0x6422, //CJK UNIFIED IDEOGRAPH + 0x937D: 0x6423, //CJK UNIFIED IDEOGRAPH + 0x937E: 0x6424, //CJK UNIFIED IDEOGRAPH + 0x9380: 0x6425, //CJK UNIFIED IDEOGRAPH + 0x9381: 0x6427, //CJK UNIFIED IDEOGRAPH + 0x9382: 0x6428, //CJK UNIFIED IDEOGRAPH + 0x9383: 0x6429, //CJK UNIFIED IDEOGRAPH + 0x9384: 0x642B, //CJK UNIFIED IDEOGRAPH + 0x9385: 0x642E, //CJK UNIFIED IDEOGRAPH + 0x9386: 0x642F, //CJK UNIFIED IDEOGRAPH + 0x9387: 0x6430, //CJK UNIFIED IDEOGRAPH + 0x9388: 0x6431, //CJK UNIFIED IDEOGRAPH + 0x9389: 0x6432, //CJK UNIFIED IDEOGRAPH + 0x938A: 0x6433, //CJK UNIFIED IDEOGRAPH + 0x938B: 0x6435, //CJK UNIFIED IDEOGRAPH + 0x938C: 0x6436, //CJK UNIFIED IDEOGRAPH + 0x938D: 0x6437, //CJK UNIFIED IDEOGRAPH + 0x938E: 0x6438, //CJK UNIFIED IDEOGRAPH + 0x938F: 0x6439, //CJK UNIFIED IDEOGRAPH + 0x9390: 0x643B, //CJK UNIFIED IDEOGRAPH + 0x9391: 0x643C, //CJK UNIFIED IDEOGRAPH + 0x9392: 0x643E, //CJK UNIFIED IDEOGRAPH + 0x9393: 0x6440, //CJK UNIFIED IDEOGRAPH + 0x9394: 0x6442, //CJK UNIFIED IDEOGRAPH + 0x9395: 0x6443, //CJK UNIFIED IDEOGRAPH + 0x9396: 0x6449, //CJK UNIFIED IDEOGRAPH + 0x9397: 0x644B, //CJK UNIFIED IDEOGRAPH + 0x9398: 0x644C, //CJK UNIFIED IDEOGRAPH + 0x9399: 0x644D, //CJK UNIFIED IDEOGRAPH + 0x939A: 0x644E, //CJK UNIFIED IDEOGRAPH + 0x939B: 0x644F, //CJK UNIFIED IDEOGRAPH + 0x939C: 0x6450, //CJK UNIFIED IDEOGRAPH + 0x939D: 0x6451, //CJK UNIFIED IDEOGRAPH + 0x939E: 0x6453, //CJK UNIFIED IDEOGRAPH + 0x939F: 0x6455, //CJK UNIFIED IDEOGRAPH + 0x93A0: 0x6456, //CJK UNIFIED IDEOGRAPH + 0x93A1: 0x6457, //CJK UNIFIED IDEOGRAPH + 0x93A2: 0x6459, //CJK UNIFIED IDEOGRAPH + 0x93A3: 0x645A, //CJK UNIFIED IDEOGRAPH + 0x93A4: 0x645B, //CJK UNIFIED IDEOGRAPH + 0x93A5: 0x645C, //CJK UNIFIED IDEOGRAPH + 0x93A6: 0x645D, //CJK UNIFIED IDEOGRAPH + 0x93A7: 0x645F, //CJK UNIFIED IDEOGRAPH + 0x93A8: 0x6460, //CJK UNIFIED IDEOGRAPH + 0x93A9: 0x6461, //CJK UNIFIED IDEOGRAPH + 0x93AA: 0x6462, //CJK UNIFIED IDEOGRAPH + 0x93AB: 0x6463, //CJK UNIFIED IDEOGRAPH + 0x93AC: 0x6464, //CJK UNIFIED IDEOGRAPH + 0x93AD: 0x6465, //CJK UNIFIED IDEOGRAPH + 0x93AE: 0x6466, //CJK UNIFIED IDEOGRAPH + 0x93AF: 0x6468, //CJK UNIFIED IDEOGRAPH + 0x93B0: 0x646A, //CJK UNIFIED IDEOGRAPH + 0x93B1: 0x646B, //CJK UNIFIED IDEOGRAPH + 0x93B2: 0x646C, //CJK UNIFIED IDEOGRAPH + 0x93B3: 0x646E, //CJK UNIFIED IDEOGRAPH + 0x93B4: 0x646F, //CJK UNIFIED IDEOGRAPH + 0x93B5: 0x6470, //CJK UNIFIED IDEOGRAPH + 0x93B6: 0x6471, //CJK UNIFIED IDEOGRAPH + 0x93B7: 0x6472, //CJK UNIFIED IDEOGRAPH + 0x93B8: 0x6473, //CJK UNIFIED IDEOGRAPH + 0x93B9: 0x6474, //CJK UNIFIED IDEOGRAPH + 0x93BA: 0x6475, //CJK UNIFIED IDEOGRAPH + 0x93BB: 0x6476, //CJK UNIFIED IDEOGRAPH + 0x93BC: 0x6477, //CJK UNIFIED IDEOGRAPH + 0x93BD: 0x647B, //CJK UNIFIED IDEOGRAPH + 0x93BE: 0x647C, //CJK UNIFIED IDEOGRAPH + 0x93BF: 0x647D, //CJK UNIFIED IDEOGRAPH + 0x93C0: 0x647E, //CJK UNIFIED IDEOGRAPH + 0x93C1: 0x647F, //CJK UNIFIED IDEOGRAPH + 0x93C2: 0x6480, //CJK UNIFIED IDEOGRAPH + 0x93C3: 0x6481, //CJK UNIFIED IDEOGRAPH + 0x93C4: 0x6483, //CJK UNIFIED IDEOGRAPH + 0x93C5: 0x6486, //CJK UNIFIED IDEOGRAPH + 0x93C6: 0x6488, //CJK UNIFIED IDEOGRAPH + 0x93C7: 0x6489, //CJK UNIFIED IDEOGRAPH + 0x93C8: 0x648A, //CJK UNIFIED IDEOGRAPH + 0x93C9: 0x648B, //CJK UNIFIED IDEOGRAPH + 0x93CA: 0x648C, //CJK UNIFIED IDEOGRAPH + 0x93CB: 0x648D, //CJK UNIFIED IDEOGRAPH + 0x93CC: 0x648E, //CJK UNIFIED IDEOGRAPH + 0x93CD: 0x648F, //CJK UNIFIED IDEOGRAPH + 0x93CE: 0x6490, //CJK UNIFIED IDEOGRAPH + 0x93CF: 0x6493, //CJK UNIFIED IDEOGRAPH + 0x93D0: 0x6494, //CJK UNIFIED IDEOGRAPH + 0x93D1: 0x6497, //CJK UNIFIED IDEOGRAPH + 0x93D2: 0x6498, //CJK UNIFIED IDEOGRAPH + 0x93D3: 0x649A, //CJK UNIFIED IDEOGRAPH + 0x93D4: 0x649B, //CJK UNIFIED IDEOGRAPH + 0x93D5: 0x649C, //CJK UNIFIED IDEOGRAPH + 0x93D6: 0x649D, //CJK UNIFIED IDEOGRAPH + 0x93D7: 0x649F, //CJK UNIFIED IDEOGRAPH + 0x93D8: 0x64A0, //CJK UNIFIED IDEOGRAPH + 0x93D9: 0x64A1, //CJK UNIFIED IDEOGRAPH + 0x93DA: 0x64A2, //CJK UNIFIED IDEOGRAPH + 0x93DB: 0x64A3, //CJK UNIFIED IDEOGRAPH + 0x93DC: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0x93DD: 0x64A6, //CJK UNIFIED IDEOGRAPH + 0x93DE: 0x64A7, //CJK UNIFIED IDEOGRAPH + 0x93DF: 0x64A8, //CJK UNIFIED IDEOGRAPH + 0x93E0: 0x64AA, //CJK UNIFIED IDEOGRAPH + 0x93E1: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0x93E2: 0x64AF, //CJK UNIFIED IDEOGRAPH + 0x93E3: 0x64B1, //CJK UNIFIED IDEOGRAPH + 0x93E4: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0x93E5: 0x64B3, //CJK UNIFIED IDEOGRAPH + 0x93E6: 0x64B4, //CJK UNIFIED IDEOGRAPH + 0x93E7: 0x64B6, //CJK UNIFIED IDEOGRAPH + 0x93E8: 0x64B9, //CJK UNIFIED IDEOGRAPH + 0x93E9: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0x93EA: 0x64BD, //CJK UNIFIED IDEOGRAPH + 0x93EB: 0x64BE, //CJK UNIFIED IDEOGRAPH + 0x93EC: 0x64BF, //CJK UNIFIED IDEOGRAPH + 0x93ED: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0x93EE: 0x64C3, //CJK UNIFIED IDEOGRAPH + 0x93EF: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0x93F0: 0x64C6, //CJK UNIFIED IDEOGRAPH + 0x93F1: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0x93F2: 0x64C8, //CJK UNIFIED IDEOGRAPH + 0x93F3: 0x64C9, //CJK UNIFIED IDEOGRAPH + 0x93F4: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0x93F5: 0x64CB, //CJK UNIFIED IDEOGRAPH + 0x93F6: 0x64CC, //CJK UNIFIED IDEOGRAPH + 0x93F7: 0x64CF, //CJK UNIFIED IDEOGRAPH + 0x93F8: 0x64D1, //CJK UNIFIED IDEOGRAPH + 0x93F9: 0x64D3, //CJK UNIFIED IDEOGRAPH + 0x93FA: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0x93FB: 0x64D5, //CJK UNIFIED IDEOGRAPH + 0x93FC: 0x64D6, //CJK UNIFIED IDEOGRAPH + 0x93FD: 0x64D9, //CJK UNIFIED IDEOGRAPH + 0x93FE: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0x9440: 0x64DB, //CJK UNIFIED IDEOGRAPH + 0x9441: 0x64DC, //CJK UNIFIED IDEOGRAPH + 0x9442: 0x64DD, //CJK UNIFIED IDEOGRAPH + 0x9443: 0x64DF, //CJK UNIFIED IDEOGRAPH + 0x9444: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0x9445: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0x9446: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0x9447: 0x64E5, //CJK UNIFIED IDEOGRAPH + 0x9448: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0x9449: 0x64E8, //CJK UNIFIED IDEOGRAPH + 0x944A: 0x64E9, //CJK UNIFIED IDEOGRAPH + 0x944B: 0x64EA, //CJK UNIFIED IDEOGRAPH + 0x944C: 0x64EB, //CJK UNIFIED IDEOGRAPH + 0x944D: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0x944E: 0x64ED, //CJK UNIFIED IDEOGRAPH + 0x944F: 0x64EE, //CJK UNIFIED IDEOGRAPH + 0x9450: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0x9451: 0x64F0, //CJK UNIFIED IDEOGRAPH + 0x9452: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0x9453: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0x9454: 0x64F3, //CJK UNIFIED IDEOGRAPH + 0x9455: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0x9456: 0x64F5, //CJK UNIFIED IDEOGRAPH + 0x9457: 0x64F6, //CJK UNIFIED IDEOGRAPH + 0x9458: 0x64F7, //CJK UNIFIED IDEOGRAPH + 0x9459: 0x64F8, //CJK UNIFIED IDEOGRAPH + 0x945A: 0x64F9, //CJK UNIFIED IDEOGRAPH + 0x945B: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0x945C: 0x64FB, //CJK UNIFIED IDEOGRAPH + 0x945D: 0x64FC, //CJK UNIFIED IDEOGRAPH + 0x945E: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0x945F: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0x9460: 0x64FF, //CJK UNIFIED IDEOGRAPH + 0x9461: 0x6501, //CJK UNIFIED IDEOGRAPH + 0x9462: 0x6502, //CJK UNIFIED IDEOGRAPH + 0x9463: 0x6503, //CJK UNIFIED IDEOGRAPH + 0x9464: 0x6504, //CJK UNIFIED IDEOGRAPH + 0x9465: 0x6505, //CJK UNIFIED IDEOGRAPH + 0x9466: 0x6506, //CJK UNIFIED IDEOGRAPH + 0x9467: 0x6507, //CJK UNIFIED IDEOGRAPH + 0x9468: 0x6508, //CJK UNIFIED IDEOGRAPH + 0x9469: 0x650A, //CJK UNIFIED IDEOGRAPH + 0x946A: 0x650B, //CJK UNIFIED IDEOGRAPH + 0x946B: 0x650C, //CJK UNIFIED IDEOGRAPH + 0x946C: 0x650D, //CJK UNIFIED IDEOGRAPH + 0x946D: 0x650E, //CJK UNIFIED IDEOGRAPH + 0x946E: 0x650F, //CJK UNIFIED IDEOGRAPH + 0x946F: 0x6510, //CJK UNIFIED IDEOGRAPH + 0x9470: 0x6511, //CJK UNIFIED IDEOGRAPH + 0x9471: 0x6513, //CJK UNIFIED IDEOGRAPH + 0x9472: 0x6514, //CJK UNIFIED IDEOGRAPH + 0x9473: 0x6515, //CJK UNIFIED IDEOGRAPH + 0x9474: 0x6516, //CJK UNIFIED IDEOGRAPH + 0x9475: 0x6517, //CJK UNIFIED IDEOGRAPH + 0x9476: 0x6519, //CJK UNIFIED IDEOGRAPH + 0x9477: 0x651A, //CJK UNIFIED IDEOGRAPH + 0x9478: 0x651B, //CJK UNIFIED IDEOGRAPH + 0x9479: 0x651C, //CJK UNIFIED IDEOGRAPH + 0x947A: 0x651D, //CJK UNIFIED IDEOGRAPH + 0x947B: 0x651E, //CJK UNIFIED IDEOGRAPH + 0x947C: 0x651F, //CJK UNIFIED IDEOGRAPH + 0x947D: 0x6520, //CJK UNIFIED IDEOGRAPH + 0x947E: 0x6521, //CJK UNIFIED IDEOGRAPH + 0x9480: 0x6522, //CJK UNIFIED IDEOGRAPH + 0x9481: 0x6523, //CJK UNIFIED IDEOGRAPH + 0x9482: 0x6524, //CJK UNIFIED IDEOGRAPH + 0x9483: 0x6526, //CJK UNIFIED IDEOGRAPH + 0x9484: 0x6527, //CJK UNIFIED IDEOGRAPH + 0x9485: 0x6528, //CJK UNIFIED IDEOGRAPH + 0x9486: 0x6529, //CJK UNIFIED IDEOGRAPH + 0x9487: 0x652A, //CJK UNIFIED IDEOGRAPH + 0x9488: 0x652C, //CJK UNIFIED IDEOGRAPH + 0x9489: 0x652D, //CJK UNIFIED IDEOGRAPH + 0x948A: 0x6530, //CJK UNIFIED IDEOGRAPH + 0x948B: 0x6531, //CJK UNIFIED IDEOGRAPH + 0x948C: 0x6532, //CJK UNIFIED IDEOGRAPH + 0x948D: 0x6533, //CJK UNIFIED IDEOGRAPH + 0x948E: 0x6537, //CJK UNIFIED IDEOGRAPH + 0x948F: 0x653A, //CJK UNIFIED IDEOGRAPH + 0x9490: 0x653C, //CJK UNIFIED IDEOGRAPH + 0x9491: 0x653D, //CJK UNIFIED IDEOGRAPH + 0x9492: 0x6540, //CJK UNIFIED IDEOGRAPH + 0x9493: 0x6541, //CJK UNIFIED IDEOGRAPH + 0x9494: 0x6542, //CJK UNIFIED IDEOGRAPH + 0x9495: 0x6543, //CJK UNIFIED IDEOGRAPH + 0x9496: 0x6544, //CJK UNIFIED IDEOGRAPH + 0x9497: 0x6546, //CJK UNIFIED IDEOGRAPH + 0x9498: 0x6547, //CJK UNIFIED IDEOGRAPH + 0x9499: 0x654A, //CJK UNIFIED IDEOGRAPH + 0x949A: 0x654B, //CJK UNIFIED IDEOGRAPH + 0x949B: 0x654D, //CJK UNIFIED IDEOGRAPH + 0x949C: 0x654E, //CJK UNIFIED IDEOGRAPH + 0x949D: 0x6550, //CJK UNIFIED IDEOGRAPH + 0x949E: 0x6552, //CJK UNIFIED IDEOGRAPH + 0x949F: 0x6553, //CJK UNIFIED IDEOGRAPH + 0x94A0: 0x6554, //CJK UNIFIED IDEOGRAPH + 0x94A1: 0x6557, //CJK UNIFIED IDEOGRAPH + 0x94A2: 0x6558, //CJK UNIFIED IDEOGRAPH + 0x94A3: 0x655A, //CJK UNIFIED IDEOGRAPH + 0x94A4: 0x655C, //CJK UNIFIED IDEOGRAPH + 0x94A5: 0x655F, //CJK UNIFIED IDEOGRAPH + 0x94A6: 0x6560, //CJK UNIFIED IDEOGRAPH + 0x94A7: 0x6561, //CJK UNIFIED IDEOGRAPH + 0x94A8: 0x6564, //CJK UNIFIED IDEOGRAPH + 0x94A9: 0x6565, //CJK UNIFIED IDEOGRAPH + 0x94AA: 0x6567, //CJK UNIFIED IDEOGRAPH + 0x94AB: 0x6568, //CJK UNIFIED IDEOGRAPH + 0x94AC: 0x6569, //CJK UNIFIED IDEOGRAPH + 0x94AD: 0x656A, //CJK UNIFIED IDEOGRAPH + 0x94AE: 0x656D, //CJK UNIFIED IDEOGRAPH + 0x94AF: 0x656E, //CJK UNIFIED IDEOGRAPH + 0x94B0: 0x656F, //CJK UNIFIED IDEOGRAPH + 0x94B1: 0x6571, //CJK UNIFIED IDEOGRAPH + 0x94B2: 0x6573, //CJK UNIFIED IDEOGRAPH + 0x94B3: 0x6575, //CJK UNIFIED IDEOGRAPH + 0x94B4: 0x6576, //CJK UNIFIED IDEOGRAPH + 0x94B5: 0x6578, //CJK UNIFIED IDEOGRAPH + 0x94B6: 0x6579, //CJK UNIFIED IDEOGRAPH + 0x94B7: 0x657A, //CJK UNIFIED IDEOGRAPH + 0x94B8: 0x657B, //CJK UNIFIED IDEOGRAPH + 0x94B9: 0x657C, //CJK UNIFIED IDEOGRAPH + 0x94BA: 0x657D, //CJK UNIFIED IDEOGRAPH + 0x94BB: 0x657E, //CJK UNIFIED IDEOGRAPH + 0x94BC: 0x657F, //CJK UNIFIED IDEOGRAPH + 0x94BD: 0x6580, //CJK UNIFIED IDEOGRAPH + 0x94BE: 0x6581, //CJK UNIFIED IDEOGRAPH + 0x94BF: 0x6582, //CJK UNIFIED IDEOGRAPH + 0x94C0: 0x6583, //CJK UNIFIED IDEOGRAPH + 0x94C1: 0x6584, //CJK UNIFIED IDEOGRAPH + 0x94C2: 0x6585, //CJK UNIFIED IDEOGRAPH + 0x94C3: 0x6586, //CJK UNIFIED IDEOGRAPH + 0x94C4: 0x6588, //CJK UNIFIED IDEOGRAPH + 0x94C5: 0x6589, //CJK UNIFIED IDEOGRAPH + 0x94C6: 0x658A, //CJK UNIFIED IDEOGRAPH + 0x94C7: 0x658D, //CJK UNIFIED IDEOGRAPH + 0x94C8: 0x658E, //CJK UNIFIED IDEOGRAPH + 0x94C9: 0x658F, //CJK UNIFIED IDEOGRAPH + 0x94CA: 0x6592, //CJK UNIFIED IDEOGRAPH + 0x94CB: 0x6594, //CJK UNIFIED IDEOGRAPH + 0x94CC: 0x6595, //CJK UNIFIED IDEOGRAPH + 0x94CD: 0x6596, //CJK UNIFIED IDEOGRAPH + 0x94CE: 0x6598, //CJK UNIFIED IDEOGRAPH + 0x94CF: 0x659A, //CJK UNIFIED IDEOGRAPH + 0x94D0: 0x659D, //CJK UNIFIED IDEOGRAPH + 0x94D1: 0x659E, //CJK UNIFIED IDEOGRAPH + 0x94D2: 0x65A0, //CJK UNIFIED IDEOGRAPH + 0x94D3: 0x65A2, //CJK UNIFIED IDEOGRAPH + 0x94D4: 0x65A3, //CJK UNIFIED IDEOGRAPH + 0x94D5: 0x65A6, //CJK UNIFIED IDEOGRAPH + 0x94D6: 0x65A8, //CJK UNIFIED IDEOGRAPH + 0x94D7: 0x65AA, //CJK UNIFIED IDEOGRAPH + 0x94D8: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0x94D9: 0x65AE, //CJK UNIFIED IDEOGRAPH + 0x94DA: 0x65B1, //CJK UNIFIED IDEOGRAPH + 0x94DB: 0x65B2, //CJK UNIFIED IDEOGRAPH + 0x94DC: 0x65B3, //CJK UNIFIED IDEOGRAPH + 0x94DD: 0x65B4, //CJK UNIFIED IDEOGRAPH + 0x94DE: 0x65B5, //CJK UNIFIED IDEOGRAPH + 0x94DF: 0x65B6, //CJK UNIFIED IDEOGRAPH + 0x94E0: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0x94E1: 0x65B8, //CJK UNIFIED IDEOGRAPH + 0x94E2: 0x65BA, //CJK UNIFIED IDEOGRAPH + 0x94E3: 0x65BB, //CJK UNIFIED IDEOGRAPH + 0x94E4: 0x65BE, //CJK UNIFIED IDEOGRAPH + 0x94E5: 0x65BF, //CJK UNIFIED IDEOGRAPH + 0x94E6: 0x65C0, //CJK UNIFIED IDEOGRAPH + 0x94E7: 0x65C2, //CJK UNIFIED IDEOGRAPH + 0x94E8: 0x65C7, //CJK UNIFIED IDEOGRAPH + 0x94E9: 0x65C8, //CJK UNIFIED IDEOGRAPH + 0x94EA: 0x65C9, //CJK UNIFIED IDEOGRAPH + 0x94EB: 0x65CA, //CJK UNIFIED IDEOGRAPH + 0x94EC: 0x65CD, //CJK UNIFIED IDEOGRAPH + 0x94ED: 0x65D0, //CJK UNIFIED IDEOGRAPH + 0x94EE: 0x65D1, //CJK UNIFIED IDEOGRAPH + 0x94EF: 0x65D3, //CJK UNIFIED IDEOGRAPH + 0x94F0: 0x65D4, //CJK UNIFIED IDEOGRAPH + 0x94F1: 0x65D5, //CJK UNIFIED IDEOGRAPH + 0x94F2: 0x65D8, //CJK UNIFIED IDEOGRAPH + 0x94F3: 0x65D9, //CJK UNIFIED IDEOGRAPH + 0x94F4: 0x65DA, //CJK UNIFIED IDEOGRAPH + 0x94F5: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0x94F6: 0x65DC, //CJK UNIFIED IDEOGRAPH + 0x94F7: 0x65DD, //CJK UNIFIED IDEOGRAPH + 0x94F8: 0x65DE, //CJK UNIFIED IDEOGRAPH + 0x94F9: 0x65DF, //CJK UNIFIED IDEOGRAPH + 0x94FA: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0x94FB: 0x65E3, //CJK UNIFIED IDEOGRAPH + 0x94FC: 0x65E4, //CJK UNIFIED IDEOGRAPH + 0x94FD: 0x65EA, //CJK UNIFIED IDEOGRAPH + 0x94FE: 0x65EB, //CJK UNIFIED IDEOGRAPH + 0x9540: 0x65F2, //CJK UNIFIED IDEOGRAPH + 0x9541: 0x65F3, //CJK UNIFIED IDEOGRAPH + 0x9542: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0x9543: 0x65F5, //CJK UNIFIED IDEOGRAPH + 0x9544: 0x65F8, //CJK UNIFIED IDEOGRAPH + 0x9545: 0x65F9, //CJK UNIFIED IDEOGRAPH + 0x9546: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0x9547: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0x9548: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0x9549: 0x65FE, //CJK UNIFIED IDEOGRAPH + 0x954A: 0x65FF, //CJK UNIFIED IDEOGRAPH + 0x954B: 0x6601, //CJK UNIFIED IDEOGRAPH + 0x954C: 0x6604, //CJK UNIFIED IDEOGRAPH + 0x954D: 0x6605, //CJK UNIFIED IDEOGRAPH + 0x954E: 0x6607, //CJK UNIFIED IDEOGRAPH + 0x954F: 0x6608, //CJK UNIFIED IDEOGRAPH + 0x9550: 0x6609, //CJK UNIFIED IDEOGRAPH + 0x9551: 0x660B, //CJK UNIFIED IDEOGRAPH + 0x9552: 0x660D, //CJK UNIFIED IDEOGRAPH + 0x9553: 0x6610, //CJK UNIFIED IDEOGRAPH + 0x9554: 0x6611, //CJK UNIFIED IDEOGRAPH + 0x9555: 0x6612, //CJK UNIFIED IDEOGRAPH + 0x9556: 0x6616, //CJK UNIFIED IDEOGRAPH + 0x9557: 0x6617, //CJK UNIFIED IDEOGRAPH + 0x9558: 0x6618, //CJK UNIFIED IDEOGRAPH + 0x9559: 0x661A, //CJK UNIFIED IDEOGRAPH + 0x955A: 0x661B, //CJK UNIFIED IDEOGRAPH + 0x955B: 0x661C, //CJK UNIFIED IDEOGRAPH + 0x955C: 0x661E, //CJK UNIFIED IDEOGRAPH + 0x955D: 0x6621, //CJK UNIFIED IDEOGRAPH + 0x955E: 0x6622, //CJK UNIFIED IDEOGRAPH + 0x955F: 0x6623, //CJK UNIFIED IDEOGRAPH + 0x9560: 0x6624, //CJK UNIFIED IDEOGRAPH + 0x9561: 0x6626, //CJK UNIFIED IDEOGRAPH + 0x9562: 0x6629, //CJK UNIFIED IDEOGRAPH + 0x9563: 0x662A, //CJK UNIFIED IDEOGRAPH + 0x9564: 0x662B, //CJK UNIFIED IDEOGRAPH + 0x9565: 0x662C, //CJK UNIFIED IDEOGRAPH + 0x9566: 0x662E, //CJK UNIFIED IDEOGRAPH + 0x9567: 0x6630, //CJK UNIFIED IDEOGRAPH + 0x9568: 0x6632, //CJK UNIFIED IDEOGRAPH + 0x9569: 0x6633, //CJK UNIFIED IDEOGRAPH + 0x956A: 0x6637, //CJK UNIFIED IDEOGRAPH + 0x956B: 0x6638, //CJK UNIFIED IDEOGRAPH + 0x956C: 0x6639, //CJK UNIFIED IDEOGRAPH + 0x956D: 0x663A, //CJK UNIFIED IDEOGRAPH + 0x956E: 0x663B, //CJK UNIFIED IDEOGRAPH + 0x956F: 0x663D, //CJK UNIFIED IDEOGRAPH + 0x9570: 0x663F, //CJK UNIFIED IDEOGRAPH + 0x9571: 0x6640, //CJK UNIFIED IDEOGRAPH + 0x9572: 0x6642, //CJK UNIFIED IDEOGRAPH + 0x9573: 0x6644, //CJK UNIFIED IDEOGRAPH + 0x9574: 0x6645, //CJK UNIFIED IDEOGRAPH + 0x9575: 0x6646, //CJK UNIFIED IDEOGRAPH + 0x9576: 0x6647, //CJK UNIFIED IDEOGRAPH + 0x9577: 0x6648, //CJK UNIFIED IDEOGRAPH + 0x9578: 0x6649, //CJK UNIFIED IDEOGRAPH + 0x9579: 0x664A, //CJK UNIFIED IDEOGRAPH + 0x957A: 0x664D, //CJK UNIFIED IDEOGRAPH + 0x957B: 0x664E, //CJK UNIFIED IDEOGRAPH + 0x957C: 0x6650, //CJK UNIFIED IDEOGRAPH + 0x957D: 0x6651, //CJK UNIFIED IDEOGRAPH + 0x957E: 0x6658, //CJK UNIFIED IDEOGRAPH + 0x9580: 0x6659, //CJK UNIFIED IDEOGRAPH + 0x9581: 0x665B, //CJK UNIFIED IDEOGRAPH + 0x9582: 0x665C, //CJK UNIFIED IDEOGRAPH + 0x9583: 0x665D, //CJK UNIFIED IDEOGRAPH + 0x9584: 0x665E, //CJK UNIFIED IDEOGRAPH + 0x9585: 0x6660, //CJK UNIFIED IDEOGRAPH + 0x9586: 0x6662, //CJK UNIFIED IDEOGRAPH + 0x9587: 0x6663, //CJK UNIFIED IDEOGRAPH + 0x9588: 0x6665, //CJK UNIFIED IDEOGRAPH + 0x9589: 0x6667, //CJK UNIFIED IDEOGRAPH + 0x958A: 0x6669, //CJK UNIFIED IDEOGRAPH + 0x958B: 0x666A, //CJK UNIFIED IDEOGRAPH + 0x958C: 0x666B, //CJK UNIFIED IDEOGRAPH + 0x958D: 0x666C, //CJK UNIFIED IDEOGRAPH + 0x958E: 0x666D, //CJK UNIFIED IDEOGRAPH + 0x958F: 0x6671, //CJK UNIFIED IDEOGRAPH + 0x9590: 0x6672, //CJK UNIFIED IDEOGRAPH + 0x9591: 0x6673, //CJK UNIFIED IDEOGRAPH + 0x9592: 0x6675, //CJK UNIFIED IDEOGRAPH + 0x9593: 0x6678, //CJK UNIFIED IDEOGRAPH + 0x9594: 0x6679, //CJK UNIFIED IDEOGRAPH + 0x9595: 0x667B, //CJK UNIFIED IDEOGRAPH + 0x9596: 0x667C, //CJK UNIFIED IDEOGRAPH + 0x9597: 0x667D, //CJK UNIFIED IDEOGRAPH + 0x9598: 0x667F, //CJK UNIFIED IDEOGRAPH + 0x9599: 0x6680, //CJK UNIFIED IDEOGRAPH + 0x959A: 0x6681, //CJK UNIFIED IDEOGRAPH + 0x959B: 0x6683, //CJK UNIFIED IDEOGRAPH + 0x959C: 0x6685, //CJK UNIFIED IDEOGRAPH + 0x959D: 0x6686, //CJK UNIFIED IDEOGRAPH + 0x959E: 0x6688, //CJK UNIFIED IDEOGRAPH + 0x959F: 0x6689, //CJK UNIFIED IDEOGRAPH + 0x95A0: 0x668A, //CJK UNIFIED IDEOGRAPH + 0x95A1: 0x668B, //CJK UNIFIED IDEOGRAPH + 0x95A2: 0x668D, //CJK UNIFIED IDEOGRAPH + 0x95A3: 0x668E, //CJK UNIFIED IDEOGRAPH + 0x95A4: 0x668F, //CJK UNIFIED IDEOGRAPH + 0x95A5: 0x6690, //CJK UNIFIED IDEOGRAPH + 0x95A6: 0x6692, //CJK UNIFIED IDEOGRAPH + 0x95A7: 0x6693, //CJK UNIFIED IDEOGRAPH + 0x95A8: 0x6694, //CJK UNIFIED IDEOGRAPH + 0x95A9: 0x6695, //CJK UNIFIED IDEOGRAPH + 0x95AA: 0x6698, //CJK UNIFIED IDEOGRAPH + 0x95AB: 0x6699, //CJK UNIFIED IDEOGRAPH + 0x95AC: 0x669A, //CJK UNIFIED IDEOGRAPH + 0x95AD: 0x669B, //CJK UNIFIED IDEOGRAPH + 0x95AE: 0x669C, //CJK UNIFIED IDEOGRAPH + 0x95AF: 0x669E, //CJK UNIFIED IDEOGRAPH + 0x95B0: 0x669F, //CJK UNIFIED IDEOGRAPH + 0x95B1: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0x95B2: 0x66A1, //CJK UNIFIED IDEOGRAPH + 0x95B3: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0x95B4: 0x66A3, //CJK UNIFIED IDEOGRAPH + 0x95B5: 0x66A4, //CJK UNIFIED IDEOGRAPH + 0x95B6: 0x66A5, //CJK UNIFIED IDEOGRAPH + 0x95B7: 0x66A6, //CJK UNIFIED IDEOGRAPH + 0x95B8: 0x66A9, //CJK UNIFIED IDEOGRAPH + 0x95B9: 0x66AA, //CJK UNIFIED IDEOGRAPH + 0x95BA: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0x95BB: 0x66AC, //CJK UNIFIED IDEOGRAPH + 0x95BC: 0x66AD, //CJK UNIFIED IDEOGRAPH + 0x95BD: 0x66AF, //CJK UNIFIED IDEOGRAPH + 0x95BE: 0x66B0, //CJK UNIFIED IDEOGRAPH + 0x95BF: 0x66B1, //CJK UNIFIED IDEOGRAPH + 0x95C0: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0x95C1: 0x66B3, //CJK UNIFIED IDEOGRAPH + 0x95C2: 0x66B5, //CJK UNIFIED IDEOGRAPH + 0x95C3: 0x66B6, //CJK UNIFIED IDEOGRAPH + 0x95C4: 0x66B7, //CJK UNIFIED IDEOGRAPH + 0x95C5: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0x95C6: 0x66BA, //CJK UNIFIED IDEOGRAPH + 0x95C7: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0x95C8: 0x66BC, //CJK UNIFIED IDEOGRAPH + 0x95C9: 0x66BD, //CJK UNIFIED IDEOGRAPH + 0x95CA: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0x95CB: 0x66C0, //CJK UNIFIED IDEOGRAPH + 0x95CC: 0x66C1, //CJK UNIFIED IDEOGRAPH + 0x95CD: 0x66C2, //CJK UNIFIED IDEOGRAPH + 0x95CE: 0x66C3, //CJK UNIFIED IDEOGRAPH + 0x95CF: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0x95D0: 0x66C5, //CJK UNIFIED IDEOGRAPH + 0x95D1: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0x95D2: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0x95D3: 0x66C8, //CJK UNIFIED IDEOGRAPH + 0x95D4: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0x95D5: 0x66CA, //CJK UNIFIED IDEOGRAPH + 0x95D6: 0x66CB, //CJK UNIFIED IDEOGRAPH + 0x95D7: 0x66CC, //CJK UNIFIED IDEOGRAPH + 0x95D8: 0x66CD, //CJK UNIFIED IDEOGRAPH + 0x95D9: 0x66CE, //CJK UNIFIED IDEOGRAPH + 0x95DA: 0x66CF, //CJK UNIFIED IDEOGRAPH + 0x95DB: 0x66D0, //CJK UNIFIED IDEOGRAPH + 0x95DC: 0x66D1, //CJK UNIFIED IDEOGRAPH + 0x95DD: 0x66D2, //CJK UNIFIED IDEOGRAPH + 0x95DE: 0x66D3, //CJK UNIFIED IDEOGRAPH + 0x95DF: 0x66D4, //CJK UNIFIED IDEOGRAPH + 0x95E0: 0x66D5, //CJK UNIFIED IDEOGRAPH + 0x95E1: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0x95E2: 0x66D7, //CJK UNIFIED IDEOGRAPH + 0x95E3: 0x66D8, //CJK UNIFIED IDEOGRAPH + 0x95E4: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0x95E5: 0x66DE, //CJK UNIFIED IDEOGRAPH + 0x95E6: 0x66DF, //CJK UNIFIED IDEOGRAPH + 0x95E7: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0x95E8: 0x66E1, //CJK UNIFIED IDEOGRAPH + 0x95E9: 0x66E2, //CJK UNIFIED IDEOGRAPH + 0x95EA: 0x66E3, //CJK UNIFIED IDEOGRAPH + 0x95EB: 0x66E4, //CJK UNIFIED IDEOGRAPH + 0x95EC: 0x66E5, //CJK UNIFIED IDEOGRAPH + 0x95ED: 0x66E7, //CJK UNIFIED IDEOGRAPH + 0x95EE: 0x66E8, //CJK UNIFIED IDEOGRAPH + 0x95EF: 0x66EA, //CJK UNIFIED IDEOGRAPH + 0x95F0: 0x66EB, //CJK UNIFIED IDEOGRAPH + 0x95F1: 0x66EC, //CJK UNIFIED IDEOGRAPH + 0x95F2: 0x66ED, //CJK UNIFIED IDEOGRAPH + 0x95F3: 0x66EE, //CJK UNIFIED IDEOGRAPH + 0x95F4: 0x66EF, //CJK UNIFIED IDEOGRAPH + 0x95F5: 0x66F1, //CJK UNIFIED IDEOGRAPH + 0x95F6: 0x66F5, //CJK UNIFIED IDEOGRAPH + 0x95F7: 0x66F6, //CJK UNIFIED IDEOGRAPH + 0x95F8: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0x95F9: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0x95FA: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0x95FB: 0x66FD, //CJK UNIFIED IDEOGRAPH + 0x95FC: 0x6701, //CJK UNIFIED IDEOGRAPH + 0x95FD: 0x6702, //CJK UNIFIED IDEOGRAPH + 0x95FE: 0x6703, //CJK UNIFIED IDEOGRAPH + 0x9640: 0x6704, //CJK UNIFIED IDEOGRAPH + 0x9641: 0x6705, //CJK UNIFIED IDEOGRAPH + 0x9642: 0x6706, //CJK UNIFIED IDEOGRAPH + 0x9643: 0x6707, //CJK UNIFIED IDEOGRAPH + 0x9644: 0x670C, //CJK UNIFIED IDEOGRAPH + 0x9645: 0x670E, //CJK UNIFIED IDEOGRAPH + 0x9646: 0x670F, //CJK UNIFIED IDEOGRAPH + 0x9647: 0x6711, //CJK UNIFIED IDEOGRAPH + 0x9648: 0x6712, //CJK UNIFIED IDEOGRAPH + 0x9649: 0x6713, //CJK UNIFIED IDEOGRAPH + 0x964A: 0x6716, //CJK UNIFIED IDEOGRAPH + 0x964B: 0x6718, //CJK UNIFIED IDEOGRAPH + 0x964C: 0x6719, //CJK UNIFIED IDEOGRAPH + 0x964D: 0x671A, //CJK UNIFIED IDEOGRAPH + 0x964E: 0x671C, //CJK UNIFIED IDEOGRAPH + 0x964F: 0x671E, //CJK UNIFIED IDEOGRAPH + 0x9650: 0x6720, //CJK UNIFIED IDEOGRAPH + 0x9651: 0x6721, //CJK UNIFIED IDEOGRAPH + 0x9652: 0x6722, //CJK UNIFIED IDEOGRAPH + 0x9653: 0x6723, //CJK UNIFIED IDEOGRAPH + 0x9654: 0x6724, //CJK UNIFIED IDEOGRAPH + 0x9655: 0x6725, //CJK UNIFIED IDEOGRAPH + 0x9656: 0x6727, //CJK UNIFIED IDEOGRAPH + 0x9657: 0x6729, //CJK UNIFIED IDEOGRAPH + 0x9658: 0x672E, //CJK UNIFIED IDEOGRAPH + 0x9659: 0x6730, //CJK UNIFIED IDEOGRAPH + 0x965A: 0x6732, //CJK UNIFIED IDEOGRAPH + 0x965B: 0x6733, //CJK UNIFIED IDEOGRAPH + 0x965C: 0x6736, //CJK UNIFIED IDEOGRAPH + 0x965D: 0x6737, //CJK UNIFIED IDEOGRAPH + 0x965E: 0x6738, //CJK UNIFIED IDEOGRAPH + 0x965F: 0x6739, //CJK UNIFIED IDEOGRAPH + 0x9660: 0x673B, //CJK UNIFIED IDEOGRAPH + 0x9661: 0x673C, //CJK UNIFIED IDEOGRAPH + 0x9662: 0x673E, //CJK UNIFIED IDEOGRAPH + 0x9663: 0x673F, //CJK UNIFIED IDEOGRAPH + 0x9664: 0x6741, //CJK UNIFIED IDEOGRAPH + 0x9665: 0x6744, //CJK UNIFIED IDEOGRAPH + 0x9666: 0x6745, //CJK UNIFIED IDEOGRAPH + 0x9667: 0x6747, //CJK UNIFIED IDEOGRAPH + 0x9668: 0x674A, //CJK UNIFIED IDEOGRAPH + 0x9669: 0x674B, //CJK UNIFIED IDEOGRAPH + 0x966A: 0x674D, //CJK UNIFIED IDEOGRAPH + 0x966B: 0x6752, //CJK UNIFIED IDEOGRAPH + 0x966C: 0x6754, //CJK UNIFIED IDEOGRAPH + 0x966D: 0x6755, //CJK UNIFIED IDEOGRAPH + 0x966E: 0x6757, //CJK UNIFIED IDEOGRAPH + 0x966F: 0x6758, //CJK UNIFIED IDEOGRAPH + 0x9670: 0x6759, //CJK UNIFIED IDEOGRAPH + 0x9671: 0x675A, //CJK UNIFIED IDEOGRAPH + 0x9672: 0x675B, //CJK UNIFIED IDEOGRAPH + 0x9673: 0x675D, //CJK UNIFIED IDEOGRAPH + 0x9674: 0x6762, //CJK UNIFIED IDEOGRAPH + 0x9675: 0x6763, //CJK UNIFIED IDEOGRAPH + 0x9676: 0x6764, //CJK UNIFIED IDEOGRAPH + 0x9677: 0x6766, //CJK UNIFIED IDEOGRAPH + 0x9678: 0x6767, //CJK UNIFIED IDEOGRAPH + 0x9679: 0x676B, //CJK UNIFIED IDEOGRAPH + 0x967A: 0x676C, //CJK UNIFIED IDEOGRAPH + 0x967B: 0x676E, //CJK UNIFIED IDEOGRAPH + 0x967C: 0x6771, //CJK UNIFIED IDEOGRAPH + 0x967D: 0x6774, //CJK UNIFIED IDEOGRAPH + 0x967E: 0x6776, //CJK UNIFIED IDEOGRAPH + 0x9680: 0x6778, //CJK UNIFIED IDEOGRAPH + 0x9681: 0x6779, //CJK UNIFIED IDEOGRAPH + 0x9682: 0x677A, //CJK UNIFIED IDEOGRAPH + 0x9683: 0x677B, //CJK UNIFIED IDEOGRAPH + 0x9684: 0x677D, //CJK UNIFIED IDEOGRAPH + 0x9685: 0x6780, //CJK UNIFIED IDEOGRAPH + 0x9686: 0x6782, //CJK UNIFIED IDEOGRAPH + 0x9687: 0x6783, //CJK UNIFIED IDEOGRAPH + 0x9688: 0x6785, //CJK UNIFIED IDEOGRAPH + 0x9689: 0x6786, //CJK UNIFIED IDEOGRAPH + 0x968A: 0x6788, //CJK UNIFIED IDEOGRAPH + 0x968B: 0x678A, //CJK UNIFIED IDEOGRAPH + 0x968C: 0x678C, //CJK UNIFIED IDEOGRAPH + 0x968D: 0x678D, //CJK UNIFIED IDEOGRAPH + 0x968E: 0x678E, //CJK UNIFIED IDEOGRAPH + 0x968F: 0x678F, //CJK UNIFIED IDEOGRAPH + 0x9690: 0x6791, //CJK UNIFIED IDEOGRAPH + 0x9691: 0x6792, //CJK UNIFIED IDEOGRAPH + 0x9692: 0x6793, //CJK UNIFIED IDEOGRAPH + 0x9693: 0x6794, //CJK UNIFIED IDEOGRAPH + 0x9694: 0x6796, //CJK UNIFIED IDEOGRAPH + 0x9695: 0x6799, //CJK UNIFIED IDEOGRAPH + 0x9696: 0x679B, //CJK UNIFIED IDEOGRAPH + 0x9697: 0x679F, //CJK UNIFIED IDEOGRAPH + 0x9698: 0x67A0, //CJK UNIFIED IDEOGRAPH + 0x9699: 0x67A1, //CJK UNIFIED IDEOGRAPH + 0x969A: 0x67A4, //CJK UNIFIED IDEOGRAPH + 0x969B: 0x67A6, //CJK UNIFIED IDEOGRAPH + 0x969C: 0x67A9, //CJK UNIFIED IDEOGRAPH + 0x969D: 0x67AC, //CJK UNIFIED IDEOGRAPH + 0x969E: 0x67AE, //CJK UNIFIED IDEOGRAPH + 0x969F: 0x67B1, //CJK UNIFIED IDEOGRAPH + 0x96A0: 0x67B2, //CJK UNIFIED IDEOGRAPH + 0x96A1: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0x96A2: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0x96A3: 0x67BA, //CJK UNIFIED IDEOGRAPH + 0x96A4: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0x96A5: 0x67BC, //CJK UNIFIED IDEOGRAPH + 0x96A6: 0x67BD, //CJK UNIFIED IDEOGRAPH + 0x96A7: 0x67BE, //CJK UNIFIED IDEOGRAPH + 0x96A8: 0x67BF, //CJK UNIFIED IDEOGRAPH + 0x96A9: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0x96AA: 0x67C2, //CJK UNIFIED IDEOGRAPH + 0x96AB: 0x67C5, //CJK UNIFIED IDEOGRAPH + 0x96AC: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0x96AD: 0x67C7, //CJK UNIFIED IDEOGRAPH + 0x96AE: 0x67C8, //CJK UNIFIED IDEOGRAPH + 0x96AF: 0x67C9, //CJK UNIFIED IDEOGRAPH + 0x96B0: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0x96B1: 0x67CB, //CJK UNIFIED IDEOGRAPH + 0x96B2: 0x67CC, //CJK UNIFIED IDEOGRAPH + 0x96B3: 0x67CD, //CJK UNIFIED IDEOGRAPH + 0x96B4: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0x96B5: 0x67D5, //CJK UNIFIED IDEOGRAPH + 0x96B6: 0x67D6, //CJK UNIFIED IDEOGRAPH + 0x96B7: 0x67D7, //CJK UNIFIED IDEOGRAPH + 0x96B8: 0x67DB, //CJK UNIFIED IDEOGRAPH + 0x96B9: 0x67DF, //CJK UNIFIED IDEOGRAPH + 0x96BA: 0x67E1, //CJK UNIFIED IDEOGRAPH + 0x96BB: 0x67E3, //CJK UNIFIED IDEOGRAPH + 0x96BC: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0x96BD: 0x67E6, //CJK UNIFIED IDEOGRAPH + 0x96BE: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0x96BF: 0x67E8, //CJK UNIFIED IDEOGRAPH + 0x96C0: 0x67EA, //CJK UNIFIED IDEOGRAPH + 0x96C1: 0x67EB, //CJK UNIFIED IDEOGRAPH + 0x96C2: 0x67ED, //CJK UNIFIED IDEOGRAPH + 0x96C3: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0x96C4: 0x67F2, //CJK UNIFIED IDEOGRAPH + 0x96C5: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0x96C6: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0x96C7: 0x67F7, //CJK UNIFIED IDEOGRAPH + 0x96C8: 0x67F8, //CJK UNIFIED IDEOGRAPH + 0x96C9: 0x67F9, //CJK UNIFIED IDEOGRAPH + 0x96CA: 0x67FA, //CJK UNIFIED IDEOGRAPH + 0x96CB: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0x96CC: 0x67FC, //CJK UNIFIED IDEOGRAPH + 0x96CD: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0x96CE: 0x6801, //CJK UNIFIED IDEOGRAPH + 0x96CF: 0x6802, //CJK UNIFIED IDEOGRAPH + 0x96D0: 0x6803, //CJK UNIFIED IDEOGRAPH + 0x96D1: 0x6804, //CJK UNIFIED IDEOGRAPH + 0x96D2: 0x6806, //CJK UNIFIED IDEOGRAPH + 0x96D3: 0x680D, //CJK UNIFIED IDEOGRAPH + 0x96D4: 0x6810, //CJK UNIFIED IDEOGRAPH + 0x96D5: 0x6812, //CJK UNIFIED IDEOGRAPH + 0x96D6: 0x6814, //CJK UNIFIED IDEOGRAPH + 0x96D7: 0x6815, //CJK UNIFIED IDEOGRAPH + 0x96D8: 0x6818, //CJK UNIFIED IDEOGRAPH + 0x96D9: 0x6819, //CJK UNIFIED IDEOGRAPH + 0x96DA: 0x681A, //CJK UNIFIED IDEOGRAPH + 0x96DB: 0x681B, //CJK UNIFIED IDEOGRAPH + 0x96DC: 0x681C, //CJK UNIFIED IDEOGRAPH + 0x96DD: 0x681E, //CJK UNIFIED IDEOGRAPH + 0x96DE: 0x681F, //CJK UNIFIED IDEOGRAPH + 0x96DF: 0x6820, //CJK UNIFIED IDEOGRAPH + 0x96E0: 0x6822, //CJK UNIFIED IDEOGRAPH + 0x96E1: 0x6823, //CJK UNIFIED IDEOGRAPH + 0x96E2: 0x6824, //CJK UNIFIED IDEOGRAPH + 0x96E3: 0x6825, //CJK UNIFIED IDEOGRAPH + 0x96E4: 0x6826, //CJK UNIFIED IDEOGRAPH + 0x96E5: 0x6827, //CJK UNIFIED IDEOGRAPH + 0x96E6: 0x6828, //CJK UNIFIED IDEOGRAPH + 0x96E7: 0x682B, //CJK UNIFIED IDEOGRAPH + 0x96E8: 0x682C, //CJK UNIFIED IDEOGRAPH + 0x96E9: 0x682D, //CJK UNIFIED IDEOGRAPH + 0x96EA: 0x682E, //CJK UNIFIED IDEOGRAPH + 0x96EB: 0x682F, //CJK UNIFIED IDEOGRAPH + 0x96EC: 0x6830, //CJK UNIFIED IDEOGRAPH + 0x96ED: 0x6831, //CJK UNIFIED IDEOGRAPH + 0x96EE: 0x6834, //CJK UNIFIED IDEOGRAPH + 0x96EF: 0x6835, //CJK UNIFIED IDEOGRAPH + 0x96F0: 0x6836, //CJK UNIFIED IDEOGRAPH + 0x96F1: 0x683A, //CJK UNIFIED IDEOGRAPH + 0x96F2: 0x683B, //CJK UNIFIED IDEOGRAPH + 0x96F3: 0x683F, //CJK UNIFIED IDEOGRAPH + 0x96F4: 0x6847, //CJK UNIFIED IDEOGRAPH + 0x96F5: 0x684B, //CJK UNIFIED IDEOGRAPH + 0x96F6: 0x684D, //CJK UNIFIED IDEOGRAPH + 0x96F7: 0x684F, //CJK UNIFIED IDEOGRAPH + 0x96F8: 0x6852, //CJK UNIFIED IDEOGRAPH + 0x96F9: 0x6856, //CJK UNIFIED IDEOGRAPH + 0x96FA: 0x6857, //CJK UNIFIED IDEOGRAPH + 0x96FB: 0x6858, //CJK UNIFIED IDEOGRAPH + 0x96FC: 0x6859, //CJK UNIFIED IDEOGRAPH + 0x96FD: 0x685A, //CJK UNIFIED IDEOGRAPH + 0x96FE: 0x685B, //CJK UNIFIED IDEOGRAPH + 0x9740: 0x685C, //CJK UNIFIED IDEOGRAPH + 0x9741: 0x685D, //CJK UNIFIED IDEOGRAPH + 0x9742: 0x685E, //CJK UNIFIED IDEOGRAPH + 0x9743: 0x685F, //CJK UNIFIED IDEOGRAPH + 0x9744: 0x686A, //CJK UNIFIED IDEOGRAPH + 0x9745: 0x686C, //CJK UNIFIED IDEOGRAPH + 0x9746: 0x686D, //CJK UNIFIED IDEOGRAPH + 0x9747: 0x686E, //CJK UNIFIED IDEOGRAPH + 0x9748: 0x686F, //CJK UNIFIED IDEOGRAPH + 0x9749: 0x6870, //CJK UNIFIED IDEOGRAPH + 0x974A: 0x6871, //CJK UNIFIED IDEOGRAPH + 0x974B: 0x6872, //CJK UNIFIED IDEOGRAPH + 0x974C: 0x6873, //CJK UNIFIED IDEOGRAPH + 0x974D: 0x6875, //CJK UNIFIED IDEOGRAPH + 0x974E: 0x6878, //CJK UNIFIED IDEOGRAPH + 0x974F: 0x6879, //CJK UNIFIED IDEOGRAPH + 0x9750: 0x687A, //CJK UNIFIED IDEOGRAPH + 0x9751: 0x687B, //CJK UNIFIED IDEOGRAPH + 0x9752: 0x687C, //CJK UNIFIED IDEOGRAPH + 0x9753: 0x687D, //CJK UNIFIED IDEOGRAPH + 0x9754: 0x687E, //CJK UNIFIED IDEOGRAPH + 0x9755: 0x687F, //CJK UNIFIED IDEOGRAPH + 0x9756: 0x6880, //CJK UNIFIED IDEOGRAPH + 0x9757: 0x6882, //CJK UNIFIED IDEOGRAPH + 0x9758: 0x6884, //CJK UNIFIED IDEOGRAPH + 0x9759: 0x6887, //CJK UNIFIED IDEOGRAPH + 0x975A: 0x6888, //CJK UNIFIED IDEOGRAPH + 0x975B: 0x6889, //CJK UNIFIED IDEOGRAPH + 0x975C: 0x688A, //CJK UNIFIED IDEOGRAPH + 0x975D: 0x688B, //CJK UNIFIED IDEOGRAPH + 0x975E: 0x688C, //CJK UNIFIED IDEOGRAPH + 0x975F: 0x688D, //CJK UNIFIED IDEOGRAPH + 0x9760: 0x688E, //CJK UNIFIED IDEOGRAPH + 0x9761: 0x6890, //CJK UNIFIED IDEOGRAPH + 0x9762: 0x6891, //CJK UNIFIED IDEOGRAPH + 0x9763: 0x6892, //CJK UNIFIED IDEOGRAPH + 0x9764: 0x6894, //CJK UNIFIED IDEOGRAPH + 0x9765: 0x6895, //CJK UNIFIED IDEOGRAPH + 0x9766: 0x6896, //CJK UNIFIED IDEOGRAPH + 0x9767: 0x6898, //CJK UNIFIED IDEOGRAPH + 0x9768: 0x6899, //CJK UNIFIED IDEOGRAPH + 0x9769: 0x689A, //CJK UNIFIED IDEOGRAPH + 0x976A: 0x689B, //CJK UNIFIED IDEOGRAPH + 0x976B: 0x689C, //CJK UNIFIED IDEOGRAPH + 0x976C: 0x689D, //CJK UNIFIED IDEOGRAPH + 0x976D: 0x689E, //CJK UNIFIED IDEOGRAPH + 0x976E: 0x689F, //CJK UNIFIED IDEOGRAPH + 0x976F: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0x9770: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0x9771: 0x68A3, //CJK UNIFIED IDEOGRAPH + 0x9772: 0x68A4, //CJK UNIFIED IDEOGRAPH + 0x9773: 0x68A5, //CJK UNIFIED IDEOGRAPH + 0x9774: 0x68A9, //CJK UNIFIED IDEOGRAPH + 0x9775: 0x68AA, //CJK UNIFIED IDEOGRAPH + 0x9776: 0x68AB, //CJK UNIFIED IDEOGRAPH + 0x9777: 0x68AC, //CJK UNIFIED IDEOGRAPH + 0x9778: 0x68AE, //CJK UNIFIED IDEOGRAPH + 0x9779: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0x977A: 0x68B2, //CJK UNIFIED IDEOGRAPH + 0x977B: 0x68B4, //CJK UNIFIED IDEOGRAPH + 0x977C: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0x977D: 0x68B7, //CJK UNIFIED IDEOGRAPH + 0x977E: 0x68B8, //CJK UNIFIED IDEOGRAPH + 0x9780: 0x68B9, //CJK UNIFIED IDEOGRAPH + 0x9781: 0x68BA, //CJK UNIFIED IDEOGRAPH + 0x9782: 0x68BB, //CJK UNIFIED IDEOGRAPH + 0x9783: 0x68BC, //CJK UNIFIED IDEOGRAPH + 0x9784: 0x68BD, //CJK UNIFIED IDEOGRAPH + 0x9785: 0x68BE, //CJK UNIFIED IDEOGRAPH + 0x9786: 0x68BF, //CJK UNIFIED IDEOGRAPH + 0x9787: 0x68C1, //CJK UNIFIED IDEOGRAPH + 0x9788: 0x68C3, //CJK UNIFIED IDEOGRAPH + 0x9789: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0x978A: 0x68C5, //CJK UNIFIED IDEOGRAPH + 0x978B: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0x978C: 0x68C7, //CJK UNIFIED IDEOGRAPH + 0x978D: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0x978E: 0x68CA, //CJK UNIFIED IDEOGRAPH + 0x978F: 0x68CC, //CJK UNIFIED IDEOGRAPH + 0x9790: 0x68CE, //CJK UNIFIED IDEOGRAPH + 0x9791: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0x9792: 0x68D0, //CJK UNIFIED IDEOGRAPH + 0x9793: 0x68D1, //CJK UNIFIED IDEOGRAPH + 0x9794: 0x68D3, //CJK UNIFIED IDEOGRAPH + 0x9795: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0x9796: 0x68D6, //CJK UNIFIED IDEOGRAPH + 0x9797: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0x9798: 0x68D9, //CJK UNIFIED IDEOGRAPH + 0x9799: 0x68DB, //CJK UNIFIED IDEOGRAPH + 0x979A: 0x68DC, //CJK UNIFIED IDEOGRAPH + 0x979B: 0x68DD, //CJK UNIFIED IDEOGRAPH + 0x979C: 0x68DE, //CJK UNIFIED IDEOGRAPH + 0x979D: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0x979E: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0x979F: 0x68E2, //CJK UNIFIED IDEOGRAPH + 0x97A0: 0x68E4, //CJK UNIFIED IDEOGRAPH + 0x97A1: 0x68E5, //CJK UNIFIED IDEOGRAPH + 0x97A2: 0x68E6, //CJK UNIFIED IDEOGRAPH + 0x97A3: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0x97A4: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0x97A5: 0x68E9, //CJK UNIFIED IDEOGRAPH + 0x97A6: 0x68EA, //CJK UNIFIED IDEOGRAPH + 0x97A7: 0x68EB, //CJK UNIFIED IDEOGRAPH + 0x97A8: 0x68EC, //CJK UNIFIED IDEOGRAPH + 0x97A9: 0x68ED, //CJK UNIFIED IDEOGRAPH + 0x97AA: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0x97AB: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0x97AC: 0x68F3, //CJK UNIFIED IDEOGRAPH + 0x97AD: 0x68F4, //CJK UNIFIED IDEOGRAPH + 0x97AE: 0x68F6, //CJK UNIFIED IDEOGRAPH + 0x97AF: 0x68F7, //CJK UNIFIED IDEOGRAPH + 0x97B0: 0x68F8, //CJK UNIFIED IDEOGRAPH + 0x97B1: 0x68FB, //CJK UNIFIED IDEOGRAPH + 0x97B2: 0x68FD, //CJK UNIFIED IDEOGRAPH + 0x97B3: 0x68FE, //CJK UNIFIED IDEOGRAPH + 0x97B4: 0x68FF, //CJK UNIFIED IDEOGRAPH + 0x97B5: 0x6900, //CJK UNIFIED IDEOGRAPH + 0x97B6: 0x6902, //CJK UNIFIED IDEOGRAPH + 0x97B7: 0x6903, //CJK UNIFIED IDEOGRAPH + 0x97B8: 0x6904, //CJK UNIFIED IDEOGRAPH + 0x97B9: 0x6906, //CJK UNIFIED IDEOGRAPH + 0x97BA: 0x6907, //CJK UNIFIED IDEOGRAPH + 0x97BB: 0x6908, //CJK UNIFIED IDEOGRAPH + 0x97BC: 0x6909, //CJK UNIFIED IDEOGRAPH + 0x97BD: 0x690A, //CJK UNIFIED IDEOGRAPH + 0x97BE: 0x690C, //CJK UNIFIED IDEOGRAPH + 0x97BF: 0x690F, //CJK UNIFIED IDEOGRAPH + 0x97C0: 0x6911, //CJK UNIFIED IDEOGRAPH + 0x97C1: 0x6913, //CJK UNIFIED IDEOGRAPH + 0x97C2: 0x6914, //CJK UNIFIED IDEOGRAPH + 0x97C3: 0x6915, //CJK UNIFIED IDEOGRAPH + 0x97C4: 0x6916, //CJK UNIFIED IDEOGRAPH + 0x97C5: 0x6917, //CJK UNIFIED IDEOGRAPH + 0x97C6: 0x6918, //CJK UNIFIED IDEOGRAPH + 0x97C7: 0x6919, //CJK UNIFIED IDEOGRAPH + 0x97C8: 0x691A, //CJK UNIFIED IDEOGRAPH + 0x97C9: 0x691B, //CJK UNIFIED IDEOGRAPH + 0x97CA: 0x691C, //CJK UNIFIED IDEOGRAPH + 0x97CB: 0x691D, //CJK UNIFIED IDEOGRAPH + 0x97CC: 0x691E, //CJK UNIFIED IDEOGRAPH + 0x97CD: 0x6921, //CJK UNIFIED IDEOGRAPH + 0x97CE: 0x6922, //CJK UNIFIED IDEOGRAPH + 0x97CF: 0x6923, //CJK UNIFIED IDEOGRAPH + 0x97D0: 0x6925, //CJK UNIFIED IDEOGRAPH + 0x97D1: 0x6926, //CJK UNIFIED IDEOGRAPH + 0x97D2: 0x6927, //CJK UNIFIED IDEOGRAPH + 0x97D3: 0x6928, //CJK UNIFIED IDEOGRAPH + 0x97D4: 0x6929, //CJK UNIFIED IDEOGRAPH + 0x97D5: 0x692A, //CJK UNIFIED IDEOGRAPH + 0x97D6: 0x692B, //CJK UNIFIED IDEOGRAPH + 0x97D7: 0x692C, //CJK UNIFIED IDEOGRAPH + 0x97D8: 0x692E, //CJK UNIFIED IDEOGRAPH + 0x97D9: 0x692F, //CJK UNIFIED IDEOGRAPH + 0x97DA: 0x6931, //CJK UNIFIED IDEOGRAPH + 0x97DB: 0x6932, //CJK UNIFIED IDEOGRAPH + 0x97DC: 0x6933, //CJK UNIFIED IDEOGRAPH + 0x97DD: 0x6935, //CJK UNIFIED IDEOGRAPH + 0x97DE: 0x6936, //CJK UNIFIED IDEOGRAPH + 0x97DF: 0x6937, //CJK UNIFIED IDEOGRAPH + 0x97E0: 0x6938, //CJK UNIFIED IDEOGRAPH + 0x97E1: 0x693A, //CJK UNIFIED IDEOGRAPH + 0x97E2: 0x693B, //CJK UNIFIED IDEOGRAPH + 0x97E3: 0x693C, //CJK UNIFIED IDEOGRAPH + 0x97E4: 0x693E, //CJK UNIFIED IDEOGRAPH + 0x97E5: 0x6940, //CJK UNIFIED IDEOGRAPH + 0x97E6: 0x6941, //CJK UNIFIED IDEOGRAPH + 0x97E7: 0x6943, //CJK UNIFIED IDEOGRAPH + 0x97E8: 0x6944, //CJK UNIFIED IDEOGRAPH + 0x97E9: 0x6945, //CJK UNIFIED IDEOGRAPH + 0x97EA: 0x6946, //CJK UNIFIED IDEOGRAPH + 0x97EB: 0x6947, //CJK UNIFIED IDEOGRAPH + 0x97EC: 0x6948, //CJK UNIFIED IDEOGRAPH + 0x97ED: 0x6949, //CJK UNIFIED IDEOGRAPH + 0x97EE: 0x694A, //CJK UNIFIED IDEOGRAPH + 0x97EF: 0x694B, //CJK UNIFIED IDEOGRAPH + 0x97F0: 0x694C, //CJK UNIFIED IDEOGRAPH + 0x97F1: 0x694D, //CJK UNIFIED IDEOGRAPH + 0x97F2: 0x694E, //CJK UNIFIED IDEOGRAPH + 0x97F3: 0x694F, //CJK UNIFIED IDEOGRAPH + 0x97F4: 0x6950, //CJK UNIFIED IDEOGRAPH + 0x97F5: 0x6951, //CJK UNIFIED IDEOGRAPH + 0x97F6: 0x6952, //CJK UNIFIED IDEOGRAPH + 0x97F7: 0x6953, //CJK UNIFIED IDEOGRAPH + 0x97F8: 0x6955, //CJK UNIFIED IDEOGRAPH + 0x97F9: 0x6956, //CJK UNIFIED IDEOGRAPH + 0x97FA: 0x6958, //CJK UNIFIED IDEOGRAPH + 0x97FB: 0x6959, //CJK UNIFIED IDEOGRAPH + 0x97FC: 0x695B, //CJK UNIFIED IDEOGRAPH + 0x97FD: 0x695C, //CJK UNIFIED IDEOGRAPH + 0x97FE: 0x695F, //CJK UNIFIED IDEOGRAPH + 0x9840: 0x6961, //CJK UNIFIED IDEOGRAPH + 0x9841: 0x6962, //CJK UNIFIED IDEOGRAPH + 0x9842: 0x6964, //CJK UNIFIED IDEOGRAPH + 0x9843: 0x6965, //CJK UNIFIED IDEOGRAPH + 0x9844: 0x6967, //CJK UNIFIED IDEOGRAPH + 0x9845: 0x6968, //CJK UNIFIED IDEOGRAPH + 0x9846: 0x6969, //CJK UNIFIED IDEOGRAPH + 0x9847: 0x696A, //CJK UNIFIED IDEOGRAPH + 0x9848: 0x696C, //CJK UNIFIED IDEOGRAPH + 0x9849: 0x696D, //CJK UNIFIED IDEOGRAPH + 0x984A: 0x696F, //CJK UNIFIED IDEOGRAPH + 0x984B: 0x6970, //CJK UNIFIED IDEOGRAPH + 0x984C: 0x6972, //CJK UNIFIED IDEOGRAPH + 0x984D: 0x6973, //CJK UNIFIED IDEOGRAPH + 0x984E: 0x6974, //CJK UNIFIED IDEOGRAPH + 0x984F: 0x6975, //CJK UNIFIED IDEOGRAPH + 0x9850: 0x6976, //CJK UNIFIED IDEOGRAPH + 0x9851: 0x697A, //CJK UNIFIED IDEOGRAPH + 0x9852: 0x697B, //CJK UNIFIED IDEOGRAPH + 0x9853: 0x697D, //CJK UNIFIED IDEOGRAPH + 0x9854: 0x697E, //CJK UNIFIED IDEOGRAPH + 0x9855: 0x697F, //CJK UNIFIED IDEOGRAPH + 0x9856: 0x6981, //CJK UNIFIED IDEOGRAPH + 0x9857: 0x6983, //CJK UNIFIED IDEOGRAPH + 0x9858: 0x6985, //CJK UNIFIED IDEOGRAPH + 0x9859: 0x698A, //CJK UNIFIED IDEOGRAPH + 0x985A: 0x698B, //CJK UNIFIED IDEOGRAPH + 0x985B: 0x698C, //CJK UNIFIED IDEOGRAPH + 0x985C: 0x698E, //CJK UNIFIED IDEOGRAPH + 0x985D: 0x698F, //CJK UNIFIED IDEOGRAPH + 0x985E: 0x6990, //CJK UNIFIED IDEOGRAPH + 0x985F: 0x6991, //CJK UNIFIED IDEOGRAPH + 0x9860: 0x6992, //CJK UNIFIED IDEOGRAPH + 0x9861: 0x6993, //CJK UNIFIED IDEOGRAPH + 0x9862: 0x6996, //CJK UNIFIED IDEOGRAPH + 0x9863: 0x6997, //CJK UNIFIED IDEOGRAPH + 0x9864: 0x6999, //CJK UNIFIED IDEOGRAPH + 0x9865: 0x699A, //CJK UNIFIED IDEOGRAPH + 0x9866: 0x699D, //CJK UNIFIED IDEOGRAPH + 0x9867: 0x699E, //CJK UNIFIED IDEOGRAPH + 0x9868: 0x699F, //CJK UNIFIED IDEOGRAPH + 0x9869: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0x986A: 0x69A1, //CJK UNIFIED IDEOGRAPH + 0x986B: 0x69A2, //CJK UNIFIED IDEOGRAPH + 0x986C: 0x69A3, //CJK UNIFIED IDEOGRAPH + 0x986D: 0x69A4, //CJK UNIFIED IDEOGRAPH + 0x986E: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0x986F: 0x69A6, //CJK UNIFIED IDEOGRAPH + 0x9870: 0x69A9, //CJK UNIFIED IDEOGRAPH + 0x9871: 0x69AA, //CJK UNIFIED IDEOGRAPH + 0x9872: 0x69AC, //CJK UNIFIED IDEOGRAPH + 0x9873: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0x9874: 0x69AF, //CJK UNIFIED IDEOGRAPH + 0x9875: 0x69B0, //CJK UNIFIED IDEOGRAPH + 0x9876: 0x69B2, //CJK UNIFIED IDEOGRAPH + 0x9877: 0x69B3, //CJK UNIFIED IDEOGRAPH + 0x9878: 0x69B5, //CJK UNIFIED IDEOGRAPH + 0x9879: 0x69B6, //CJK UNIFIED IDEOGRAPH + 0x987A: 0x69B8, //CJK UNIFIED IDEOGRAPH + 0x987B: 0x69B9, //CJK UNIFIED IDEOGRAPH + 0x987C: 0x69BA, //CJK UNIFIED IDEOGRAPH + 0x987D: 0x69BC, //CJK UNIFIED IDEOGRAPH + 0x987E: 0x69BD, //CJK UNIFIED IDEOGRAPH + 0x9880: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0x9881: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0x9882: 0x69C0, //CJK UNIFIED IDEOGRAPH + 0x9883: 0x69C2, //CJK UNIFIED IDEOGRAPH + 0x9884: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0x9885: 0x69C4, //CJK UNIFIED IDEOGRAPH + 0x9886: 0x69C5, //CJK UNIFIED IDEOGRAPH + 0x9887: 0x69C6, //CJK UNIFIED IDEOGRAPH + 0x9888: 0x69C7, //CJK UNIFIED IDEOGRAPH + 0x9889: 0x69C8, //CJK UNIFIED IDEOGRAPH + 0x988A: 0x69C9, //CJK UNIFIED IDEOGRAPH + 0x988B: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0x988C: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0x988D: 0x69CF, //CJK UNIFIED IDEOGRAPH + 0x988E: 0x69D1, //CJK UNIFIED IDEOGRAPH + 0x988F: 0x69D2, //CJK UNIFIED IDEOGRAPH + 0x9890: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0x9891: 0x69D5, //CJK UNIFIED IDEOGRAPH + 0x9892: 0x69D6, //CJK UNIFIED IDEOGRAPH + 0x9893: 0x69D7, //CJK UNIFIED IDEOGRAPH + 0x9894: 0x69D8, //CJK UNIFIED IDEOGRAPH + 0x9895: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0x9896: 0x69DA, //CJK UNIFIED IDEOGRAPH + 0x9897: 0x69DC, //CJK UNIFIED IDEOGRAPH + 0x9898: 0x69DD, //CJK UNIFIED IDEOGRAPH + 0x9899: 0x69DE, //CJK UNIFIED IDEOGRAPH + 0x989A: 0x69E1, //CJK UNIFIED IDEOGRAPH + 0x989B: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0x989C: 0x69E3, //CJK UNIFIED IDEOGRAPH + 0x989D: 0x69E4, //CJK UNIFIED IDEOGRAPH + 0x989E: 0x69E5, //CJK UNIFIED IDEOGRAPH + 0x989F: 0x69E6, //CJK UNIFIED IDEOGRAPH + 0x98A0: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0x98A1: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0x98A2: 0x69E9, //CJK UNIFIED IDEOGRAPH + 0x98A3: 0x69EA, //CJK UNIFIED IDEOGRAPH + 0x98A4: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0x98A5: 0x69EC, //CJK UNIFIED IDEOGRAPH + 0x98A6: 0x69EE, //CJK UNIFIED IDEOGRAPH + 0x98A7: 0x69EF, //CJK UNIFIED IDEOGRAPH + 0x98A8: 0x69F0, //CJK UNIFIED IDEOGRAPH + 0x98A9: 0x69F1, //CJK UNIFIED IDEOGRAPH + 0x98AA: 0x69F3, //CJK UNIFIED IDEOGRAPH + 0x98AB: 0x69F4, //CJK UNIFIED IDEOGRAPH + 0x98AC: 0x69F5, //CJK UNIFIED IDEOGRAPH + 0x98AD: 0x69F6, //CJK UNIFIED IDEOGRAPH + 0x98AE: 0x69F7, //CJK UNIFIED IDEOGRAPH + 0x98AF: 0x69F8, //CJK UNIFIED IDEOGRAPH + 0x98B0: 0x69F9, //CJK UNIFIED IDEOGRAPH + 0x98B1: 0x69FA, //CJK UNIFIED IDEOGRAPH + 0x98B2: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0x98B3: 0x69FC, //CJK UNIFIED IDEOGRAPH + 0x98B4: 0x69FE, //CJK UNIFIED IDEOGRAPH + 0x98B5: 0x6A00, //CJK UNIFIED IDEOGRAPH + 0x98B6: 0x6A01, //CJK UNIFIED IDEOGRAPH + 0x98B7: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0x98B8: 0x6A03, //CJK UNIFIED IDEOGRAPH + 0x98B9: 0x6A04, //CJK UNIFIED IDEOGRAPH + 0x98BA: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0x98BB: 0x6A06, //CJK UNIFIED IDEOGRAPH + 0x98BC: 0x6A07, //CJK UNIFIED IDEOGRAPH + 0x98BD: 0x6A08, //CJK UNIFIED IDEOGRAPH + 0x98BE: 0x6A09, //CJK UNIFIED IDEOGRAPH + 0x98BF: 0x6A0B, //CJK UNIFIED IDEOGRAPH + 0x98C0: 0x6A0C, //CJK UNIFIED IDEOGRAPH + 0x98C1: 0x6A0D, //CJK UNIFIED IDEOGRAPH + 0x98C2: 0x6A0E, //CJK UNIFIED IDEOGRAPH + 0x98C3: 0x6A0F, //CJK UNIFIED IDEOGRAPH + 0x98C4: 0x6A10, //CJK UNIFIED IDEOGRAPH + 0x98C5: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0x98C6: 0x6A12, //CJK UNIFIED IDEOGRAPH + 0x98C7: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0x98C8: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0x98C9: 0x6A15, //CJK UNIFIED IDEOGRAPH + 0x98CA: 0x6A16, //CJK UNIFIED IDEOGRAPH + 0x98CB: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0x98CC: 0x6A1A, //CJK UNIFIED IDEOGRAPH + 0x98CD: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0x98CE: 0x6A1C, //CJK UNIFIED IDEOGRAPH + 0x98CF: 0x6A1D, //CJK UNIFIED IDEOGRAPH + 0x98D0: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0x98D1: 0x6A20, //CJK UNIFIED IDEOGRAPH + 0x98D2: 0x6A22, //CJK UNIFIED IDEOGRAPH + 0x98D3: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0x98D4: 0x6A24, //CJK UNIFIED IDEOGRAPH + 0x98D5: 0x6A25, //CJK UNIFIED IDEOGRAPH + 0x98D6: 0x6A26, //CJK UNIFIED IDEOGRAPH + 0x98D7: 0x6A27, //CJK UNIFIED IDEOGRAPH + 0x98D8: 0x6A29, //CJK UNIFIED IDEOGRAPH + 0x98D9: 0x6A2B, //CJK UNIFIED IDEOGRAPH + 0x98DA: 0x6A2C, //CJK UNIFIED IDEOGRAPH + 0x98DB: 0x6A2D, //CJK UNIFIED IDEOGRAPH + 0x98DC: 0x6A2E, //CJK UNIFIED IDEOGRAPH + 0x98DD: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0x98DE: 0x6A32, //CJK UNIFIED IDEOGRAPH + 0x98DF: 0x6A33, //CJK UNIFIED IDEOGRAPH + 0x98E0: 0x6A34, //CJK UNIFIED IDEOGRAPH + 0x98E1: 0x6A36, //CJK UNIFIED IDEOGRAPH + 0x98E2: 0x6A37, //CJK UNIFIED IDEOGRAPH + 0x98E3: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0x98E4: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0x98E5: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0x98E6: 0x6A3B, //CJK UNIFIED IDEOGRAPH + 0x98E7: 0x6A3C, //CJK UNIFIED IDEOGRAPH + 0x98E8: 0x6A3F, //CJK UNIFIED IDEOGRAPH + 0x98E9: 0x6A40, //CJK UNIFIED IDEOGRAPH + 0x98EA: 0x6A41, //CJK UNIFIED IDEOGRAPH + 0x98EB: 0x6A42, //CJK UNIFIED IDEOGRAPH + 0x98EC: 0x6A43, //CJK UNIFIED IDEOGRAPH + 0x98ED: 0x6A45, //CJK UNIFIED IDEOGRAPH + 0x98EE: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0x98EF: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0x98F0: 0x6A49, //CJK UNIFIED IDEOGRAPH + 0x98F1: 0x6A4A, //CJK UNIFIED IDEOGRAPH + 0x98F2: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0x98F3: 0x6A4C, //CJK UNIFIED IDEOGRAPH + 0x98F4: 0x6A4D, //CJK UNIFIED IDEOGRAPH + 0x98F5: 0x6A4E, //CJK UNIFIED IDEOGRAPH + 0x98F6: 0x6A4F, //CJK UNIFIED IDEOGRAPH + 0x98F7: 0x6A51, //CJK UNIFIED IDEOGRAPH + 0x98F8: 0x6A52, //CJK UNIFIED IDEOGRAPH + 0x98F9: 0x6A53, //CJK UNIFIED IDEOGRAPH + 0x98FA: 0x6A54, //CJK UNIFIED IDEOGRAPH + 0x98FB: 0x6A55, //CJK UNIFIED IDEOGRAPH + 0x98FC: 0x6A56, //CJK UNIFIED IDEOGRAPH + 0x98FD: 0x6A57, //CJK UNIFIED IDEOGRAPH + 0x98FE: 0x6A5A, //CJK UNIFIED IDEOGRAPH + 0x9940: 0x6A5C, //CJK UNIFIED IDEOGRAPH + 0x9941: 0x6A5D, //CJK UNIFIED IDEOGRAPH + 0x9942: 0x6A5E, //CJK UNIFIED IDEOGRAPH + 0x9943: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0x9944: 0x6A60, //CJK UNIFIED IDEOGRAPH + 0x9945: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0x9946: 0x6A63, //CJK UNIFIED IDEOGRAPH + 0x9947: 0x6A64, //CJK UNIFIED IDEOGRAPH + 0x9948: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0x9949: 0x6A67, //CJK UNIFIED IDEOGRAPH + 0x994A: 0x6A68, //CJK UNIFIED IDEOGRAPH + 0x994B: 0x6A69, //CJK UNIFIED IDEOGRAPH + 0x994C: 0x6A6A, //CJK UNIFIED IDEOGRAPH + 0x994D: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0x994E: 0x6A6C, //CJK UNIFIED IDEOGRAPH + 0x994F: 0x6A6D, //CJK UNIFIED IDEOGRAPH + 0x9950: 0x6A6E, //CJK UNIFIED IDEOGRAPH + 0x9951: 0x6A6F, //CJK UNIFIED IDEOGRAPH + 0x9952: 0x6A70, //CJK UNIFIED IDEOGRAPH + 0x9953: 0x6A72, //CJK UNIFIED IDEOGRAPH + 0x9954: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0x9955: 0x6A74, //CJK UNIFIED IDEOGRAPH + 0x9956: 0x6A75, //CJK UNIFIED IDEOGRAPH + 0x9957: 0x6A76, //CJK UNIFIED IDEOGRAPH + 0x9958: 0x6A77, //CJK UNIFIED IDEOGRAPH + 0x9959: 0x6A78, //CJK UNIFIED IDEOGRAPH + 0x995A: 0x6A7A, //CJK UNIFIED IDEOGRAPH + 0x995B: 0x6A7B, //CJK UNIFIED IDEOGRAPH + 0x995C: 0x6A7D, //CJK UNIFIED IDEOGRAPH + 0x995D: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0x995E: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0x995F: 0x6A81, //CJK UNIFIED IDEOGRAPH + 0x9960: 0x6A82, //CJK UNIFIED IDEOGRAPH + 0x9961: 0x6A83, //CJK UNIFIED IDEOGRAPH + 0x9962: 0x6A85, //CJK UNIFIED IDEOGRAPH + 0x9963: 0x6A86, //CJK UNIFIED IDEOGRAPH + 0x9964: 0x6A87, //CJK UNIFIED IDEOGRAPH + 0x9965: 0x6A88, //CJK UNIFIED IDEOGRAPH + 0x9966: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0x9967: 0x6A8A, //CJK UNIFIED IDEOGRAPH + 0x9968: 0x6A8B, //CJK UNIFIED IDEOGRAPH + 0x9969: 0x6A8C, //CJK UNIFIED IDEOGRAPH + 0x996A: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0x996B: 0x6A8F, //CJK UNIFIED IDEOGRAPH + 0x996C: 0x6A92, //CJK UNIFIED IDEOGRAPH + 0x996D: 0x6A93, //CJK UNIFIED IDEOGRAPH + 0x996E: 0x6A94, //CJK UNIFIED IDEOGRAPH + 0x996F: 0x6A95, //CJK UNIFIED IDEOGRAPH + 0x9970: 0x6A96, //CJK UNIFIED IDEOGRAPH + 0x9971: 0x6A98, //CJK UNIFIED IDEOGRAPH + 0x9972: 0x6A99, //CJK UNIFIED IDEOGRAPH + 0x9973: 0x6A9A, //CJK UNIFIED IDEOGRAPH + 0x9974: 0x6A9B, //CJK UNIFIED IDEOGRAPH + 0x9975: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0x9976: 0x6A9D, //CJK UNIFIED IDEOGRAPH + 0x9977: 0x6A9E, //CJK UNIFIED IDEOGRAPH + 0x9978: 0x6A9F, //CJK UNIFIED IDEOGRAPH + 0x9979: 0x6AA1, //CJK UNIFIED IDEOGRAPH + 0x997A: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0x997B: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0x997C: 0x6AA4, //CJK UNIFIED IDEOGRAPH + 0x997D: 0x6AA5, //CJK UNIFIED IDEOGRAPH + 0x997E: 0x6AA6, //CJK UNIFIED IDEOGRAPH + 0x9980: 0x6AA7, //CJK UNIFIED IDEOGRAPH + 0x9981: 0x6AA8, //CJK UNIFIED IDEOGRAPH + 0x9982: 0x6AAA, //CJK UNIFIED IDEOGRAPH + 0x9983: 0x6AAD, //CJK UNIFIED IDEOGRAPH + 0x9984: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0x9985: 0x6AAF, //CJK UNIFIED IDEOGRAPH + 0x9986: 0x6AB0, //CJK UNIFIED IDEOGRAPH + 0x9987: 0x6AB1, //CJK UNIFIED IDEOGRAPH + 0x9988: 0x6AB2, //CJK UNIFIED IDEOGRAPH + 0x9989: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0x998A: 0x6AB4, //CJK UNIFIED IDEOGRAPH + 0x998B: 0x6AB5, //CJK UNIFIED IDEOGRAPH + 0x998C: 0x6AB6, //CJK UNIFIED IDEOGRAPH + 0x998D: 0x6AB7, //CJK UNIFIED IDEOGRAPH + 0x998E: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0x998F: 0x6AB9, //CJK UNIFIED IDEOGRAPH + 0x9990: 0x6ABA, //CJK UNIFIED IDEOGRAPH + 0x9991: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0x9992: 0x6ABC, //CJK UNIFIED IDEOGRAPH + 0x9993: 0x6ABD, //CJK UNIFIED IDEOGRAPH + 0x9994: 0x6ABE, //CJK UNIFIED IDEOGRAPH + 0x9995: 0x6ABF, //CJK UNIFIED IDEOGRAPH + 0x9996: 0x6AC0, //CJK UNIFIED IDEOGRAPH + 0x9997: 0x6AC1, //CJK UNIFIED IDEOGRAPH + 0x9998: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0x9999: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0x999A: 0x6AC4, //CJK UNIFIED IDEOGRAPH + 0x999B: 0x6AC5, //CJK UNIFIED IDEOGRAPH + 0x999C: 0x6AC6, //CJK UNIFIED IDEOGRAPH + 0x999D: 0x6AC7, //CJK UNIFIED IDEOGRAPH + 0x999E: 0x6AC8, //CJK UNIFIED IDEOGRAPH + 0x999F: 0x6AC9, //CJK UNIFIED IDEOGRAPH + 0x99A0: 0x6ACA, //CJK UNIFIED IDEOGRAPH + 0x99A1: 0x6ACB, //CJK UNIFIED IDEOGRAPH + 0x99A2: 0x6ACC, //CJK UNIFIED IDEOGRAPH + 0x99A3: 0x6ACD, //CJK UNIFIED IDEOGRAPH + 0x99A4: 0x6ACE, //CJK UNIFIED IDEOGRAPH + 0x99A5: 0x6ACF, //CJK UNIFIED IDEOGRAPH + 0x99A6: 0x6AD0, //CJK UNIFIED IDEOGRAPH + 0x99A7: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0x99A8: 0x6AD2, //CJK UNIFIED IDEOGRAPH + 0x99A9: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0x99AA: 0x6AD4, //CJK UNIFIED IDEOGRAPH + 0x99AB: 0x6AD5, //CJK UNIFIED IDEOGRAPH + 0x99AC: 0x6AD6, //CJK UNIFIED IDEOGRAPH + 0x99AD: 0x6AD7, //CJK UNIFIED IDEOGRAPH + 0x99AE: 0x6AD8, //CJK UNIFIED IDEOGRAPH + 0x99AF: 0x6AD9, //CJK UNIFIED IDEOGRAPH + 0x99B0: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0x99B1: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0x99B2: 0x6ADC, //CJK UNIFIED IDEOGRAPH + 0x99B3: 0x6ADD, //CJK UNIFIED IDEOGRAPH + 0x99B4: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0x99B5: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0x99B6: 0x6AE0, //CJK UNIFIED IDEOGRAPH + 0x99B7: 0x6AE1, //CJK UNIFIED IDEOGRAPH + 0x99B8: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0x99B9: 0x6AE3, //CJK UNIFIED IDEOGRAPH + 0x99BA: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0x99BB: 0x6AE5, //CJK UNIFIED IDEOGRAPH + 0x99BC: 0x6AE6, //CJK UNIFIED IDEOGRAPH + 0x99BD: 0x6AE7, //CJK UNIFIED IDEOGRAPH + 0x99BE: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0x99BF: 0x6AE9, //CJK UNIFIED IDEOGRAPH + 0x99C0: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0x99C1: 0x6AEB, //CJK UNIFIED IDEOGRAPH + 0x99C2: 0x6AEC, //CJK UNIFIED IDEOGRAPH + 0x99C3: 0x6AED, //CJK UNIFIED IDEOGRAPH + 0x99C4: 0x6AEE, //CJK UNIFIED IDEOGRAPH + 0x99C5: 0x6AEF, //CJK UNIFIED IDEOGRAPH + 0x99C6: 0x6AF0, //CJK UNIFIED IDEOGRAPH + 0x99C7: 0x6AF1, //CJK UNIFIED IDEOGRAPH + 0x99C8: 0x6AF2, //CJK UNIFIED IDEOGRAPH + 0x99C9: 0x6AF3, //CJK UNIFIED IDEOGRAPH + 0x99CA: 0x6AF4, //CJK UNIFIED IDEOGRAPH + 0x99CB: 0x6AF5, //CJK UNIFIED IDEOGRAPH + 0x99CC: 0x6AF6, //CJK UNIFIED IDEOGRAPH + 0x99CD: 0x6AF7, //CJK UNIFIED IDEOGRAPH + 0x99CE: 0x6AF8, //CJK UNIFIED IDEOGRAPH + 0x99CF: 0x6AF9, //CJK UNIFIED IDEOGRAPH + 0x99D0: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0x99D1: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0x99D2: 0x6AFC, //CJK UNIFIED IDEOGRAPH + 0x99D3: 0x6AFD, //CJK UNIFIED IDEOGRAPH + 0x99D4: 0x6AFE, //CJK UNIFIED IDEOGRAPH + 0x99D5: 0x6AFF, //CJK UNIFIED IDEOGRAPH + 0x99D6: 0x6B00, //CJK UNIFIED IDEOGRAPH + 0x99D7: 0x6B01, //CJK UNIFIED IDEOGRAPH + 0x99D8: 0x6B02, //CJK UNIFIED IDEOGRAPH + 0x99D9: 0x6B03, //CJK UNIFIED IDEOGRAPH + 0x99DA: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0x99DB: 0x6B05, //CJK UNIFIED IDEOGRAPH + 0x99DC: 0x6B06, //CJK UNIFIED IDEOGRAPH + 0x99DD: 0x6B07, //CJK UNIFIED IDEOGRAPH + 0x99DE: 0x6B08, //CJK UNIFIED IDEOGRAPH + 0x99DF: 0x6B09, //CJK UNIFIED IDEOGRAPH + 0x99E0: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0x99E1: 0x6B0B, //CJK UNIFIED IDEOGRAPH + 0x99E2: 0x6B0C, //CJK UNIFIED IDEOGRAPH + 0x99E3: 0x6B0D, //CJK UNIFIED IDEOGRAPH + 0x99E4: 0x6B0E, //CJK UNIFIED IDEOGRAPH + 0x99E5: 0x6B0F, //CJK UNIFIED IDEOGRAPH + 0x99E6: 0x6B10, //CJK UNIFIED IDEOGRAPH + 0x99E7: 0x6B11, //CJK UNIFIED IDEOGRAPH + 0x99E8: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0x99E9: 0x6B13, //CJK UNIFIED IDEOGRAPH + 0x99EA: 0x6B14, //CJK UNIFIED IDEOGRAPH + 0x99EB: 0x6B15, //CJK UNIFIED IDEOGRAPH + 0x99EC: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0x99ED: 0x6B17, //CJK UNIFIED IDEOGRAPH + 0x99EE: 0x6B18, //CJK UNIFIED IDEOGRAPH + 0x99EF: 0x6B19, //CJK UNIFIED IDEOGRAPH + 0x99F0: 0x6B1A, //CJK UNIFIED IDEOGRAPH + 0x99F1: 0x6B1B, //CJK UNIFIED IDEOGRAPH + 0x99F2: 0x6B1C, //CJK UNIFIED IDEOGRAPH + 0x99F3: 0x6B1D, //CJK UNIFIED IDEOGRAPH + 0x99F4: 0x6B1E, //CJK UNIFIED IDEOGRAPH + 0x99F5: 0x6B1F, //CJK UNIFIED IDEOGRAPH + 0x99F6: 0x6B25, //CJK UNIFIED IDEOGRAPH + 0x99F7: 0x6B26, //CJK UNIFIED IDEOGRAPH + 0x99F8: 0x6B28, //CJK UNIFIED IDEOGRAPH + 0x99F9: 0x6B29, //CJK UNIFIED IDEOGRAPH + 0x99FA: 0x6B2A, //CJK UNIFIED IDEOGRAPH + 0x99FB: 0x6B2B, //CJK UNIFIED IDEOGRAPH + 0x99FC: 0x6B2C, //CJK UNIFIED IDEOGRAPH + 0x99FD: 0x6B2D, //CJK UNIFIED IDEOGRAPH + 0x99FE: 0x6B2E, //CJK UNIFIED IDEOGRAPH + 0x9A40: 0x6B2F, //CJK UNIFIED IDEOGRAPH + 0x9A41: 0x6B30, //CJK UNIFIED IDEOGRAPH + 0x9A42: 0x6B31, //CJK UNIFIED IDEOGRAPH + 0x9A43: 0x6B33, //CJK UNIFIED IDEOGRAPH + 0x9A44: 0x6B34, //CJK UNIFIED IDEOGRAPH + 0x9A45: 0x6B35, //CJK UNIFIED IDEOGRAPH + 0x9A46: 0x6B36, //CJK UNIFIED IDEOGRAPH + 0x9A47: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0x9A48: 0x6B3B, //CJK UNIFIED IDEOGRAPH + 0x9A49: 0x6B3C, //CJK UNIFIED IDEOGRAPH + 0x9A4A: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0x9A4B: 0x6B3F, //CJK UNIFIED IDEOGRAPH + 0x9A4C: 0x6B40, //CJK UNIFIED IDEOGRAPH + 0x9A4D: 0x6B41, //CJK UNIFIED IDEOGRAPH + 0x9A4E: 0x6B42, //CJK UNIFIED IDEOGRAPH + 0x9A4F: 0x6B44, //CJK UNIFIED IDEOGRAPH + 0x9A50: 0x6B45, //CJK UNIFIED IDEOGRAPH + 0x9A51: 0x6B48, //CJK UNIFIED IDEOGRAPH + 0x9A52: 0x6B4A, //CJK UNIFIED IDEOGRAPH + 0x9A53: 0x6B4B, //CJK UNIFIED IDEOGRAPH + 0x9A54: 0x6B4D, //CJK UNIFIED IDEOGRAPH + 0x9A55: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0x9A56: 0x6B4F, //CJK UNIFIED IDEOGRAPH + 0x9A57: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0x9A58: 0x6B51, //CJK UNIFIED IDEOGRAPH + 0x9A59: 0x6B52, //CJK UNIFIED IDEOGRAPH + 0x9A5A: 0x6B53, //CJK UNIFIED IDEOGRAPH + 0x9A5B: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0x9A5C: 0x6B55, //CJK UNIFIED IDEOGRAPH + 0x9A5D: 0x6B56, //CJK UNIFIED IDEOGRAPH + 0x9A5E: 0x6B57, //CJK UNIFIED IDEOGRAPH + 0x9A5F: 0x6B58, //CJK UNIFIED IDEOGRAPH + 0x9A60: 0x6B5A, //CJK UNIFIED IDEOGRAPH + 0x9A61: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0x9A62: 0x6B5C, //CJK UNIFIED IDEOGRAPH + 0x9A63: 0x6B5D, //CJK UNIFIED IDEOGRAPH + 0x9A64: 0x6B5E, //CJK UNIFIED IDEOGRAPH + 0x9A65: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0x9A66: 0x6B60, //CJK UNIFIED IDEOGRAPH + 0x9A67: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0x9A68: 0x6B68, //CJK UNIFIED IDEOGRAPH + 0x9A69: 0x6B69, //CJK UNIFIED IDEOGRAPH + 0x9A6A: 0x6B6B, //CJK UNIFIED IDEOGRAPH + 0x9A6B: 0x6B6C, //CJK UNIFIED IDEOGRAPH + 0x9A6C: 0x6B6D, //CJK UNIFIED IDEOGRAPH + 0x9A6D: 0x6B6E, //CJK UNIFIED IDEOGRAPH + 0x9A6E: 0x6B6F, //CJK UNIFIED IDEOGRAPH + 0x9A6F: 0x6B70, //CJK UNIFIED IDEOGRAPH + 0x9A70: 0x6B71, //CJK UNIFIED IDEOGRAPH + 0x9A71: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0x9A72: 0x6B73, //CJK UNIFIED IDEOGRAPH + 0x9A73: 0x6B74, //CJK UNIFIED IDEOGRAPH + 0x9A74: 0x6B75, //CJK UNIFIED IDEOGRAPH + 0x9A75: 0x6B76, //CJK UNIFIED IDEOGRAPH + 0x9A76: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0x9A77: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0x9A78: 0x6B7A, //CJK UNIFIED IDEOGRAPH + 0x9A79: 0x6B7D, //CJK UNIFIED IDEOGRAPH + 0x9A7A: 0x6B7E, //CJK UNIFIED IDEOGRAPH + 0x9A7B: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0x9A7C: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0x9A7D: 0x6B85, //CJK UNIFIED IDEOGRAPH + 0x9A7E: 0x6B88, //CJK UNIFIED IDEOGRAPH + 0x9A80: 0x6B8C, //CJK UNIFIED IDEOGRAPH + 0x9A81: 0x6B8E, //CJK UNIFIED IDEOGRAPH + 0x9A82: 0x6B8F, //CJK UNIFIED IDEOGRAPH + 0x9A83: 0x6B90, //CJK UNIFIED IDEOGRAPH + 0x9A84: 0x6B91, //CJK UNIFIED IDEOGRAPH + 0x9A85: 0x6B94, //CJK UNIFIED IDEOGRAPH + 0x9A86: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0x9A87: 0x6B97, //CJK UNIFIED IDEOGRAPH + 0x9A88: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0x9A89: 0x6B99, //CJK UNIFIED IDEOGRAPH + 0x9A8A: 0x6B9C, //CJK UNIFIED IDEOGRAPH + 0x9A8B: 0x6B9D, //CJK UNIFIED IDEOGRAPH + 0x9A8C: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0x9A8D: 0x6B9F, //CJK UNIFIED IDEOGRAPH + 0x9A8E: 0x6BA0, //CJK UNIFIED IDEOGRAPH + 0x9A8F: 0x6BA2, //CJK UNIFIED IDEOGRAPH + 0x9A90: 0x6BA3, //CJK UNIFIED IDEOGRAPH + 0x9A91: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0x9A92: 0x6BA5, //CJK UNIFIED IDEOGRAPH + 0x9A93: 0x6BA6, //CJK UNIFIED IDEOGRAPH + 0x9A94: 0x6BA7, //CJK UNIFIED IDEOGRAPH + 0x9A95: 0x6BA8, //CJK UNIFIED IDEOGRAPH + 0x9A96: 0x6BA9, //CJK UNIFIED IDEOGRAPH + 0x9A97: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0x9A98: 0x6BAC, //CJK UNIFIED IDEOGRAPH + 0x9A99: 0x6BAD, //CJK UNIFIED IDEOGRAPH + 0x9A9A: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0x9A9B: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0x9A9C: 0x6BB0, //CJK UNIFIED IDEOGRAPH + 0x9A9D: 0x6BB1, //CJK UNIFIED IDEOGRAPH + 0x9A9E: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0x9A9F: 0x6BB6, //CJK UNIFIED IDEOGRAPH + 0x9AA0: 0x6BB8, //CJK UNIFIED IDEOGRAPH + 0x9AA1: 0x6BB9, //CJK UNIFIED IDEOGRAPH + 0x9AA2: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0x9AA3: 0x6BBB, //CJK UNIFIED IDEOGRAPH + 0x9AA4: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0x9AA5: 0x6BBD, //CJK UNIFIED IDEOGRAPH + 0x9AA6: 0x6BBE, //CJK UNIFIED IDEOGRAPH + 0x9AA7: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0x9AA8: 0x6BC3, //CJK UNIFIED IDEOGRAPH + 0x9AA9: 0x6BC4, //CJK UNIFIED IDEOGRAPH + 0x9AAA: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0x9AAB: 0x6BC7, //CJK UNIFIED IDEOGRAPH + 0x9AAC: 0x6BC8, //CJK UNIFIED IDEOGRAPH + 0x9AAD: 0x6BC9, //CJK UNIFIED IDEOGRAPH + 0x9AAE: 0x6BCA, //CJK UNIFIED IDEOGRAPH + 0x9AAF: 0x6BCC, //CJK UNIFIED IDEOGRAPH + 0x9AB0: 0x6BCE, //CJK UNIFIED IDEOGRAPH + 0x9AB1: 0x6BD0, //CJK UNIFIED IDEOGRAPH + 0x9AB2: 0x6BD1, //CJK UNIFIED IDEOGRAPH + 0x9AB3: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0x9AB4: 0x6BDA, //CJK UNIFIED IDEOGRAPH + 0x9AB5: 0x6BDC, //CJK UNIFIED IDEOGRAPH + 0x9AB6: 0x6BDD, //CJK UNIFIED IDEOGRAPH + 0x9AB7: 0x6BDE, //CJK UNIFIED IDEOGRAPH + 0x9AB8: 0x6BDF, //CJK UNIFIED IDEOGRAPH + 0x9AB9: 0x6BE0, //CJK UNIFIED IDEOGRAPH + 0x9ABA: 0x6BE2, //CJK UNIFIED IDEOGRAPH + 0x9ABB: 0x6BE3, //CJK UNIFIED IDEOGRAPH + 0x9ABC: 0x6BE4, //CJK UNIFIED IDEOGRAPH + 0x9ABD: 0x6BE5, //CJK UNIFIED IDEOGRAPH + 0x9ABE: 0x6BE6, //CJK UNIFIED IDEOGRAPH + 0x9ABF: 0x6BE7, //CJK UNIFIED IDEOGRAPH + 0x9AC0: 0x6BE8, //CJK UNIFIED IDEOGRAPH + 0x9AC1: 0x6BE9, //CJK UNIFIED IDEOGRAPH + 0x9AC2: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0x9AC3: 0x6BED, //CJK UNIFIED IDEOGRAPH + 0x9AC4: 0x6BEE, //CJK UNIFIED IDEOGRAPH + 0x9AC5: 0x6BF0, //CJK UNIFIED IDEOGRAPH + 0x9AC6: 0x6BF1, //CJK UNIFIED IDEOGRAPH + 0x9AC7: 0x6BF2, //CJK UNIFIED IDEOGRAPH + 0x9AC8: 0x6BF4, //CJK UNIFIED IDEOGRAPH + 0x9AC9: 0x6BF6, //CJK UNIFIED IDEOGRAPH + 0x9ACA: 0x6BF7, //CJK UNIFIED IDEOGRAPH + 0x9ACB: 0x6BF8, //CJK UNIFIED IDEOGRAPH + 0x9ACC: 0x6BFA, //CJK UNIFIED IDEOGRAPH + 0x9ACD: 0x6BFB, //CJK UNIFIED IDEOGRAPH + 0x9ACE: 0x6BFC, //CJK UNIFIED IDEOGRAPH + 0x9ACF: 0x6BFE, //CJK UNIFIED IDEOGRAPH + 0x9AD0: 0x6BFF, //CJK UNIFIED IDEOGRAPH + 0x9AD1: 0x6C00, //CJK UNIFIED IDEOGRAPH + 0x9AD2: 0x6C01, //CJK UNIFIED IDEOGRAPH + 0x9AD3: 0x6C02, //CJK UNIFIED IDEOGRAPH + 0x9AD4: 0x6C03, //CJK UNIFIED IDEOGRAPH + 0x9AD5: 0x6C04, //CJK UNIFIED IDEOGRAPH + 0x9AD6: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0x9AD7: 0x6C09, //CJK UNIFIED IDEOGRAPH + 0x9AD8: 0x6C0A, //CJK UNIFIED IDEOGRAPH + 0x9AD9: 0x6C0B, //CJK UNIFIED IDEOGRAPH + 0x9ADA: 0x6C0C, //CJK UNIFIED IDEOGRAPH + 0x9ADB: 0x6C0E, //CJK UNIFIED IDEOGRAPH + 0x9ADC: 0x6C12, //CJK UNIFIED IDEOGRAPH + 0x9ADD: 0x6C17, //CJK UNIFIED IDEOGRAPH + 0x9ADE: 0x6C1C, //CJK UNIFIED IDEOGRAPH + 0x9ADF: 0x6C1D, //CJK UNIFIED IDEOGRAPH + 0x9AE0: 0x6C1E, //CJK UNIFIED IDEOGRAPH + 0x9AE1: 0x6C20, //CJK UNIFIED IDEOGRAPH + 0x9AE2: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0x9AE3: 0x6C25, //CJK UNIFIED IDEOGRAPH + 0x9AE4: 0x6C2B, //CJK UNIFIED IDEOGRAPH + 0x9AE5: 0x6C2C, //CJK UNIFIED IDEOGRAPH + 0x9AE6: 0x6C2D, //CJK UNIFIED IDEOGRAPH + 0x9AE7: 0x6C31, //CJK UNIFIED IDEOGRAPH + 0x9AE8: 0x6C33, //CJK UNIFIED IDEOGRAPH + 0x9AE9: 0x6C36, //CJK UNIFIED IDEOGRAPH + 0x9AEA: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0x9AEB: 0x6C39, //CJK UNIFIED IDEOGRAPH + 0x9AEC: 0x6C3A, //CJK UNIFIED IDEOGRAPH + 0x9AED: 0x6C3B, //CJK UNIFIED IDEOGRAPH + 0x9AEE: 0x6C3C, //CJK UNIFIED IDEOGRAPH + 0x9AEF: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0x9AF0: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0x9AF1: 0x6C43, //CJK UNIFIED IDEOGRAPH + 0x9AF2: 0x6C44, //CJK UNIFIED IDEOGRAPH + 0x9AF3: 0x6C45, //CJK UNIFIED IDEOGRAPH + 0x9AF4: 0x6C48, //CJK UNIFIED IDEOGRAPH + 0x9AF5: 0x6C4B, //CJK UNIFIED IDEOGRAPH + 0x9AF6: 0x6C4C, //CJK UNIFIED IDEOGRAPH + 0x9AF7: 0x6C4D, //CJK UNIFIED IDEOGRAPH + 0x9AF8: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0x9AF9: 0x6C4F, //CJK UNIFIED IDEOGRAPH + 0x9AFA: 0x6C51, //CJK UNIFIED IDEOGRAPH + 0x9AFB: 0x6C52, //CJK UNIFIED IDEOGRAPH + 0x9AFC: 0x6C53, //CJK UNIFIED IDEOGRAPH + 0x9AFD: 0x6C56, //CJK UNIFIED IDEOGRAPH + 0x9AFE: 0x6C58, //CJK UNIFIED IDEOGRAPH + 0x9B40: 0x6C59, //CJK UNIFIED IDEOGRAPH + 0x9B41: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0x9B42: 0x6C62, //CJK UNIFIED IDEOGRAPH + 0x9B43: 0x6C63, //CJK UNIFIED IDEOGRAPH + 0x9B44: 0x6C65, //CJK UNIFIED IDEOGRAPH + 0x9B45: 0x6C66, //CJK UNIFIED IDEOGRAPH + 0x9B46: 0x6C67, //CJK UNIFIED IDEOGRAPH + 0x9B47: 0x6C6B, //CJK UNIFIED IDEOGRAPH + 0x9B48: 0x6C6C, //CJK UNIFIED IDEOGRAPH + 0x9B49: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0x9B4A: 0x6C6E, //CJK UNIFIED IDEOGRAPH + 0x9B4B: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0x9B4C: 0x6C71, //CJK UNIFIED IDEOGRAPH + 0x9B4D: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0x9B4E: 0x6C75, //CJK UNIFIED IDEOGRAPH + 0x9B4F: 0x6C77, //CJK UNIFIED IDEOGRAPH + 0x9B50: 0x6C78, //CJK UNIFIED IDEOGRAPH + 0x9B51: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0x9B52: 0x6C7B, //CJK UNIFIED IDEOGRAPH + 0x9B53: 0x6C7C, //CJK UNIFIED IDEOGRAPH + 0x9B54: 0x6C7F, //CJK UNIFIED IDEOGRAPH + 0x9B55: 0x6C80, //CJK UNIFIED IDEOGRAPH + 0x9B56: 0x6C84, //CJK UNIFIED IDEOGRAPH + 0x9B57: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0x9B58: 0x6C8A, //CJK UNIFIED IDEOGRAPH + 0x9B59: 0x6C8B, //CJK UNIFIED IDEOGRAPH + 0x9B5A: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0x9B5B: 0x6C8E, //CJK UNIFIED IDEOGRAPH + 0x9B5C: 0x6C91, //CJK UNIFIED IDEOGRAPH + 0x9B5D: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0x9B5E: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0x9B5F: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0x9B60: 0x6C97, //CJK UNIFIED IDEOGRAPH + 0x9B61: 0x6C98, //CJK UNIFIED IDEOGRAPH + 0x9B62: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0x9B63: 0x6C9C, //CJK UNIFIED IDEOGRAPH + 0x9B64: 0x6C9D, //CJK UNIFIED IDEOGRAPH + 0x9B65: 0x6C9E, //CJK UNIFIED IDEOGRAPH + 0x9B66: 0x6CA0, //CJK UNIFIED IDEOGRAPH + 0x9B67: 0x6CA2, //CJK UNIFIED IDEOGRAPH + 0x9B68: 0x6CA8, //CJK UNIFIED IDEOGRAPH + 0x9B69: 0x6CAC, //CJK UNIFIED IDEOGRAPH + 0x9B6A: 0x6CAF, //CJK UNIFIED IDEOGRAPH + 0x9B6B: 0x6CB0, //CJK UNIFIED IDEOGRAPH + 0x9B6C: 0x6CB4, //CJK UNIFIED IDEOGRAPH + 0x9B6D: 0x6CB5, //CJK UNIFIED IDEOGRAPH + 0x9B6E: 0x6CB6, //CJK UNIFIED IDEOGRAPH + 0x9B6F: 0x6CB7, //CJK UNIFIED IDEOGRAPH + 0x9B70: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0x9B71: 0x6CC0, //CJK UNIFIED IDEOGRAPH + 0x9B72: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0x9B73: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0x9B74: 0x6CC3, //CJK UNIFIED IDEOGRAPH + 0x9B75: 0x6CC6, //CJK UNIFIED IDEOGRAPH + 0x9B76: 0x6CC7, //CJK UNIFIED IDEOGRAPH + 0x9B77: 0x6CC8, //CJK UNIFIED IDEOGRAPH + 0x9B78: 0x6CCB, //CJK UNIFIED IDEOGRAPH + 0x9B79: 0x6CCD, //CJK UNIFIED IDEOGRAPH + 0x9B7A: 0x6CCE, //CJK UNIFIED IDEOGRAPH + 0x9B7B: 0x6CCF, //CJK UNIFIED IDEOGRAPH + 0x9B7C: 0x6CD1, //CJK UNIFIED IDEOGRAPH + 0x9B7D: 0x6CD2, //CJK UNIFIED IDEOGRAPH + 0x9B7E: 0x6CD8, //CJK UNIFIED IDEOGRAPH + 0x9B80: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0x9B81: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0x9B82: 0x6CDC, //CJK UNIFIED IDEOGRAPH + 0x9B83: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0x9B84: 0x6CDF, //CJK UNIFIED IDEOGRAPH + 0x9B85: 0x6CE4, //CJK UNIFIED IDEOGRAPH + 0x9B86: 0x6CE6, //CJK UNIFIED IDEOGRAPH + 0x9B87: 0x6CE7, //CJK UNIFIED IDEOGRAPH + 0x9B88: 0x6CE9, //CJK UNIFIED IDEOGRAPH + 0x9B89: 0x6CEC, //CJK UNIFIED IDEOGRAPH + 0x9B8A: 0x6CED, //CJK UNIFIED IDEOGRAPH + 0x9B8B: 0x6CF2, //CJK UNIFIED IDEOGRAPH + 0x9B8C: 0x6CF4, //CJK UNIFIED IDEOGRAPH + 0x9B8D: 0x6CF9, //CJK UNIFIED IDEOGRAPH + 0x9B8E: 0x6CFF, //CJK UNIFIED IDEOGRAPH + 0x9B8F: 0x6D00, //CJK UNIFIED IDEOGRAPH + 0x9B90: 0x6D02, //CJK UNIFIED IDEOGRAPH + 0x9B91: 0x6D03, //CJK UNIFIED IDEOGRAPH + 0x9B92: 0x6D05, //CJK UNIFIED IDEOGRAPH + 0x9B93: 0x6D06, //CJK UNIFIED IDEOGRAPH + 0x9B94: 0x6D08, //CJK UNIFIED IDEOGRAPH + 0x9B95: 0x6D09, //CJK UNIFIED IDEOGRAPH + 0x9B96: 0x6D0A, //CJK UNIFIED IDEOGRAPH + 0x9B97: 0x6D0D, //CJK UNIFIED IDEOGRAPH + 0x9B98: 0x6D0F, //CJK UNIFIED IDEOGRAPH + 0x9B99: 0x6D10, //CJK UNIFIED IDEOGRAPH + 0x9B9A: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0x9B9B: 0x6D13, //CJK UNIFIED IDEOGRAPH + 0x9B9C: 0x6D14, //CJK UNIFIED IDEOGRAPH + 0x9B9D: 0x6D15, //CJK UNIFIED IDEOGRAPH + 0x9B9E: 0x6D16, //CJK UNIFIED IDEOGRAPH + 0x9B9F: 0x6D18, //CJK UNIFIED IDEOGRAPH + 0x9BA0: 0x6D1C, //CJK UNIFIED IDEOGRAPH + 0x9BA1: 0x6D1D, //CJK UNIFIED IDEOGRAPH + 0x9BA2: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0x9BA3: 0x6D20, //CJK UNIFIED IDEOGRAPH + 0x9BA4: 0x6D21, //CJK UNIFIED IDEOGRAPH + 0x9BA5: 0x6D22, //CJK UNIFIED IDEOGRAPH + 0x9BA6: 0x6D23, //CJK UNIFIED IDEOGRAPH + 0x9BA7: 0x6D24, //CJK UNIFIED IDEOGRAPH + 0x9BA8: 0x6D26, //CJK UNIFIED IDEOGRAPH + 0x9BA9: 0x6D28, //CJK UNIFIED IDEOGRAPH + 0x9BAA: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0x9BAB: 0x6D2C, //CJK UNIFIED IDEOGRAPH + 0x9BAC: 0x6D2D, //CJK UNIFIED IDEOGRAPH + 0x9BAD: 0x6D2F, //CJK UNIFIED IDEOGRAPH + 0x9BAE: 0x6D30, //CJK UNIFIED IDEOGRAPH + 0x9BAF: 0x6D34, //CJK UNIFIED IDEOGRAPH + 0x9BB0: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0x9BB1: 0x6D37, //CJK UNIFIED IDEOGRAPH + 0x9BB2: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0x9BB3: 0x6D3A, //CJK UNIFIED IDEOGRAPH + 0x9BB4: 0x6D3F, //CJK UNIFIED IDEOGRAPH + 0x9BB5: 0x6D40, //CJK UNIFIED IDEOGRAPH + 0x9BB6: 0x6D42, //CJK UNIFIED IDEOGRAPH + 0x9BB7: 0x6D44, //CJK UNIFIED IDEOGRAPH + 0x9BB8: 0x6D49, //CJK UNIFIED IDEOGRAPH + 0x9BB9: 0x6D4C, //CJK UNIFIED IDEOGRAPH + 0x9BBA: 0x6D50, //CJK UNIFIED IDEOGRAPH + 0x9BBB: 0x6D55, //CJK UNIFIED IDEOGRAPH + 0x9BBC: 0x6D56, //CJK UNIFIED IDEOGRAPH + 0x9BBD: 0x6D57, //CJK UNIFIED IDEOGRAPH + 0x9BBE: 0x6D58, //CJK UNIFIED IDEOGRAPH + 0x9BBF: 0x6D5B, //CJK UNIFIED IDEOGRAPH + 0x9BC0: 0x6D5D, //CJK UNIFIED IDEOGRAPH + 0x9BC1: 0x6D5F, //CJK UNIFIED IDEOGRAPH + 0x9BC2: 0x6D61, //CJK UNIFIED IDEOGRAPH + 0x9BC3: 0x6D62, //CJK UNIFIED IDEOGRAPH + 0x9BC4: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0x9BC5: 0x6D65, //CJK UNIFIED IDEOGRAPH + 0x9BC6: 0x6D67, //CJK UNIFIED IDEOGRAPH + 0x9BC7: 0x6D68, //CJK UNIFIED IDEOGRAPH + 0x9BC8: 0x6D6B, //CJK UNIFIED IDEOGRAPH + 0x9BC9: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0x9BCA: 0x6D6D, //CJK UNIFIED IDEOGRAPH + 0x9BCB: 0x6D70, //CJK UNIFIED IDEOGRAPH + 0x9BCC: 0x6D71, //CJK UNIFIED IDEOGRAPH + 0x9BCD: 0x6D72, //CJK UNIFIED IDEOGRAPH + 0x9BCE: 0x6D73, //CJK UNIFIED IDEOGRAPH + 0x9BCF: 0x6D75, //CJK UNIFIED IDEOGRAPH + 0x9BD0: 0x6D76, //CJK UNIFIED IDEOGRAPH + 0x9BD1: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0x9BD2: 0x6D7A, //CJK UNIFIED IDEOGRAPH + 0x9BD3: 0x6D7B, //CJK UNIFIED IDEOGRAPH + 0x9BD4: 0x6D7D, //CJK UNIFIED IDEOGRAPH + 0x9BD5: 0x6D7E, //CJK UNIFIED IDEOGRAPH + 0x9BD6: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0x9BD7: 0x6D80, //CJK UNIFIED IDEOGRAPH + 0x9BD8: 0x6D81, //CJK UNIFIED IDEOGRAPH + 0x9BD9: 0x6D83, //CJK UNIFIED IDEOGRAPH + 0x9BDA: 0x6D84, //CJK UNIFIED IDEOGRAPH + 0x9BDB: 0x6D86, //CJK UNIFIED IDEOGRAPH + 0x9BDC: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0x9BDD: 0x6D8A, //CJK UNIFIED IDEOGRAPH + 0x9BDE: 0x6D8B, //CJK UNIFIED IDEOGRAPH + 0x9BDF: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0x9BE0: 0x6D8F, //CJK UNIFIED IDEOGRAPH + 0x9BE1: 0x6D90, //CJK UNIFIED IDEOGRAPH + 0x9BE2: 0x6D92, //CJK UNIFIED IDEOGRAPH + 0x9BE3: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0x9BE4: 0x6D97, //CJK UNIFIED IDEOGRAPH + 0x9BE5: 0x6D98, //CJK UNIFIED IDEOGRAPH + 0x9BE6: 0x6D99, //CJK UNIFIED IDEOGRAPH + 0x9BE7: 0x6D9A, //CJK UNIFIED IDEOGRAPH + 0x9BE8: 0x6D9C, //CJK UNIFIED IDEOGRAPH + 0x9BE9: 0x6DA2, //CJK UNIFIED IDEOGRAPH + 0x9BEA: 0x6DA5, //CJK UNIFIED IDEOGRAPH + 0x9BEB: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0x9BEC: 0x6DAD, //CJK UNIFIED IDEOGRAPH + 0x9BED: 0x6DB0, //CJK UNIFIED IDEOGRAPH + 0x9BEE: 0x6DB1, //CJK UNIFIED IDEOGRAPH + 0x9BEF: 0x6DB3, //CJK UNIFIED IDEOGRAPH + 0x9BF0: 0x6DB4, //CJK UNIFIED IDEOGRAPH + 0x9BF1: 0x6DB6, //CJK UNIFIED IDEOGRAPH + 0x9BF2: 0x6DB7, //CJK UNIFIED IDEOGRAPH + 0x9BF3: 0x6DB9, //CJK UNIFIED IDEOGRAPH + 0x9BF4: 0x6DBA, //CJK UNIFIED IDEOGRAPH + 0x9BF5: 0x6DBB, //CJK UNIFIED IDEOGRAPH + 0x9BF6: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0x9BF7: 0x6DBD, //CJK UNIFIED IDEOGRAPH + 0x9BF8: 0x6DBE, //CJK UNIFIED IDEOGRAPH + 0x9BF9: 0x6DC1, //CJK UNIFIED IDEOGRAPH + 0x9BFA: 0x6DC2, //CJK UNIFIED IDEOGRAPH + 0x9BFB: 0x6DC3, //CJK UNIFIED IDEOGRAPH + 0x9BFC: 0x6DC8, //CJK UNIFIED IDEOGRAPH + 0x9BFD: 0x6DC9, //CJK UNIFIED IDEOGRAPH + 0x9BFE: 0x6DCA, //CJK UNIFIED IDEOGRAPH + 0x9C40: 0x6DCD, //CJK UNIFIED IDEOGRAPH + 0x9C41: 0x6DCE, //CJK UNIFIED IDEOGRAPH + 0x9C42: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0x9C43: 0x6DD0, //CJK UNIFIED IDEOGRAPH + 0x9C44: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0x9C45: 0x6DD3, //CJK UNIFIED IDEOGRAPH + 0x9C46: 0x6DD4, //CJK UNIFIED IDEOGRAPH + 0x9C47: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0x9C48: 0x6DD7, //CJK UNIFIED IDEOGRAPH + 0x9C49: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0x9C4A: 0x6DDB, //CJK UNIFIED IDEOGRAPH + 0x9C4B: 0x6DDC, //CJK UNIFIED IDEOGRAPH + 0x9C4C: 0x6DDF, //CJK UNIFIED IDEOGRAPH + 0x9C4D: 0x6DE2, //CJK UNIFIED IDEOGRAPH + 0x9C4E: 0x6DE3, //CJK UNIFIED IDEOGRAPH + 0x9C4F: 0x6DE5, //CJK UNIFIED IDEOGRAPH + 0x9C50: 0x6DE7, //CJK UNIFIED IDEOGRAPH + 0x9C51: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0x9C52: 0x6DE9, //CJK UNIFIED IDEOGRAPH + 0x9C53: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0x9C54: 0x6DED, //CJK UNIFIED IDEOGRAPH + 0x9C55: 0x6DEF, //CJK UNIFIED IDEOGRAPH + 0x9C56: 0x6DF0, //CJK UNIFIED IDEOGRAPH + 0x9C57: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0x9C58: 0x6DF4, //CJK UNIFIED IDEOGRAPH + 0x9C59: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0x9C5A: 0x6DF6, //CJK UNIFIED IDEOGRAPH + 0x9C5B: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0x9C5C: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0x9C5D: 0x6DFD, //CJK UNIFIED IDEOGRAPH + 0x9C5E: 0x6DFE, //CJK UNIFIED IDEOGRAPH + 0x9C5F: 0x6DFF, //CJK UNIFIED IDEOGRAPH + 0x9C60: 0x6E00, //CJK UNIFIED IDEOGRAPH + 0x9C61: 0x6E01, //CJK UNIFIED IDEOGRAPH + 0x9C62: 0x6E02, //CJK UNIFIED IDEOGRAPH + 0x9C63: 0x6E03, //CJK UNIFIED IDEOGRAPH + 0x9C64: 0x6E04, //CJK UNIFIED IDEOGRAPH + 0x9C65: 0x6E06, //CJK UNIFIED IDEOGRAPH + 0x9C66: 0x6E07, //CJK UNIFIED IDEOGRAPH + 0x9C67: 0x6E08, //CJK UNIFIED IDEOGRAPH + 0x9C68: 0x6E09, //CJK UNIFIED IDEOGRAPH + 0x9C69: 0x6E0B, //CJK UNIFIED IDEOGRAPH + 0x9C6A: 0x6E0F, //CJK UNIFIED IDEOGRAPH + 0x9C6B: 0x6E12, //CJK UNIFIED IDEOGRAPH + 0x9C6C: 0x6E13, //CJK UNIFIED IDEOGRAPH + 0x9C6D: 0x6E15, //CJK UNIFIED IDEOGRAPH + 0x9C6E: 0x6E18, //CJK UNIFIED IDEOGRAPH + 0x9C6F: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0x9C70: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0x9C71: 0x6E1C, //CJK UNIFIED IDEOGRAPH + 0x9C72: 0x6E1E, //CJK UNIFIED IDEOGRAPH + 0x9C73: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0x9C74: 0x6E22, //CJK UNIFIED IDEOGRAPH + 0x9C75: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0x9C76: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0x9C77: 0x6E28, //CJK UNIFIED IDEOGRAPH + 0x9C78: 0x6E2A, //CJK UNIFIED IDEOGRAPH + 0x9C79: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0x9C7A: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0x9C7B: 0x6E30, //CJK UNIFIED IDEOGRAPH + 0x9C7C: 0x6E31, //CJK UNIFIED IDEOGRAPH + 0x9C7D: 0x6E33, //CJK UNIFIED IDEOGRAPH + 0x9C7E: 0x6E35, //CJK UNIFIED IDEOGRAPH + 0x9C80: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0x9C81: 0x6E37, //CJK UNIFIED IDEOGRAPH + 0x9C82: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0x9C83: 0x6E3B, //CJK UNIFIED IDEOGRAPH + 0x9C84: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0x9C85: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0x9C86: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0x9C87: 0x6E3F, //CJK UNIFIED IDEOGRAPH + 0x9C88: 0x6E40, //CJK UNIFIED IDEOGRAPH + 0x9C89: 0x6E41, //CJK UNIFIED IDEOGRAPH + 0x9C8A: 0x6E42, //CJK UNIFIED IDEOGRAPH + 0x9C8B: 0x6E45, //CJK UNIFIED IDEOGRAPH + 0x9C8C: 0x6E46, //CJK UNIFIED IDEOGRAPH + 0x9C8D: 0x6E47, //CJK UNIFIED IDEOGRAPH + 0x9C8E: 0x6E48, //CJK UNIFIED IDEOGRAPH + 0x9C8F: 0x6E49, //CJK UNIFIED IDEOGRAPH + 0x9C90: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0x9C91: 0x6E4B, //CJK UNIFIED IDEOGRAPH + 0x9C92: 0x6E4C, //CJK UNIFIED IDEOGRAPH + 0x9C93: 0x6E4F, //CJK UNIFIED IDEOGRAPH + 0x9C94: 0x6E50, //CJK UNIFIED IDEOGRAPH + 0x9C95: 0x6E51, //CJK UNIFIED IDEOGRAPH + 0x9C96: 0x6E52, //CJK UNIFIED IDEOGRAPH + 0x9C97: 0x6E55, //CJK UNIFIED IDEOGRAPH + 0x9C98: 0x6E57, //CJK UNIFIED IDEOGRAPH + 0x9C99: 0x6E59, //CJK UNIFIED IDEOGRAPH + 0x9C9A: 0x6E5A, //CJK UNIFIED IDEOGRAPH + 0x9C9B: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0x9C9C: 0x6E5D, //CJK UNIFIED IDEOGRAPH + 0x9C9D: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0x9C9E: 0x6E60, //CJK UNIFIED IDEOGRAPH + 0x9C9F: 0x6E61, //CJK UNIFIED IDEOGRAPH + 0x9CA0: 0x6E62, //CJK UNIFIED IDEOGRAPH + 0x9CA1: 0x6E63, //CJK UNIFIED IDEOGRAPH + 0x9CA2: 0x6E64, //CJK UNIFIED IDEOGRAPH + 0x9CA3: 0x6E65, //CJK UNIFIED IDEOGRAPH + 0x9CA4: 0x6E66, //CJK UNIFIED IDEOGRAPH + 0x9CA5: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0x9CA6: 0x6E68, //CJK UNIFIED IDEOGRAPH + 0x9CA7: 0x6E69, //CJK UNIFIED IDEOGRAPH + 0x9CA8: 0x6E6A, //CJK UNIFIED IDEOGRAPH + 0x9CA9: 0x6E6C, //CJK UNIFIED IDEOGRAPH + 0x9CAA: 0x6E6D, //CJK UNIFIED IDEOGRAPH + 0x9CAB: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0x9CAC: 0x6E70, //CJK UNIFIED IDEOGRAPH + 0x9CAD: 0x6E71, //CJK UNIFIED IDEOGRAPH + 0x9CAE: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0x9CAF: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0x9CB0: 0x6E74, //CJK UNIFIED IDEOGRAPH + 0x9CB1: 0x6E75, //CJK UNIFIED IDEOGRAPH + 0x9CB2: 0x6E76, //CJK UNIFIED IDEOGRAPH + 0x9CB3: 0x6E77, //CJK UNIFIED IDEOGRAPH + 0x9CB4: 0x6E78, //CJK UNIFIED IDEOGRAPH + 0x9CB5: 0x6E79, //CJK UNIFIED IDEOGRAPH + 0x9CB6: 0x6E7A, //CJK UNIFIED IDEOGRAPH + 0x9CB7: 0x6E7B, //CJK UNIFIED IDEOGRAPH + 0x9CB8: 0x6E7C, //CJK UNIFIED IDEOGRAPH + 0x9CB9: 0x6E7D, //CJK UNIFIED IDEOGRAPH + 0x9CBA: 0x6E80, //CJK UNIFIED IDEOGRAPH + 0x9CBB: 0x6E81, //CJK UNIFIED IDEOGRAPH + 0x9CBC: 0x6E82, //CJK UNIFIED IDEOGRAPH + 0x9CBD: 0x6E84, //CJK UNIFIED IDEOGRAPH + 0x9CBE: 0x6E87, //CJK UNIFIED IDEOGRAPH + 0x9CBF: 0x6E88, //CJK UNIFIED IDEOGRAPH + 0x9CC0: 0x6E8A, //CJK UNIFIED IDEOGRAPH + 0x9CC1: 0x6E8B, //CJK UNIFIED IDEOGRAPH + 0x9CC2: 0x6E8C, //CJK UNIFIED IDEOGRAPH + 0x9CC3: 0x6E8D, //CJK UNIFIED IDEOGRAPH + 0x9CC4: 0x6E8E, //CJK UNIFIED IDEOGRAPH + 0x9CC5: 0x6E91, //CJK UNIFIED IDEOGRAPH + 0x9CC6: 0x6E92, //CJK UNIFIED IDEOGRAPH + 0x9CC7: 0x6E93, //CJK UNIFIED IDEOGRAPH + 0x9CC8: 0x6E94, //CJK UNIFIED IDEOGRAPH + 0x9CC9: 0x6E95, //CJK UNIFIED IDEOGRAPH + 0x9CCA: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0x9CCB: 0x6E97, //CJK UNIFIED IDEOGRAPH + 0x9CCC: 0x6E99, //CJK UNIFIED IDEOGRAPH + 0x9CCD: 0x6E9A, //CJK UNIFIED IDEOGRAPH + 0x9CCE: 0x6E9B, //CJK UNIFIED IDEOGRAPH + 0x9CCF: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0x9CD0: 0x6E9E, //CJK UNIFIED IDEOGRAPH + 0x9CD1: 0x6EA0, //CJK UNIFIED IDEOGRAPH + 0x9CD2: 0x6EA1, //CJK UNIFIED IDEOGRAPH + 0x9CD3: 0x6EA3, //CJK UNIFIED IDEOGRAPH + 0x9CD4: 0x6EA4, //CJK UNIFIED IDEOGRAPH + 0x9CD5: 0x6EA6, //CJK UNIFIED IDEOGRAPH + 0x9CD6: 0x6EA8, //CJK UNIFIED IDEOGRAPH + 0x9CD7: 0x6EA9, //CJK UNIFIED IDEOGRAPH + 0x9CD8: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0x9CD9: 0x6EAC, //CJK UNIFIED IDEOGRAPH + 0x9CDA: 0x6EAD, //CJK UNIFIED IDEOGRAPH + 0x9CDB: 0x6EAE, //CJK UNIFIED IDEOGRAPH + 0x9CDC: 0x6EB0, //CJK UNIFIED IDEOGRAPH + 0x9CDD: 0x6EB3, //CJK UNIFIED IDEOGRAPH + 0x9CDE: 0x6EB5, //CJK UNIFIED IDEOGRAPH + 0x9CDF: 0x6EB8, //CJK UNIFIED IDEOGRAPH + 0x9CE0: 0x6EB9, //CJK UNIFIED IDEOGRAPH + 0x9CE1: 0x6EBC, //CJK UNIFIED IDEOGRAPH + 0x9CE2: 0x6EBE, //CJK UNIFIED IDEOGRAPH + 0x9CE3: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0x9CE4: 0x6EC0, //CJK UNIFIED IDEOGRAPH + 0x9CE5: 0x6EC3, //CJK UNIFIED IDEOGRAPH + 0x9CE6: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0x9CE7: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0x9CE8: 0x6EC6, //CJK UNIFIED IDEOGRAPH + 0x9CE9: 0x6EC8, //CJK UNIFIED IDEOGRAPH + 0x9CEA: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0x9CEB: 0x6ECA, //CJK UNIFIED IDEOGRAPH + 0x9CEC: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0x9CED: 0x6ECD, //CJK UNIFIED IDEOGRAPH + 0x9CEE: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0x9CEF: 0x6ED0, //CJK UNIFIED IDEOGRAPH + 0x9CF0: 0x6ED2, //CJK UNIFIED IDEOGRAPH + 0x9CF1: 0x6ED6, //CJK UNIFIED IDEOGRAPH + 0x9CF2: 0x6ED8, //CJK UNIFIED IDEOGRAPH + 0x9CF3: 0x6ED9, //CJK UNIFIED IDEOGRAPH + 0x9CF4: 0x6EDB, //CJK UNIFIED IDEOGRAPH + 0x9CF5: 0x6EDC, //CJK UNIFIED IDEOGRAPH + 0x9CF6: 0x6EDD, //CJK UNIFIED IDEOGRAPH + 0x9CF7: 0x6EE3, //CJK UNIFIED IDEOGRAPH + 0x9CF8: 0x6EE7, //CJK UNIFIED IDEOGRAPH + 0x9CF9: 0x6EEA, //CJK UNIFIED IDEOGRAPH + 0x9CFA: 0x6EEB, //CJK UNIFIED IDEOGRAPH + 0x9CFB: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0x9CFC: 0x6EED, //CJK UNIFIED IDEOGRAPH + 0x9CFD: 0x6EEE, //CJK UNIFIED IDEOGRAPH + 0x9CFE: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0x9D40: 0x6EF0, //CJK UNIFIED IDEOGRAPH + 0x9D41: 0x6EF1, //CJK UNIFIED IDEOGRAPH + 0x9D42: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0x9D43: 0x6EF3, //CJK UNIFIED IDEOGRAPH + 0x9D44: 0x6EF5, //CJK UNIFIED IDEOGRAPH + 0x9D45: 0x6EF6, //CJK UNIFIED IDEOGRAPH + 0x9D46: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0x9D47: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0x9D48: 0x6EFA, //CJK UNIFIED IDEOGRAPH + 0x9D49: 0x6EFB, //CJK UNIFIED IDEOGRAPH + 0x9D4A: 0x6EFC, //CJK UNIFIED IDEOGRAPH + 0x9D4B: 0x6EFD, //CJK UNIFIED IDEOGRAPH + 0x9D4C: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0x9D4D: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0x9D4E: 0x6F00, //CJK UNIFIED IDEOGRAPH + 0x9D4F: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0x9D50: 0x6F03, //CJK UNIFIED IDEOGRAPH + 0x9D51: 0x6F04, //CJK UNIFIED IDEOGRAPH + 0x9D52: 0x6F05, //CJK UNIFIED IDEOGRAPH + 0x9D53: 0x6F07, //CJK UNIFIED IDEOGRAPH + 0x9D54: 0x6F08, //CJK UNIFIED IDEOGRAPH + 0x9D55: 0x6F0A, //CJK UNIFIED IDEOGRAPH + 0x9D56: 0x6F0B, //CJK UNIFIED IDEOGRAPH + 0x9D57: 0x6F0C, //CJK UNIFIED IDEOGRAPH + 0x9D58: 0x6F0D, //CJK UNIFIED IDEOGRAPH + 0x9D59: 0x6F0E, //CJK UNIFIED IDEOGRAPH + 0x9D5A: 0x6F10, //CJK UNIFIED IDEOGRAPH + 0x9D5B: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0x9D5C: 0x6F12, //CJK UNIFIED IDEOGRAPH + 0x9D5D: 0x6F16, //CJK UNIFIED IDEOGRAPH + 0x9D5E: 0x6F17, //CJK UNIFIED IDEOGRAPH + 0x9D5F: 0x6F18, //CJK UNIFIED IDEOGRAPH + 0x9D60: 0x6F19, //CJK UNIFIED IDEOGRAPH + 0x9D61: 0x6F1A, //CJK UNIFIED IDEOGRAPH + 0x9D62: 0x6F1B, //CJK UNIFIED IDEOGRAPH + 0x9D63: 0x6F1C, //CJK UNIFIED IDEOGRAPH + 0x9D64: 0x6F1D, //CJK UNIFIED IDEOGRAPH + 0x9D65: 0x6F1E, //CJK UNIFIED IDEOGRAPH + 0x9D66: 0x6F1F, //CJK UNIFIED IDEOGRAPH + 0x9D67: 0x6F21, //CJK UNIFIED IDEOGRAPH + 0x9D68: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0x9D69: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0x9D6A: 0x6F25, //CJK UNIFIED IDEOGRAPH + 0x9D6B: 0x6F26, //CJK UNIFIED IDEOGRAPH + 0x9D6C: 0x6F27, //CJK UNIFIED IDEOGRAPH + 0x9D6D: 0x6F28, //CJK UNIFIED IDEOGRAPH + 0x9D6E: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0x9D6F: 0x6F2E, //CJK UNIFIED IDEOGRAPH + 0x9D70: 0x6F30, //CJK UNIFIED IDEOGRAPH + 0x9D71: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0x9D72: 0x6F34, //CJK UNIFIED IDEOGRAPH + 0x9D73: 0x6F35, //CJK UNIFIED IDEOGRAPH + 0x9D74: 0x6F37, //CJK UNIFIED IDEOGRAPH + 0x9D75: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0x9D76: 0x6F39, //CJK UNIFIED IDEOGRAPH + 0x9D77: 0x6F3A, //CJK UNIFIED IDEOGRAPH + 0x9D78: 0x6F3B, //CJK UNIFIED IDEOGRAPH + 0x9D79: 0x6F3C, //CJK UNIFIED IDEOGRAPH + 0x9D7A: 0x6F3D, //CJK UNIFIED IDEOGRAPH + 0x9D7B: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0x9D7C: 0x6F40, //CJK UNIFIED IDEOGRAPH + 0x9D7D: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0x9D7E: 0x6F42, //CJK UNIFIED IDEOGRAPH + 0x9D80: 0x6F43, //CJK UNIFIED IDEOGRAPH + 0x9D81: 0x6F44, //CJK UNIFIED IDEOGRAPH + 0x9D82: 0x6F45, //CJK UNIFIED IDEOGRAPH + 0x9D83: 0x6F48, //CJK UNIFIED IDEOGRAPH + 0x9D84: 0x6F49, //CJK UNIFIED IDEOGRAPH + 0x9D85: 0x6F4A, //CJK UNIFIED IDEOGRAPH + 0x9D86: 0x6F4C, //CJK UNIFIED IDEOGRAPH + 0x9D87: 0x6F4E, //CJK UNIFIED IDEOGRAPH + 0x9D88: 0x6F4F, //CJK UNIFIED IDEOGRAPH + 0x9D89: 0x6F50, //CJK UNIFIED IDEOGRAPH + 0x9D8A: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0x9D8B: 0x6F52, //CJK UNIFIED IDEOGRAPH + 0x9D8C: 0x6F53, //CJK UNIFIED IDEOGRAPH + 0x9D8D: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0x9D8E: 0x6F55, //CJK UNIFIED IDEOGRAPH + 0x9D8F: 0x6F56, //CJK UNIFIED IDEOGRAPH + 0x9D90: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0x9D91: 0x6F59, //CJK UNIFIED IDEOGRAPH + 0x9D92: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0x9D93: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0x9D94: 0x6F5D, //CJK UNIFIED IDEOGRAPH + 0x9D95: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0x9D96: 0x6F60, //CJK UNIFIED IDEOGRAPH + 0x9D97: 0x6F61, //CJK UNIFIED IDEOGRAPH + 0x9D98: 0x6F63, //CJK UNIFIED IDEOGRAPH + 0x9D99: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0x9D9A: 0x6F65, //CJK UNIFIED IDEOGRAPH + 0x9D9B: 0x6F67, //CJK UNIFIED IDEOGRAPH + 0x9D9C: 0x6F68, //CJK UNIFIED IDEOGRAPH + 0x9D9D: 0x6F69, //CJK UNIFIED IDEOGRAPH + 0x9D9E: 0x6F6A, //CJK UNIFIED IDEOGRAPH + 0x9D9F: 0x6F6B, //CJK UNIFIED IDEOGRAPH + 0x9DA0: 0x6F6C, //CJK UNIFIED IDEOGRAPH + 0x9DA1: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0x9DA2: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0x9DA3: 0x6F71, //CJK UNIFIED IDEOGRAPH + 0x9DA4: 0x6F73, //CJK UNIFIED IDEOGRAPH + 0x9DA5: 0x6F75, //CJK UNIFIED IDEOGRAPH + 0x9DA6: 0x6F76, //CJK UNIFIED IDEOGRAPH + 0x9DA7: 0x6F77, //CJK UNIFIED IDEOGRAPH + 0x9DA8: 0x6F79, //CJK UNIFIED IDEOGRAPH + 0x9DA9: 0x6F7B, //CJK UNIFIED IDEOGRAPH + 0x9DAA: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0x9DAB: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0x9DAC: 0x6F7F, //CJK UNIFIED IDEOGRAPH + 0x9DAD: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0x9DAE: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0x9DAF: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0x9DB0: 0x6F83, //CJK UNIFIED IDEOGRAPH + 0x9DB1: 0x6F85, //CJK UNIFIED IDEOGRAPH + 0x9DB2: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0x9DB3: 0x6F87, //CJK UNIFIED IDEOGRAPH + 0x9DB4: 0x6F8A, //CJK UNIFIED IDEOGRAPH + 0x9DB5: 0x6F8B, //CJK UNIFIED IDEOGRAPH + 0x9DB6: 0x6F8F, //CJK UNIFIED IDEOGRAPH + 0x9DB7: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0x9DB8: 0x6F91, //CJK UNIFIED IDEOGRAPH + 0x9DB9: 0x6F92, //CJK UNIFIED IDEOGRAPH + 0x9DBA: 0x6F93, //CJK UNIFIED IDEOGRAPH + 0x9DBB: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0x9DBC: 0x6F95, //CJK UNIFIED IDEOGRAPH + 0x9DBD: 0x6F96, //CJK UNIFIED IDEOGRAPH + 0x9DBE: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0x9DBF: 0x6F98, //CJK UNIFIED IDEOGRAPH + 0x9DC0: 0x6F99, //CJK UNIFIED IDEOGRAPH + 0x9DC1: 0x6F9A, //CJK UNIFIED IDEOGRAPH + 0x9DC2: 0x6F9B, //CJK UNIFIED IDEOGRAPH + 0x9DC3: 0x6F9D, //CJK UNIFIED IDEOGRAPH + 0x9DC4: 0x6F9E, //CJK UNIFIED IDEOGRAPH + 0x9DC5: 0x6F9F, //CJK UNIFIED IDEOGRAPH + 0x9DC6: 0x6FA0, //CJK UNIFIED IDEOGRAPH + 0x9DC7: 0x6FA2, //CJK UNIFIED IDEOGRAPH + 0x9DC8: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0x9DC9: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0x9DCA: 0x6FA5, //CJK UNIFIED IDEOGRAPH + 0x9DCB: 0x6FA6, //CJK UNIFIED IDEOGRAPH + 0x9DCC: 0x6FA8, //CJK UNIFIED IDEOGRAPH + 0x9DCD: 0x6FA9, //CJK UNIFIED IDEOGRAPH + 0x9DCE: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0x9DCF: 0x6FAB, //CJK UNIFIED IDEOGRAPH + 0x9DD0: 0x6FAC, //CJK UNIFIED IDEOGRAPH + 0x9DD1: 0x6FAD, //CJK UNIFIED IDEOGRAPH + 0x9DD2: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0x9DD3: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0x9DD4: 0x6FB0, //CJK UNIFIED IDEOGRAPH + 0x9DD5: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0x9DD6: 0x6FB2, //CJK UNIFIED IDEOGRAPH + 0x9DD7: 0x6FB4, //CJK UNIFIED IDEOGRAPH + 0x9DD8: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0x9DD9: 0x6FB7, //CJK UNIFIED IDEOGRAPH + 0x9DDA: 0x6FB8, //CJK UNIFIED IDEOGRAPH + 0x9DDB: 0x6FBA, //CJK UNIFIED IDEOGRAPH + 0x9DDC: 0x6FBB, //CJK UNIFIED IDEOGRAPH + 0x9DDD: 0x6FBC, //CJK UNIFIED IDEOGRAPH + 0x9DDE: 0x6FBD, //CJK UNIFIED IDEOGRAPH + 0x9DDF: 0x6FBE, //CJK UNIFIED IDEOGRAPH + 0x9DE0: 0x6FBF, //CJK UNIFIED IDEOGRAPH + 0x9DE1: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0x9DE2: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0x9DE3: 0x6FC4, //CJK UNIFIED IDEOGRAPH + 0x9DE4: 0x6FC5, //CJK UNIFIED IDEOGRAPH + 0x9DE5: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0x9DE6: 0x6FC7, //CJK UNIFIED IDEOGRAPH + 0x9DE7: 0x6FC8, //CJK UNIFIED IDEOGRAPH + 0x9DE8: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0x9DE9: 0x6FCB, //CJK UNIFIED IDEOGRAPH + 0x9DEA: 0x6FCC, //CJK UNIFIED IDEOGRAPH + 0x9DEB: 0x6FCD, //CJK UNIFIED IDEOGRAPH + 0x9DEC: 0x6FCE, //CJK UNIFIED IDEOGRAPH + 0x9DED: 0x6FCF, //CJK UNIFIED IDEOGRAPH + 0x9DEE: 0x6FD0, //CJK UNIFIED IDEOGRAPH + 0x9DEF: 0x6FD3, //CJK UNIFIED IDEOGRAPH + 0x9DF0: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0x9DF1: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0x9DF2: 0x6FD6, //CJK UNIFIED IDEOGRAPH + 0x9DF3: 0x6FD7, //CJK UNIFIED IDEOGRAPH + 0x9DF4: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0x9DF5: 0x6FD9, //CJK UNIFIED IDEOGRAPH + 0x9DF6: 0x6FDA, //CJK UNIFIED IDEOGRAPH + 0x9DF7: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0x9DF8: 0x6FDC, //CJK UNIFIED IDEOGRAPH + 0x9DF9: 0x6FDD, //CJK UNIFIED IDEOGRAPH + 0x9DFA: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0x9DFB: 0x6FE2, //CJK UNIFIED IDEOGRAPH + 0x9DFC: 0x6FE3, //CJK UNIFIED IDEOGRAPH + 0x9DFD: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0x9DFE: 0x6FE5, //CJK UNIFIED IDEOGRAPH + 0x9E40: 0x6FE6, //CJK UNIFIED IDEOGRAPH + 0x9E41: 0x6FE7, //CJK UNIFIED IDEOGRAPH + 0x9E42: 0x6FE8, //CJK UNIFIED IDEOGRAPH + 0x9E43: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0x9E44: 0x6FEA, //CJK UNIFIED IDEOGRAPH + 0x9E45: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0x9E46: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0x9E47: 0x6FED, //CJK UNIFIED IDEOGRAPH + 0x9E48: 0x6FF0, //CJK UNIFIED IDEOGRAPH + 0x9E49: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0x9E4A: 0x6FF2, //CJK UNIFIED IDEOGRAPH + 0x9E4B: 0x6FF3, //CJK UNIFIED IDEOGRAPH + 0x9E4C: 0x6FF4, //CJK UNIFIED IDEOGRAPH + 0x9E4D: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0x9E4E: 0x6FF6, //CJK UNIFIED IDEOGRAPH + 0x9E4F: 0x6FF7, //CJK UNIFIED IDEOGRAPH + 0x9E50: 0x6FF8, //CJK UNIFIED IDEOGRAPH + 0x9E51: 0x6FF9, //CJK UNIFIED IDEOGRAPH + 0x9E52: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0x9E53: 0x6FFB, //CJK UNIFIED IDEOGRAPH + 0x9E54: 0x6FFC, //CJK UNIFIED IDEOGRAPH + 0x9E55: 0x6FFD, //CJK UNIFIED IDEOGRAPH + 0x9E56: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0x9E57: 0x6FFF, //CJK UNIFIED IDEOGRAPH + 0x9E58: 0x7000, //CJK UNIFIED IDEOGRAPH + 0x9E59: 0x7001, //CJK UNIFIED IDEOGRAPH + 0x9E5A: 0x7002, //CJK UNIFIED IDEOGRAPH + 0x9E5B: 0x7003, //CJK UNIFIED IDEOGRAPH + 0x9E5C: 0x7004, //CJK UNIFIED IDEOGRAPH + 0x9E5D: 0x7005, //CJK UNIFIED IDEOGRAPH + 0x9E5E: 0x7006, //CJK UNIFIED IDEOGRAPH + 0x9E5F: 0x7007, //CJK UNIFIED IDEOGRAPH + 0x9E60: 0x7008, //CJK UNIFIED IDEOGRAPH + 0x9E61: 0x7009, //CJK UNIFIED IDEOGRAPH + 0x9E62: 0x700A, //CJK UNIFIED IDEOGRAPH + 0x9E63: 0x700B, //CJK UNIFIED IDEOGRAPH + 0x9E64: 0x700C, //CJK UNIFIED IDEOGRAPH + 0x9E65: 0x700D, //CJK UNIFIED IDEOGRAPH + 0x9E66: 0x700E, //CJK UNIFIED IDEOGRAPH + 0x9E67: 0x700F, //CJK UNIFIED IDEOGRAPH + 0x9E68: 0x7010, //CJK UNIFIED IDEOGRAPH + 0x9E69: 0x7012, //CJK UNIFIED IDEOGRAPH + 0x9E6A: 0x7013, //CJK UNIFIED IDEOGRAPH + 0x9E6B: 0x7014, //CJK UNIFIED IDEOGRAPH + 0x9E6C: 0x7015, //CJK UNIFIED IDEOGRAPH + 0x9E6D: 0x7016, //CJK UNIFIED IDEOGRAPH + 0x9E6E: 0x7017, //CJK UNIFIED IDEOGRAPH + 0x9E6F: 0x7018, //CJK UNIFIED IDEOGRAPH + 0x9E70: 0x7019, //CJK UNIFIED IDEOGRAPH + 0x9E71: 0x701C, //CJK UNIFIED IDEOGRAPH + 0x9E72: 0x701D, //CJK UNIFIED IDEOGRAPH + 0x9E73: 0x701E, //CJK UNIFIED IDEOGRAPH + 0x9E74: 0x701F, //CJK UNIFIED IDEOGRAPH + 0x9E75: 0x7020, //CJK UNIFIED IDEOGRAPH + 0x9E76: 0x7021, //CJK UNIFIED IDEOGRAPH + 0x9E77: 0x7022, //CJK UNIFIED IDEOGRAPH + 0x9E78: 0x7024, //CJK UNIFIED IDEOGRAPH + 0x9E79: 0x7025, //CJK UNIFIED IDEOGRAPH + 0x9E7A: 0x7026, //CJK UNIFIED IDEOGRAPH + 0x9E7B: 0x7027, //CJK UNIFIED IDEOGRAPH + 0x9E7C: 0x7028, //CJK UNIFIED IDEOGRAPH + 0x9E7D: 0x7029, //CJK UNIFIED IDEOGRAPH + 0x9E7E: 0x702A, //CJK UNIFIED IDEOGRAPH + 0x9E80: 0x702B, //CJK UNIFIED IDEOGRAPH + 0x9E81: 0x702C, //CJK UNIFIED IDEOGRAPH + 0x9E82: 0x702D, //CJK UNIFIED IDEOGRAPH + 0x9E83: 0x702E, //CJK UNIFIED IDEOGRAPH + 0x9E84: 0x702F, //CJK UNIFIED IDEOGRAPH + 0x9E85: 0x7030, //CJK UNIFIED IDEOGRAPH + 0x9E86: 0x7031, //CJK UNIFIED IDEOGRAPH + 0x9E87: 0x7032, //CJK UNIFIED IDEOGRAPH + 0x9E88: 0x7033, //CJK UNIFIED IDEOGRAPH + 0x9E89: 0x7034, //CJK UNIFIED IDEOGRAPH + 0x9E8A: 0x7036, //CJK UNIFIED IDEOGRAPH + 0x9E8B: 0x7037, //CJK UNIFIED IDEOGRAPH + 0x9E8C: 0x7038, //CJK UNIFIED IDEOGRAPH + 0x9E8D: 0x703A, //CJK UNIFIED IDEOGRAPH + 0x9E8E: 0x703B, //CJK UNIFIED IDEOGRAPH + 0x9E8F: 0x703C, //CJK UNIFIED IDEOGRAPH + 0x9E90: 0x703D, //CJK UNIFIED IDEOGRAPH + 0x9E91: 0x703E, //CJK UNIFIED IDEOGRAPH + 0x9E92: 0x703F, //CJK UNIFIED IDEOGRAPH + 0x9E93: 0x7040, //CJK UNIFIED IDEOGRAPH + 0x9E94: 0x7041, //CJK UNIFIED IDEOGRAPH + 0x9E95: 0x7042, //CJK UNIFIED IDEOGRAPH + 0x9E96: 0x7043, //CJK UNIFIED IDEOGRAPH + 0x9E97: 0x7044, //CJK UNIFIED IDEOGRAPH + 0x9E98: 0x7045, //CJK UNIFIED IDEOGRAPH + 0x9E99: 0x7046, //CJK UNIFIED IDEOGRAPH + 0x9E9A: 0x7047, //CJK UNIFIED IDEOGRAPH + 0x9E9B: 0x7048, //CJK UNIFIED IDEOGRAPH + 0x9E9C: 0x7049, //CJK UNIFIED IDEOGRAPH + 0x9E9D: 0x704A, //CJK UNIFIED IDEOGRAPH + 0x9E9E: 0x704B, //CJK UNIFIED IDEOGRAPH + 0x9E9F: 0x704D, //CJK UNIFIED IDEOGRAPH + 0x9EA0: 0x704E, //CJK UNIFIED IDEOGRAPH + 0x9EA1: 0x7050, //CJK UNIFIED IDEOGRAPH + 0x9EA2: 0x7051, //CJK UNIFIED IDEOGRAPH + 0x9EA3: 0x7052, //CJK UNIFIED IDEOGRAPH + 0x9EA4: 0x7053, //CJK UNIFIED IDEOGRAPH + 0x9EA5: 0x7054, //CJK UNIFIED IDEOGRAPH + 0x9EA6: 0x7055, //CJK UNIFIED IDEOGRAPH + 0x9EA7: 0x7056, //CJK UNIFIED IDEOGRAPH + 0x9EA8: 0x7057, //CJK UNIFIED IDEOGRAPH + 0x9EA9: 0x7058, //CJK UNIFIED IDEOGRAPH + 0x9EAA: 0x7059, //CJK UNIFIED IDEOGRAPH + 0x9EAB: 0x705A, //CJK UNIFIED IDEOGRAPH + 0x9EAC: 0x705B, //CJK UNIFIED IDEOGRAPH + 0x9EAD: 0x705C, //CJK UNIFIED IDEOGRAPH + 0x9EAE: 0x705D, //CJK UNIFIED IDEOGRAPH + 0x9EAF: 0x705F, //CJK UNIFIED IDEOGRAPH + 0x9EB0: 0x7060, //CJK UNIFIED IDEOGRAPH + 0x9EB1: 0x7061, //CJK UNIFIED IDEOGRAPH + 0x9EB2: 0x7062, //CJK UNIFIED IDEOGRAPH + 0x9EB3: 0x7063, //CJK UNIFIED IDEOGRAPH + 0x9EB4: 0x7064, //CJK UNIFIED IDEOGRAPH + 0x9EB5: 0x7065, //CJK UNIFIED IDEOGRAPH + 0x9EB6: 0x7066, //CJK UNIFIED IDEOGRAPH + 0x9EB7: 0x7067, //CJK UNIFIED IDEOGRAPH + 0x9EB8: 0x7068, //CJK UNIFIED IDEOGRAPH + 0x9EB9: 0x7069, //CJK UNIFIED IDEOGRAPH + 0x9EBA: 0x706A, //CJK UNIFIED IDEOGRAPH + 0x9EBB: 0x706E, //CJK UNIFIED IDEOGRAPH + 0x9EBC: 0x7071, //CJK UNIFIED IDEOGRAPH + 0x9EBD: 0x7072, //CJK UNIFIED IDEOGRAPH + 0x9EBE: 0x7073, //CJK UNIFIED IDEOGRAPH + 0x9EBF: 0x7074, //CJK UNIFIED IDEOGRAPH + 0x9EC0: 0x7077, //CJK UNIFIED IDEOGRAPH + 0x9EC1: 0x7079, //CJK UNIFIED IDEOGRAPH + 0x9EC2: 0x707A, //CJK UNIFIED IDEOGRAPH + 0x9EC3: 0x707B, //CJK UNIFIED IDEOGRAPH + 0x9EC4: 0x707D, //CJK UNIFIED IDEOGRAPH + 0x9EC5: 0x7081, //CJK UNIFIED IDEOGRAPH + 0x9EC6: 0x7082, //CJK UNIFIED IDEOGRAPH + 0x9EC7: 0x7083, //CJK UNIFIED IDEOGRAPH + 0x9EC8: 0x7084, //CJK UNIFIED IDEOGRAPH + 0x9EC9: 0x7086, //CJK UNIFIED IDEOGRAPH + 0x9ECA: 0x7087, //CJK UNIFIED IDEOGRAPH + 0x9ECB: 0x7088, //CJK UNIFIED IDEOGRAPH + 0x9ECC: 0x708B, //CJK UNIFIED IDEOGRAPH + 0x9ECD: 0x708C, //CJK UNIFIED IDEOGRAPH + 0x9ECE: 0x708D, //CJK UNIFIED IDEOGRAPH + 0x9ECF: 0x708F, //CJK UNIFIED IDEOGRAPH + 0x9ED0: 0x7090, //CJK UNIFIED IDEOGRAPH + 0x9ED1: 0x7091, //CJK UNIFIED IDEOGRAPH + 0x9ED2: 0x7093, //CJK UNIFIED IDEOGRAPH + 0x9ED3: 0x7097, //CJK UNIFIED IDEOGRAPH + 0x9ED4: 0x7098, //CJK UNIFIED IDEOGRAPH + 0x9ED5: 0x709A, //CJK UNIFIED IDEOGRAPH + 0x9ED6: 0x709B, //CJK UNIFIED IDEOGRAPH + 0x9ED7: 0x709E, //CJK UNIFIED IDEOGRAPH + 0x9ED8: 0x709F, //CJK UNIFIED IDEOGRAPH + 0x9ED9: 0x70A0, //CJK UNIFIED IDEOGRAPH + 0x9EDA: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0x9EDB: 0x70A2, //CJK UNIFIED IDEOGRAPH + 0x9EDC: 0x70A3, //CJK UNIFIED IDEOGRAPH + 0x9EDD: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0x9EDE: 0x70A5, //CJK UNIFIED IDEOGRAPH + 0x9EDF: 0x70A6, //CJK UNIFIED IDEOGRAPH + 0x9EE0: 0x70A7, //CJK UNIFIED IDEOGRAPH + 0x9EE1: 0x70A8, //CJK UNIFIED IDEOGRAPH + 0x9EE2: 0x70A9, //CJK UNIFIED IDEOGRAPH + 0x9EE3: 0x70AA, //CJK UNIFIED IDEOGRAPH + 0x9EE4: 0x70B0, //CJK UNIFIED IDEOGRAPH + 0x9EE5: 0x70B2, //CJK UNIFIED IDEOGRAPH + 0x9EE6: 0x70B4, //CJK UNIFIED IDEOGRAPH + 0x9EE7: 0x70B5, //CJK UNIFIED IDEOGRAPH + 0x9EE8: 0x70B6, //CJK UNIFIED IDEOGRAPH + 0x9EE9: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0x9EEA: 0x70BE, //CJK UNIFIED IDEOGRAPH + 0x9EEB: 0x70BF, //CJK UNIFIED IDEOGRAPH + 0x9EEC: 0x70C4, //CJK UNIFIED IDEOGRAPH + 0x9EED: 0x70C5, //CJK UNIFIED IDEOGRAPH + 0x9EEE: 0x70C6, //CJK UNIFIED IDEOGRAPH + 0x9EEF: 0x70C7, //CJK UNIFIED IDEOGRAPH + 0x9EF0: 0x70C9, //CJK UNIFIED IDEOGRAPH + 0x9EF1: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0x9EF2: 0x70CC, //CJK UNIFIED IDEOGRAPH + 0x9EF3: 0x70CD, //CJK UNIFIED IDEOGRAPH + 0x9EF4: 0x70CE, //CJK UNIFIED IDEOGRAPH + 0x9EF5: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0x9EF6: 0x70D0, //CJK UNIFIED IDEOGRAPH + 0x9EF7: 0x70D1, //CJK UNIFIED IDEOGRAPH + 0x9EF8: 0x70D2, //CJK UNIFIED IDEOGRAPH + 0x9EF9: 0x70D3, //CJK UNIFIED IDEOGRAPH + 0x9EFA: 0x70D4, //CJK UNIFIED IDEOGRAPH + 0x9EFB: 0x70D5, //CJK UNIFIED IDEOGRAPH + 0x9EFC: 0x70D6, //CJK UNIFIED IDEOGRAPH + 0x9EFD: 0x70D7, //CJK UNIFIED IDEOGRAPH + 0x9EFE: 0x70DA, //CJK UNIFIED IDEOGRAPH + 0x9F40: 0x70DC, //CJK UNIFIED IDEOGRAPH + 0x9F41: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0x9F42: 0x70DE, //CJK UNIFIED IDEOGRAPH + 0x9F43: 0x70E0, //CJK UNIFIED IDEOGRAPH + 0x9F44: 0x70E1, //CJK UNIFIED IDEOGRAPH + 0x9F45: 0x70E2, //CJK UNIFIED IDEOGRAPH + 0x9F46: 0x70E3, //CJK UNIFIED IDEOGRAPH + 0x9F47: 0x70E5, //CJK UNIFIED IDEOGRAPH + 0x9F48: 0x70EA, //CJK UNIFIED IDEOGRAPH + 0x9F49: 0x70EE, //CJK UNIFIED IDEOGRAPH + 0x9F4A: 0x70F0, //CJK UNIFIED IDEOGRAPH + 0x9F4B: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0x9F4C: 0x70F2, //CJK UNIFIED IDEOGRAPH + 0x9F4D: 0x70F3, //CJK UNIFIED IDEOGRAPH + 0x9F4E: 0x70F4, //CJK UNIFIED IDEOGRAPH + 0x9F4F: 0x70F5, //CJK UNIFIED IDEOGRAPH + 0x9F50: 0x70F6, //CJK UNIFIED IDEOGRAPH + 0x9F51: 0x70F8, //CJK UNIFIED IDEOGRAPH + 0x9F52: 0x70FA, //CJK UNIFIED IDEOGRAPH + 0x9F53: 0x70FB, //CJK UNIFIED IDEOGRAPH + 0x9F54: 0x70FC, //CJK UNIFIED IDEOGRAPH + 0x9F55: 0x70FE, //CJK UNIFIED IDEOGRAPH + 0x9F56: 0x70FF, //CJK UNIFIED IDEOGRAPH + 0x9F57: 0x7100, //CJK UNIFIED IDEOGRAPH + 0x9F58: 0x7101, //CJK UNIFIED IDEOGRAPH + 0x9F59: 0x7102, //CJK UNIFIED IDEOGRAPH + 0x9F5A: 0x7103, //CJK UNIFIED IDEOGRAPH + 0x9F5B: 0x7104, //CJK UNIFIED IDEOGRAPH + 0x9F5C: 0x7105, //CJK UNIFIED IDEOGRAPH + 0x9F5D: 0x7106, //CJK UNIFIED IDEOGRAPH + 0x9F5E: 0x7107, //CJK UNIFIED IDEOGRAPH + 0x9F5F: 0x7108, //CJK UNIFIED IDEOGRAPH + 0x9F60: 0x710B, //CJK UNIFIED IDEOGRAPH + 0x9F61: 0x710C, //CJK UNIFIED IDEOGRAPH + 0x9F62: 0x710D, //CJK UNIFIED IDEOGRAPH + 0x9F63: 0x710E, //CJK UNIFIED IDEOGRAPH + 0x9F64: 0x710F, //CJK UNIFIED IDEOGRAPH + 0x9F65: 0x7111, //CJK UNIFIED IDEOGRAPH + 0x9F66: 0x7112, //CJK UNIFIED IDEOGRAPH + 0x9F67: 0x7114, //CJK UNIFIED IDEOGRAPH + 0x9F68: 0x7117, //CJK UNIFIED IDEOGRAPH + 0x9F69: 0x711B, //CJK UNIFIED IDEOGRAPH + 0x9F6A: 0x711C, //CJK UNIFIED IDEOGRAPH + 0x9F6B: 0x711D, //CJK UNIFIED IDEOGRAPH + 0x9F6C: 0x711E, //CJK UNIFIED IDEOGRAPH + 0x9F6D: 0x711F, //CJK UNIFIED IDEOGRAPH + 0x9F6E: 0x7120, //CJK UNIFIED IDEOGRAPH + 0x9F6F: 0x7121, //CJK UNIFIED IDEOGRAPH + 0x9F70: 0x7122, //CJK UNIFIED IDEOGRAPH + 0x9F71: 0x7123, //CJK UNIFIED IDEOGRAPH + 0x9F72: 0x7124, //CJK UNIFIED IDEOGRAPH + 0x9F73: 0x7125, //CJK UNIFIED IDEOGRAPH + 0x9F74: 0x7127, //CJK UNIFIED IDEOGRAPH + 0x9F75: 0x7128, //CJK UNIFIED IDEOGRAPH + 0x9F76: 0x7129, //CJK UNIFIED IDEOGRAPH + 0x9F77: 0x712A, //CJK UNIFIED IDEOGRAPH + 0x9F78: 0x712B, //CJK UNIFIED IDEOGRAPH + 0x9F79: 0x712C, //CJK UNIFIED IDEOGRAPH + 0x9F7A: 0x712D, //CJK UNIFIED IDEOGRAPH + 0x9F7B: 0x712E, //CJK UNIFIED IDEOGRAPH + 0x9F7C: 0x7132, //CJK UNIFIED IDEOGRAPH + 0x9F7D: 0x7133, //CJK UNIFIED IDEOGRAPH + 0x9F7E: 0x7134, //CJK UNIFIED IDEOGRAPH + 0x9F80: 0x7135, //CJK UNIFIED IDEOGRAPH + 0x9F81: 0x7137, //CJK UNIFIED IDEOGRAPH + 0x9F82: 0x7138, //CJK UNIFIED IDEOGRAPH + 0x9F83: 0x7139, //CJK UNIFIED IDEOGRAPH + 0x9F84: 0x713A, //CJK UNIFIED IDEOGRAPH + 0x9F85: 0x713B, //CJK UNIFIED IDEOGRAPH + 0x9F86: 0x713C, //CJK UNIFIED IDEOGRAPH + 0x9F87: 0x713D, //CJK UNIFIED IDEOGRAPH + 0x9F88: 0x713E, //CJK UNIFIED IDEOGRAPH + 0x9F89: 0x713F, //CJK UNIFIED IDEOGRAPH + 0x9F8A: 0x7140, //CJK UNIFIED IDEOGRAPH + 0x9F8B: 0x7141, //CJK UNIFIED IDEOGRAPH + 0x9F8C: 0x7142, //CJK UNIFIED IDEOGRAPH + 0x9F8D: 0x7143, //CJK UNIFIED IDEOGRAPH + 0x9F8E: 0x7144, //CJK UNIFIED IDEOGRAPH + 0x9F8F: 0x7146, //CJK UNIFIED IDEOGRAPH + 0x9F90: 0x7147, //CJK UNIFIED IDEOGRAPH + 0x9F91: 0x7148, //CJK UNIFIED IDEOGRAPH + 0x9F92: 0x7149, //CJK UNIFIED IDEOGRAPH + 0x9F93: 0x714B, //CJK UNIFIED IDEOGRAPH + 0x9F94: 0x714D, //CJK UNIFIED IDEOGRAPH + 0x9F95: 0x714F, //CJK UNIFIED IDEOGRAPH + 0x9F96: 0x7150, //CJK UNIFIED IDEOGRAPH + 0x9F97: 0x7151, //CJK UNIFIED IDEOGRAPH + 0x9F98: 0x7152, //CJK UNIFIED IDEOGRAPH + 0x9F99: 0x7153, //CJK UNIFIED IDEOGRAPH + 0x9F9A: 0x7154, //CJK UNIFIED IDEOGRAPH + 0x9F9B: 0x7155, //CJK UNIFIED IDEOGRAPH + 0x9F9C: 0x7156, //CJK UNIFIED IDEOGRAPH + 0x9F9D: 0x7157, //CJK UNIFIED IDEOGRAPH + 0x9F9E: 0x7158, //CJK UNIFIED IDEOGRAPH + 0x9F9F: 0x7159, //CJK UNIFIED IDEOGRAPH + 0x9FA0: 0x715A, //CJK UNIFIED IDEOGRAPH + 0x9FA1: 0x715B, //CJK UNIFIED IDEOGRAPH + 0x9FA2: 0x715D, //CJK UNIFIED IDEOGRAPH + 0x9FA3: 0x715F, //CJK UNIFIED IDEOGRAPH + 0x9FA4: 0x7160, //CJK UNIFIED IDEOGRAPH + 0x9FA5: 0x7161, //CJK UNIFIED IDEOGRAPH + 0x9FA6: 0x7162, //CJK UNIFIED IDEOGRAPH + 0x9FA7: 0x7163, //CJK UNIFIED IDEOGRAPH + 0x9FA8: 0x7165, //CJK UNIFIED IDEOGRAPH + 0x9FA9: 0x7169, //CJK UNIFIED IDEOGRAPH + 0x9FAA: 0x716A, //CJK UNIFIED IDEOGRAPH + 0x9FAB: 0x716B, //CJK UNIFIED IDEOGRAPH + 0x9FAC: 0x716C, //CJK UNIFIED IDEOGRAPH + 0x9FAD: 0x716D, //CJK UNIFIED IDEOGRAPH + 0x9FAE: 0x716F, //CJK UNIFIED IDEOGRAPH + 0x9FAF: 0x7170, //CJK UNIFIED IDEOGRAPH + 0x9FB0: 0x7171, //CJK UNIFIED IDEOGRAPH + 0x9FB1: 0x7174, //CJK UNIFIED IDEOGRAPH + 0x9FB2: 0x7175, //CJK UNIFIED IDEOGRAPH + 0x9FB3: 0x7176, //CJK UNIFIED IDEOGRAPH + 0x9FB4: 0x7177, //CJK UNIFIED IDEOGRAPH + 0x9FB5: 0x7179, //CJK UNIFIED IDEOGRAPH + 0x9FB6: 0x717B, //CJK UNIFIED IDEOGRAPH + 0x9FB7: 0x717C, //CJK UNIFIED IDEOGRAPH + 0x9FB8: 0x717E, //CJK UNIFIED IDEOGRAPH + 0x9FB9: 0x717F, //CJK UNIFIED IDEOGRAPH + 0x9FBA: 0x7180, //CJK UNIFIED IDEOGRAPH + 0x9FBB: 0x7181, //CJK UNIFIED IDEOGRAPH + 0x9FBC: 0x7182, //CJK UNIFIED IDEOGRAPH + 0x9FBD: 0x7183, //CJK UNIFIED IDEOGRAPH + 0x9FBE: 0x7185, //CJK UNIFIED IDEOGRAPH + 0x9FBF: 0x7186, //CJK UNIFIED IDEOGRAPH + 0x9FC0: 0x7187, //CJK UNIFIED IDEOGRAPH + 0x9FC1: 0x7188, //CJK UNIFIED IDEOGRAPH + 0x9FC2: 0x7189, //CJK UNIFIED IDEOGRAPH + 0x9FC3: 0x718B, //CJK UNIFIED IDEOGRAPH + 0x9FC4: 0x718C, //CJK UNIFIED IDEOGRAPH + 0x9FC5: 0x718D, //CJK UNIFIED IDEOGRAPH + 0x9FC6: 0x718E, //CJK UNIFIED IDEOGRAPH + 0x9FC7: 0x7190, //CJK UNIFIED IDEOGRAPH + 0x9FC8: 0x7191, //CJK UNIFIED IDEOGRAPH + 0x9FC9: 0x7192, //CJK UNIFIED IDEOGRAPH + 0x9FCA: 0x7193, //CJK UNIFIED IDEOGRAPH + 0x9FCB: 0x7195, //CJK UNIFIED IDEOGRAPH + 0x9FCC: 0x7196, //CJK UNIFIED IDEOGRAPH + 0x9FCD: 0x7197, //CJK UNIFIED IDEOGRAPH + 0x9FCE: 0x719A, //CJK UNIFIED IDEOGRAPH + 0x9FCF: 0x719B, //CJK UNIFIED IDEOGRAPH + 0x9FD0: 0x719C, //CJK UNIFIED IDEOGRAPH + 0x9FD1: 0x719D, //CJK UNIFIED IDEOGRAPH + 0x9FD2: 0x719E, //CJK UNIFIED IDEOGRAPH + 0x9FD3: 0x71A1, //CJK UNIFIED IDEOGRAPH + 0x9FD4: 0x71A2, //CJK UNIFIED IDEOGRAPH + 0x9FD5: 0x71A3, //CJK UNIFIED IDEOGRAPH + 0x9FD6: 0x71A4, //CJK UNIFIED IDEOGRAPH + 0x9FD7: 0x71A5, //CJK UNIFIED IDEOGRAPH + 0x9FD8: 0x71A6, //CJK UNIFIED IDEOGRAPH + 0x9FD9: 0x71A7, //CJK UNIFIED IDEOGRAPH + 0x9FDA: 0x71A9, //CJK UNIFIED IDEOGRAPH + 0x9FDB: 0x71AA, //CJK UNIFIED IDEOGRAPH + 0x9FDC: 0x71AB, //CJK UNIFIED IDEOGRAPH + 0x9FDD: 0x71AD, //CJK UNIFIED IDEOGRAPH + 0x9FDE: 0x71AE, //CJK UNIFIED IDEOGRAPH + 0x9FDF: 0x71AF, //CJK UNIFIED IDEOGRAPH + 0x9FE0: 0x71B0, //CJK UNIFIED IDEOGRAPH + 0x9FE1: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0x9FE2: 0x71B2, //CJK UNIFIED IDEOGRAPH + 0x9FE3: 0x71B4, //CJK UNIFIED IDEOGRAPH + 0x9FE4: 0x71B6, //CJK UNIFIED IDEOGRAPH + 0x9FE5: 0x71B7, //CJK UNIFIED IDEOGRAPH + 0x9FE6: 0x71B8, //CJK UNIFIED IDEOGRAPH + 0x9FE7: 0x71BA, //CJK UNIFIED IDEOGRAPH + 0x9FE8: 0x71BB, //CJK UNIFIED IDEOGRAPH + 0x9FE9: 0x71BC, //CJK UNIFIED IDEOGRAPH + 0x9FEA: 0x71BD, //CJK UNIFIED IDEOGRAPH + 0x9FEB: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0x9FEC: 0x71BF, //CJK UNIFIED IDEOGRAPH + 0x9FED: 0x71C0, //CJK UNIFIED IDEOGRAPH + 0x9FEE: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0x9FEF: 0x71C2, //CJK UNIFIED IDEOGRAPH + 0x9FF0: 0x71C4, //CJK UNIFIED IDEOGRAPH + 0x9FF1: 0x71C5, //CJK UNIFIED IDEOGRAPH + 0x9FF2: 0x71C6, //CJK UNIFIED IDEOGRAPH + 0x9FF3: 0x71C7, //CJK UNIFIED IDEOGRAPH + 0x9FF4: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0x9FF5: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0x9FF6: 0x71CA, //CJK UNIFIED IDEOGRAPH + 0x9FF7: 0x71CB, //CJK UNIFIED IDEOGRAPH + 0x9FF8: 0x71CC, //CJK UNIFIED IDEOGRAPH + 0x9FF9: 0x71CD, //CJK UNIFIED IDEOGRAPH + 0x9FFA: 0x71CF, //CJK UNIFIED IDEOGRAPH + 0x9FFB: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0x9FFC: 0x71D1, //CJK UNIFIED IDEOGRAPH + 0x9FFD: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0x9FFE: 0x71D3, //CJK UNIFIED IDEOGRAPH + 0xA040: 0x71D6, //CJK UNIFIED IDEOGRAPH + 0xA041: 0x71D7, //CJK UNIFIED IDEOGRAPH + 0xA042: 0x71D8, //CJK UNIFIED IDEOGRAPH + 0xA043: 0x71D9, //CJK UNIFIED IDEOGRAPH + 0xA044: 0x71DA, //CJK UNIFIED IDEOGRAPH + 0xA045: 0x71DB, //CJK UNIFIED IDEOGRAPH + 0xA046: 0x71DC, //CJK UNIFIED IDEOGRAPH + 0xA047: 0x71DD, //CJK UNIFIED IDEOGRAPH + 0xA048: 0x71DE, //CJK UNIFIED IDEOGRAPH + 0xA049: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xA04A: 0x71E1, //CJK UNIFIED IDEOGRAPH + 0xA04B: 0x71E2, //CJK UNIFIED IDEOGRAPH + 0xA04C: 0x71E3, //CJK UNIFIED IDEOGRAPH + 0xA04D: 0x71E4, //CJK UNIFIED IDEOGRAPH + 0xA04E: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xA04F: 0x71E8, //CJK UNIFIED IDEOGRAPH + 0xA050: 0x71E9, //CJK UNIFIED IDEOGRAPH + 0xA051: 0x71EA, //CJK UNIFIED IDEOGRAPH + 0xA052: 0x71EB, //CJK UNIFIED IDEOGRAPH + 0xA053: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xA054: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xA055: 0x71EF, //CJK UNIFIED IDEOGRAPH + 0xA056: 0x71F0, //CJK UNIFIED IDEOGRAPH + 0xA057: 0x71F1, //CJK UNIFIED IDEOGRAPH + 0xA058: 0x71F2, //CJK UNIFIED IDEOGRAPH + 0xA059: 0x71F3, //CJK UNIFIED IDEOGRAPH + 0xA05A: 0x71F4, //CJK UNIFIED IDEOGRAPH + 0xA05B: 0x71F5, //CJK UNIFIED IDEOGRAPH + 0xA05C: 0x71F6, //CJK UNIFIED IDEOGRAPH + 0xA05D: 0x71F7, //CJK UNIFIED IDEOGRAPH + 0xA05E: 0x71F8, //CJK UNIFIED IDEOGRAPH + 0xA05F: 0x71FA, //CJK UNIFIED IDEOGRAPH + 0xA060: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xA061: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xA062: 0x71FD, //CJK UNIFIED IDEOGRAPH + 0xA063: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xA064: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xA065: 0x7200, //CJK UNIFIED IDEOGRAPH + 0xA066: 0x7201, //CJK UNIFIED IDEOGRAPH + 0xA067: 0x7202, //CJK UNIFIED IDEOGRAPH + 0xA068: 0x7203, //CJK UNIFIED IDEOGRAPH + 0xA069: 0x7204, //CJK UNIFIED IDEOGRAPH + 0xA06A: 0x7205, //CJK UNIFIED IDEOGRAPH + 0xA06B: 0x7207, //CJK UNIFIED IDEOGRAPH + 0xA06C: 0x7208, //CJK UNIFIED IDEOGRAPH + 0xA06D: 0x7209, //CJK UNIFIED IDEOGRAPH + 0xA06E: 0x720A, //CJK UNIFIED IDEOGRAPH + 0xA06F: 0x720B, //CJK UNIFIED IDEOGRAPH + 0xA070: 0x720C, //CJK UNIFIED IDEOGRAPH + 0xA071: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xA072: 0x720E, //CJK UNIFIED IDEOGRAPH + 0xA073: 0x720F, //CJK UNIFIED IDEOGRAPH + 0xA074: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xA075: 0x7211, //CJK UNIFIED IDEOGRAPH + 0xA076: 0x7212, //CJK UNIFIED IDEOGRAPH + 0xA077: 0x7213, //CJK UNIFIED IDEOGRAPH + 0xA078: 0x7214, //CJK UNIFIED IDEOGRAPH + 0xA079: 0x7215, //CJK UNIFIED IDEOGRAPH + 0xA07A: 0x7216, //CJK UNIFIED IDEOGRAPH + 0xA07B: 0x7217, //CJK UNIFIED IDEOGRAPH + 0xA07C: 0x7218, //CJK UNIFIED IDEOGRAPH + 0xA07D: 0x7219, //CJK UNIFIED IDEOGRAPH + 0xA07E: 0x721A, //CJK UNIFIED IDEOGRAPH + 0xA080: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xA081: 0x721C, //CJK UNIFIED IDEOGRAPH + 0xA082: 0x721E, //CJK UNIFIED IDEOGRAPH + 0xA083: 0x721F, //CJK UNIFIED IDEOGRAPH + 0xA084: 0x7220, //CJK UNIFIED IDEOGRAPH + 0xA085: 0x7221, //CJK UNIFIED IDEOGRAPH + 0xA086: 0x7222, //CJK UNIFIED IDEOGRAPH + 0xA087: 0x7223, //CJK UNIFIED IDEOGRAPH + 0xA088: 0x7224, //CJK UNIFIED IDEOGRAPH + 0xA089: 0x7225, //CJK UNIFIED IDEOGRAPH + 0xA08A: 0x7226, //CJK UNIFIED IDEOGRAPH + 0xA08B: 0x7227, //CJK UNIFIED IDEOGRAPH + 0xA08C: 0x7229, //CJK UNIFIED IDEOGRAPH + 0xA08D: 0x722B, //CJK UNIFIED IDEOGRAPH + 0xA08E: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xA08F: 0x722E, //CJK UNIFIED IDEOGRAPH + 0xA090: 0x722F, //CJK UNIFIED IDEOGRAPH + 0xA091: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xA092: 0x7233, //CJK UNIFIED IDEOGRAPH + 0xA093: 0x7234, //CJK UNIFIED IDEOGRAPH + 0xA094: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xA095: 0x723C, //CJK UNIFIED IDEOGRAPH + 0xA096: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xA097: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xA098: 0x7241, //CJK UNIFIED IDEOGRAPH + 0xA099: 0x7242, //CJK UNIFIED IDEOGRAPH + 0xA09A: 0x7243, //CJK UNIFIED IDEOGRAPH + 0xA09B: 0x7244, //CJK UNIFIED IDEOGRAPH + 0xA09C: 0x7245, //CJK UNIFIED IDEOGRAPH + 0xA09D: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xA09E: 0x7249, //CJK UNIFIED IDEOGRAPH + 0xA09F: 0x724A, //CJK UNIFIED IDEOGRAPH + 0xA0A0: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xA0A1: 0x724E, //CJK UNIFIED IDEOGRAPH + 0xA0A2: 0x724F, //CJK UNIFIED IDEOGRAPH + 0xA0A3: 0x7250, //CJK UNIFIED IDEOGRAPH + 0xA0A4: 0x7251, //CJK UNIFIED IDEOGRAPH + 0xA0A5: 0x7253, //CJK UNIFIED IDEOGRAPH + 0xA0A6: 0x7254, //CJK UNIFIED IDEOGRAPH + 0xA0A7: 0x7255, //CJK UNIFIED IDEOGRAPH + 0xA0A8: 0x7257, //CJK UNIFIED IDEOGRAPH + 0xA0A9: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xA0AA: 0x725A, //CJK UNIFIED IDEOGRAPH + 0xA0AB: 0x725C, //CJK UNIFIED IDEOGRAPH + 0xA0AC: 0x725E, //CJK UNIFIED IDEOGRAPH + 0xA0AD: 0x7260, //CJK UNIFIED IDEOGRAPH + 0xA0AE: 0x7263, //CJK UNIFIED IDEOGRAPH + 0xA0AF: 0x7264, //CJK UNIFIED IDEOGRAPH + 0xA0B0: 0x7265, //CJK UNIFIED IDEOGRAPH + 0xA0B1: 0x7268, //CJK UNIFIED IDEOGRAPH + 0xA0B2: 0x726A, //CJK UNIFIED IDEOGRAPH + 0xA0B3: 0x726B, //CJK UNIFIED IDEOGRAPH + 0xA0B4: 0x726C, //CJK UNIFIED IDEOGRAPH + 0xA0B5: 0x726D, //CJK UNIFIED IDEOGRAPH + 0xA0B6: 0x7270, //CJK UNIFIED IDEOGRAPH + 0xA0B7: 0x7271, //CJK UNIFIED IDEOGRAPH + 0xA0B8: 0x7273, //CJK UNIFIED IDEOGRAPH + 0xA0B9: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xA0BA: 0x7276, //CJK UNIFIED IDEOGRAPH + 0xA0BB: 0x7277, //CJK UNIFIED IDEOGRAPH + 0xA0BC: 0x7278, //CJK UNIFIED IDEOGRAPH + 0xA0BD: 0x727B, //CJK UNIFIED IDEOGRAPH + 0xA0BE: 0x727C, //CJK UNIFIED IDEOGRAPH + 0xA0BF: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xA0C0: 0x7282, //CJK UNIFIED IDEOGRAPH + 0xA0C1: 0x7283, //CJK UNIFIED IDEOGRAPH + 0xA0C2: 0x7285, //CJK UNIFIED IDEOGRAPH + 0xA0C3: 0x7286, //CJK UNIFIED IDEOGRAPH + 0xA0C4: 0x7287, //CJK UNIFIED IDEOGRAPH + 0xA0C5: 0x7288, //CJK UNIFIED IDEOGRAPH + 0xA0C6: 0x7289, //CJK UNIFIED IDEOGRAPH + 0xA0C7: 0x728C, //CJK UNIFIED IDEOGRAPH + 0xA0C8: 0x728E, //CJK UNIFIED IDEOGRAPH + 0xA0C9: 0x7290, //CJK UNIFIED IDEOGRAPH + 0xA0CA: 0x7291, //CJK UNIFIED IDEOGRAPH + 0xA0CB: 0x7293, //CJK UNIFIED IDEOGRAPH + 0xA0CC: 0x7294, //CJK UNIFIED IDEOGRAPH + 0xA0CD: 0x7295, //CJK UNIFIED IDEOGRAPH + 0xA0CE: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xA0CF: 0x7297, //CJK UNIFIED IDEOGRAPH + 0xA0D0: 0x7298, //CJK UNIFIED IDEOGRAPH + 0xA0D1: 0x7299, //CJK UNIFIED IDEOGRAPH + 0xA0D2: 0x729A, //CJK UNIFIED IDEOGRAPH + 0xA0D3: 0x729B, //CJK UNIFIED IDEOGRAPH + 0xA0D4: 0x729C, //CJK UNIFIED IDEOGRAPH + 0xA0D5: 0x729D, //CJK UNIFIED IDEOGRAPH + 0xA0D6: 0x729E, //CJK UNIFIED IDEOGRAPH + 0xA0D7: 0x72A0, //CJK UNIFIED IDEOGRAPH + 0xA0D8: 0x72A1, //CJK UNIFIED IDEOGRAPH + 0xA0D9: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xA0DA: 0x72A3, //CJK UNIFIED IDEOGRAPH + 0xA0DB: 0x72A4, //CJK UNIFIED IDEOGRAPH + 0xA0DC: 0x72A5, //CJK UNIFIED IDEOGRAPH + 0xA0DD: 0x72A6, //CJK UNIFIED IDEOGRAPH + 0xA0DE: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xA0DF: 0x72A8, //CJK UNIFIED IDEOGRAPH + 0xA0E0: 0x72A9, //CJK UNIFIED IDEOGRAPH + 0xA0E1: 0x72AA, //CJK UNIFIED IDEOGRAPH + 0xA0E2: 0x72AB, //CJK UNIFIED IDEOGRAPH + 0xA0E3: 0x72AE, //CJK UNIFIED IDEOGRAPH + 0xA0E4: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xA0E5: 0x72B2, //CJK UNIFIED IDEOGRAPH + 0xA0E6: 0x72B3, //CJK UNIFIED IDEOGRAPH + 0xA0E7: 0x72B5, //CJK UNIFIED IDEOGRAPH + 0xA0E8: 0x72BA, //CJK UNIFIED IDEOGRAPH + 0xA0E9: 0x72BB, //CJK UNIFIED IDEOGRAPH + 0xA0EA: 0x72BC, //CJK UNIFIED IDEOGRAPH + 0xA0EB: 0x72BD, //CJK UNIFIED IDEOGRAPH + 0xA0EC: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xA0ED: 0x72BF, //CJK UNIFIED IDEOGRAPH + 0xA0EE: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xA0EF: 0x72C5, //CJK UNIFIED IDEOGRAPH + 0xA0F0: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xA0F1: 0x72C7, //CJK UNIFIED IDEOGRAPH + 0xA0F2: 0x72C9, //CJK UNIFIED IDEOGRAPH + 0xA0F3: 0x72CA, //CJK UNIFIED IDEOGRAPH + 0xA0F4: 0x72CB, //CJK UNIFIED IDEOGRAPH + 0xA0F5: 0x72CC, //CJK UNIFIED IDEOGRAPH + 0xA0F6: 0x72CF, //CJK UNIFIED IDEOGRAPH + 0xA0F7: 0x72D1, //CJK UNIFIED IDEOGRAPH + 0xA0F8: 0x72D3, //CJK UNIFIED IDEOGRAPH + 0xA0F9: 0x72D4, //CJK UNIFIED IDEOGRAPH + 0xA0FA: 0x72D5, //CJK UNIFIED IDEOGRAPH + 0xA0FB: 0x72D6, //CJK UNIFIED IDEOGRAPH + 0xA0FC: 0x72D8, //CJK UNIFIED IDEOGRAPH + 0xA0FD: 0x72DA, //CJK UNIFIED IDEOGRAPH + 0xA0FE: 0x72DB, //CJK UNIFIED IDEOGRAPH + 0xA1A1: 0x3000, //IDEOGRAPHIC SPACE + 0xA1A2: 0x3001, //IDEOGRAPHIC COMMA + 0xA1A3: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA1A4: 0x00B7, //MIDDLE DOT + 0xA1A5: 0x02C9, //MODIFIER LETTER MACRON + 0xA1A6: 0x02C7, //CARON + 0xA1A7: 0x00A8, //DIAERESIS + 0xA1A8: 0x3003, //DITTO MARK + 0xA1A9: 0x3005, //IDEOGRAPHIC ITERATION MARK + 0xA1AA: 0x2014, //EM DASH + 0xA1AB: 0xFF5E, //FULLWIDTH TILDE + 0xA1AC: 0x2016, //DOUBLE VERTICAL LINE + 0xA1AD: 0x2026, //HORIZONTAL ELLIPSIS + 0xA1AE: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1AF: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1B0: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1B1: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1B2: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA1B3: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA1B4: 0x3008, //LEFT ANGLE BRACKET + 0xA1B5: 0x3009, //RIGHT ANGLE BRACKET + 0xA1B6: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA1B7: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA1B8: 0x300C, //LEFT CORNER BRACKET + 0xA1B9: 0x300D, //RIGHT CORNER BRACKET + 0xA1BA: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA1BB: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA1BC: 0x3016, //LEFT WHITE LENTICULAR BRACKET + 0xA1BD: 0x3017, //RIGHT WHITE LENTICULAR BRACKET + 0xA1BE: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA1BF: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA1C0: 0x00B1, //PLUS-MINUS SIGN + 0xA1C1: 0x00D7, //MULTIPLICATION SIGN + 0xA1C2: 0x00F7, //DIVISION SIGN + 0xA1C3: 0x2236, //RATIO + 0xA1C4: 0x2227, //LOGICAL AND + 0xA1C5: 0x2228, //LOGICAL OR + 0xA1C6: 0x2211, //N-ARY SUMMATION + 0xA1C7: 0x220F, //N-ARY PRODUCT + 0xA1C8: 0x222A, //UNION + 0xA1C9: 0x2229, //INTERSECTION + 0xA1CA: 0x2208, //ELEMENT OF + 0xA1CB: 0x2237, //PROPORTION + 0xA1CC: 0x221A, //SQUARE ROOT + 0xA1CD: 0x22A5, //UP TACK + 0xA1CE: 0x2225, //PARALLEL TO + 0xA1CF: 0x2220, //ANGLE + 0xA1D0: 0x2312, //ARC + 0xA1D1: 0x2299, //CIRCLED DOT OPERATOR + 0xA1D2: 0x222B, //INTEGRAL + 0xA1D3: 0x222E, //CONTOUR INTEGRAL + 0xA1D4: 0x2261, //IDENTICAL TO + 0xA1D5: 0x224C, //ALL EQUAL TO + 0xA1D6: 0x2248, //ALMOST EQUAL TO + 0xA1D7: 0x223D, //REVERSED TILDE + 0xA1D8: 0x221D, //PROPORTIONAL TO + 0xA1D9: 0x2260, //NOT EQUAL TO + 0xA1DA: 0x226E, //NOT LESS-THAN + 0xA1DB: 0x226F, //NOT GREATER-THAN + 0xA1DC: 0x2264, //LESS-THAN OR EQUAL TO + 0xA1DD: 0x2265, //GREATER-THAN OR EQUAL TO + 0xA1DE: 0x221E, //INFINITY + 0xA1DF: 0x2235, //BECAUSE + 0xA1E0: 0x2234, //THEREFORE + 0xA1E1: 0x2642, //MALE SIGN + 0xA1E2: 0x2640, //FEMALE SIGN + 0xA1E3: 0x00B0, //DEGREE SIGN + 0xA1E4: 0x2032, //PRIME + 0xA1E5: 0x2033, //DOUBLE PRIME + 0xA1E6: 0x2103, //DEGREE CELSIUS + 0xA1E7: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA1E8: 0x00A4, //CURRENCY SIGN + 0xA1E9: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA1EA: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA1EB: 0x2030, //PER MILLE SIGN + 0xA1EC: 0x00A7, //SECTION SIGN + 0xA1ED: 0x2116, //NUMERO SIGN + 0xA1EE: 0x2606, //WHITE STAR + 0xA1EF: 0x2605, //BLACK STAR + 0xA1F0: 0x25CB, //WHITE CIRCLE + 0xA1F1: 0x25CF, //BLACK CIRCLE + 0xA1F2: 0x25CE, //BULLSEYE + 0xA1F3: 0x25C7, //WHITE DIAMOND + 0xA1F4: 0x25C6, //BLACK DIAMOND + 0xA1F5: 0x25A1, //WHITE SQUARE + 0xA1F6: 0x25A0, //BLACK SQUARE + 0xA1F7: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1F8: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1F9: 0x203B, //REFERENCE MARK + 0xA1FA: 0x2192, //RIGHTWARDS ARROW + 0xA1FB: 0x2190, //LEFTWARDS ARROW + 0xA1FC: 0x2191, //UPWARDS ARROW + 0xA1FD: 0x2193, //DOWNWARDS ARROW + 0xA1FE: 0x3013, //GETA MARK + 0xA2A1: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xA2A2: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xA2A3: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xA2A4: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xA2A5: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xA2A6: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xA2A7: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xA2A8: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xA2A9: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xA2AA: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xA2B1: 0x2488, //DIGIT ONE FULL STOP + 0xA2B2: 0x2489, //DIGIT TWO FULL STOP + 0xA2B3: 0x248A, //DIGIT THREE FULL STOP + 0xA2B4: 0x248B, //DIGIT FOUR FULL STOP + 0xA2B5: 0x248C, //DIGIT FIVE FULL STOP + 0xA2B6: 0x248D, //DIGIT SIX FULL STOP + 0xA2B7: 0x248E, //DIGIT SEVEN FULL STOP + 0xA2B8: 0x248F, //DIGIT EIGHT FULL STOP + 0xA2B9: 0x2490, //DIGIT NINE FULL STOP + 0xA2BA: 0x2491, //NUMBER TEN FULL STOP + 0xA2BB: 0x2492, //NUMBER ELEVEN FULL STOP + 0xA2BC: 0x2493, //NUMBER TWELVE FULL STOP + 0xA2BD: 0x2494, //NUMBER THIRTEEN FULL STOP + 0xA2BE: 0x2495, //NUMBER FOURTEEN FULL STOP + 0xA2BF: 0x2496, //NUMBER FIFTEEN FULL STOP + 0xA2C0: 0x2497, //NUMBER SIXTEEN FULL STOP + 0xA2C1: 0x2498, //NUMBER SEVENTEEN FULL STOP + 0xA2C2: 0x2499, //NUMBER EIGHTEEN FULL STOP + 0xA2C3: 0x249A, //NUMBER NINETEEN FULL STOP + 0xA2C4: 0x249B, //NUMBER TWENTY FULL STOP + 0xA2C5: 0x2474, //PARENTHESIZED DIGIT ONE + 0xA2C6: 0x2475, //PARENTHESIZED DIGIT TWO + 0xA2C7: 0x2476, //PARENTHESIZED DIGIT THREE + 0xA2C8: 0x2477, //PARENTHESIZED DIGIT FOUR + 0xA2C9: 0x2478, //PARENTHESIZED DIGIT FIVE + 0xA2CA: 0x2479, //PARENTHESIZED DIGIT SIX + 0xA2CB: 0x247A, //PARENTHESIZED DIGIT SEVEN + 0xA2CC: 0x247B, //PARENTHESIZED DIGIT EIGHT + 0xA2CD: 0x247C, //PARENTHESIZED DIGIT NINE + 0xA2CE: 0x247D, //PARENTHESIZED NUMBER TEN + 0xA2CF: 0x247E, //PARENTHESIZED NUMBER ELEVEN + 0xA2D0: 0x247F, //PARENTHESIZED NUMBER TWELVE + 0xA2D1: 0x2480, //PARENTHESIZED NUMBER THIRTEEN + 0xA2D2: 0x2481, //PARENTHESIZED NUMBER FOURTEEN + 0xA2D3: 0x2482, //PARENTHESIZED NUMBER FIFTEEN + 0xA2D4: 0x2483, //PARENTHESIZED NUMBER SIXTEEN + 0xA2D5: 0x2484, //PARENTHESIZED NUMBER SEVENTEEN + 0xA2D6: 0x2485, //PARENTHESIZED NUMBER EIGHTEEN + 0xA2D7: 0x2486, //PARENTHESIZED NUMBER NINETEEN + 0xA2D8: 0x2487, //PARENTHESIZED NUMBER TWENTY + 0xA2D9: 0x2460, //CIRCLED DIGIT ONE + 0xA2DA: 0x2461, //CIRCLED DIGIT TWO + 0xA2DB: 0x2462, //CIRCLED DIGIT THREE + 0xA2DC: 0x2463, //CIRCLED DIGIT FOUR + 0xA2DD: 0x2464, //CIRCLED DIGIT FIVE + 0xA2DE: 0x2465, //CIRCLED DIGIT SIX + 0xA2DF: 0x2466, //CIRCLED DIGIT SEVEN + 0xA2E0: 0x2467, //CIRCLED DIGIT EIGHT + 0xA2E1: 0x2468, //CIRCLED DIGIT NINE + 0xA2E2: 0x2469, //CIRCLED NUMBER TEN + 0xA2E5: 0x3220, //PARENTHESIZED IDEOGRAPH ONE + 0xA2E6: 0x3221, //PARENTHESIZED IDEOGRAPH TWO + 0xA2E7: 0x3222, //PARENTHESIZED IDEOGRAPH THREE + 0xA2E8: 0x3223, //PARENTHESIZED IDEOGRAPH FOUR + 0xA2E9: 0x3224, //PARENTHESIZED IDEOGRAPH FIVE + 0xA2EA: 0x3225, //PARENTHESIZED IDEOGRAPH SIX + 0xA2EB: 0x3226, //PARENTHESIZED IDEOGRAPH SEVEN + 0xA2EC: 0x3227, //PARENTHESIZED IDEOGRAPH EIGHT + 0xA2ED: 0x3228, //PARENTHESIZED IDEOGRAPH NINE + 0xA2EE: 0x3229, //PARENTHESIZED IDEOGRAPH TEN + 0xA2F1: 0x2160, //ROMAN NUMERAL ONE + 0xA2F2: 0x2161, //ROMAN NUMERAL TWO + 0xA2F3: 0x2162, //ROMAN NUMERAL THREE + 0xA2F4: 0x2163, //ROMAN NUMERAL FOUR + 0xA2F5: 0x2164, //ROMAN NUMERAL FIVE + 0xA2F6: 0x2165, //ROMAN NUMERAL SIX + 0xA2F7: 0x2166, //ROMAN NUMERAL SEVEN + 0xA2F8: 0x2167, //ROMAN NUMERAL EIGHT + 0xA2F9: 0x2168, //ROMAN NUMERAL NINE + 0xA2FA: 0x2169, //ROMAN NUMERAL TEN + 0xA2FB: 0x216A, //ROMAN NUMERAL ELEVEN + 0xA2FC: 0x216B, //ROMAN NUMERAL TWELVE + 0xA3A1: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA3A2: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xA3A3: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA3A4: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA3A5: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA3A6: 0xFF06, //FULLWIDTH AMPERSAND + 0xA3A7: 0xFF07, //FULLWIDTH APOSTROPHE + 0xA3A8: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA3A9: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA3AA: 0xFF0A, //FULLWIDTH ASTERISK + 0xA3AB: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA3AC: 0xFF0C, //FULLWIDTH COMMA + 0xA3AD: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA3AE: 0xFF0E, //FULLWIDTH FULL STOP + 0xA3AF: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA3B0: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA3B1: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA3B2: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA3B3: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA3B4: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA3B5: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA3B6: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA3B7: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA3B8: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA3B9: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA3BA: 0xFF1A, //FULLWIDTH COLON + 0xA3BB: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA3BC: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA3BD: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA3BE: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA3BF: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA3C0: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA3C1: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA3C2: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA3C3: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA3C4: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA3C5: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA3C6: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA3C7: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA3C8: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA3C9: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA3CA: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA3CB: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA3CC: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA3CD: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA3CE: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA3CF: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA3D0: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA3D1: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA3D2: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA3D3: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA3D4: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA3D5: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA3D6: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA3D7: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA3D8: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA3D9: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA3DA: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA3DB: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0xA3DC: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA3DD: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0xA3DE: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0xA3DF: 0xFF3F, //FULLWIDTH LOW LINE + 0xA3E0: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0xA3E1: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA3E2: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA3E3: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA3E4: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA3E5: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA3E6: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA3E7: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA3E8: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA3E9: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA3EA: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA3EB: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA3EC: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA3ED: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA3EE: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA3EF: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA3F0: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA3F1: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA3F2: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA3F3: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA3F4: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA3F5: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA3F6: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA3F7: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA3F8: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA3F9: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA3FA: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA3FB: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA3FC: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA3FD: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA3FE: 0xFFE3, //FULLWIDTH MACRON + 0xA4A1: 0x3041, //HIRAGANA LETTER SMALL A + 0xA4A2: 0x3042, //HIRAGANA LETTER A + 0xA4A3: 0x3043, //HIRAGANA LETTER SMALL I + 0xA4A4: 0x3044, //HIRAGANA LETTER I + 0xA4A5: 0x3045, //HIRAGANA LETTER SMALL U + 0xA4A6: 0x3046, //HIRAGANA LETTER U + 0xA4A7: 0x3047, //HIRAGANA LETTER SMALL E + 0xA4A8: 0x3048, //HIRAGANA LETTER E + 0xA4A9: 0x3049, //HIRAGANA LETTER SMALL O + 0xA4AA: 0x304A, //HIRAGANA LETTER O + 0xA4AB: 0x304B, //HIRAGANA LETTER KA + 0xA4AC: 0x304C, //HIRAGANA LETTER GA + 0xA4AD: 0x304D, //HIRAGANA LETTER KI + 0xA4AE: 0x304E, //HIRAGANA LETTER GI + 0xA4AF: 0x304F, //HIRAGANA LETTER KU + 0xA4B0: 0x3050, //HIRAGANA LETTER GU + 0xA4B1: 0x3051, //HIRAGANA LETTER KE + 0xA4B2: 0x3052, //HIRAGANA LETTER GE + 0xA4B3: 0x3053, //HIRAGANA LETTER KO + 0xA4B4: 0x3054, //HIRAGANA LETTER GO + 0xA4B5: 0x3055, //HIRAGANA LETTER SA + 0xA4B6: 0x3056, //HIRAGANA LETTER ZA + 0xA4B7: 0x3057, //HIRAGANA LETTER SI + 0xA4B8: 0x3058, //HIRAGANA LETTER ZI + 0xA4B9: 0x3059, //HIRAGANA LETTER SU + 0xA4BA: 0x305A, //HIRAGANA LETTER ZU + 0xA4BB: 0x305B, //HIRAGANA LETTER SE + 0xA4BC: 0x305C, //HIRAGANA LETTER ZE + 0xA4BD: 0x305D, //HIRAGANA LETTER SO + 0xA4BE: 0x305E, //HIRAGANA LETTER ZO + 0xA4BF: 0x305F, //HIRAGANA LETTER TA + 0xA4C0: 0x3060, //HIRAGANA LETTER DA + 0xA4C1: 0x3061, //HIRAGANA LETTER TI + 0xA4C2: 0x3062, //HIRAGANA LETTER DI + 0xA4C3: 0x3063, //HIRAGANA LETTER SMALL TU + 0xA4C4: 0x3064, //HIRAGANA LETTER TU + 0xA4C5: 0x3065, //HIRAGANA LETTER DU + 0xA4C6: 0x3066, //HIRAGANA LETTER TE + 0xA4C7: 0x3067, //HIRAGANA LETTER DE + 0xA4C8: 0x3068, //HIRAGANA LETTER TO + 0xA4C9: 0x3069, //HIRAGANA LETTER DO + 0xA4CA: 0x306A, //HIRAGANA LETTER NA + 0xA4CB: 0x306B, //HIRAGANA LETTER NI + 0xA4CC: 0x306C, //HIRAGANA LETTER NU + 0xA4CD: 0x306D, //HIRAGANA LETTER NE + 0xA4CE: 0x306E, //HIRAGANA LETTER NO + 0xA4CF: 0x306F, //HIRAGANA LETTER HA + 0xA4D0: 0x3070, //HIRAGANA LETTER BA + 0xA4D1: 0x3071, //HIRAGANA LETTER PA + 0xA4D2: 0x3072, //HIRAGANA LETTER HI + 0xA4D3: 0x3073, //HIRAGANA LETTER BI + 0xA4D4: 0x3074, //HIRAGANA LETTER PI + 0xA4D5: 0x3075, //HIRAGANA LETTER HU + 0xA4D6: 0x3076, //HIRAGANA LETTER BU + 0xA4D7: 0x3077, //HIRAGANA LETTER PU + 0xA4D8: 0x3078, //HIRAGANA LETTER HE + 0xA4D9: 0x3079, //HIRAGANA LETTER BE + 0xA4DA: 0x307A, //HIRAGANA LETTER PE + 0xA4DB: 0x307B, //HIRAGANA LETTER HO + 0xA4DC: 0x307C, //HIRAGANA LETTER BO + 0xA4DD: 0x307D, //HIRAGANA LETTER PO + 0xA4DE: 0x307E, //HIRAGANA LETTER MA + 0xA4DF: 0x307F, //HIRAGANA LETTER MI + 0xA4E0: 0x3080, //HIRAGANA LETTER MU + 0xA4E1: 0x3081, //HIRAGANA LETTER ME + 0xA4E2: 0x3082, //HIRAGANA LETTER MO + 0xA4E3: 0x3083, //HIRAGANA LETTER SMALL YA + 0xA4E4: 0x3084, //HIRAGANA LETTER YA + 0xA4E5: 0x3085, //HIRAGANA LETTER SMALL YU + 0xA4E6: 0x3086, //HIRAGANA LETTER YU + 0xA4E7: 0x3087, //HIRAGANA LETTER SMALL YO + 0xA4E8: 0x3088, //HIRAGANA LETTER YO + 0xA4E9: 0x3089, //HIRAGANA LETTER RA + 0xA4EA: 0x308A, //HIRAGANA LETTER RI + 0xA4EB: 0x308B, //HIRAGANA LETTER RU + 0xA4EC: 0x308C, //HIRAGANA LETTER RE + 0xA4ED: 0x308D, //HIRAGANA LETTER RO + 0xA4EE: 0x308E, //HIRAGANA LETTER SMALL WA + 0xA4EF: 0x308F, //HIRAGANA LETTER WA + 0xA4F0: 0x3090, //HIRAGANA LETTER WI + 0xA4F1: 0x3091, //HIRAGANA LETTER WE + 0xA4F2: 0x3092, //HIRAGANA LETTER WO + 0xA4F3: 0x3093, //HIRAGANA LETTER N + 0xA5A1: 0x30A1, //KATAKANA LETTER SMALL A + 0xA5A2: 0x30A2, //KATAKANA LETTER A + 0xA5A3: 0x30A3, //KATAKANA LETTER SMALL I + 0xA5A4: 0x30A4, //KATAKANA LETTER I + 0xA5A5: 0x30A5, //KATAKANA LETTER SMALL U + 0xA5A6: 0x30A6, //KATAKANA LETTER U + 0xA5A7: 0x30A7, //KATAKANA LETTER SMALL E + 0xA5A8: 0x30A8, //KATAKANA LETTER E + 0xA5A9: 0x30A9, //KATAKANA LETTER SMALL O + 0xA5AA: 0x30AA, //KATAKANA LETTER O + 0xA5AB: 0x30AB, //KATAKANA LETTER KA + 0xA5AC: 0x30AC, //KATAKANA LETTER GA + 0xA5AD: 0x30AD, //KATAKANA LETTER KI + 0xA5AE: 0x30AE, //KATAKANA LETTER GI + 0xA5AF: 0x30AF, //KATAKANA LETTER KU + 0xA5B0: 0x30B0, //KATAKANA LETTER GU + 0xA5B1: 0x30B1, //KATAKANA LETTER KE + 0xA5B2: 0x30B2, //KATAKANA LETTER GE + 0xA5B3: 0x30B3, //KATAKANA LETTER KO + 0xA5B4: 0x30B4, //KATAKANA LETTER GO + 0xA5B5: 0x30B5, //KATAKANA LETTER SA + 0xA5B6: 0x30B6, //KATAKANA LETTER ZA + 0xA5B7: 0x30B7, //KATAKANA LETTER SI + 0xA5B8: 0x30B8, //KATAKANA LETTER ZI + 0xA5B9: 0x30B9, //KATAKANA LETTER SU + 0xA5BA: 0x30BA, //KATAKANA LETTER ZU + 0xA5BB: 0x30BB, //KATAKANA LETTER SE + 0xA5BC: 0x30BC, //KATAKANA LETTER ZE + 0xA5BD: 0x30BD, //KATAKANA LETTER SO + 0xA5BE: 0x30BE, //KATAKANA LETTER ZO + 0xA5BF: 0x30BF, //KATAKANA LETTER TA + 0xA5C0: 0x30C0, //KATAKANA LETTER DA + 0xA5C1: 0x30C1, //KATAKANA LETTER TI + 0xA5C2: 0x30C2, //KATAKANA LETTER DI + 0xA5C3: 0x30C3, //KATAKANA LETTER SMALL TU + 0xA5C4: 0x30C4, //KATAKANA LETTER TU + 0xA5C5: 0x30C5, //KATAKANA LETTER DU + 0xA5C6: 0x30C6, //KATAKANA LETTER TE + 0xA5C7: 0x30C7, //KATAKANA LETTER DE + 0xA5C8: 0x30C8, //KATAKANA LETTER TO + 0xA5C9: 0x30C9, //KATAKANA LETTER DO + 0xA5CA: 0x30CA, //KATAKANA LETTER NA + 0xA5CB: 0x30CB, //KATAKANA LETTER NI + 0xA5CC: 0x30CC, //KATAKANA LETTER NU + 0xA5CD: 0x30CD, //KATAKANA LETTER NE + 0xA5CE: 0x30CE, //KATAKANA LETTER NO + 0xA5CF: 0x30CF, //KATAKANA LETTER HA + 0xA5D0: 0x30D0, //KATAKANA LETTER BA + 0xA5D1: 0x30D1, //KATAKANA LETTER PA + 0xA5D2: 0x30D2, //KATAKANA LETTER HI + 0xA5D3: 0x30D3, //KATAKANA LETTER BI + 0xA5D4: 0x30D4, //KATAKANA LETTER PI + 0xA5D5: 0x30D5, //KATAKANA LETTER HU + 0xA5D6: 0x30D6, //KATAKANA LETTER BU + 0xA5D7: 0x30D7, //KATAKANA LETTER PU + 0xA5D8: 0x30D8, //KATAKANA LETTER HE + 0xA5D9: 0x30D9, //KATAKANA LETTER BE + 0xA5DA: 0x30DA, //KATAKANA LETTER PE + 0xA5DB: 0x30DB, //KATAKANA LETTER HO + 0xA5DC: 0x30DC, //KATAKANA LETTER BO + 0xA5DD: 0x30DD, //KATAKANA LETTER PO + 0xA5DE: 0x30DE, //KATAKANA LETTER MA + 0xA5DF: 0x30DF, //KATAKANA LETTER MI + 0xA5E0: 0x30E0, //KATAKANA LETTER MU + 0xA5E1: 0x30E1, //KATAKANA LETTER ME + 0xA5E2: 0x30E2, //KATAKANA LETTER MO + 0xA5E3: 0x30E3, //KATAKANA LETTER SMALL YA + 0xA5E4: 0x30E4, //KATAKANA LETTER YA + 0xA5E5: 0x30E5, //KATAKANA LETTER SMALL YU + 0xA5E6: 0x30E6, //KATAKANA LETTER YU + 0xA5E7: 0x30E7, //KATAKANA LETTER SMALL YO + 0xA5E8: 0x30E8, //KATAKANA LETTER YO + 0xA5E9: 0x30E9, //KATAKANA LETTER RA + 0xA5EA: 0x30EA, //KATAKANA LETTER RI + 0xA5EB: 0x30EB, //KATAKANA LETTER RU + 0xA5EC: 0x30EC, //KATAKANA LETTER RE + 0xA5ED: 0x30ED, //KATAKANA LETTER RO + 0xA5EE: 0x30EE, //KATAKANA LETTER SMALL WA + 0xA5EF: 0x30EF, //KATAKANA LETTER WA + 0xA5F0: 0x30F0, //KATAKANA LETTER WI + 0xA5F1: 0x30F1, //KATAKANA LETTER WE + 0xA5F2: 0x30F2, //KATAKANA LETTER WO + 0xA5F3: 0x30F3, //KATAKANA LETTER N + 0xA5F4: 0x30F4, //KATAKANA LETTER VU + 0xA5F5: 0x30F5, //KATAKANA LETTER SMALL KA + 0xA5F6: 0x30F6, //KATAKANA LETTER SMALL KE + 0xA6A1: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA6A2: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA6A3: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA6A4: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA6A5: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA6A6: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA6A7: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA6A8: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA6A9: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA6AA: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA6AB: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA6AC: 0x039C, //GREEK CAPITAL LETTER MU + 0xA6AD: 0x039D, //GREEK CAPITAL LETTER NU + 0xA6AE: 0x039E, //GREEK CAPITAL LETTER XI + 0xA6AF: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA6B0: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA6B1: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA6B2: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA6B3: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA6B4: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA6B5: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA6B6: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA6B7: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA6B8: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA6C1: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA6C2: 0x03B2, //GREEK SMALL LETTER BETA + 0xA6C3: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA6C4: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA6C5: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA6C6: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA6C7: 0x03B7, //GREEK SMALL LETTER ETA + 0xA6C8: 0x03B8, //GREEK SMALL LETTER THETA + 0xA6C9: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA6CA: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA6CB: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA6CC: 0x03BC, //GREEK SMALL LETTER MU + 0xA6CD: 0x03BD, //GREEK SMALL LETTER NU + 0xA6CE: 0x03BE, //GREEK SMALL LETTER XI + 0xA6CF: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA6D0: 0x03C0, //GREEK SMALL LETTER PI + 0xA6D1: 0x03C1, //GREEK SMALL LETTER RHO + 0xA6D2: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA6D3: 0x03C4, //GREEK SMALL LETTER TAU + 0xA6D4: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA6D5: 0x03C6, //GREEK SMALL LETTER PHI + 0xA6D6: 0x03C7, //GREEK SMALL LETTER CHI + 0xA6D7: 0x03C8, //GREEK SMALL LETTER PSI + 0xA6D8: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA6E0: 0xFE35, //PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS + 0xA6E1: 0xFE36, //PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS + 0xA6E2: 0xFE39, //PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET + 0xA6E3: 0xFE3A, //PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET + 0xA6E4: 0xFE3F, //PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET + 0xA6E5: 0xFE40, //PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET + 0xA6E6: 0xFE3D, //PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET + 0xA6E7: 0xFE3E, //PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET + 0xA6E8: 0xFE41, //PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET + 0xA6E9: 0xFE42, //PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET + 0xA6EA: 0xFE43, //PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET + 0xA6EB: 0xFE44, //PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET + 0xA6EE: 0xFE3B, //PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET + 0xA6EF: 0xFE3C, //PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET + 0xA6F0: 0xFE37, //PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET + 0xA6F1: 0xFE38, //PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET + 0xA6F2: 0xFE31, //PRESENTATION FORM FOR VERTICAL EM DASH + 0xA6F4: 0xFE33, //PRESENTATION FORM FOR VERTICAL LOW LINE + 0xA6F5: 0xFE34, //PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + 0xA7A1: 0x0410, //CYRILLIC CAPITAL LETTER A + 0xA7A2: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0xA7A3: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0xA7A4: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0xA7A5: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0xA7A6: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0xA7A7: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0xA7A8: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0xA7A9: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0xA7AA: 0x0418, //CYRILLIC CAPITAL LETTER I + 0xA7AB: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0xA7AC: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0xA7AD: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0xA7AE: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0xA7AF: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0xA7B0: 0x041E, //CYRILLIC CAPITAL LETTER O + 0xA7B1: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0xA7B2: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0xA7B3: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0xA7B4: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0xA7B5: 0x0423, //CYRILLIC CAPITAL LETTER U + 0xA7B6: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0xA7B7: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0xA7B8: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0xA7B9: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0xA7BA: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0xA7BB: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0xA7BC: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0xA7BD: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0xA7BE: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0xA7BF: 0x042D, //CYRILLIC CAPITAL LETTER E + 0xA7C0: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0xA7C1: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0xA7D1: 0x0430, //CYRILLIC SMALL LETTER A + 0xA7D2: 0x0431, //CYRILLIC SMALL LETTER BE + 0xA7D3: 0x0432, //CYRILLIC SMALL LETTER VE + 0xA7D4: 0x0433, //CYRILLIC SMALL LETTER GHE + 0xA7D5: 0x0434, //CYRILLIC SMALL LETTER DE + 0xA7D6: 0x0435, //CYRILLIC SMALL LETTER IE + 0xA7D7: 0x0451, //CYRILLIC SMALL LETTER IO + 0xA7D8: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0xA7D9: 0x0437, //CYRILLIC SMALL LETTER ZE + 0xA7DA: 0x0438, //CYRILLIC SMALL LETTER I + 0xA7DB: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0xA7DC: 0x043A, //CYRILLIC SMALL LETTER KA + 0xA7DD: 0x043B, //CYRILLIC SMALL LETTER EL + 0xA7DE: 0x043C, //CYRILLIC SMALL LETTER EM + 0xA7DF: 0x043D, //CYRILLIC SMALL LETTER EN + 0xA7E0: 0x043E, //CYRILLIC SMALL LETTER O + 0xA7E1: 0x043F, //CYRILLIC SMALL LETTER PE + 0xA7E2: 0x0440, //CYRILLIC SMALL LETTER ER + 0xA7E3: 0x0441, //CYRILLIC SMALL LETTER ES + 0xA7E4: 0x0442, //CYRILLIC SMALL LETTER TE + 0xA7E5: 0x0443, //CYRILLIC SMALL LETTER U + 0xA7E6: 0x0444, //CYRILLIC SMALL LETTER EF + 0xA7E7: 0x0445, //CYRILLIC SMALL LETTER HA + 0xA7E8: 0x0446, //CYRILLIC SMALL LETTER TSE + 0xA7E9: 0x0447, //CYRILLIC SMALL LETTER CHE + 0xA7EA: 0x0448, //CYRILLIC SMALL LETTER SHA + 0xA7EB: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0xA7EC: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0xA7ED: 0x044B, //CYRILLIC SMALL LETTER YERU + 0xA7EE: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0xA7EF: 0x044D, //CYRILLIC SMALL LETTER E + 0xA7F0: 0x044E, //CYRILLIC SMALL LETTER YU + 0xA7F1: 0x044F, //CYRILLIC SMALL LETTER YA + 0xA840: 0x02CA, //MODIFIER LETTER ACUTE ACCENT + 0xA841: 0x02CB, //MODIFIER LETTER GRAVE ACCENT + 0xA842: 0x02D9, //DOT ABOVE + 0xA843: 0x2013, //EN DASH + 0xA844: 0x2015, //HORIZONTAL BAR + 0xA845: 0x2025, //TWO DOT LEADER + 0xA846: 0x2035, //REVERSED PRIME + 0xA847: 0x2105, //CARE OF + 0xA848: 0x2109, //DEGREE FAHRENHEIT + 0xA849: 0x2196, //NORTH WEST ARROW + 0xA84A: 0x2197, //NORTH EAST ARROW + 0xA84B: 0x2198, //SOUTH EAST ARROW + 0xA84C: 0x2199, //SOUTH WEST ARROW + 0xA84D: 0x2215, //DIVISION SLASH + 0xA84E: 0x221F, //RIGHT ANGLE + 0xA84F: 0x2223, //DIVIDES + 0xA850: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA851: 0x2266, //LESS-THAN OVER EQUAL TO + 0xA852: 0x2267, //GREATER-THAN OVER EQUAL TO + 0xA853: 0x22BF, //RIGHT TRIANGLE + 0xA854: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xA855: 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0xA856: 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0xA857: 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0xA858: 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0xA859: 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0xA85A: 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0xA85B: 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0xA85C: 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0xA85D: 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0xA85E: 0x255A, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0xA85F: 0x255B, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0xA860: 0x255C, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0xA861: 0x255D, //BOX DRAWINGS DOUBLE UP AND LEFT + 0xA862: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xA863: 0x255F, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0xA864: 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0xA865: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xA866: 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0xA867: 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0xA868: 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0xA869: 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0xA86A: 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0xA86B: 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0xA86C: 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0xA86D: 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0xA86E: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xA86F: 0x256B, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0xA870: 0x256C, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0xA871: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xA872: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xA873: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xA874: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xA875: 0x2571, //BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + 0xA876: 0x2572, //BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + 0xA877: 0x2573, //BOX DRAWINGS LIGHT DIAGONAL CROSS + 0xA878: 0x2581, //LOWER ONE EIGHTH BLOCK + 0xA879: 0x2582, //LOWER ONE QUARTER BLOCK + 0xA87A: 0x2583, //LOWER THREE EIGHTHS BLOCK + 0xA87B: 0x2584, //LOWER HALF BLOCK + 0xA87C: 0x2585, //LOWER FIVE EIGHTHS BLOCK + 0xA87D: 0x2586, //LOWER THREE QUARTERS BLOCK + 0xA87E: 0x2587, //LOWER SEVEN EIGHTHS BLOCK + 0xA880: 0x2588, //FULL BLOCK + 0xA881: 0x2589, //LEFT SEVEN EIGHTHS BLOCK + 0xA882: 0x258A, //LEFT THREE QUARTERS BLOCK + 0xA883: 0x258B, //LEFT FIVE EIGHTHS BLOCK + 0xA884: 0x258C, //LEFT HALF BLOCK + 0xA885: 0x258D, //LEFT THREE EIGHTHS BLOCK + 0xA886: 0x258E, //LEFT ONE QUARTER BLOCK + 0xA887: 0x258F, //LEFT ONE EIGHTH BLOCK + 0xA888: 0x2593, //DARK SHADE + 0xA889: 0x2594, //UPPER ONE EIGHTH BLOCK + 0xA88A: 0x2595, //RIGHT ONE EIGHTH BLOCK + 0xA88B: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA88C: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA88D: 0x25E2, //BLACK LOWER RIGHT TRIANGLE + 0xA88E: 0x25E3, //BLACK LOWER LEFT TRIANGLE + 0xA88F: 0x25E4, //BLACK UPPER LEFT TRIANGLE + 0xA890: 0x25E5, //BLACK UPPER RIGHT TRIANGLE + 0xA891: 0x2609, //SUN + 0xA892: 0x2295, //CIRCLED PLUS + 0xA893: 0x3012, //POSTAL MARK + 0xA894: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0xA895: 0x301E, //DOUBLE PRIME QUOTATION MARK + 0xA8A1: 0x0101, //LATIN SMALL LETTER A WITH MACRON + 0xA8A2: 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0xA8A3: 0x01CE, //LATIN SMALL LETTER A WITH CARON + 0xA8A4: 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0xA8A5: 0x0113, //LATIN SMALL LETTER E WITH MACRON + 0xA8A6: 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0xA8A7: 0x011B, //LATIN SMALL LETTER E WITH CARON + 0xA8A8: 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0xA8A9: 0x012B, //LATIN SMALL LETTER I WITH MACRON + 0xA8AA: 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0xA8AB: 0x01D0, //LATIN SMALL LETTER I WITH CARON + 0xA8AC: 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0xA8AD: 0x014D, //LATIN SMALL LETTER O WITH MACRON + 0xA8AE: 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0xA8AF: 0x01D2, //LATIN SMALL LETTER O WITH CARON + 0xA8B0: 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0xA8B1: 0x016B, //LATIN SMALL LETTER U WITH MACRON + 0xA8B2: 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0xA8B3: 0x01D4, //LATIN SMALL LETTER U WITH CARON + 0xA8B4: 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0xA8B5: 0x01D6, //LATIN SMALL LETTER U WITH DIAERESIS AND MACRON + 0xA8B6: 0x01D8, //LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE + 0xA8B7: 0x01DA, //LATIN SMALL LETTER U WITH DIAERESIS AND CARON + 0xA8B8: 0x01DC, //LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE + 0xA8B9: 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0xA8BA: 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0xA8BB: 0x0251, //LATIN SMALL LETTER ALPHA + 0xA8BD: 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0xA8BE: 0x0148, //LATIN SMALL LETTER N WITH CARON + 0xA8C0: 0x0261, //LATIN SMALL LETTER SCRIPT G + 0xA8C5: 0x3105, //BOPOMOFO LETTER B + 0xA8C6: 0x3106, //BOPOMOFO LETTER P + 0xA8C7: 0x3107, //BOPOMOFO LETTER M + 0xA8C8: 0x3108, //BOPOMOFO LETTER F + 0xA8C9: 0x3109, //BOPOMOFO LETTER D + 0xA8CA: 0x310A, //BOPOMOFO LETTER T + 0xA8CB: 0x310B, //BOPOMOFO LETTER N + 0xA8CC: 0x310C, //BOPOMOFO LETTER L + 0xA8CD: 0x310D, //BOPOMOFO LETTER G + 0xA8CE: 0x310E, //BOPOMOFO LETTER K + 0xA8CF: 0x310F, //BOPOMOFO LETTER H + 0xA8D0: 0x3110, //BOPOMOFO LETTER J + 0xA8D1: 0x3111, //BOPOMOFO LETTER Q + 0xA8D2: 0x3112, //BOPOMOFO LETTER X + 0xA8D3: 0x3113, //BOPOMOFO LETTER ZH + 0xA8D4: 0x3114, //BOPOMOFO LETTER CH + 0xA8D5: 0x3115, //BOPOMOFO LETTER SH + 0xA8D6: 0x3116, //BOPOMOFO LETTER R + 0xA8D7: 0x3117, //BOPOMOFO LETTER Z + 0xA8D8: 0x3118, //BOPOMOFO LETTER C + 0xA8D9: 0x3119, //BOPOMOFO LETTER S + 0xA8DA: 0x311A, //BOPOMOFO LETTER A + 0xA8DB: 0x311B, //BOPOMOFO LETTER O + 0xA8DC: 0x311C, //BOPOMOFO LETTER E + 0xA8DD: 0x311D, //BOPOMOFO LETTER EH + 0xA8DE: 0x311E, //BOPOMOFO LETTER AI + 0xA8DF: 0x311F, //BOPOMOFO LETTER EI + 0xA8E0: 0x3120, //BOPOMOFO LETTER AU + 0xA8E1: 0x3121, //BOPOMOFO LETTER OU + 0xA8E2: 0x3122, //BOPOMOFO LETTER AN + 0xA8E3: 0x3123, //BOPOMOFO LETTER EN + 0xA8E4: 0x3124, //BOPOMOFO LETTER ANG + 0xA8E5: 0x3125, //BOPOMOFO LETTER ENG + 0xA8E6: 0x3126, //BOPOMOFO LETTER ER + 0xA8E7: 0x3127, //BOPOMOFO LETTER I + 0xA8E8: 0x3128, //BOPOMOFO LETTER U + 0xA8E9: 0x3129, //BOPOMOFO LETTER IU + 0xA940: 0x3021, //HANGZHOU NUMERAL ONE + 0xA941: 0x3022, //HANGZHOU NUMERAL TWO + 0xA942: 0x3023, //HANGZHOU NUMERAL THREE + 0xA943: 0x3024, //HANGZHOU NUMERAL FOUR + 0xA944: 0x3025, //HANGZHOU NUMERAL FIVE + 0xA945: 0x3026, //HANGZHOU NUMERAL SIX + 0xA946: 0x3027, //HANGZHOU NUMERAL SEVEN + 0xA947: 0x3028, //HANGZHOU NUMERAL EIGHT + 0xA948: 0x3029, //HANGZHOU NUMERAL NINE + 0xA949: 0x32A3, //CIRCLED IDEOGRAPH CORRECT + 0xA94A: 0x338E, //SQUARE MG + 0xA94B: 0x338F, //SQUARE KG + 0xA94C: 0x339C, //SQUARE MM + 0xA94D: 0x339D, //SQUARE CM + 0xA94E: 0x339E, //SQUARE KM + 0xA94F: 0x33A1, //SQUARE M SQUARED + 0xA950: 0x33C4, //SQUARE CC + 0xA951: 0x33CE, //SQUARE KM CAPITAL + 0xA952: 0x33D1, //SQUARE LN + 0xA953: 0x33D2, //SQUARE LOG + 0xA954: 0x33D5, //SQUARE MIL + 0xA955: 0xFE30, //PRESENTATION FORM FOR VERTICAL TWO DOT LEADER + 0xA956: 0xFFE2, //FULLWIDTH NOT SIGN + 0xA957: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xA959: 0x2121, //TELEPHONE SIGN + 0xA95A: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0xA95C: 0x2010, //HYPHEN + 0xA960: 0x30FC, //KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0xA961: 0x309B, //KATAKANA-HIRAGANA VOICED SOUND MARK + 0xA962: 0x309C, //KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + 0xA963: 0x30FD, //KATAKANA ITERATION MARK + 0xA964: 0x30FE, //KATAKANA VOICED ITERATION MARK + 0xA965: 0x3006, //IDEOGRAPHIC CLOSING MARK + 0xA966: 0x309D, //HIRAGANA ITERATION MARK + 0xA967: 0x309E, //HIRAGANA VOICED ITERATION MARK + 0xA968: 0xFE49, //DASHED OVERLINE + 0xA969: 0xFE4A, //CENTRELINE OVERLINE + 0xA96A: 0xFE4B, //WAVY OVERLINE + 0xA96B: 0xFE4C, //DOUBLE WAVY OVERLINE + 0xA96C: 0xFE4D, //DASHED LOW LINE + 0xA96D: 0xFE4E, //CENTRELINE LOW LINE + 0xA96E: 0xFE4F, //WAVY LOW LINE + 0xA96F: 0xFE50, //SMALL COMMA + 0xA970: 0xFE51, //SMALL IDEOGRAPHIC COMMA + 0xA971: 0xFE52, //SMALL FULL STOP + 0xA972: 0xFE54, //SMALL SEMICOLON + 0xA973: 0xFE55, //SMALL COLON + 0xA974: 0xFE56, //SMALL QUESTION MARK + 0xA975: 0xFE57, //SMALL EXCLAMATION MARK + 0xA976: 0xFE59, //SMALL LEFT PARENTHESIS + 0xA977: 0xFE5A, //SMALL RIGHT PARENTHESIS + 0xA978: 0xFE5B, //SMALL LEFT CURLY BRACKET + 0xA979: 0xFE5C, //SMALL RIGHT CURLY BRACKET + 0xA97A: 0xFE5D, //SMALL LEFT TORTOISE SHELL BRACKET + 0xA97B: 0xFE5E, //SMALL RIGHT TORTOISE SHELL BRACKET + 0xA97C: 0xFE5F, //SMALL NUMBER SIGN + 0xA97D: 0xFE60, //SMALL AMPERSAND + 0xA97E: 0xFE61, //SMALL ASTERISK + 0xA980: 0xFE62, //SMALL PLUS SIGN + 0xA981: 0xFE63, //SMALL HYPHEN-MINUS + 0xA982: 0xFE64, //SMALL LESS-THAN SIGN + 0xA983: 0xFE65, //SMALL GREATER-THAN SIGN + 0xA984: 0xFE66, //SMALL EQUALS SIGN + 0xA985: 0xFE68, //SMALL REVERSE SOLIDUS + 0xA986: 0xFE69, //SMALL DOLLAR SIGN + 0xA987: 0xFE6A, //SMALL PERCENT SIGN + 0xA988: 0xFE6B, //SMALL COMMERCIAL AT + 0xA996: 0x3007, //IDEOGRAPHIC NUMBER ZERO + 0xA9A4: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA9A5: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0xA9A6: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA9A7: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0xA9A8: 0x2504, //BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL + 0xA9A9: 0x2505, //BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL + 0xA9AA: 0x2506, //BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + 0xA9AB: 0x2507, //BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL + 0xA9AC: 0x2508, //BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL + 0xA9AD: 0x2509, //BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL + 0xA9AE: 0x250A, //BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL + 0xA9AF: 0x250B, //BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL + 0xA9B0: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA9B1: 0x250D, //BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY + 0xA9B2: 0x250E, //BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT + 0xA9B3: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0xA9B4: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA9B5: 0x2511, //BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY + 0xA9B6: 0x2512, //BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT + 0xA9B7: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0xA9B8: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA9B9: 0x2515, //BOX DRAWINGS UP LIGHT AND RIGHT HEAVY + 0xA9BA: 0x2516, //BOX DRAWINGS UP HEAVY AND RIGHT LIGHT + 0xA9BB: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0xA9BC: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA9BD: 0x2519, //BOX DRAWINGS UP LIGHT AND LEFT HEAVY + 0xA9BE: 0x251A, //BOX DRAWINGS UP HEAVY AND LEFT LIGHT + 0xA9BF: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0xA9C0: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA9C1: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0xA9C2: 0x251E, //BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT + 0xA9C3: 0x251F, //BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT + 0xA9C4: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0xA9C5: 0x2521, //BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY + 0xA9C6: 0x2522, //BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY + 0xA9C7: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0xA9C8: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA9C9: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0xA9CA: 0x2526, //BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT + 0xA9CB: 0x2527, //BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT + 0xA9CC: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0xA9CD: 0x2529, //BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY + 0xA9CE: 0x252A, //BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY + 0xA9CF: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0xA9D0: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA9D1: 0x252D, //BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT + 0xA9D2: 0x252E, //BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT + 0xA9D3: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0xA9D4: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0xA9D5: 0x2531, //BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY + 0xA9D6: 0x2532, //BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY + 0xA9D7: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0xA9D8: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA9D9: 0x2535, //BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT + 0xA9DA: 0x2536, //BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT + 0xA9DB: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0xA9DC: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0xA9DD: 0x2539, //BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY + 0xA9DE: 0x253A, //BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY + 0xA9DF: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0xA9E0: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA9E1: 0x253D, //BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT + 0xA9E2: 0x253E, //BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT + 0xA9E3: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0xA9E4: 0x2540, //BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT + 0xA9E5: 0x2541, //BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT + 0xA9E6: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0xA9E7: 0x2543, //BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT + 0xA9E8: 0x2544, //BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT + 0xA9E9: 0x2545, //BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT + 0xA9EA: 0x2546, //BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT + 0xA9EB: 0x2547, //BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY + 0xA9EC: 0x2548, //BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY + 0xA9ED: 0x2549, //BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY + 0xA9EE: 0x254A, //BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY + 0xA9EF: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0xAA40: 0x72DC, //CJK UNIFIED IDEOGRAPH + 0xAA41: 0x72DD, //CJK UNIFIED IDEOGRAPH + 0xAA42: 0x72DF, //CJK UNIFIED IDEOGRAPH + 0xAA43: 0x72E2, //CJK UNIFIED IDEOGRAPH + 0xAA44: 0x72E3, //CJK UNIFIED IDEOGRAPH + 0xAA45: 0x72E4, //CJK UNIFIED IDEOGRAPH + 0xAA46: 0x72E5, //CJK UNIFIED IDEOGRAPH + 0xAA47: 0x72E6, //CJK UNIFIED IDEOGRAPH + 0xAA48: 0x72E7, //CJK UNIFIED IDEOGRAPH + 0xAA49: 0x72EA, //CJK UNIFIED IDEOGRAPH + 0xAA4A: 0x72EB, //CJK UNIFIED IDEOGRAPH + 0xAA4B: 0x72F5, //CJK UNIFIED IDEOGRAPH + 0xAA4C: 0x72F6, //CJK UNIFIED IDEOGRAPH + 0xAA4D: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xAA4E: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xAA4F: 0x72FE, //CJK UNIFIED IDEOGRAPH + 0xAA50: 0x72FF, //CJK UNIFIED IDEOGRAPH + 0xAA51: 0x7300, //CJK UNIFIED IDEOGRAPH + 0xAA52: 0x7302, //CJK UNIFIED IDEOGRAPH + 0xAA53: 0x7304, //CJK UNIFIED IDEOGRAPH + 0xAA54: 0x7305, //CJK UNIFIED IDEOGRAPH + 0xAA55: 0x7306, //CJK UNIFIED IDEOGRAPH + 0xAA56: 0x7307, //CJK UNIFIED IDEOGRAPH + 0xAA57: 0x7308, //CJK UNIFIED IDEOGRAPH + 0xAA58: 0x7309, //CJK UNIFIED IDEOGRAPH + 0xAA59: 0x730B, //CJK UNIFIED IDEOGRAPH + 0xAA5A: 0x730C, //CJK UNIFIED IDEOGRAPH + 0xAA5B: 0x730D, //CJK UNIFIED IDEOGRAPH + 0xAA5C: 0x730F, //CJK UNIFIED IDEOGRAPH + 0xAA5D: 0x7310, //CJK UNIFIED IDEOGRAPH + 0xAA5E: 0x7311, //CJK UNIFIED IDEOGRAPH + 0xAA5F: 0x7312, //CJK UNIFIED IDEOGRAPH + 0xAA60: 0x7314, //CJK UNIFIED IDEOGRAPH + 0xAA61: 0x7318, //CJK UNIFIED IDEOGRAPH + 0xAA62: 0x7319, //CJK UNIFIED IDEOGRAPH + 0xAA63: 0x731A, //CJK UNIFIED IDEOGRAPH + 0xAA64: 0x731F, //CJK UNIFIED IDEOGRAPH + 0xAA65: 0x7320, //CJK UNIFIED IDEOGRAPH + 0xAA66: 0x7323, //CJK UNIFIED IDEOGRAPH + 0xAA67: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xAA68: 0x7326, //CJK UNIFIED IDEOGRAPH + 0xAA69: 0x7327, //CJK UNIFIED IDEOGRAPH + 0xAA6A: 0x7328, //CJK UNIFIED IDEOGRAPH + 0xAA6B: 0x732D, //CJK UNIFIED IDEOGRAPH + 0xAA6C: 0x732F, //CJK UNIFIED IDEOGRAPH + 0xAA6D: 0x7330, //CJK UNIFIED IDEOGRAPH + 0xAA6E: 0x7332, //CJK UNIFIED IDEOGRAPH + 0xAA6F: 0x7333, //CJK UNIFIED IDEOGRAPH + 0xAA70: 0x7335, //CJK UNIFIED IDEOGRAPH + 0xAA71: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xAA72: 0x733A, //CJK UNIFIED IDEOGRAPH + 0xAA73: 0x733B, //CJK UNIFIED IDEOGRAPH + 0xAA74: 0x733C, //CJK UNIFIED IDEOGRAPH + 0xAA75: 0x733D, //CJK UNIFIED IDEOGRAPH + 0xAA76: 0x7340, //CJK UNIFIED IDEOGRAPH + 0xAA77: 0x7341, //CJK UNIFIED IDEOGRAPH + 0xAA78: 0x7342, //CJK UNIFIED IDEOGRAPH + 0xAA79: 0x7343, //CJK UNIFIED IDEOGRAPH + 0xAA7A: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xAA7B: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xAA7C: 0x7346, //CJK UNIFIED IDEOGRAPH + 0xAA7D: 0x7347, //CJK UNIFIED IDEOGRAPH + 0xAA7E: 0x7348, //CJK UNIFIED IDEOGRAPH + 0xAA80: 0x7349, //CJK UNIFIED IDEOGRAPH + 0xAA81: 0x734A, //CJK UNIFIED IDEOGRAPH + 0xAA82: 0x734B, //CJK UNIFIED IDEOGRAPH + 0xAA83: 0x734C, //CJK UNIFIED IDEOGRAPH + 0xAA84: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xAA85: 0x734F, //CJK UNIFIED IDEOGRAPH + 0xAA86: 0x7351, //CJK UNIFIED IDEOGRAPH + 0xAA87: 0x7353, //CJK UNIFIED IDEOGRAPH + 0xAA88: 0x7354, //CJK UNIFIED IDEOGRAPH + 0xAA89: 0x7355, //CJK UNIFIED IDEOGRAPH + 0xAA8A: 0x7356, //CJK UNIFIED IDEOGRAPH + 0xAA8B: 0x7358, //CJK UNIFIED IDEOGRAPH + 0xAA8C: 0x7359, //CJK UNIFIED IDEOGRAPH + 0xAA8D: 0x735A, //CJK UNIFIED IDEOGRAPH + 0xAA8E: 0x735B, //CJK UNIFIED IDEOGRAPH + 0xAA8F: 0x735C, //CJK UNIFIED IDEOGRAPH + 0xAA90: 0x735D, //CJK UNIFIED IDEOGRAPH + 0xAA91: 0x735E, //CJK UNIFIED IDEOGRAPH + 0xAA92: 0x735F, //CJK UNIFIED IDEOGRAPH + 0xAA93: 0x7361, //CJK UNIFIED IDEOGRAPH + 0xAA94: 0x7362, //CJK UNIFIED IDEOGRAPH + 0xAA95: 0x7363, //CJK UNIFIED IDEOGRAPH + 0xAA96: 0x7364, //CJK UNIFIED IDEOGRAPH + 0xAA97: 0x7365, //CJK UNIFIED IDEOGRAPH + 0xAA98: 0x7366, //CJK UNIFIED IDEOGRAPH + 0xAA99: 0x7367, //CJK UNIFIED IDEOGRAPH + 0xAA9A: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xAA9B: 0x7369, //CJK UNIFIED IDEOGRAPH + 0xAA9C: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xAA9D: 0x736B, //CJK UNIFIED IDEOGRAPH + 0xAA9E: 0x736E, //CJK UNIFIED IDEOGRAPH + 0xAA9F: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xAAA0: 0x7371, //CJK UNIFIED IDEOGRAPH + 0xAB40: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xAB41: 0x7373, //CJK UNIFIED IDEOGRAPH + 0xAB42: 0x7374, //CJK UNIFIED IDEOGRAPH + 0xAB43: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xAB44: 0x7376, //CJK UNIFIED IDEOGRAPH + 0xAB45: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xAB46: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xAB47: 0x7379, //CJK UNIFIED IDEOGRAPH + 0xAB48: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xAB49: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xAB4A: 0x737C, //CJK UNIFIED IDEOGRAPH + 0xAB4B: 0x737D, //CJK UNIFIED IDEOGRAPH + 0xAB4C: 0x737F, //CJK UNIFIED IDEOGRAPH + 0xAB4D: 0x7380, //CJK UNIFIED IDEOGRAPH + 0xAB4E: 0x7381, //CJK UNIFIED IDEOGRAPH + 0xAB4F: 0x7382, //CJK UNIFIED IDEOGRAPH + 0xAB50: 0x7383, //CJK UNIFIED IDEOGRAPH + 0xAB51: 0x7385, //CJK UNIFIED IDEOGRAPH + 0xAB52: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xAB53: 0x7388, //CJK UNIFIED IDEOGRAPH + 0xAB54: 0x738A, //CJK UNIFIED IDEOGRAPH + 0xAB55: 0x738C, //CJK UNIFIED IDEOGRAPH + 0xAB56: 0x738D, //CJK UNIFIED IDEOGRAPH + 0xAB57: 0x738F, //CJK UNIFIED IDEOGRAPH + 0xAB58: 0x7390, //CJK UNIFIED IDEOGRAPH + 0xAB59: 0x7392, //CJK UNIFIED IDEOGRAPH + 0xAB5A: 0x7393, //CJK UNIFIED IDEOGRAPH + 0xAB5B: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xAB5C: 0x7395, //CJK UNIFIED IDEOGRAPH + 0xAB5D: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xAB5E: 0x7398, //CJK UNIFIED IDEOGRAPH + 0xAB5F: 0x7399, //CJK UNIFIED IDEOGRAPH + 0xAB60: 0x739A, //CJK UNIFIED IDEOGRAPH + 0xAB61: 0x739C, //CJK UNIFIED IDEOGRAPH + 0xAB62: 0x739D, //CJK UNIFIED IDEOGRAPH + 0xAB63: 0x739E, //CJK UNIFIED IDEOGRAPH + 0xAB64: 0x73A0, //CJK UNIFIED IDEOGRAPH + 0xAB65: 0x73A1, //CJK UNIFIED IDEOGRAPH + 0xAB66: 0x73A3, //CJK UNIFIED IDEOGRAPH + 0xAB67: 0x73A4, //CJK UNIFIED IDEOGRAPH + 0xAB68: 0x73A5, //CJK UNIFIED IDEOGRAPH + 0xAB69: 0x73A6, //CJK UNIFIED IDEOGRAPH + 0xAB6A: 0x73A7, //CJK UNIFIED IDEOGRAPH + 0xAB6B: 0x73A8, //CJK UNIFIED IDEOGRAPH + 0xAB6C: 0x73AA, //CJK UNIFIED IDEOGRAPH + 0xAB6D: 0x73AC, //CJK UNIFIED IDEOGRAPH + 0xAB6E: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xAB6F: 0x73B1, //CJK UNIFIED IDEOGRAPH + 0xAB70: 0x73B4, //CJK UNIFIED IDEOGRAPH + 0xAB71: 0x73B5, //CJK UNIFIED IDEOGRAPH + 0xAB72: 0x73B6, //CJK UNIFIED IDEOGRAPH + 0xAB73: 0x73B8, //CJK UNIFIED IDEOGRAPH + 0xAB74: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xAB75: 0x73BC, //CJK UNIFIED IDEOGRAPH + 0xAB76: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xAB77: 0x73BE, //CJK UNIFIED IDEOGRAPH + 0xAB78: 0x73BF, //CJK UNIFIED IDEOGRAPH + 0xAB79: 0x73C1, //CJK UNIFIED IDEOGRAPH + 0xAB7A: 0x73C3, //CJK UNIFIED IDEOGRAPH + 0xAB7B: 0x73C4, //CJK UNIFIED IDEOGRAPH + 0xAB7C: 0x73C5, //CJK UNIFIED IDEOGRAPH + 0xAB7D: 0x73C6, //CJK UNIFIED IDEOGRAPH + 0xAB7E: 0x73C7, //CJK UNIFIED IDEOGRAPH + 0xAB80: 0x73CB, //CJK UNIFIED IDEOGRAPH + 0xAB81: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xAB82: 0x73CE, //CJK UNIFIED IDEOGRAPH + 0xAB83: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xAB84: 0x73D3, //CJK UNIFIED IDEOGRAPH + 0xAB85: 0x73D4, //CJK UNIFIED IDEOGRAPH + 0xAB86: 0x73D5, //CJK UNIFIED IDEOGRAPH + 0xAB87: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xAB88: 0x73D7, //CJK UNIFIED IDEOGRAPH + 0xAB89: 0x73D8, //CJK UNIFIED IDEOGRAPH + 0xAB8A: 0x73DA, //CJK UNIFIED IDEOGRAPH + 0xAB8B: 0x73DB, //CJK UNIFIED IDEOGRAPH + 0xAB8C: 0x73DC, //CJK UNIFIED IDEOGRAPH + 0xAB8D: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xAB8E: 0x73DF, //CJK UNIFIED IDEOGRAPH + 0xAB8F: 0x73E1, //CJK UNIFIED IDEOGRAPH + 0xAB90: 0x73E2, //CJK UNIFIED IDEOGRAPH + 0xAB91: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xAB92: 0x73E4, //CJK UNIFIED IDEOGRAPH + 0xAB93: 0x73E6, //CJK UNIFIED IDEOGRAPH + 0xAB94: 0x73E8, //CJK UNIFIED IDEOGRAPH + 0xAB95: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xAB96: 0x73EB, //CJK UNIFIED IDEOGRAPH + 0xAB97: 0x73EC, //CJK UNIFIED IDEOGRAPH + 0xAB98: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xAB99: 0x73EF, //CJK UNIFIED IDEOGRAPH + 0xAB9A: 0x73F0, //CJK UNIFIED IDEOGRAPH + 0xAB9B: 0x73F1, //CJK UNIFIED IDEOGRAPH + 0xAB9C: 0x73F3, //CJK UNIFIED IDEOGRAPH + 0xAB9D: 0x73F4, //CJK UNIFIED IDEOGRAPH + 0xAB9E: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xAB9F: 0x73F6, //CJK UNIFIED IDEOGRAPH + 0xABA0: 0x73F7, //CJK UNIFIED IDEOGRAPH + 0xAC40: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xAC41: 0x73F9, //CJK UNIFIED IDEOGRAPH + 0xAC42: 0x73FA, //CJK UNIFIED IDEOGRAPH + 0xAC43: 0x73FB, //CJK UNIFIED IDEOGRAPH + 0xAC44: 0x73FC, //CJK UNIFIED IDEOGRAPH + 0xAC45: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xAC46: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xAC47: 0x73FF, //CJK UNIFIED IDEOGRAPH + 0xAC48: 0x7400, //CJK UNIFIED IDEOGRAPH + 0xAC49: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xAC4A: 0x7402, //CJK UNIFIED IDEOGRAPH + 0xAC4B: 0x7404, //CJK UNIFIED IDEOGRAPH + 0xAC4C: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xAC4D: 0x7408, //CJK UNIFIED IDEOGRAPH + 0xAC4E: 0x740B, //CJK UNIFIED IDEOGRAPH + 0xAC4F: 0x740C, //CJK UNIFIED IDEOGRAPH + 0xAC50: 0x740D, //CJK UNIFIED IDEOGRAPH + 0xAC51: 0x740E, //CJK UNIFIED IDEOGRAPH + 0xAC52: 0x7411, //CJK UNIFIED IDEOGRAPH + 0xAC53: 0x7412, //CJK UNIFIED IDEOGRAPH + 0xAC54: 0x7413, //CJK UNIFIED IDEOGRAPH + 0xAC55: 0x7414, //CJK UNIFIED IDEOGRAPH + 0xAC56: 0x7415, //CJK UNIFIED IDEOGRAPH + 0xAC57: 0x7416, //CJK UNIFIED IDEOGRAPH + 0xAC58: 0x7417, //CJK UNIFIED IDEOGRAPH + 0xAC59: 0x7418, //CJK UNIFIED IDEOGRAPH + 0xAC5A: 0x7419, //CJK UNIFIED IDEOGRAPH + 0xAC5B: 0x741C, //CJK UNIFIED IDEOGRAPH + 0xAC5C: 0x741D, //CJK UNIFIED IDEOGRAPH + 0xAC5D: 0x741E, //CJK UNIFIED IDEOGRAPH + 0xAC5E: 0x741F, //CJK UNIFIED IDEOGRAPH + 0xAC5F: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xAC60: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xAC61: 0x7423, //CJK UNIFIED IDEOGRAPH + 0xAC62: 0x7424, //CJK UNIFIED IDEOGRAPH + 0xAC63: 0x7427, //CJK UNIFIED IDEOGRAPH + 0xAC64: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xAC65: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xAC66: 0x742D, //CJK UNIFIED IDEOGRAPH + 0xAC67: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xAC68: 0x7431, //CJK UNIFIED IDEOGRAPH + 0xAC69: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xAC6A: 0x7437, //CJK UNIFIED IDEOGRAPH + 0xAC6B: 0x7438, //CJK UNIFIED IDEOGRAPH + 0xAC6C: 0x7439, //CJK UNIFIED IDEOGRAPH + 0xAC6D: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xAC6E: 0x743B, //CJK UNIFIED IDEOGRAPH + 0xAC6F: 0x743D, //CJK UNIFIED IDEOGRAPH + 0xAC70: 0x743E, //CJK UNIFIED IDEOGRAPH + 0xAC71: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xAC72: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xAC73: 0x7442, //CJK UNIFIED IDEOGRAPH + 0xAC74: 0x7443, //CJK UNIFIED IDEOGRAPH + 0xAC75: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xAC76: 0x7445, //CJK UNIFIED IDEOGRAPH + 0xAC77: 0x7446, //CJK UNIFIED IDEOGRAPH + 0xAC78: 0x7447, //CJK UNIFIED IDEOGRAPH + 0xAC79: 0x7448, //CJK UNIFIED IDEOGRAPH + 0xAC7A: 0x7449, //CJK UNIFIED IDEOGRAPH + 0xAC7B: 0x744A, //CJK UNIFIED IDEOGRAPH + 0xAC7C: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xAC7D: 0x744C, //CJK UNIFIED IDEOGRAPH + 0xAC7E: 0x744D, //CJK UNIFIED IDEOGRAPH + 0xAC80: 0x744E, //CJK UNIFIED IDEOGRAPH + 0xAC81: 0x744F, //CJK UNIFIED IDEOGRAPH + 0xAC82: 0x7450, //CJK UNIFIED IDEOGRAPH + 0xAC83: 0x7451, //CJK UNIFIED IDEOGRAPH + 0xAC84: 0x7452, //CJK UNIFIED IDEOGRAPH + 0xAC85: 0x7453, //CJK UNIFIED IDEOGRAPH + 0xAC86: 0x7454, //CJK UNIFIED IDEOGRAPH + 0xAC87: 0x7456, //CJK UNIFIED IDEOGRAPH + 0xAC88: 0x7458, //CJK UNIFIED IDEOGRAPH + 0xAC89: 0x745D, //CJK UNIFIED IDEOGRAPH + 0xAC8A: 0x7460, //CJK UNIFIED IDEOGRAPH + 0xAC8B: 0x7461, //CJK UNIFIED IDEOGRAPH + 0xAC8C: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xAC8D: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xAC8E: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xAC8F: 0x7465, //CJK UNIFIED IDEOGRAPH + 0xAC90: 0x7466, //CJK UNIFIED IDEOGRAPH + 0xAC91: 0x7467, //CJK UNIFIED IDEOGRAPH + 0xAC92: 0x7468, //CJK UNIFIED IDEOGRAPH + 0xAC93: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xAC94: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xAC95: 0x746B, //CJK UNIFIED IDEOGRAPH + 0xAC96: 0x746C, //CJK UNIFIED IDEOGRAPH + 0xAC97: 0x746E, //CJK UNIFIED IDEOGRAPH + 0xAC98: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xAC99: 0x7471, //CJK UNIFIED IDEOGRAPH + 0xAC9A: 0x7472, //CJK UNIFIED IDEOGRAPH + 0xAC9B: 0x7473, //CJK UNIFIED IDEOGRAPH + 0xAC9C: 0x7474, //CJK UNIFIED IDEOGRAPH + 0xAC9D: 0x7475, //CJK UNIFIED IDEOGRAPH + 0xAC9E: 0x7478, //CJK UNIFIED IDEOGRAPH + 0xAC9F: 0x7479, //CJK UNIFIED IDEOGRAPH + 0xACA0: 0x747A, //CJK UNIFIED IDEOGRAPH + 0xAD40: 0x747B, //CJK UNIFIED IDEOGRAPH + 0xAD41: 0x747C, //CJK UNIFIED IDEOGRAPH + 0xAD42: 0x747D, //CJK UNIFIED IDEOGRAPH + 0xAD43: 0x747F, //CJK UNIFIED IDEOGRAPH + 0xAD44: 0x7482, //CJK UNIFIED IDEOGRAPH + 0xAD45: 0x7484, //CJK UNIFIED IDEOGRAPH + 0xAD46: 0x7485, //CJK UNIFIED IDEOGRAPH + 0xAD47: 0x7486, //CJK UNIFIED IDEOGRAPH + 0xAD48: 0x7488, //CJK UNIFIED IDEOGRAPH + 0xAD49: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xAD4A: 0x748A, //CJK UNIFIED IDEOGRAPH + 0xAD4B: 0x748C, //CJK UNIFIED IDEOGRAPH + 0xAD4C: 0x748D, //CJK UNIFIED IDEOGRAPH + 0xAD4D: 0x748F, //CJK UNIFIED IDEOGRAPH + 0xAD4E: 0x7491, //CJK UNIFIED IDEOGRAPH + 0xAD4F: 0x7492, //CJK UNIFIED IDEOGRAPH + 0xAD50: 0x7493, //CJK UNIFIED IDEOGRAPH + 0xAD51: 0x7494, //CJK UNIFIED IDEOGRAPH + 0xAD52: 0x7495, //CJK UNIFIED IDEOGRAPH + 0xAD53: 0x7496, //CJK UNIFIED IDEOGRAPH + 0xAD54: 0x7497, //CJK UNIFIED IDEOGRAPH + 0xAD55: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xAD56: 0x7499, //CJK UNIFIED IDEOGRAPH + 0xAD57: 0x749A, //CJK UNIFIED IDEOGRAPH + 0xAD58: 0x749B, //CJK UNIFIED IDEOGRAPH + 0xAD59: 0x749D, //CJK UNIFIED IDEOGRAPH + 0xAD5A: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xAD5B: 0x74A0, //CJK UNIFIED IDEOGRAPH + 0xAD5C: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xAD5D: 0x74A2, //CJK UNIFIED IDEOGRAPH + 0xAD5E: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xAD5F: 0x74A4, //CJK UNIFIED IDEOGRAPH + 0xAD60: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xAD61: 0x74A6, //CJK UNIFIED IDEOGRAPH + 0xAD62: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xAD63: 0x74AB, //CJK UNIFIED IDEOGRAPH + 0xAD64: 0x74AC, //CJK UNIFIED IDEOGRAPH + 0xAD65: 0x74AD, //CJK UNIFIED IDEOGRAPH + 0xAD66: 0x74AE, //CJK UNIFIED IDEOGRAPH + 0xAD67: 0x74AF, //CJK UNIFIED IDEOGRAPH + 0xAD68: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xAD69: 0x74B1, //CJK UNIFIED IDEOGRAPH + 0xAD6A: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xAD6B: 0x74B3, //CJK UNIFIED IDEOGRAPH + 0xAD6C: 0x74B4, //CJK UNIFIED IDEOGRAPH + 0xAD6D: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xAD6E: 0x74B6, //CJK UNIFIED IDEOGRAPH + 0xAD6F: 0x74B7, //CJK UNIFIED IDEOGRAPH + 0xAD70: 0x74B8, //CJK UNIFIED IDEOGRAPH + 0xAD71: 0x74B9, //CJK UNIFIED IDEOGRAPH + 0xAD72: 0x74BB, //CJK UNIFIED IDEOGRAPH + 0xAD73: 0x74BC, //CJK UNIFIED IDEOGRAPH + 0xAD74: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xAD75: 0x74BE, //CJK UNIFIED IDEOGRAPH + 0xAD76: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xAD77: 0x74C0, //CJK UNIFIED IDEOGRAPH + 0xAD78: 0x74C1, //CJK UNIFIED IDEOGRAPH + 0xAD79: 0x74C2, //CJK UNIFIED IDEOGRAPH + 0xAD7A: 0x74C3, //CJK UNIFIED IDEOGRAPH + 0xAD7B: 0x74C4, //CJK UNIFIED IDEOGRAPH + 0xAD7C: 0x74C5, //CJK UNIFIED IDEOGRAPH + 0xAD7D: 0x74C6, //CJK UNIFIED IDEOGRAPH + 0xAD7E: 0x74C7, //CJK UNIFIED IDEOGRAPH + 0xAD80: 0x74C8, //CJK UNIFIED IDEOGRAPH + 0xAD81: 0x74C9, //CJK UNIFIED IDEOGRAPH + 0xAD82: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xAD83: 0x74CB, //CJK UNIFIED IDEOGRAPH + 0xAD84: 0x74CC, //CJK UNIFIED IDEOGRAPH + 0xAD85: 0x74CD, //CJK UNIFIED IDEOGRAPH + 0xAD86: 0x74CE, //CJK UNIFIED IDEOGRAPH + 0xAD87: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xAD88: 0x74D0, //CJK UNIFIED IDEOGRAPH + 0xAD89: 0x74D1, //CJK UNIFIED IDEOGRAPH + 0xAD8A: 0x74D3, //CJK UNIFIED IDEOGRAPH + 0xAD8B: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xAD8C: 0x74D5, //CJK UNIFIED IDEOGRAPH + 0xAD8D: 0x74D6, //CJK UNIFIED IDEOGRAPH + 0xAD8E: 0x74D7, //CJK UNIFIED IDEOGRAPH + 0xAD8F: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xAD90: 0x74D9, //CJK UNIFIED IDEOGRAPH + 0xAD91: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xAD92: 0x74DB, //CJK UNIFIED IDEOGRAPH + 0xAD93: 0x74DD, //CJK UNIFIED IDEOGRAPH + 0xAD94: 0x74DF, //CJK UNIFIED IDEOGRAPH + 0xAD95: 0x74E1, //CJK UNIFIED IDEOGRAPH + 0xAD96: 0x74E5, //CJK UNIFIED IDEOGRAPH + 0xAD97: 0x74E7, //CJK UNIFIED IDEOGRAPH + 0xAD98: 0x74E8, //CJK UNIFIED IDEOGRAPH + 0xAD99: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xAD9A: 0x74EA, //CJK UNIFIED IDEOGRAPH + 0xAD9B: 0x74EB, //CJK UNIFIED IDEOGRAPH + 0xAD9C: 0x74EC, //CJK UNIFIED IDEOGRAPH + 0xAD9D: 0x74ED, //CJK UNIFIED IDEOGRAPH + 0xAD9E: 0x74F0, //CJK UNIFIED IDEOGRAPH + 0xAD9F: 0x74F1, //CJK UNIFIED IDEOGRAPH + 0xADA0: 0x74F2, //CJK UNIFIED IDEOGRAPH + 0xAE40: 0x74F3, //CJK UNIFIED IDEOGRAPH + 0xAE41: 0x74F5, //CJK UNIFIED IDEOGRAPH + 0xAE42: 0x74F8, //CJK UNIFIED IDEOGRAPH + 0xAE43: 0x74F9, //CJK UNIFIED IDEOGRAPH + 0xAE44: 0x74FA, //CJK UNIFIED IDEOGRAPH + 0xAE45: 0x74FB, //CJK UNIFIED IDEOGRAPH + 0xAE46: 0x74FC, //CJK UNIFIED IDEOGRAPH + 0xAE47: 0x74FD, //CJK UNIFIED IDEOGRAPH + 0xAE48: 0x74FE, //CJK UNIFIED IDEOGRAPH + 0xAE49: 0x7500, //CJK UNIFIED IDEOGRAPH + 0xAE4A: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xAE4B: 0x7502, //CJK UNIFIED IDEOGRAPH + 0xAE4C: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xAE4D: 0x7505, //CJK UNIFIED IDEOGRAPH + 0xAE4E: 0x7506, //CJK UNIFIED IDEOGRAPH + 0xAE4F: 0x7507, //CJK UNIFIED IDEOGRAPH + 0xAE50: 0x7508, //CJK UNIFIED IDEOGRAPH + 0xAE51: 0x7509, //CJK UNIFIED IDEOGRAPH + 0xAE52: 0x750A, //CJK UNIFIED IDEOGRAPH + 0xAE53: 0x750B, //CJK UNIFIED IDEOGRAPH + 0xAE54: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xAE55: 0x750E, //CJK UNIFIED IDEOGRAPH + 0xAE56: 0x7510, //CJK UNIFIED IDEOGRAPH + 0xAE57: 0x7512, //CJK UNIFIED IDEOGRAPH + 0xAE58: 0x7514, //CJK UNIFIED IDEOGRAPH + 0xAE59: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xAE5A: 0x7516, //CJK UNIFIED IDEOGRAPH + 0xAE5B: 0x7517, //CJK UNIFIED IDEOGRAPH + 0xAE5C: 0x751B, //CJK UNIFIED IDEOGRAPH + 0xAE5D: 0x751D, //CJK UNIFIED IDEOGRAPH + 0xAE5E: 0x751E, //CJK UNIFIED IDEOGRAPH + 0xAE5F: 0x7520, //CJK UNIFIED IDEOGRAPH + 0xAE60: 0x7521, //CJK UNIFIED IDEOGRAPH + 0xAE61: 0x7522, //CJK UNIFIED IDEOGRAPH + 0xAE62: 0x7523, //CJK UNIFIED IDEOGRAPH + 0xAE63: 0x7524, //CJK UNIFIED IDEOGRAPH + 0xAE64: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xAE65: 0x7527, //CJK UNIFIED IDEOGRAPH + 0xAE66: 0x752A, //CJK UNIFIED IDEOGRAPH + 0xAE67: 0x752E, //CJK UNIFIED IDEOGRAPH + 0xAE68: 0x7534, //CJK UNIFIED IDEOGRAPH + 0xAE69: 0x7536, //CJK UNIFIED IDEOGRAPH + 0xAE6A: 0x7539, //CJK UNIFIED IDEOGRAPH + 0xAE6B: 0x753C, //CJK UNIFIED IDEOGRAPH + 0xAE6C: 0x753D, //CJK UNIFIED IDEOGRAPH + 0xAE6D: 0x753F, //CJK UNIFIED IDEOGRAPH + 0xAE6E: 0x7541, //CJK UNIFIED IDEOGRAPH + 0xAE6F: 0x7542, //CJK UNIFIED IDEOGRAPH + 0xAE70: 0x7543, //CJK UNIFIED IDEOGRAPH + 0xAE71: 0x7544, //CJK UNIFIED IDEOGRAPH + 0xAE72: 0x7546, //CJK UNIFIED IDEOGRAPH + 0xAE73: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xAE74: 0x7549, //CJK UNIFIED IDEOGRAPH + 0xAE75: 0x754A, //CJK UNIFIED IDEOGRAPH + 0xAE76: 0x754D, //CJK UNIFIED IDEOGRAPH + 0xAE77: 0x7550, //CJK UNIFIED IDEOGRAPH + 0xAE78: 0x7551, //CJK UNIFIED IDEOGRAPH + 0xAE79: 0x7552, //CJK UNIFIED IDEOGRAPH + 0xAE7A: 0x7553, //CJK UNIFIED IDEOGRAPH + 0xAE7B: 0x7555, //CJK UNIFIED IDEOGRAPH + 0xAE7C: 0x7556, //CJK UNIFIED IDEOGRAPH + 0xAE7D: 0x7557, //CJK UNIFIED IDEOGRAPH + 0xAE7E: 0x7558, //CJK UNIFIED IDEOGRAPH + 0xAE80: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xAE81: 0x755E, //CJK UNIFIED IDEOGRAPH + 0xAE82: 0x755F, //CJK UNIFIED IDEOGRAPH + 0xAE83: 0x7560, //CJK UNIFIED IDEOGRAPH + 0xAE84: 0x7561, //CJK UNIFIED IDEOGRAPH + 0xAE85: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xAE86: 0x7563, //CJK UNIFIED IDEOGRAPH + 0xAE87: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xAE88: 0x7567, //CJK UNIFIED IDEOGRAPH + 0xAE89: 0x7568, //CJK UNIFIED IDEOGRAPH + 0xAE8A: 0x7569, //CJK UNIFIED IDEOGRAPH + 0xAE8B: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xAE8C: 0x756C, //CJK UNIFIED IDEOGRAPH + 0xAE8D: 0x756D, //CJK UNIFIED IDEOGRAPH + 0xAE8E: 0x756E, //CJK UNIFIED IDEOGRAPH + 0xAE8F: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xAE90: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xAE91: 0x7571, //CJK UNIFIED IDEOGRAPH + 0xAE92: 0x7573, //CJK UNIFIED IDEOGRAPH + 0xAE93: 0x7575, //CJK UNIFIED IDEOGRAPH + 0xAE94: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xAE95: 0x7577, //CJK UNIFIED IDEOGRAPH + 0xAE96: 0x757A, //CJK UNIFIED IDEOGRAPH + 0xAE97: 0x757B, //CJK UNIFIED IDEOGRAPH + 0xAE98: 0x757C, //CJK UNIFIED IDEOGRAPH + 0xAE99: 0x757D, //CJK UNIFIED IDEOGRAPH + 0xAE9A: 0x757E, //CJK UNIFIED IDEOGRAPH + 0xAE9B: 0x7580, //CJK UNIFIED IDEOGRAPH + 0xAE9C: 0x7581, //CJK UNIFIED IDEOGRAPH + 0xAE9D: 0x7582, //CJK UNIFIED IDEOGRAPH + 0xAE9E: 0x7584, //CJK UNIFIED IDEOGRAPH + 0xAE9F: 0x7585, //CJK UNIFIED IDEOGRAPH + 0xAEA0: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xAF40: 0x7588, //CJK UNIFIED IDEOGRAPH + 0xAF41: 0x7589, //CJK UNIFIED IDEOGRAPH + 0xAF42: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xAF43: 0x758C, //CJK UNIFIED IDEOGRAPH + 0xAF44: 0x758D, //CJK UNIFIED IDEOGRAPH + 0xAF45: 0x758E, //CJK UNIFIED IDEOGRAPH + 0xAF46: 0x7590, //CJK UNIFIED IDEOGRAPH + 0xAF47: 0x7593, //CJK UNIFIED IDEOGRAPH + 0xAF48: 0x7595, //CJK UNIFIED IDEOGRAPH + 0xAF49: 0x7598, //CJK UNIFIED IDEOGRAPH + 0xAF4A: 0x759B, //CJK UNIFIED IDEOGRAPH + 0xAF4B: 0x759C, //CJK UNIFIED IDEOGRAPH + 0xAF4C: 0x759E, //CJK UNIFIED IDEOGRAPH + 0xAF4D: 0x75A2, //CJK UNIFIED IDEOGRAPH + 0xAF4E: 0x75A6, //CJK UNIFIED IDEOGRAPH + 0xAF4F: 0x75A7, //CJK UNIFIED IDEOGRAPH + 0xAF50: 0x75A8, //CJK UNIFIED IDEOGRAPH + 0xAF51: 0x75A9, //CJK UNIFIED IDEOGRAPH + 0xAF52: 0x75AA, //CJK UNIFIED IDEOGRAPH + 0xAF53: 0x75AD, //CJK UNIFIED IDEOGRAPH + 0xAF54: 0x75B6, //CJK UNIFIED IDEOGRAPH + 0xAF55: 0x75B7, //CJK UNIFIED IDEOGRAPH + 0xAF56: 0x75BA, //CJK UNIFIED IDEOGRAPH + 0xAF57: 0x75BB, //CJK UNIFIED IDEOGRAPH + 0xAF58: 0x75BF, //CJK UNIFIED IDEOGRAPH + 0xAF59: 0x75C0, //CJK UNIFIED IDEOGRAPH + 0xAF5A: 0x75C1, //CJK UNIFIED IDEOGRAPH + 0xAF5B: 0x75C6, //CJK UNIFIED IDEOGRAPH + 0xAF5C: 0x75CB, //CJK UNIFIED IDEOGRAPH + 0xAF5D: 0x75CC, //CJK UNIFIED IDEOGRAPH + 0xAF5E: 0x75CE, //CJK UNIFIED IDEOGRAPH + 0xAF5F: 0x75CF, //CJK UNIFIED IDEOGRAPH + 0xAF60: 0x75D0, //CJK UNIFIED IDEOGRAPH + 0xAF61: 0x75D1, //CJK UNIFIED IDEOGRAPH + 0xAF62: 0x75D3, //CJK UNIFIED IDEOGRAPH + 0xAF63: 0x75D7, //CJK UNIFIED IDEOGRAPH + 0xAF64: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xAF65: 0x75DA, //CJK UNIFIED IDEOGRAPH + 0xAF66: 0x75DC, //CJK UNIFIED IDEOGRAPH + 0xAF67: 0x75DD, //CJK UNIFIED IDEOGRAPH + 0xAF68: 0x75DF, //CJK UNIFIED IDEOGRAPH + 0xAF69: 0x75E0, //CJK UNIFIED IDEOGRAPH + 0xAF6A: 0x75E1, //CJK UNIFIED IDEOGRAPH + 0xAF6B: 0x75E5, //CJK UNIFIED IDEOGRAPH + 0xAF6C: 0x75E9, //CJK UNIFIED IDEOGRAPH + 0xAF6D: 0x75EC, //CJK UNIFIED IDEOGRAPH + 0xAF6E: 0x75ED, //CJK UNIFIED IDEOGRAPH + 0xAF6F: 0x75EE, //CJK UNIFIED IDEOGRAPH + 0xAF70: 0x75EF, //CJK UNIFIED IDEOGRAPH + 0xAF71: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xAF72: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xAF73: 0x75F5, //CJK UNIFIED IDEOGRAPH + 0xAF74: 0x75F6, //CJK UNIFIED IDEOGRAPH + 0xAF75: 0x75F7, //CJK UNIFIED IDEOGRAPH + 0xAF76: 0x75F8, //CJK UNIFIED IDEOGRAPH + 0xAF77: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xAF78: 0x75FB, //CJK UNIFIED IDEOGRAPH + 0xAF79: 0x75FD, //CJK UNIFIED IDEOGRAPH + 0xAF7A: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xAF7B: 0x7602, //CJK UNIFIED IDEOGRAPH + 0xAF7C: 0x7604, //CJK UNIFIED IDEOGRAPH + 0xAF7D: 0x7606, //CJK UNIFIED IDEOGRAPH + 0xAF7E: 0x7607, //CJK UNIFIED IDEOGRAPH + 0xAF80: 0x7608, //CJK UNIFIED IDEOGRAPH + 0xAF81: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xAF82: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xAF83: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xAF84: 0x760E, //CJK UNIFIED IDEOGRAPH + 0xAF85: 0x760F, //CJK UNIFIED IDEOGRAPH + 0xAF86: 0x7611, //CJK UNIFIED IDEOGRAPH + 0xAF87: 0x7612, //CJK UNIFIED IDEOGRAPH + 0xAF88: 0x7613, //CJK UNIFIED IDEOGRAPH + 0xAF89: 0x7614, //CJK UNIFIED IDEOGRAPH + 0xAF8A: 0x7616, //CJK UNIFIED IDEOGRAPH + 0xAF8B: 0x761A, //CJK UNIFIED IDEOGRAPH + 0xAF8C: 0x761C, //CJK UNIFIED IDEOGRAPH + 0xAF8D: 0x761D, //CJK UNIFIED IDEOGRAPH + 0xAF8E: 0x761E, //CJK UNIFIED IDEOGRAPH + 0xAF8F: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xAF90: 0x7623, //CJK UNIFIED IDEOGRAPH + 0xAF91: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xAF92: 0x7628, //CJK UNIFIED IDEOGRAPH + 0xAF93: 0x762C, //CJK UNIFIED IDEOGRAPH + 0xAF94: 0x762E, //CJK UNIFIED IDEOGRAPH + 0xAF95: 0x762F, //CJK UNIFIED IDEOGRAPH + 0xAF96: 0x7631, //CJK UNIFIED IDEOGRAPH + 0xAF97: 0x7632, //CJK UNIFIED IDEOGRAPH + 0xAF98: 0x7636, //CJK UNIFIED IDEOGRAPH + 0xAF99: 0x7637, //CJK UNIFIED IDEOGRAPH + 0xAF9A: 0x7639, //CJK UNIFIED IDEOGRAPH + 0xAF9B: 0x763A, //CJK UNIFIED IDEOGRAPH + 0xAF9C: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xAF9D: 0x763D, //CJK UNIFIED IDEOGRAPH + 0xAF9E: 0x7641, //CJK UNIFIED IDEOGRAPH + 0xAF9F: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xAFA0: 0x7644, //CJK UNIFIED IDEOGRAPH + 0xB040: 0x7645, //CJK UNIFIED IDEOGRAPH + 0xB041: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xB042: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xB043: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xB044: 0x7649, //CJK UNIFIED IDEOGRAPH + 0xB045: 0x764A, //CJK UNIFIED IDEOGRAPH + 0xB046: 0x764B, //CJK UNIFIED IDEOGRAPH + 0xB047: 0x764E, //CJK UNIFIED IDEOGRAPH + 0xB048: 0x764F, //CJK UNIFIED IDEOGRAPH + 0xB049: 0x7650, //CJK UNIFIED IDEOGRAPH + 0xB04A: 0x7651, //CJK UNIFIED IDEOGRAPH + 0xB04B: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xB04C: 0x7653, //CJK UNIFIED IDEOGRAPH + 0xB04D: 0x7655, //CJK UNIFIED IDEOGRAPH + 0xB04E: 0x7657, //CJK UNIFIED IDEOGRAPH + 0xB04F: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xB050: 0x7659, //CJK UNIFIED IDEOGRAPH + 0xB051: 0x765A, //CJK UNIFIED IDEOGRAPH + 0xB052: 0x765B, //CJK UNIFIED IDEOGRAPH + 0xB053: 0x765D, //CJK UNIFIED IDEOGRAPH + 0xB054: 0x765F, //CJK UNIFIED IDEOGRAPH + 0xB055: 0x7660, //CJK UNIFIED IDEOGRAPH + 0xB056: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xB057: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xB058: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xB059: 0x7665, //CJK UNIFIED IDEOGRAPH + 0xB05A: 0x7666, //CJK UNIFIED IDEOGRAPH + 0xB05B: 0x7667, //CJK UNIFIED IDEOGRAPH + 0xB05C: 0x7668, //CJK UNIFIED IDEOGRAPH + 0xB05D: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xB05E: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xB05F: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xB060: 0x766D, //CJK UNIFIED IDEOGRAPH + 0xB061: 0x766E, //CJK UNIFIED IDEOGRAPH + 0xB062: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xB063: 0x7671, //CJK UNIFIED IDEOGRAPH + 0xB064: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xB065: 0x7673, //CJK UNIFIED IDEOGRAPH + 0xB066: 0x7674, //CJK UNIFIED IDEOGRAPH + 0xB067: 0x7675, //CJK UNIFIED IDEOGRAPH + 0xB068: 0x7676, //CJK UNIFIED IDEOGRAPH + 0xB069: 0x7677, //CJK UNIFIED IDEOGRAPH + 0xB06A: 0x7679, //CJK UNIFIED IDEOGRAPH + 0xB06B: 0x767A, //CJK UNIFIED IDEOGRAPH + 0xB06C: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xB06D: 0x767F, //CJK UNIFIED IDEOGRAPH + 0xB06E: 0x7680, //CJK UNIFIED IDEOGRAPH + 0xB06F: 0x7681, //CJK UNIFIED IDEOGRAPH + 0xB070: 0x7683, //CJK UNIFIED IDEOGRAPH + 0xB071: 0x7685, //CJK UNIFIED IDEOGRAPH + 0xB072: 0x7689, //CJK UNIFIED IDEOGRAPH + 0xB073: 0x768A, //CJK UNIFIED IDEOGRAPH + 0xB074: 0x768C, //CJK UNIFIED IDEOGRAPH + 0xB075: 0x768D, //CJK UNIFIED IDEOGRAPH + 0xB076: 0x768F, //CJK UNIFIED IDEOGRAPH + 0xB077: 0x7690, //CJK UNIFIED IDEOGRAPH + 0xB078: 0x7692, //CJK UNIFIED IDEOGRAPH + 0xB079: 0x7694, //CJK UNIFIED IDEOGRAPH + 0xB07A: 0x7695, //CJK UNIFIED IDEOGRAPH + 0xB07B: 0x7697, //CJK UNIFIED IDEOGRAPH + 0xB07C: 0x7698, //CJK UNIFIED IDEOGRAPH + 0xB07D: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xB07E: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xB080: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xB081: 0x769D, //CJK UNIFIED IDEOGRAPH + 0xB082: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xB083: 0x769F, //CJK UNIFIED IDEOGRAPH + 0xB084: 0x76A0, //CJK UNIFIED IDEOGRAPH + 0xB085: 0x76A1, //CJK UNIFIED IDEOGRAPH + 0xB086: 0x76A2, //CJK UNIFIED IDEOGRAPH + 0xB087: 0x76A3, //CJK UNIFIED IDEOGRAPH + 0xB088: 0x76A5, //CJK UNIFIED IDEOGRAPH + 0xB089: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xB08A: 0x76A7, //CJK UNIFIED IDEOGRAPH + 0xB08B: 0x76A8, //CJK UNIFIED IDEOGRAPH + 0xB08C: 0x76A9, //CJK UNIFIED IDEOGRAPH + 0xB08D: 0x76AA, //CJK UNIFIED IDEOGRAPH + 0xB08E: 0x76AB, //CJK UNIFIED IDEOGRAPH + 0xB08F: 0x76AC, //CJK UNIFIED IDEOGRAPH + 0xB090: 0x76AD, //CJK UNIFIED IDEOGRAPH + 0xB091: 0x76AF, //CJK UNIFIED IDEOGRAPH + 0xB092: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xB093: 0x76B3, //CJK UNIFIED IDEOGRAPH + 0xB094: 0x76B5, //CJK UNIFIED IDEOGRAPH + 0xB095: 0x76B6, //CJK UNIFIED IDEOGRAPH + 0xB096: 0x76B7, //CJK UNIFIED IDEOGRAPH + 0xB097: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xB098: 0x76B9, //CJK UNIFIED IDEOGRAPH + 0xB099: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xB09A: 0x76BB, //CJK UNIFIED IDEOGRAPH + 0xB09B: 0x76BC, //CJK UNIFIED IDEOGRAPH + 0xB09C: 0x76BD, //CJK UNIFIED IDEOGRAPH + 0xB09D: 0x76BE, //CJK UNIFIED IDEOGRAPH + 0xB09E: 0x76C0, //CJK UNIFIED IDEOGRAPH + 0xB09F: 0x76C1, //CJK UNIFIED IDEOGRAPH + 0xB0A0: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xB0A1: 0x554A, //CJK UNIFIED IDEOGRAPH + 0xB0A2: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xB0A3: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xB0A4: 0x6328, //CJK UNIFIED IDEOGRAPH + 0xB0A5: 0x54CE, //CJK UNIFIED IDEOGRAPH + 0xB0A6: 0x5509, //CJK UNIFIED IDEOGRAPH + 0xB0A7: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xB0A8: 0x7691, //CJK UNIFIED IDEOGRAPH + 0xB0A9: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xB0AA: 0x853C, //CJK UNIFIED IDEOGRAPH + 0xB0AB: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xB0AC: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xB0AD: 0x788D, //CJK UNIFIED IDEOGRAPH + 0xB0AE: 0x7231, //CJK UNIFIED IDEOGRAPH + 0xB0AF: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xB0B0: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xB0B1: 0x6C28, //CJK UNIFIED IDEOGRAPH + 0xB0B2: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xB0B3: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xB0B4: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xB0B5: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xB0B6: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xB0B7: 0x80FA, //CJK UNIFIED IDEOGRAPH + 0xB0B8: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xB0B9: 0x80AE, //CJK UNIFIED IDEOGRAPH + 0xB0BA: 0x6602, //CJK UNIFIED IDEOGRAPH + 0xB0BB: 0x76CE, //CJK UNIFIED IDEOGRAPH + 0xB0BC: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xB0BD: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xB0BE: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xB0BF: 0x7FF1, //CJK UNIFIED IDEOGRAPH + 0xB0C0: 0x8884, //CJK UNIFIED IDEOGRAPH + 0xB0C1: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xB0C2: 0x5965, //CJK UNIFIED IDEOGRAPH + 0xB0C3: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xB0C4: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xB0C5: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xB0C6: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xB0C7: 0x6252, //CJK UNIFIED IDEOGRAPH + 0xB0C8: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xB0C9: 0x5427, //CJK UNIFIED IDEOGRAPH + 0xB0CA: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xB0CB: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xB0CC: 0x75A4, //CJK UNIFIED IDEOGRAPH + 0xB0CD: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xB0CE: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xB0CF: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xB0D0: 0x9776, //CJK UNIFIED IDEOGRAPH + 0xB0D1: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xB0D2: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xB0D3: 0x575D, //CJK UNIFIED IDEOGRAPH + 0xB0D4: 0x9738, //CJK UNIFIED IDEOGRAPH + 0xB0D5: 0x7F62, //CJK UNIFIED IDEOGRAPH + 0xB0D6: 0x7238, //CJK UNIFIED IDEOGRAPH + 0xB0D7: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xB0D8: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xB0D9: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xB0DA: 0x6446, //CJK UNIFIED IDEOGRAPH + 0xB0DB: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xB0DC: 0x8D25, //CJK UNIFIED IDEOGRAPH + 0xB0DD: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xB0DE: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xB0DF: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xB0E0: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xB0E1: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xB0E2: 0x6273, //CJK UNIFIED IDEOGRAPH + 0xB0E3: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xB0E4: 0x9881, //CJK UNIFIED IDEOGRAPH + 0xB0E5: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xB0E6: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xB0E7: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xB0E8: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xB0E9: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xB0EA: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xB0EB: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xB0EC: 0x529E, //CJK UNIFIED IDEOGRAPH + 0xB0ED: 0x7ECA, //CJK UNIFIED IDEOGRAPH + 0xB0EE: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xB0EF: 0x5E2E, //CJK UNIFIED IDEOGRAPH + 0xB0F0: 0x6886, //CJK UNIFIED IDEOGRAPH + 0xB0F1: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xB0F2: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xB0F3: 0x7ED1, //CJK UNIFIED IDEOGRAPH + 0xB0F4: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xB0F5: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xB0F6: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xB0F7: 0x9551, //CJK UNIFIED IDEOGRAPH + 0xB0F8: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xB0F9: 0x8C24, //CJK UNIFIED IDEOGRAPH + 0xB0FA: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xB0FB: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xB0FC: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xB0FD: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xB0FE: 0x5265, //CJK UNIFIED IDEOGRAPH + 0xB140: 0x76C4, //CJK UNIFIED IDEOGRAPH + 0xB141: 0x76C7, //CJK UNIFIED IDEOGRAPH + 0xB142: 0x76C9, //CJK UNIFIED IDEOGRAPH + 0xB143: 0x76CB, //CJK UNIFIED IDEOGRAPH + 0xB144: 0x76CC, //CJK UNIFIED IDEOGRAPH + 0xB145: 0x76D3, //CJK UNIFIED IDEOGRAPH + 0xB146: 0x76D5, //CJK UNIFIED IDEOGRAPH + 0xB147: 0x76D9, //CJK UNIFIED IDEOGRAPH + 0xB148: 0x76DA, //CJK UNIFIED IDEOGRAPH + 0xB149: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xB14A: 0x76DD, //CJK UNIFIED IDEOGRAPH + 0xB14B: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xB14C: 0x76E0, //CJK UNIFIED IDEOGRAPH + 0xB14D: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xB14E: 0x76E2, //CJK UNIFIED IDEOGRAPH + 0xB14F: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xB150: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xB151: 0x76E6, //CJK UNIFIED IDEOGRAPH + 0xB152: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xB153: 0x76E8, //CJK UNIFIED IDEOGRAPH + 0xB154: 0x76E9, //CJK UNIFIED IDEOGRAPH + 0xB155: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xB156: 0x76EB, //CJK UNIFIED IDEOGRAPH + 0xB157: 0x76EC, //CJK UNIFIED IDEOGRAPH + 0xB158: 0x76ED, //CJK UNIFIED IDEOGRAPH + 0xB159: 0x76F0, //CJK UNIFIED IDEOGRAPH + 0xB15A: 0x76F3, //CJK UNIFIED IDEOGRAPH + 0xB15B: 0x76F5, //CJK UNIFIED IDEOGRAPH + 0xB15C: 0x76F6, //CJK UNIFIED IDEOGRAPH + 0xB15D: 0x76F7, //CJK UNIFIED IDEOGRAPH + 0xB15E: 0x76FA, //CJK UNIFIED IDEOGRAPH + 0xB15F: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xB160: 0x76FD, //CJK UNIFIED IDEOGRAPH + 0xB161: 0x76FF, //CJK UNIFIED IDEOGRAPH + 0xB162: 0x7700, //CJK UNIFIED IDEOGRAPH + 0xB163: 0x7702, //CJK UNIFIED IDEOGRAPH + 0xB164: 0x7703, //CJK UNIFIED IDEOGRAPH + 0xB165: 0x7705, //CJK UNIFIED IDEOGRAPH + 0xB166: 0x7706, //CJK UNIFIED IDEOGRAPH + 0xB167: 0x770A, //CJK UNIFIED IDEOGRAPH + 0xB168: 0x770C, //CJK UNIFIED IDEOGRAPH + 0xB169: 0x770E, //CJK UNIFIED IDEOGRAPH + 0xB16A: 0x770F, //CJK UNIFIED IDEOGRAPH + 0xB16B: 0x7710, //CJK UNIFIED IDEOGRAPH + 0xB16C: 0x7711, //CJK UNIFIED IDEOGRAPH + 0xB16D: 0x7712, //CJK UNIFIED IDEOGRAPH + 0xB16E: 0x7713, //CJK UNIFIED IDEOGRAPH + 0xB16F: 0x7714, //CJK UNIFIED IDEOGRAPH + 0xB170: 0x7715, //CJK UNIFIED IDEOGRAPH + 0xB171: 0x7716, //CJK UNIFIED IDEOGRAPH + 0xB172: 0x7717, //CJK UNIFIED IDEOGRAPH + 0xB173: 0x7718, //CJK UNIFIED IDEOGRAPH + 0xB174: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xB175: 0x771C, //CJK UNIFIED IDEOGRAPH + 0xB176: 0x771D, //CJK UNIFIED IDEOGRAPH + 0xB177: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xB178: 0x7721, //CJK UNIFIED IDEOGRAPH + 0xB179: 0x7723, //CJK UNIFIED IDEOGRAPH + 0xB17A: 0x7724, //CJK UNIFIED IDEOGRAPH + 0xB17B: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xB17C: 0x7727, //CJK UNIFIED IDEOGRAPH + 0xB17D: 0x772A, //CJK UNIFIED IDEOGRAPH + 0xB17E: 0x772B, //CJK UNIFIED IDEOGRAPH + 0xB180: 0x772C, //CJK UNIFIED IDEOGRAPH + 0xB181: 0x772E, //CJK UNIFIED IDEOGRAPH + 0xB182: 0x7730, //CJK UNIFIED IDEOGRAPH + 0xB183: 0x7731, //CJK UNIFIED IDEOGRAPH + 0xB184: 0x7732, //CJK UNIFIED IDEOGRAPH + 0xB185: 0x7733, //CJK UNIFIED IDEOGRAPH + 0xB186: 0x7734, //CJK UNIFIED IDEOGRAPH + 0xB187: 0x7739, //CJK UNIFIED IDEOGRAPH + 0xB188: 0x773B, //CJK UNIFIED IDEOGRAPH + 0xB189: 0x773D, //CJK UNIFIED IDEOGRAPH + 0xB18A: 0x773E, //CJK UNIFIED IDEOGRAPH + 0xB18B: 0x773F, //CJK UNIFIED IDEOGRAPH + 0xB18C: 0x7742, //CJK UNIFIED IDEOGRAPH + 0xB18D: 0x7744, //CJK UNIFIED IDEOGRAPH + 0xB18E: 0x7745, //CJK UNIFIED IDEOGRAPH + 0xB18F: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xB190: 0x7748, //CJK UNIFIED IDEOGRAPH + 0xB191: 0x7749, //CJK UNIFIED IDEOGRAPH + 0xB192: 0x774A, //CJK UNIFIED IDEOGRAPH + 0xB193: 0x774B, //CJK UNIFIED IDEOGRAPH + 0xB194: 0x774C, //CJK UNIFIED IDEOGRAPH + 0xB195: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xB196: 0x774E, //CJK UNIFIED IDEOGRAPH + 0xB197: 0x774F, //CJK UNIFIED IDEOGRAPH + 0xB198: 0x7752, //CJK UNIFIED IDEOGRAPH + 0xB199: 0x7753, //CJK UNIFIED IDEOGRAPH + 0xB19A: 0x7754, //CJK UNIFIED IDEOGRAPH + 0xB19B: 0x7755, //CJK UNIFIED IDEOGRAPH + 0xB19C: 0x7756, //CJK UNIFIED IDEOGRAPH + 0xB19D: 0x7757, //CJK UNIFIED IDEOGRAPH + 0xB19E: 0x7758, //CJK UNIFIED IDEOGRAPH + 0xB19F: 0x7759, //CJK UNIFIED IDEOGRAPH + 0xB1A0: 0x775C, //CJK UNIFIED IDEOGRAPH + 0xB1A1: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xB1A2: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xB1A3: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xB1A4: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xB1A5: 0x9971, //CJK UNIFIED IDEOGRAPH + 0xB1A6: 0x5B9D, //CJK UNIFIED IDEOGRAPH + 0xB1A7: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xB1A8: 0x62A5, //CJK UNIFIED IDEOGRAPH + 0xB1A9: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xB1AA: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xB1AB: 0x9C8D, //CJK UNIFIED IDEOGRAPH + 0xB1AC: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xB1AD: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xB1AE: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xB1AF: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xB1B0: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xB1B1: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xB1B2: 0x8F88, //CJK UNIFIED IDEOGRAPH + 0xB1B3: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xB1B4: 0x8D1D, //CJK UNIFIED IDEOGRAPH + 0xB1B5: 0x94A1, //CJK UNIFIED IDEOGRAPH + 0xB1B6: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xB1B7: 0x72C8, //CJK UNIFIED IDEOGRAPH + 0xB1B8: 0x5907, //CJK UNIFIED IDEOGRAPH + 0xB1B9: 0x60EB, //CJK UNIFIED IDEOGRAPH + 0xB1BA: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xB1BB: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xB1BC: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xB1BD: 0x82EF, //CJK UNIFIED IDEOGRAPH + 0xB1BE: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xB1BF: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xB1C0: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xB1C1: 0x7EF7, //CJK UNIFIED IDEOGRAPH + 0xB1C2: 0x752D, //CJK UNIFIED IDEOGRAPH + 0xB1C3: 0x6CF5, //CJK UNIFIED IDEOGRAPH + 0xB1C4: 0x8E66, //CJK UNIFIED IDEOGRAPH + 0xB1C5: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xB1C6: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xB1C7: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xB1C8: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xB1C9: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xB1CA: 0x7B14, //CJK UNIFIED IDEOGRAPH + 0xB1CB: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xB1CC: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xB1CD: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xB1CE: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xB1CF: 0x6BD5, //CJK UNIFIED IDEOGRAPH + 0xB1D0: 0x6BD9, //CJK UNIFIED IDEOGRAPH + 0xB1D1: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xB1D2: 0x5E01, //CJK UNIFIED IDEOGRAPH + 0xB1D3: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xB1D4: 0x75F9, //CJK UNIFIED IDEOGRAPH + 0xB1D5: 0x95ED, //CJK UNIFIED IDEOGRAPH + 0xB1D6: 0x655D, //CJK UNIFIED IDEOGRAPH + 0xB1D7: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xB1D8: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xB1D9: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xB1DA: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xB1DB: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xB1DC: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xB1DD: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xB1DE: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xB1DF: 0x8FB9, //CJK UNIFIED IDEOGRAPH + 0xB1E0: 0x7F16, //CJK UNIFIED IDEOGRAPH + 0xB1E1: 0x8D2C, //CJK UNIFIED IDEOGRAPH + 0xB1E2: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xB1E3: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xB1E4: 0x53D8, //CJK UNIFIED IDEOGRAPH + 0xB1E5: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xB1E6: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xB1E7: 0x8FA9, //CJK UNIFIED IDEOGRAPH + 0xB1E8: 0x8FAB, //CJK UNIFIED IDEOGRAPH + 0xB1E9: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xB1EA: 0x6807, //CJK UNIFIED IDEOGRAPH + 0xB1EB: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xB1EC: 0x8198, //CJK UNIFIED IDEOGRAPH + 0xB1ED: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xB1EE: 0x9CD6, //CJK UNIFIED IDEOGRAPH + 0xB1EF: 0x618B, //CJK UNIFIED IDEOGRAPH + 0xB1F0: 0x522B, //CJK UNIFIED IDEOGRAPH + 0xB1F1: 0x762A, //CJK UNIFIED IDEOGRAPH + 0xB1F2: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xB1F3: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xB1F4: 0x6FD2, //CJK UNIFIED IDEOGRAPH + 0xB1F5: 0x6EE8, //CJK UNIFIED IDEOGRAPH + 0xB1F6: 0x5BBE, //CJK UNIFIED IDEOGRAPH + 0xB1F7: 0x6448, //CJK UNIFIED IDEOGRAPH + 0xB1F8: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xB1F9: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0xB1FA: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xB1FB: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xB1FC: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xB1FD: 0x997C, //CJK UNIFIED IDEOGRAPH + 0xB1FE: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xB240: 0x775D, //CJK UNIFIED IDEOGRAPH + 0xB241: 0x775E, //CJK UNIFIED IDEOGRAPH + 0xB242: 0x775F, //CJK UNIFIED IDEOGRAPH + 0xB243: 0x7760, //CJK UNIFIED IDEOGRAPH + 0xB244: 0x7764, //CJK UNIFIED IDEOGRAPH + 0xB245: 0x7767, //CJK UNIFIED IDEOGRAPH + 0xB246: 0x7769, //CJK UNIFIED IDEOGRAPH + 0xB247: 0x776A, //CJK UNIFIED IDEOGRAPH + 0xB248: 0x776D, //CJK UNIFIED IDEOGRAPH + 0xB249: 0x776E, //CJK UNIFIED IDEOGRAPH + 0xB24A: 0x776F, //CJK UNIFIED IDEOGRAPH + 0xB24B: 0x7770, //CJK UNIFIED IDEOGRAPH + 0xB24C: 0x7771, //CJK UNIFIED IDEOGRAPH + 0xB24D: 0x7772, //CJK UNIFIED IDEOGRAPH + 0xB24E: 0x7773, //CJK UNIFIED IDEOGRAPH + 0xB24F: 0x7774, //CJK UNIFIED IDEOGRAPH + 0xB250: 0x7775, //CJK UNIFIED IDEOGRAPH + 0xB251: 0x7776, //CJK UNIFIED IDEOGRAPH + 0xB252: 0x7777, //CJK UNIFIED IDEOGRAPH + 0xB253: 0x7778, //CJK UNIFIED IDEOGRAPH + 0xB254: 0x777A, //CJK UNIFIED IDEOGRAPH + 0xB255: 0x777B, //CJK UNIFIED IDEOGRAPH + 0xB256: 0x777C, //CJK UNIFIED IDEOGRAPH + 0xB257: 0x7781, //CJK UNIFIED IDEOGRAPH + 0xB258: 0x7782, //CJK UNIFIED IDEOGRAPH + 0xB259: 0x7783, //CJK UNIFIED IDEOGRAPH + 0xB25A: 0x7786, //CJK UNIFIED IDEOGRAPH + 0xB25B: 0x7787, //CJK UNIFIED IDEOGRAPH + 0xB25C: 0x7788, //CJK UNIFIED IDEOGRAPH + 0xB25D: 0x7789, //CJK UNIFIED IDEOGRAPH + 0xB25E: 0x778A, //CJK UNIFIED IDEOGRAPH + 0xB25F: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xB260: 0x778F, //CJK UNIFIED IDEOGRAPH + 0xB261: 0x7790, //CJK UNIFIED IDEOGRAPH + 0xB262: 0x7793, //CJK UNIFIED IDEOGRAPH + 0xB263: 0x7794, //CJK UNIFIED IDEOGRAPH + 0xB264: 0x7795, //CJK UNIFIED IDEOGRAPH + 0xB265: 0x7796, //CJK UNIFIED IDEOGRAPH + 0xB266: 0x7797, //CJK UNIFIED IDEOGRAPH + 0xB267: 0x7798, //CJK UNIFIED IDEOGRAPH + 0xB268: 0x7799, //CJK UNIFIED IDEOGRAPH + 0xB269: 0x779A, //CJK UNIFIED IDEOGRAPH + 0xB26A: 0x779B, //CJK UNIFIED IDEOGRAPH + 0xB26B: 0x779C, //CJK UNIFIED IDEOGRAPH + 0xB26C: 0x779D, //CJK UNIFIED IDEOGRAPH + 0xB26D: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xB26E: 0x77A1, //CJK UNIFIED IDEOGRAPH + 0xB26F: 0x77A3, //CJK UNIFIED IDEOGRAPH + 0xB270: 0x77A4, //CJK UNIFIED IDEOGRAPH + 0xB271: 0x77A6, //CJK UNIFIED IDEOGRAPH + 0xB272: 0x77A8, //CJK UNIFIED IDEOGRAPH + 0xB273: 0x77AB, //CJK UNIFIED IDEOGRAPH + 0xB274: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xB275: 0x77AE, //CJK UNIFIED IDEOGRAPH + 0xB276: 0x77AF, //CJK UNIFIED IDEOGRAPH + 0xB277: 0x77B1, //CJK UNIFIED IDEOGRAPH + 0xB278: 0x77B2, //CJK UNIFIED IDEOGRAPH + 0xB279: 0x77B4, //CJK UNIFIED IDEOGRAPH + 0xB27A: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xB27B: 0x77B7, //CJK UNIFIED IDEOGRAPH + 0xB27C: 0x77B8, //CJK UNIFIED IDEOGRAPH + 0xB27D: 0x77B9, //CJK UNIFIED IDEOGRAPH + 0xB27E: 0x77BA, //CJK UNIFIED IDEOGRAPH + 0xB280: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xB281: 0x77BE, //CJK UNIFIED IDEOGRAPH + 0xB282: 0x77C0, //CJK UNIFIED IDEOGRAPH + 0xB283: 0x77C1, //CJK UNIFIED IDEOGRAPH + 0xB284: 0x77C2, //CJK UNIFIED IDEOGRAPH + 0xB285: 0x77C3, //CJK UNIFIED IDEOGRAPH + 0xB286: 0x77C4, //CJK UNIFIED IDEOGRAPH + 0xB287: 0x77C5, //CJK UNIFIED IDEOGRAPH + 0xB288: 0x77C6, //CJK UNIFIED IDEOGRAPH + 0xB289: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xB28A: 0x77C8, //CJK UNIFIED IDEOGRAPH + 0xB28B: 0x77C9, //CJK UNIFIED IDEOGRAPH + 0xB28C: 0x77CA, //CJK UNIFIED IDEOGRAPH + 0xB28D: 0x77CB, //CJK UNIFIED IDEOGRAPH + 0xB28E: 0x77CC, //CJK UNIFIED IDEOGRAPH + 0xB28F: 0x77CE, //CJK UNIFIED IDEOGRAPH + 0xB290: 0x77CF, //CJK UNIFIED IDEOGRAPH + 0xB291: 0x77D0, //CJK UNIFIED IDEOGRAPH + 0xB292: 0x77D1, //CJK UNIFIED IDEOGRAPH + 0xB293: 0x77D2, //CJK UNIFIED IDEOGRAPH + 0xB294: 0x77D3, //CJK UNIFIED IDEOGRAPH + 0xB295: 0x77D4, //CJK UNIFIED IDEOGRAPH + 0xB296: 0x77D5, //CJK UNIFIED IDEOGRAPH + 0xB297: 0x77D6, //CJK UNIFIED IDEOGRAPH + 0xB298: 0x77D8, //CJK UNIFIED IDEOGRAPH + 0xB299: 0x77D9, //CJK UNIFIED IDEOGRAPH + 0xB29A: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xB29B: 0x77DD, //CJK UNIFIED IDEOGRAPH + 0xB29C: 0x77DE, //CJK UNIFIED IDEOGRAPH + 0xB29D: 0x77DF, //CJK UNIFIED IDEOGRAPH + 0xB29E: 0x77E0, //CJK UNIFIED IDEOGRAPH + 0xB29F: 0x77E1, //CJK UNIFIED IDEOGRAPH + 0xB2A0: 0x77E4, //CJK UNIFIED IDEOGRAPH + 0xB2A1: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xB2A2: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0xB2A3: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xB2A4: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xB2A5: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xB2A6: 0x62E8, //CJK UNIFIED IDEOGRAPH + 0xB2A7: 0x94B5, //CJK UNIFIED IDEOGRAPH + 0xB2A8: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xB2A9: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xB2AA: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xB2AB: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xB2AC: 0x94C2, //CJK UNIFIED IDEOGRAPH + 0xB2AD: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xB2AE: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xB2AF: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xB2B0: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xB2B1: 0x8116, //CJK UNIFIED IDEOGRAPH + 0xB2B2: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xB2B3: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xB2B4: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xB2B5: 0x9A73, //CJK UNIFIED IDEOGRAPH + 0xB2B6: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xB2B7: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xB2B8: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xB2B9: 0x8865, //CJK UNIFIED IDEOGRAPH + 0xB2BA: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xB2BB: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xB2BC: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xB2BD: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xB2BE: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xB2BF: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xB2C0: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xB2C1: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xB2C2: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xB2C3: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xB2C4: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xB2C5: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xB2C6: 0x8D22, //CJK UNIFIED IDEOGRAPH + 0xB2C7: 0x776C, //CJK UNIFIED IDEOGRAPH + 0xB2C8: 0x8E29, //CJK UNIFIED IDEOGRAPH + 0xB2C9: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xB2CA: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xB2CB: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xB2CC: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xB2CD: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xB2CE: 0x53C2, //CJK UNIFIED IDEOGRAPH + 0xB2CF: 0x8695, //CJK UNIFIED IDEOGRAPH + 0xB2D0: 0x6B8B, //CJK UNIFIED IDEOGRAPH + 0xB2D1: 0x60ED, //CJK UNIFIED IDEOGRAPH + 0xB2D2: 0x60E8, //CJK UNIFIED IDEOGRAPH + 0xB2D3: 0x707F, //CJK UNIFIED IDEOGRAPH + 0xB2D4: 0x82CD, //CJK UNIFIED IDEOGRAPH + 0xB2D5: 0x8231, //CJK UNIFIED IDEOGRAPH + 0xB2D6: 0x4ED3, //CJK UNIFIED IDEOGRAPH + 0xB2D7: 0x6CA7, //CJK UNIFIED IDEOGRAPH + 0xB2D8: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xB2D9: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xB2DA: 0x7CD9, //CJK UNIFIED IDEOGRAPH + 0xB2DB: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xB2DC: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xB2DD: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xB2DE: 0x5395, //CJK UNIFIED IDEOGRAPH + 0xB2DF: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xB2E0: 0x4FA7, //CJK UNIFIED IDEOGRAPH + 0xB2E1: 0x518C, //CJK UNIFIED IDEOGRAPH + 0xB2E2: 0x6D4B, //CJK UNIFIED IDEOGRAPH + 0xB2E3: 0x5C42, //CJK UNIFIED IDEOGRAPH + 0xB2E4: 0x8E6D, //CJK UNIFIED IDEOGRAPH + 0xB2E5: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0xB2E6: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xB2E7: 0x832C, //CJK UNIFIED IDEOGRAPH + 0xB2E8: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xB2E9: 0x67E5, //CJK UNIFIED IDEOGRAPH + 0xB2EA: 0x78B4, //CJK UNIFIED IDEOGRAPH + 0xB2EB: 0x643D, //CJK UNIFIED IDEOGRAPH + 0xB2EC: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xB2ED: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0xB2EE: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xB2EF: 0x8BE7, //CJK UNIFIED IDEOGRAPH + 0xB2F0: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0xB2F1: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xB2F2: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xB2F3: 0x6400, //CJK UNIFIED IDEOGRAPH + 0xB2F4: 0x63BA, //CJK UNIFIED IDEOGRAPH + 0xB2F5: 0x8749, //CJK UNIFIED IDEOGRAPH + 0xB2F6: 0x998B, //CJK UNIFIED IDEOGRAPH + 0xB2F7: 0x8C17, //CJK UNIFIED IDEOGRAPH + 0xB2F8: 0x7F20, //CJK UNIFIED IDEOGRAPH + 0xB2F9: 0x94F2, //CJK UNIFIED IDEOGRAPH + 0xB2FA: 0x4EA7, //CJK UNIFIED IDEOGRAPH + 0xB2FB: 0x9610, //CJK UNIFIED IDEOGRAPH + 0xB2FC: 0x98A4, //CJK UNIFIED IDEOGRAPH + 0xB2FD: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xB2FE: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xB340: 0x77E6, //CJK UNIFIED IDEOGRAPH + 0xB341: 0x77E8, //CJK UNIFIED IDEOGRAPH + 0xB342: 0x77EA, //CJK UNIFIED IDEOGRAPH + 0xB343: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xB344: 0x77F0, //CJK UNIFIED IDEOGRAPH + 0xB345: 0x77F1, //CJK UNIFIED IDEOGRAPH + 0xB346: 0x77F2, //CJK UNIFIED IDEOGRAPH + 0xB347: 0x77F4, //CJK UNIFIED IDEOGRAPH + 0xB348: 0x77F5, //CJK UNIFIED IDEOGRAPH + 0xB349: 0x77F7, //CJK UNIFIED IDEOGRAPH + 0xB34A: 0x77F9, //CJK UNIFIED IDEOGRAPH + 0xB34B: 0x77FA, //CJK UNIFIED IDEOGRAPH + 0xB34C: 0x77FB, //CJK UNIFIED IDEOGRAPH + 0xB34D: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xB34E: 0x7803, //CJK UNIFIED IDEOGRAPH + 0xB34F: 0x7804, //CJK UNIFIED IDEOGRAPH + 0xB350: 0x7805, //CJK UNIFIED IDEOGRAPH + 0xB351: 0x7806, //CJK UNIFIED IDEOGRAPH + 0xB352: 0x7807, //CJK UNIFIED IDEOGRAPH + 0xB353: 0x7808, //CJK UNIFIED IDEOGRAPH + 0xB354: 0x780A, //CJK UNIFIED IDEOGRAPH + 0xB355: 0x780B, //CJK UNIFIED IDEOGRAPH + 0xB356: 0x780E, //CJK UNIFIED IDEOGRAPH + 0xB357: 0x780F, //CJK UNIFIED IDEOGRAPH + 0xB358: 0x7810, //CJK UNIFIED IDEOGRAPH + 0xB359: 0x7813, //CJK UNIFIED IDEOGRAPH + 0xB35A: 0x7815, //CJK UNIFIED IDEOGRAPH + 0xB35B: 0x7819, //CJK UNIFIED IDEOGRAPH + 0xB35C: 0x781B, //CJK UNIFIED IDEOGRAPH + 0xB35D: 0x781E, //CJK UNIFIED IDEOGRAPH + 0xB35E: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xB35F: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xB360: 0x7822, //CJK UNIFIED IDEOGRAPH + 0xB361: 0x7824, //CJK UNIFIED IDEOGRAPH + 0xB362: 0x7828, //CJK UNIFIED IDEOGRAPH + 0xB363: 0x782A, //CJK UNIFIED IDEOGRAPH + 0xB364: 0x782B, //CJK UNIFIED IDEOGRAPH + 0xB365: 0x782E, //CJK UNIFIED IDEOGRAPH + 0xB366: 0x782F, //CJK UNIFIED IDEOGRAPH + 0xB367: 0x7831, //CJK UNIFIED IDEOGRAPH + 0xB368: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xB369: 0x7833, //CJK UNIFIED IDEOGRAPH + 0xB36A: 0x7835, //CJK UNIFIED IDEOGRAPH + 0xB36B: 0x7836, //CJK UNIFIED IDEOGRAPH + 0xB36C: 0x783D, //CJK UNIFIED IDEOGRAPH + 0xB36D: 0x783F, //CJK UNIFIED IDEOGRAPH + 0xB36E: 0x7841, //CJK UNIFIED IDEOGRAPH + 0xB36F: 0x7842, //CJK UNIFIED IDEOGRAPH + 0xB370: 0x7843, //CJK UNIFIED IDEOGRAPH + 0xB371: 0x7844, //CJK UNIFIED IDEOGRAPH + 0xB372: 0x7846, //CJK UNIFIED IDEOGRAPH + 0xB373: 0x7848, //CJK UNIFIED IDEOGRAPH + 0xB374: 0x7849, //CJK UNIFIED IDEOGRAPH + 0xB375: 0x784A, //CJK UNIFIED IDEOGRAPH + 0xB376: 0x784B, //CJK UNIFIED IDEOGRAPH + 0xB377: 0x784D, //CJK UNIFIED IDEOGRAPH + 0xB378: 0x784F, //CJK UNIFIED IDEOGRAPH + 0xB379: 0x7851, //CJK UNIFIED IDEOGRAPH + 0xB37A: 0x7853, //CJK UNIFIED IDEOGRAPH + 0xB37B: 0x7854, //CJK UNIFIED IDEOGRAPH + 0xB37C: 0x7858, //CJK UNIFIED IDEOGRAPH + 0xB37D: 0x7859, //CJK UNIFIED IDEOGRAPH + 0xB37E: 0x785A, //CJK UNIFIED IDEOGRAPH + 0xB380: 0x785B, //CJK UNIFIED IDEOGRAPH + 0xB381: 0x785C, //CJK UNIFIED IDEOGRAPH + 0xB382: 0x785E, //CJK UNIFIED IDEOGRAPH + 0xB383: 0x785F, //CJK UNIFIED IDEOGRAPH + 0xB384: 0x7860, //CJK UNIFIED IDEOGRAPH + 0xB385: 0x7861, //CJK UNIFIED IDEOGRAPH + 0xB386: 0x7862, //CJK UNIFIED IDEOGRAPH + 0xB387: 0x7863, //CJK UNIFIED IDEOGRAPH + 0xB388: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xB389: 0x7865, //CJK UNIFIED IDEOGRAPH + 0xB38A: 0x7866, //CJK UNIFIED IDEOGRAPH + 0xB38B: 0x7867, //CJK UNIFIED IDEOGRAPH + 0xB38C: 0x7868, //CJK UNIFIED IDEOGRAPH + 0xB38D: 0x7869, //CJK UNIFIED IDEOGRAPH + 0xB38E: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xB38F: 0x7870, //CJK UNIFIED IDEOGRAPH + 0xB390: 0x7871, //CJK UNIFIED IDEOGRAPH + 0xB391: 0x7872, //CJK UNIFIED IDEOGRAPH + 0xB392: 0x7873, //CJK UNIFIED IDEOGRAPH + 0xB393: 0x7874, //CJK UNIFIED IDEOGRAPH + 0xB394: 0x7875, //CJK UNIFIED IDEOGRAPH + 0xB395: 0x7876, //CJK UNIFIED IDEOGRAPH + 0xB396: 0x7878, //CJK UNIFIED IDEOGRAPH + 0xB397: 0x7879, //CJK UNIFIED IDEOGRAPH + 0xB398: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xB399: 0x787B, //CJK UNIFIED IDEOGRAPH + 0xB39A: 0x787D, //CJK UNIFIED IDEOGRAPH + 0xB39B: 0x787E, //CJK UNIFIED IDEOGRAPH + 0xB39C: 0x787F, //CJK UNIFIED IDEOGRAPH + 0xB39D: 0x7880, //CJK UNIFIED IDEOGRAPH + 0xB39E: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xB39F: 0x7882, //CJK UNIFIED IDEOGRAPH + 0xB3A0: 0x7883, //CJK UNIFIED IDEOGRAPH + 0xB3A1: 0x573A, //CJK UNIFIED IDEOGRAPH + 0xB3A2: 0x5C1D, //CJK UNIFIED IDEOGRAPH + 0xB3A3: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xB3A4: 0x957F, //CJK UNIFIED IDEOGRAPH + 0xB3A5: 0x507F, //CJK UNIFIED IDEOGRAPH + 0xB3A6: 0x80A0, //CJK UNIFIED IDEOGRAPH + 0xB3A7: 0x5382, //CJK UNIFIED IDEOGRAPH + 0xB3A8: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xB3A9: 0x7545, //CJK UNIFIED IDEOGRAPH + 0xB3AA: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xB3AB: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xB3AC: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xB3AD: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xB3AE: 0x949E, //CJK UNIFIED IDEOGRAPH + 0xB3AF: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xB3B0: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xB3B1: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xB3B2: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xB3B3: 0x5435, //CJK UNIFIED IDEOGRAPH + 0xB3B4: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xB3B5: 0x8F66, //CJK UNIFIED IDEOGRAPH + 0xB3B6: 0x626F, //CJK UNIFIED IDEOGRAPH + 0xB3B7: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xB3B8: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0xB3B9: 0x5F7B, //CJK UNIFIED IDEOGRAPH + 0xB3BA: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xB3BB: 0x90F4, //CJK UNIFIED IDEOGRAPH + 0xB3BC: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xB3BD: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xB3BE: 0x5C18, //CJK UNIFIED IDEOGRAPH + 0xB3BF: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xB3C0: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0xB3C1: 0x6C89, //CJK UNIFIED IDEOGRAPH + 0xB3C2: 0x9648, //CJK UNIFIED IDEOGRAPH + 0xB3C3: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xB3C4: 0x886C, //CJK UNIFIED IDEOGRAPH + 0xB3C5: 0x6491, //CJK UNIFIED IDEOGRAPH + 0xB3C6: 0x79F0, //CJK UNIFIED IDEOGRAPH + 0xB3C7: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xB3C8: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xB3C9: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xB3CA: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xB3CB: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xB3CC: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xB3CD: 0x60E9, //CJK UNIFIED IDEOGRAPH + 0xB3CE: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xB3CF: 0x8BDA, //CJK UNIFIED IDEOGRAPH + 0xB3D0: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xB3D1: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xB3D2: 0x9A8B, //CJK UNIFIED IDEOGRAPH + 0xB3D3: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xB3D4: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xB3D5: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xB3D6: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xB3D7: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xB3D8: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xB3D9: 0x8FDF, //CJK UNIFIED IDEOGRAPH + 0xB3DA: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xB3DB: 0x9A70, //CJK UNIFIED IDEOGRAPH + 0xB3DC: 0x803B, //CJK UNIFIED IDEOGRAPH + 0xB3DD: 0x9F7F, //CJK UNIFIED IDEOGRAPH + 0xB3DE: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xB3DF: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xB3E0: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xB3E1: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xB3E2: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xB3E3: 0x70BD, //CJK UNIFIED IDEOGRAPH + 0xB3E4: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xB3E5: 0x51B2, //CJK UNIFIED IDEOGRAPH + 0xB3E6: 0x866B, //CJK UNIFIED IDEOGRAPH + 0xB3E7: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xB3E8: 0x5BA0, //CJK UNIFIED IDEOGRAPH + 0xB3E9: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xB3EA: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xB3EB: 0x7574, //CJK UNIFIED IDEOGRAPH + 0xB3EC: 0x8E0C, //CJK UNIFIED IDEOGRAPH + 0xB3ED: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xB3EE: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xB3EF: 0x7B79, //CJK UNIFIED IDEOGRAPH + 0xB3F0: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xB3F1: 0x7EF8, //CJK UNIFIED IDEOGRAPH + 0xB3F2: 0x7785, //CJK UNIFIED IDEOGRAPH + 0xB3F3: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xB3F4: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xB3F5: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xB3F6: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xB3F7: 0x6A71, //CJK UNIFIED IDEOGRAPH + 0xB3F8: 0x53A8, //CJK UNIFIED IDEOGRAPH + 0xB3F9: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xB3FA: 0x9504, //CJK UNIFIED IDEOGRAPH + 0xB3FB: 0x96CF, //CJK UNIFIED IDEOGRAPH + 0xB3FC: 0x6EC1, //CJK UNIFIED IDEOGRAPH + 0xB3FD: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xB3FE: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xB440: 0x7884, //CJK UNIFIED IDEOGRAPH + 0xB441: 0x7885, //CJK UNIFIED IDEOGRAPH + 0xB442: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xB443: 0x7888, //CJK UNIFIED IDEOGRAPH + 0xB444: 0x788A, //CJK UNIFIED IDEOGRAPH + 0xB445: 0x788B, //CJK UNIFIED IDEOGRAPH + 0xB446: 0x788F, //CJK UNIFIED IDEOGRAPH + 0xB447: 0x7890, //CJK UNIFIED IDEOGRAPH + 0xB448: 0x7892, //CJK UNIFIED IDEOGRAPH + 0xB449: 0x7894, //CJK UNIFIED IDEOGRAPH + 0xB44A: 0x7895, //CJK UNIFIED IDEOGRAPH + 0xB44B: 0x7896, //CJK UNIFIED IDEOGRAPH + 0xB44C: 0x7899, //CJK UNIFIED IDEOGRAPH + 0xB44D: 0x789D, //CJK UNIFIED IDEOGRAPH + 0xB44E: 0x789E, //CJK UNIFIED IDEOGRAPH + 0xB44F: 0x78A0, //CJK UNIFIED IDEOGRAPH + 0xB450: 0x78A2, //CJK UNIFIED IDEOGRAPH + 0xB451: 0x78A4, //CJK UNIFIED IDEOGRAPH + 0xB452: 0x78A6, //CJK UNIFIED IDEOGRAPH + 0xB453: 0x78A8, //CJK UNIFIED IDEOGRAPH + 0xB454: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xB455: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xB456: 0x78AB, //CJK UNIFIED IDEOGRAPH + 0xB457: 0x78AC, //CJK UNIFIED IDEOGRAPH + 0xB458: 0x78AD, //CJK UNIFIED IDEOGRAPH + 0xB459: 0x78AE, //CJK UNIFIED IDEOGRAPH + 0xB45A: 0x78AF, //CJK UNIFIED IDEOGRAPH + 0xB45B: 0x78B5, //CJK UNIFIED IDEOGRAPH + 0xB45C: 0x78B6, //CJK UNIFIED IDEOGRAPH + 0xB45D: 0x78B7, //CJK UNIFIED IDEOGRAPH + 0xB45E: 0x78B8, //CJK UNIFIED IDEOGRAPH + 0xB45F: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xB460: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xB461: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xB462: 0x78BD, //CJK UNIFIED IDEOGRAPH + 0xB463: 0x78BF, //CJK UNIFIED IDEOGRAPH + 0xB464: 0x78C0, //CJK UNIFIED IDEOGRAPH + 0xB465: 0x78C2, //CJK UNIFIED IDEOGRAPH + 0xB466: 0x78C3, //CJK UNIFIED IDEOGRAPH + 0xB467: 0x78C4, //CJK UNIFIED IDEOGRAPH + 0xB468: 0x78C6, //CJK UNIFIED IDEOGRAPH + 0xB469: 0x78C7, //CJK UNIFIED IDEOGRAPH + 0xB46A: 0x78C8, //CJK UNIFIED IDEOGRAPH + 0xB46B: 0x78CC, //CJK UNIFIED IDEOGRAPH + 0xB46C: 0x78CD, //CJK UNIFIED IDEOGRAPH + 0xB46D: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xB46E: 0x78CF, //CJK UNIFIED IDEOGRAPH + 0xB46F: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xB470: 0x78D2, //CJK UNIFIED IDEOGRAPH + 0xB471: 0x78D3, //CJK UNIFIED IDEOGRAPH + 0xB472: 0x78D6, //CJK UNIFIED IDEOGRAPH + 0xB473: 0x78D7, //CJK UNIFIED IDEOGRAPH + 0xB474: 0x78D8, //CJK UNIFIED IDEOGRAPH + 0xB475: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xB476: 0x78DB, //CJK UNIFIED IDEOGRAPH + 0xB477: 0x78DC, //CJK UNIFIED IDEOGRAPH + 0xB478: 0x78DD, //CJK UNIFIED IDEOGRAPH + 0xB479: 0x78DE, //CJK UNIFIED IDEOGRAPH + 0xB47A: 0x78DF, //CJK UNIFIED IDEOGRAPH + 0xB47B: 0x78E0, //CJK UNIFIED IDEOGRAPH + 0xB47C: 0x78E1, //CJK UNIFIED IDEOGRAPH + 0xB47D: 0x78E2, //CJK UNIFIED IDEOGRAPH + 0xB47E: 0x78E3, //CJK UNIFIED IDEOGRAPH + 0xB480: 0x78E4, //CJK UNIFIED IDEOGRAPH + 0xB481: 0x78E5, //CJK UNIFIED IDEOGRAPH + 0xB482: 0x78E6, //CJK UNIFIED IDEOGRAPH + 0xB483: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xB484: 0x78E9, //CJK UNIFIED IDEOGRAPH + 0xB485: 0x78EA, //CJK UNIFIED IDEOGRAPH + 0xB486: 0x78EB, //CJK UNIFIED IDEOGRAPH + 0xB487: 0x78ED, //CJK UNIFIED IDEOGRAPH + 0xB488: 0x78EE, //CJK UNIFIED IDEOGRAPH + 0xB489: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xB48A: 0x78F0, //CJK UNIFIED IDEOGRAPH + 0xB48B: 0x78F1, //CJK UNIFIED IDEOGRAPH + 0xB48C: 0x78F3, //CJK UNIFIED IDEOGRAPH + 0xB48D: 0x78F5, //CJK UNIFIED IDEOGRAPH + 0xB48E: 0x78F6, //CJK UNIFIED IDEOGRAPH + 0xB48F: 0x78F8, //CJK UNIFIED IDEOGRAPH + 0xB490: 0x78F9, //CJK UNIFIED IDEOGRAPH + 0xB491: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xB492: 0x78FC, //CJK UNIFIED IDEOGRAPH + 0xB493: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xB494: 0x78FE, //CJK UNIFIED IDEOGRAPH + 0xB495: 0x78FF, //CJK UNIFIED IDEOGRAPH + 0xB496: 0x7900, //CJK UNIFIED IDEOGRAPH + 0xB497: 0x7902, //CJK UNIFIED IDEOGRAPH + 0xB498: 0x7903, //CJK UNIFIED IDEOGRAPH + 0xB499: 0x7904, //CJK UNIFIED IDEOGRAPH + 0xB49A: 0x7906, //CJK UNIFIED IDEOGRAPH + 0xB49B: 0x7907, //CJK UNIFIED IDEOGRAPH + 0xB49C: 0x7908, //CJK UNIFIED IDEOGRAPH + 0xB49D: 0x7909, //CJK UNIFIED IDEOGRAPH + 0xB49E: 0x790A, //CJK UNIFIED IDEOGRAPH + 0xB49F: 0x790B, //CJK UNIFIED IDEOGRAPH + 0xB4A0: 0x790C, //CJK UNIFIED IDEOGRAPH + 0xB4A1: 0x7840, //CJK UNIFIED IDEOGRAPH + 0xB4A2: 0x50A8, //CJK UNIFIED IDEOGRAPH + 0xB4A3: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xB4A4: 0x6410, //CJK UNIFIED IDEOGRAPH + 0xB4A5: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0xB4A6: 0x5904, //CJK UNIFIED IDEOGRAPH + 0xB4A7: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0xB4A8: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xB4A9: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xB4AA: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xB4AB: 0x4F20, //CJK UNIFIED IDEOGRAPH + 0xB4AC: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xB4AD: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xB4AE: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xB4AF: 0x75AE, //CJK UNIFIED IDEOGRAPH + 0xB4B0: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xB4B1: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xB4B2: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xB4B3: 0x95EF, //CJK UNIFIED IDEOGRAPH + 0xB4B4: 0x521B, //CJK UNIFIED IDEOGRAPH + 0xB4B5: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xB4B6: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xB4B7: 0x6376, //CJK UNIFIED IDEOGRAPH + 0xB4B8: 0x9524, //CJK UNIFIED IDEOGRAPH + 0xB4B9: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xB4BA: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xB4BB: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xB4BC: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xB4BD: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xB4BE: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xB4BF: 0x7EAF, //CJK UNIFIED IDEOGRAPH + 0xB4C0: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xB4C1: 0x6233, //CJK UNIFIED IDEOGRAPH + 0xB4C2: 0x7EF0, //CJK UNIFIED IDEOGRAPH + 0xB4C3: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xB4C4: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xB4C5: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xB4C6: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xB4C7: 0x8F9E, //CJK UNIFIED IDEOGRAPH + 0xB4C8: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xB4C9: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xB4CA: 0x8BCD, //CJK UNIFIED IDEOGRAPH + 0xB4CB: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xB4CC: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xB4CD: 0x8D50, //CJK UNIFIED IDEOGRAPH + 0xB4CE: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xB4CF: 0x806A, //CJK UNIFIED IDEOGRAPH + 0xB4D0: 0x8471, //CJK UNIFIED IDEOGRAPH + 0xB4D1: 0x56F1, //CJK UNIFIED IDEOGRAPH + 0xB4D2: 0x5306, //CJK UNIFIED IDEOGRAPH + 0xB4D3: 0x4ECE, //CJK UNIFIED IDEOGRAPH + 0xB4D4: 0x4E1B, //CJK UNIFIED IDEOGRAPH + 0xB4D5: 0x51D1, //CJK UNIFIED IDEOGRAPH + 0xB4D6: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xB4D7: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xB4D8: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xB4D9: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xB4DA: 0x8E7F, //CJK UNIFIED IDEOGRAPH + 0xB4DB: 0x7BE1, //CJK UNIFIED IDEOGRAPH + 0xB4DC: 0x7A9C, //CJK UNIFIED IDEOGRAPH + 0xB4DD: 0x6467, //CJK UNIFIED IDEOGRAPH + 0xB4DE: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xB4DF: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xB4E0: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xB4E1: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xB4E2: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xB4E3: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0xB4E4: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xB4E5: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xB4E6: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xB4E7: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xB4E8: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xB4E9: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xB4EA: 0x6413, //CJK UNIFIED IDEOGRAPH + 0xB4EB: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xB4EC: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xB4ED: 0x9519, //CJK UNIFIED IDEOGRAPH + 0xB4EE: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xB4EF: 0x8FBE, //CJK UNIFIED IDEOGRAPH + 0xB4F0: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xB4F1: 0x7629, //CJK UNIFIED IDEOGRAPH + 0xB4F2: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xB4F3: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xB4F4: 0x5446, //CJK UNIFIED IDEOGRAPH + 0xB4F5: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0xB4F6: 0x50A3, //CJK UNIFIED IDEOGRAPH + 0xB4F7: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xB4F8: 0x5E26, //CJK UNIFIED IDEOGRAPH + 0xB4F9: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xB4FA: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xB4FB: 0x8D37, //CJK UNIFIED IDEOGRAPH + 0xB4FC: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xB4FD: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xB4FE: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xB540: 0x790D, //CJK UNIFIED IDEOGRAPH + 0xB541: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xB542: 0x790F, //CJK UNIFIED IDEOGRAPH + 0xB543: 0x7910, //CJK UNIFIED IDEOGRAPH + 0xB544: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xB545: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xB546: 0x7914, //CJK UNIFIED IDEOGRAPH + 0xB547: 0x7915, //CJK UNIFIED IDEOGRAPH + 0xB548: 0x7916, //CJK UNIFIED IDEOGRAPH + 0xB549: 0x7917, //CJK UNIFIED IDEOGRAPH + 0xB54A: 0x7918, //CJK UNIFIED IDEOGRAPH + 0xB54B: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xB54C: 0x791A, //CJK UNIFIED IDEOGRAPH + 0xB54D: 0x791B, //CJK UNIFIED IDEOGRAPH + 0xB54E: 0x791C, //CJK UNIFIED IDEOGRAPH + 0xB54F: 0x791D, //CJK UNIFIED IDEOGRAPH + 0xB550: 0x791F, //CJK UNIFIED IDEOGRAPH + 0xB551: 0x7920, //CJK UNIFIED IDEOGRAPH + 0xB552: 0x7921, //CJK UNIFIED IDEOGRAPH + 0xB553: 0x7922, //CJK UNIFIED IDEOGRAPH + 0xB554: 0x7923, //CJK UNIFIED IDEOGRAPH + 0xB555: 0x7925, //CJK UNIFIED IDEOGRAPH + 0xB556: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xB557: 0x7927, //CJK UNIFIED IDEOGRAPH + 0xB558: 0x7928, //CJK UNIFIED IDEOGRAPH + 0xB559: 0x7929, //CJK UNIFIED IDEOGRAPH + 0xB55A: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xB55B: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xB55C: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xB55D: 0x792D, //CJK UNIFIED IDEOGRAPH + 0xB55E: 0x792E, //CJK UNIFIED IDEOGRAPH + 0xB55F: 0x792F, //CJK UNIFIED IDEOGRAPH + 0xB560: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xB561: 0x7931, //CJK UNIFIED IDEOGRAPH + 0xB562: 0x7932, //CJK UNIFIED IDEOGRAPH + 0xB563: 0x7933, //CJK UNIFIED IDEOGRAPH + 0xB564: 0x7935, //CJK UNIFIED IDEOGRAPH + 0xB565: 0x7936, //CJK UNIFIED IDEOGRAPH + 0xB566: 0x7937, //CJK UNIFIED IDEOGRAPH + 0xB567: 0x7938, //CJK UNIFIED IDEOGRAPH + 0xB568: 0x7939, //CJK UNIFIED IDEOGRAPH + 0xB569: 0x793D, //CJK UNIFIED IDEOGRAPH + 0xB56A: 0x793F, //CJK UNIFIED IDEOGRAPH + 0xB56B: 0x7942, //CJK UNIFIED IDEOGRAPH + 0xB56C: 0x7943, //CJK UNIFIED IDEOGRAPH + 0xB56D: 0x7944, //CJK UNIFIED IDEOGRAPH + 0xB56E: 0x7945, //CJK UNIFIED IDEOGRAPH + 0xB56F: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xB570: 0x794A, //CJK UNIFIED IDEOGRAPH + 0xB571: 0x794B, //CJK UNIFIED IDEOGRAPH + 0xB572: 0x794C, //CJK UNIFIED IDEOGRAPH + 0xB573: 0x794D, //CJK UNIFIED IDEOGRAPH + 0xB574: 0x794E, //CJK UNIFIED IDEOGRAPH + 0xB575: 0x794F, //CJK UNIFIED IDEOGRAPH + 0xB576: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xB577: 0x7951, //CJK UNIFIED IDEOGRAPH + 0xB578: 0x7952, //CJK UNIFIED IDEOGRAPH + 0xB579: 0x7954, //CJK UNIFIED IDEOGRAPH + 0xB57A: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xB57B: 0x7958, //CJK UNIFIED IDEOGRAPH + 0xB57C: 0x7959, //CJK UNIFIED IDEOGRAPH + 0xB57D: 0x7961, //CJK UNIFIED IDEOGRAPH + 0xB57E: 0x7963, //CJK UNIFIED IDEOGRAPH + 0xB580: 0x7964, //CJK UNIFIED IDEOGRAPH + 0xB581: 0x7966, //CJK UNIFIED IDEOGRAPH + 0xB582: 0x7969, //CJK UNIFIED IDEOGRAPH + 0xB583: 0x796A, //CJK UNIFIED IDEOGRAPH + 0xB584: 0x796B, //CJK UNIFIED IDEOGRAPH + 0xB585: 0x796C, //CJK UNIFIED IDEOGRAPH + 0xB586: 0x796E, //CJK UNIFIED IDEOGRAPH + 0xB587: 0x7970, //CJK UNIFIED IDEOGRAPH + 0xB588: 0x7971, //CJK UNIFIED IDEOGRAPH + 0xB589: 0x7972, //CJK UNIFIED IDEOGRAPH + 0xB58A: 0x7973, //CJK UNIFIED IDEOGRAPH + 0xB58B: 0x7974, //CJK UNIFIED IDEOGRAPH + 0xB58C: 0x7975, //CJK UNIFIED IDEOGRAPH + 0xB58D: 0x7976, //CJK UNIFIED IDEOGRAPH + 0xB58E: 0x7979, //CJK UNIFIED IDEOGRAPH + 0xB58F: 0x797B, //CJK UNIFIED IDEOGRAPH + 0xB590: 0x797C, //CJK UNIFIED IDEOGRAPH + 0xB591: 0x797D, //CJK UNIFIED IDEOGRAPH + 0xB592: 0x797E, //CJK UNIFIED IDEOGRAPH + 0xB593: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xB594: 0x7982, //CJK UNIFIED IDEOGRAPH + 0xB595: 0x7983, //CJK UNIFIED IDEOGRAPH + 0xB596: 0x7986, //CJK UNIFIED IDEOGRAPH + 0xB597: 0x7987, //CJK UNIFIED IDEOGRAPH + 0xB598: 0x7988, //CJK UNIFIED IDEOGRAPH + 0xB599: 0x7989, //CJK UNIFIED IDEOGRAPH + 0xB59A: 0x798B, //CJK UNIFIED IDEOGRAPH + 0xB59B: 0x798C, //CJK UNIFIED IDEOGRAPH + 0xB59C: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xB59D: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xB59E: 0x7990, //CJK UNIFIED IDEOGRAPH + 0xB59F: 0x7991, //CJK UNIFIED IDEOGRAPH + 0xB5A0: 0x7992, //CJK UNIFIED IDEOGRAPH + 0xB5A1: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xB5A2: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xB5A3: 0x62C5, //CJK UNIFIED IDEOGRAPH + 0xB5A4: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xB5A5: 0x5355, //CJK UNIFIED IDEOGRAPH + 0xB5A6: 0x90F8, //CJK UNIFIED IDEOGRAPH + 0xB5A7: 0x63B8, //CJK UNIFIED IDEOGRAPH + 0xB5A8: 0x80C6, //CJK UNIFIED IDEOGRAPH + 0xB5A9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xB5AA: 0x6C2E, //CJK UNIFIED IDEOGRAPH + 0xB5AB: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xB5AC: 0x60EE, //CJK UNIFIED IDEOGRAPH + 0xB5AD: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xB5AE: 0x8BDE, //CJK UNIFIED IDEOGRAPH + 0xB5AF: 0x5F39, //CJK UNIFIED IDEOGRAPH + 0xB5B0: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xB5B1: 0x5F53, //CJK UNIFIED IDEOGRAPH + 0xB5B2: 0x6321, //CJK UNIFIED IDEOGRAPH + 0xB5B3: 0x515A, //CJK UNIFIED IDEOGRAPH + 0xB5B4: 0x8361, //CJK UNIFIED IDEOGRAPH + 0xB5B5: 0x6863, //CJK UNIFIED IDEOGRAPH + 0xB5B6: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xB5B7: 0x6363, //CJK UNIFIED IDEOGRAPH + 0xB5B8: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xB5B9: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xB5BA: 0x5C9B, //CJK UNIFIED IDEOGRAPH + 0xB5BB: 0x7977, //CJK UNIFIED IDEOGRAPH + 0xB5BC: 0x5BFC, //CJK UNIFIED IDEOGRAPH + 0xB5BD: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xB5BE: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xB5BF: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xB5C0: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xB5C1: 0x76D7, //CJK UNIFIED IDEOGRAPH + 0xB5C2: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xB5C3: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xB5C4: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xB5C5: 0x8E6C, //CJK UNIFIED IDEOGRAPH + 0xB5C6: 0x706F, //CJK UNIFIED IDEOGRAPH + 0xB5C7: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xB5C8: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xB5C9: 0x77AA, //CJK UNIFIED IDEOGRAPH + 0xB5CA: 0x51F3, //CJK UNIFIED IDEOGRAPH + 0xB5CB: 0x9093, //CJK UNIFIED IDEOGRAPH + 0xB5CC: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xB5CD: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xB5CE: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xB5CF: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xB5D0: 0x654C, //CJK UNIFIED IDEOGRAPH + 0xB5D1: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xB5D2: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xB5D3: 0x6DA4, //CJK UNIFIED IDEOGRAPH + 0xB5D4: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xB5D5: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xB5D6: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xB5D7: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xB5D8: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xB5D9: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xB5DA: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xB5DB: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xB5DC: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xB5DD: 0x9012, //CJK UNIFIED IDEOGRAPH + 0xB5DE: 0x7F14, //CJK UNIFIED IDEOGRAPH + 0xB5DF: 0x98A0, //CJK UNIFIED IDEOGRAPH + 0xB5E0: 0x6382, //CJK UNIFIED IDEOGRAPH + 0xB5E1: 0x6EC7, //CJK UNIFIED IDEOGRAPH + 0xB5E2: 0x7898, //CJK UNIFIED IDEOGRAPH + 0xB5E3: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0xB5E4: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xB5E5: 0x975B, //CJK UNIFIED IDEOGRAPH + 0xB5E6: 0x57AB, //CJK UNIFIED IDEOGRAPH + 0xB5E7: 0x7535, //CJK UNIFIED IDEOGRAPH + 0xB5E8: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xB5E9: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xB5EA: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xB5EB: 0x60E6, //CJK UNIFIED IDEOGRAPH + 0xB5EC: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xB5ED: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xB5EE: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xB5EF: 0x7889, //CJK UNIFIED IDEOGRAPH + 0xB5F0: 0x53FC, //CJK UNIFIED IDEOGRAPH + 0xB5F1: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xB5F2: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xB5F3: 0x5201, //CJK UNIFIED IDEOGRAPH + 0xB5F4: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xB5F5: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xB5F6: 0x9493, //CJK UNIFIED IDEOGRAPH + 0xB5F7: 0x8C03, //CJK UNIFIED IDEOGRAPH + 0xB5F8: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xB5F9: 0x7239, //CJK UNIFIED IDEOGRAPH + 0xB5FA: 0x789F, //CJK UNIFIED IDEOGRAPH + 0xB5FB: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xB5FC: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xB5FD: 0x8C0D, //CJK UNIFIED IDEOGRAPH + 0xB5FE: 0x53E0, //CJK UNIFIED IDEOGRAPH + 0xB640: 0x7993, //CJK UNIFIED IDEOGRAPH + 0xB641: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xB642: 0x7995, //CJK UNIFIED IDEOGRAPH + 0xB643: 0x7996, //CJK UNIFIED IDEOGRAPH + 0xB644: 0x7997, //CJK UNIFIED IDEOGRAPH + 0xB645: 0x7998, //CJK UNIFIED IDEOGRAPH + 0xB646: 0x7999, //CJK UNIFIED IDEOGRAPH + 0xB647: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xB648: 0x799C, //CJK UNIFIED IDEOGRAPH + 0xB649: 0x799D, //CJK UNIFIED IDEOGRAPH + 0xB64A: 0x799E, //CJK UNIFIED IDEOGRAPH + 0xB64B: 0x799F, //CJK UNIFIED IDEOGRAPH + 0xB64C: 0x79A0, //CJK UNIFIED IDEOGRAPH + 0xB64D: 0x79A1, //CJK UNIFIED IDEOGRAPH + 0xB64E: 0x79A2, //CJK UNIFIED IDEOGRAPH + 0xB64F: 0x79A3, //CJK UNIFIED IDEOGRAPH + 0xB650: 0x79A4, //CJK UNIFIED IDEOGRAPH + 0xB651: 0x79A5, //CJK UNIFIED IDEOGRAPH + 0xB652: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xB653: 0x79A8, //CJK UNIFIED IDEOGRAPH + 0xB654: 0x79A9, //CJK UNIFIED IDEOGRAPH + 0xB655: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xB656: 0x79AB, //CJK UNIFIED IDEOGRAPH + 0xB657: 0x79AC, //CJK UNIFIED IDEOGRAPH + 0xB658: 0x79AD, //CJK UNIFIED IDEOGRAPH + 0xB659: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xB65A: 0x79AF, //CJK UNIFIED IDEOGRAPH + 0xB65B: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0xB65C: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xB65D: 0x79B2, //CJK UNIFIED IDEOGRAPH + 0xB65E: 0x79B4, //CJK UNIFIED IDEOGRAPH + 0xB65F: 0x79B5, //CJK UNIFIED IDEOGRAPH + 0xB660: 0x79B6, //CJK UNIFIED IDEOGRAPH + 0xB661: 0x79B7, //CJK UNIFIED IDEOGRAPH + 0xB662: 0x79B8, //CJK UNIFIED IDEOGRAPH + 0xB663: 0x79BC, //CJK UNIFIED IDEOGRAPH + 0xB664: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xB665: 0x79C2, //CJK UNIFIED IDEOGRAPH + 0xB666: 0x79C4, //CJK UNIFIED IDEOGRAPH + 0xB667: 0x79C5, //CJK UNIFIED IDEOGRAPH + 0xB668: 0x79C7, //CJK UNIFIED IDEOGRAPH + 0xB669: 0x79C8, //CJK UNIFIED IDEOGRAPH + 0xB66A: 0x79CA, //CJK UNIFIED IDEOGRAPH + 0xB66B: 0x79CC, //CJK UNIFIED IDEOGRAPH + 0xB66C: 0x79CE, //CJK UNIFIED IDEOGRAPH + 0xB66D: 0x79CF, //CJK UNIFIED IDEOGRAPH + 0xB66E: 0x79D0, //CJK UNIFIED IDEOGRAPH + 0xB66F: 0x79D3, //CJK UNIFIED IDEOGRAPH + 0xB670: 0x79D4, //CJK UNIFIED IDEOGRAPH + 0xB671: 0x79D6, //CJK UNIFIED IDEOGRAPH + 0xB672: 0x79D7, //CJK UNIFIED IDEOGRAPH + 0xB673: 0x79D9, //CJK UNIFIED IDEOGRAPH + 0xB674: 0x79DA, //CJK UNIFIED IDEOGRAPH + 0xB675: 0x79DB, //CJK UNIFIED IDEOGRAPH + 0xB676: 0x79DC, //CJK UNIFIED IDEOGRAPH + 0xB677: 0x79DD, //CJK UNIFIED IDEOGRAPH + 0xB678: 0x79DE, //CJK UNIFIED IDEOGRAPH + 0xB679: 0x79E0, //CJK UNIFIED IDEOGRAPH + 0xB67A: 0x79E1, //CJK UNIFIED IDEOGRAPH + 0xB67B: 0x79E2, //CJK UNIFIED IDEOGRAPH + 0xB67C: 0x79E5, //CJK UNIFIED IDEOGRAPH + 0xB67D: 0x79E8, //CJK UNIFIED IDEOGRAPH + 0xB67E: 0x79EA, //CJK UNIFIED IDEOGRAPH + 0xB680: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xB681: 0x79EE, //CJK UNIFIED IDEOGRAPH + 0xB682: 0x79F1, //CJK UNIFIED IDEOGRAPH + 0xB683: 0x79F2, //CJK UNIFIED IDEOGRAPH + 0xB684: 0x79F3, //CJK UNIFIED IDEOGRAPH + 0xB685: 0x79F4, //CJK UNIFIED IDEOGRAPH + 0xB686: 0x79F5, //CJK UNIFIED IDEOGRAPH + 0xB687: 0x79F6, //CJK UNIFIED IDEOGRAPH + 0xB688: 0x79F7, //CJK UNIFIED IDEOGRAPH + 0xB689: 0x79F9, //CJK UNIFIED IDEOGRAPH + 0xB68A: 0x79FA, //CJK UNIFIED IDEOGRAPH + 0xB68B: 0x79FC, //CJK UNIFIED IDEOGRAPH + 0xB68C: 0x79FE, //CJK UNIFIED IDEOGRAPH + 0xB68D: 0x79FF, //CJK UNIFIED IDEOGRAPH + 0xB68E: 0x7A01, //CJK UNIFIED IDEOGRAPH + 0xB68F: 0x7A04, //CJK UNIFIED IDEOGRAPH + 0xB690: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xB691: 0x7A07, //CJK UNIFIED IDEOGRAPH + 0xB692: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xB693: 0x7A09, //CJK UNIFIED IDEOGRAPH + 0xB694: 0x7A0A, //CJK UNIFIED IDEOGRAPH + 0xB695: 0x7A0C, //CJK UNIFIED IDEOGRAPH + 0xB696: 0x7A0F, //CJK UNIFIED IDEOGRAPH + 0xB697: 0x7A10, //CJK UNIFIED IDEOGRAPH + 0xB698: 0x7A11, //CJK UNIFIED IDEOGRAPH + 0xB699: 0x7A12, //CJK UNIFIED IDEOGRAPH + 0xB69A: 0x7A13, //CJK UNIFIED IDEOGRAPH + 0xB69B: 0x7A15, //CJK UNIFIED IDEOGRAPH + 0xB69C: 0x7A16, //CJK UNIFIED IDEOGRAPH + 0xB69D: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xB69E: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xB69F: 0x7A1B, //CJK UNIFIED IDEOGRAPH + 0xB6A0: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xB6A1: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xB6A2: 0x76EF, //CJK UNIFIED IDEOGRAPH + 0xB6A3: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0xB6A4: 0x9489, //CJK UNIFIED IDEOGRAPH + 0xB6A5: 0x9876, //CJK UNIFIED IDEOGRAPH + 0xB6A6: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xB6A7: 0x952D, //CJK UNIFIED IDEOGRAPH + 0xB6A8: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xB6A9: 0x8BA2, //CJK UNIFIED IDEOGRAPH + 0xB6AA: 0x4E22, //CJK UNIFIED IDEOGRAPH + 0xB6AB: 0x4E1C, //CJK UNIFIED IDEOGRAPH + 0xB6AC: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xB6AD: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xB6AE: 0x61C2, //CJK UNIFIED IDEOGRAPH + 0xB6AF: 0x52A8, //CJK UNIFIED IDEOGRAPH + 0xB6B0: 0x680B, //CJK UNIFIED IDEOGRAPH + 0xB6B1: 0x4F97, //CJK UNIFIED IDEOGRAPH + 0xB6B2: 0x606B, //CJK UNIFIED IDEOGRAPH + 0xB6B3: 0x51BB, //CJK UNIFIED IDEOGRAPH + 0xB6B4: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xB6B5: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xB6B6: 0x6296, //CJK UNIFIED IDEOGRAPH + 0xB6B7: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xB6B8: 0x9661, //CJK UNIFIED IDEOGRAPH + 0xB6B9: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xB6BA: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xB6BB: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xB6BC: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xB6BD: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xB6BE: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xB6BF: 0x728A, //CJK UNIFIED IDEOGRAPH + 0xB6C0: 0x72EC, //CJK UNIFIED IDEOGRAPH + 0xB6C1: 0x8BFB, //CJK UNIFIED IDEOGRAPH + 0xB6C2: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xB6C3: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xB6C4: 0x8D4C, //CJK UNIFIED IDEOGRAPH + 0xB6C5: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xB6C6: 0x9540, //CJK UNIFIED IDEOGRAPH + 0xB6C7: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xB6C8: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xB6C9: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xB6CA: 0x5992, //CJK UNIFIED IDEOGRAPH + 0xB6CB: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xB6CC: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xB6CD: 0x953B, //CJK UNIFIED IDEOGRAPH + 0xB6CE: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xB6CF: 0x65AD, //CJK UNIFIED IDEOGRAPH + 0xB6D0: 0x7F0E, //CJK UNIFIED IDEOGRAPH + 0xB6D1: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xB6D2: 0x5151, //CJK UNIFIED IDEOGRAPH + 0xB6D3: 0x961F, //CJK UNIFIED IDEOGRAPH + 0xB6D4: 0x5BF9, //CJK UNIFIED IDEOGRAPH + 0xB6D5: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xB6D6: 0x5428, //CJK UNIFIED IDEOGRAPH + 0xB6D7: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xB6D8: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xB6D9: 0x987F, //CJK UNIFIED IDEOGRAPH + 0xB6DA: 0x56E4, //CJK UNIFIED IDEOGRAPH + 0xB6DB: 0x949D, //CJK UNIFIED IDEOGRAPH + 0xB6DC: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xB6DD: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xB6DE: 0x6387, //CJK UNIFIED IDEOGRAPH + 0xB6DF: 0x54C6, //CJK UNIFIED IDEOGRAPH + 0xB6E0: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xB6E1: 0x593A, //CJK UNIFIED IDEOGRAPH + 0xB6E2: 0x579B, //CJK UNIFIED IDEOGRAPH + 0xB6E3: 0x8EB2, //CJK UNIFIED IDEOGRAPH + 0xB6E4: 0x6735, //CJK UNIFIED IDEOGRAPH + 0xB6E5: 0x8DFA, //CJK UNIFIED IDEOGRAPH + 0xB6E6: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xB6E7: 0x5241, //CJK UNIFIED IDEOGRAPH + 0xB6E8: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xB6E9: 0x5815, //CJK UNIFIED IDEOGRAPH + 0xB6EA: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xB6EB: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xB6EC: 0x9E45, //CJK UNIFIED IDEOGRAPH + 0xB6ED: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xB6EE: 0x989D, //CJK UNIFIED IDEOGRAPH + 0xB6EF: 0x8BB9, //CJK UNIFIED IDEOGRAPH + 0xB6F0: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xB6F1: 0x6076, //CJK UNIFIED IDEOGRAPH + 0xB6F2: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xB6F3: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xB6F4: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xB6F5: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xB6F6: 0x997F, //CJK UNIFIED IDEOGRAPH + 0xB6F7: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xB6F8: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xB6F9: 0x513F, //CJK UNIFIED IDEOGRAPH + 0xB6FA: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xB6FB: 0x5C14, //CJK UNIFIED IDEOGRAPH + 0xB6FC: 0x9975, //CJK UNIFIED IDEOGRAPH + 0xB6FD: 0x6D31, //CJK UNIFIED IDEOGRAPH + 0xB6FE: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xB740: 0x7A1D, //CJK UNIFIED IDEOGRAPH + 0xB741: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xB742: 0x7A21, //CJK UNIFIED IDEOGRAPH + 0xB743: 0x7A22, //CJK UNIFIED IDEOGRAPH + 0xB744: 0x7A24, //CJK UNIFIED IDEOGRAPH + 0xB745: 0x7A25, //CJK UNIFIED IDEOGRAPH + 0xB746: 0x7A26, //CJK UNIFIED IDEOGRAPH + 0xB747: 0x7A27, //CJK UNIFIED IDEOGRAPH + 0xB748: 0x7A28, //CJK UNIFIED IDEOGRAPH + 0xB749: 0x7A29, //CJK UNIFIED IDEOGRAPH + 0xB74A: 0x7A2A, //CJK UNIFIED IDEOGRAPH + 0xB74B: 0x7A2B, //CJK UNIFIED IDEOGRAPH + 0xB74C: 0x7A2C, //CJK UNIFIED IDEOGRAPH + 0xB74D: 0x7A2D, //CJK UNIFIED IDEOGRAPH + 0xB74E: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xB74F: 0x7A2F, //CJK UNIFIED IDEOGRAPH + 0xB750: 0x7A30, //CJK UNIFIED IDEOGRAPH + 0xB751: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xB752: 0x7A32, //CJK UNIFIED IDEOGRAPH + 0xB753: 0x7A34, //CJK UNIFIED IDEOGRAPH + 0xB754: 0x7A35, //CJK UNIFIED IDEOGRAPH + 0xB755: 0x7A36, //CJK UNIFIED IDEOGRAPH + 0xB756: 0x7A38, //CJK UNIFIED IDEOGRAPH + 0xB757: 0x7A3A, //CJK UNIFIED IDEOGRAPH + 0xB758: 0x7A3E, //CJK UNIFIED IDEOGRAPH + 0xB759: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xB75A: 0x7A41, //CJK UNIFIED IDEOGRAPH + 0xB75B: 0x7A42, //CJK UNIFIED IDEOGRAPH + 0xB75C: 0x7A43, //CJK UNIFIED IDEOGRAPH + 0xB75D: 0x7A44, //CJK UNIFIED IDEOGRAPH + 0xB75E: 0x7A45, //CJK UNIFIED IDEOGRAPH + 0xB75F: 0x7A47, //CJK UNIFIED IDEOGRAPH + 0xB760: 0x7A48, //CJK UNIFIED IDEOGRAPH + 0xB761: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xB762: 0x7A4A, //CJK UNIFIED IDEOGRAPH + 0xB763: 0x7A4B, //CJK UNIFIED IDEOGRAPH + 0xB764: 0x7A4C, //CJK UNIFIED IDEOGRAPH + 0xB765: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xB766: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xB767: 0x7A4F, //CJK UNIFIED IDEOGRAPH + 0xB768: 0x7A50, //CJK UNIFIED IDEOGRAPH + 0xB769: 0x7A52, //CJK UNIFIED IDEOGRAPH + 0xB76A: 0x7A53, //CJK UNIFIED IDEOGRAPH + 0xB76B: 0x7A54, //CJK UNIFIED IDEOGRAPH + 0xB76C: 0x7A55, //CJK UNIFIED IDEOGRAPH + 0xB76D: 0x7A56, //CJK UNIFIED IDEOGRAPH + 0xB76E: 0x7A58, //CJK UNIFIED IDEOGRAPH + 0xB76F: 0x7A59, //CJK UNIFIED IDEOGRAPH + 0xB770: 0x7A5A, //CJK UNIFIED IDEOGRAPH + 0xB771: 0x7A5B, //CJK UNIFIED IDEOGRAPH + 0xB772: 0x7A5C, //CJK UNIFIED IDEOGRAPH + 0xB773: 0x7A5D, //CJK UNIFIED IDEOGRAPH + 0xB774: 0x7A5E, //CJK UNIFIED IDEOGRAPH + 0xB775: 0x7A5F, //CJK UNIFIED IDEOGRAPH + 0xB776: 0x7A60, //CJK UNIFIED IDEOGRAPH + 0xB777: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xB778: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xB779: 0x7A63, //CJK UNIFIED IDEOGRAPH + 0xB77A: 0x7A64, //CJK UNIFIED IDEOGRAPH + 0xB77B: 0x7A65, //CJK UNIFIED IDEOGRAPH + 0xB77C: 0x7A66, //CJK UNIFIED IDEOGRAPH + 0xB77D: 0x7A67, //CJK UNIFIED IDEOGRAPH + 0xB77E: 0x7A68, //CJK UNIFIED IDEOGRAPH + 0xB780: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xB781: 0x7A6A, //CJK UNIFIED IDEOGRAPH + 0xB782: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xB783: 0x7A6C, //CJK UNIFIED IDEOGRAPH + 0xB784: 0x7A6D, //CJK UNIFIED IDEOGRAPH + 0xB785: 0x7A6E, //CJK UNIFIED IDEOGRAPH + 0xB786: 0x7A6F, //CJK UNIFIED IDEOGRAPH + 0xB787: 0x7A71, //CJK UNIFIED IDEOGRAPH + 0xB788: 0x7A72, //CJK UNIFIED IDEOGRAPH + 0xB789: 0x7A73, //CJK UNIFIED IDEOGRAPH + 0xB78A: 0x7A75, //CJK UNIFIED IDEOGRAPH + 0xB78B: 0x7A7B, //CJK UNIFIED IDEOGRAPH + 0xB78C: 0x7A7C, //CJK UNIFIED IDEOGRAPH + 0xB78D: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xB78E: 0x7A7E, //CJK UNIFIED IDEOGRAPH + 0xB78F: 0x7A82, //CJK UNIFIED IDEOGRAPH + 0xB790: 0x7A85, //CJK UNIFIED IDEOGRAPH + 0xB791: 0x7A87, //CJK UNIFIED IDEOGRAPH + 0xB792: 0x7A89, //CJK UNIFIED IDEOGRAPH + 0xB793: 0x7A8A, //CJK UNIFIED IDEOGRAPH + 0xB794: 0x7A8B, //CJK UNIFIED IDEOGRAPH + 0xB795: 0x7A8C, //CJK UNIFIED IDEOGRAPH + 0xB796: 0x7A8E, //CJK UNIFIED IDEOGRAPH + 0xB797: 0x7A8F, //CJK UNIFIED IDEOGRAPH + 0xB798: 0x7A90, //CJK UNIFIED IDEOGRAPH + 0xB799: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0xB79A: 0x7A94, //CJK UNIFIED IDEOGRAPH + 0xB79B: 0x7A99, //CJK UNIFIED IDEOGRAPH + 0xB79C: 0x7A9A, //CJK UNIFIED IDEOGRAPH + 0xB79D: 0x7A9B, //CJK UNIFIED IDEOGRAPH + 0xB79E: 0x7A9E, //CJK UNIFIED IDEOGRAPH + 0xB79F: 0x7AA1, //CJK UNIFIED IDEOGRAPH + 0xB7A0: 0x7AA2, //CJK UNIFIED IDEOGRAPH + 0xB7A1: 0x8D30, //CJK UNIFIED IDEOGRAPH + 0xB7A2: 0x53D1, //CJK UNIFIED IDEOGRAPH + 0xB7A3: 0x7F5A, //CJK UNIFIED IDEOGRAPH + 0xB7A4: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xB7A5: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xB7A6: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xB7A7: 0x9600, //CJK UNIFIED IDEOGRAPH + 0xB7A8: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xB7A9: 0x73D0, //CJK UNIFIED IDEOGRAPH + 0xB7AA: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xB7AB: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xB7AC: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xB7AD: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0xB7AE: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xB7AF: 0x77FE, //CJK UNIFIED IDEOGRAPH + 0xB7B0: 0x9492, //CJK UNIFIED IDEOGRAPH + 0xB7B1: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xB7B2: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xB7B3: 0x70E6, //CJK UNIFIED IDEOGRAPH + 0xB7B4: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xB7B5: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xB7B6: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xB7B7: 0x8D29, //CJK UNIFIED IDEOGRAPH + 0xB7B8: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xB7B9: 0x996D, //CJK UNIFIED IDEOGRAPH + 0xB7BA: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xB7BB: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xB7BC: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xB7BD: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xB7BE: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xB7BF: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xB7C0: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xB7C1: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xB7C2: 0x4EFF, //CJK UNIFIED IDEOGRAPH + 0xB7C3: 0x8BBF, //CJK UNIFIED IDEOGRAPH + 0xB7C4: 0x7EBA, //CJK UNIFIED IDEOGRAPH + 0xB7C5: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xB7C6: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xB7C7: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xB7C8: 0x5561, //CJK UNIFIED IDEOGRAPH + 0xB7C9: 0x98DE, //CJK UNIFIED IDEOGRAPH + 0xB7CA: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xB7CB: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xB7CC: 0x8BFD, //CJK UNIFIED IDEOGRAPH + 0xB7CD: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xB7CE: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xB7CF: 0x5E9F, //CJK UNIFIED IDEOGRAPH + 0xB7D0: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xB7D1: 0x8D39, //CJK UNIFIED IDEOGRAPH + 0xB7D2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xB7D3: 0x915A, //CJK UNIFIED IDEOGRAPH + 0xB7D4: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xB7D5: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0xB7D6: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xB7D7: 0x7EB7, //CJK UNIFIED IDEOGRAPH + 0xB7D8: 0x575F, //CJK UNIFIED IDEOGRAPH + 0xB7D9: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xB7DA: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xB7DB: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xB7DC: 0x594B, //CJK UNIFIED IDEOGRAPH + 0xB7DD: 0x4EFD, //CJK UNIFIED IDEOGRAPH + 0xB7DE: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xB7DF: 0x6124, //CJK UNIFIED IDEOGRAPH + 0xB7E0: 0x7CAA, //CJK UNIFIED IDEOGRAPH + 0xB7E1: 0x4E30, //CJK UNIFIED IDEOGRAPH + 0xB7E2: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xB7E3: 0x67AB, //CJK UNIFIED IDEOGRAPH + 0xB7E4: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xB7E5: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xB7E6: 0x950B, //CJK UNIFIED IDEOGRAPH + 0xB7E7: 0x98CE, //CJK UNIFIED IDEOGRAPH + 0xB7E8: 0x75AF, //CJK UNIFIED IDEOGRAPH + 0xB7E9: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xB7EA: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xB7EB: 0x51AF, //CJK UNIFIED IDEOGRAPH + 0xB7EC: 0x7F1D, //CJK UNIFIED IDEOGRAPH + 0xB7ED: 0x8BBD, //CJK UNIFIED IDEOGRAPH + 0xB7EE: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xB7EF: 0x51E4, //CJK UNIFIED IDEOGRAPH + 0xB7F0: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xB7F1: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xB7F2: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xB7F3: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xB7F4: 0x80A4, //CJK UNIFIED IDEOGRAPH + 0xB7F5: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xB7F6: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xB7F7: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xB7F8: 0x8F90, //CJK UNIFIED IDEOGRAPH + 0xB7F9: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xB7FA: 0x6C1F, //CJK UNIFIED IDEOGRAPH + 0xB7FB: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xB7FC: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xB7FD: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0xB7FE: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xB840: 0x7AA3, //CJK UNIFIED IDEOGRAPH + 0xB841: 0x7AA4, //CJK UNIFIED IDEOGRAPH + 0xB842: 0x7AA7, //CJK UNIFIED IDEOGRAPH + 0xB843: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xB844: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xB845: 0x7AAB, //CJK UNIFIED IDEOGRAPH + 0xB846: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xB847: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xB848: 0x7AB0, //CJK UNIFIED IDEOGRAPH + 0xB849: 0x7AB1, //CJK UNIFIED IDEOGRAPH + 0xB84A: 0x7AB2, //CJK UNIFIED IDEOGRAPH + 0xB84B: 0x7AB4, //CJK UNIFIED IDEOGRAPH + 0xB84C: 0x7AB5, //CJK UNIFIED IDEOGRAPH + 0xB84D: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xB84E: 0x7AB7, //CJK UNIFIED IDEOGRAPH + 0xB84F: 0x7AB8, //CJK UNIFIED IDEOGRAPH + 0xB850: 0x7AB9, //CJK UNIFIED IDEOGRAPH + 0xB851: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xB852: 0x7ABB, //CJK UNIFIED IDEOGRAPH + 0xB853: 0x7ABC, //CJK UNIFIED IDEOGRAPH + 0xB854: 0x7ABD, //CJK UNIFIED IDEOGRAPH + 0xB855: 0x7ABE, //CJK UNIFIED IDEOGRAPH + 0xB856: 0x7AC0, //CJK UNIFIED IDEOGRAPH + 0xB857: 0x7AC1, //CJK UNIFIED IDEOGRAPH + 0xB858: 0x7AC2, //CJK UNIFIED IDEOGRAPH + 0xB859: 0x7AC3, //CJK UNIFIED IDEOGRAPH + 0xB85A: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xB85B: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xB85C: 0x7AC6, //CJK UNIFIED IDEOGRAPH + 0xB85D: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xB85E: 0x7AC8, //CJK UNIFIED IDEOGRAPH + 0xB85F: 0x7AC9, //CJK UNIFIED IDEOGRAPH + 0xB860: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xB861: 0x7ACC, //CJK UNIFIED IDEOGRAPH + 0xB862: 0x7ACD, //CJK UNIFIED IDEOGRAPH + 0xB863: 0x7ACE, //CJK UNIFIED IDEOGRAPH + 0xB864: 0x7ACF, //CJK UNIFIED IDEOGRAPH + 0xB865: 0x7AD0, //CJK UNIFIED IDEOGRAPH + 0xB866: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xB867: 0x7AD2, //CJK UNIFIED IDEOGRAPH + 0xB868: 0x7AD3, //CJK UNIFIED IDEOGRAPH + 0xB869: 0x7AD4, //CJK UNIFIED IDEOGRAPH + 0xB86A: 0x7AD5, //CJK UNIFIED IDEOGRAPH + 0xB86B: 0x7AD7, //CJK UNIFIED IDEOGRAPH + 0xB86C: 0x7AD8, //CJK UNIFIED IDEOGRAPH + 0xB86D: 0x7ADA, //CJK UNIFIED IDEOGRAPH + 0xB86E: 0x7ADB, //CJK UNIFIED IDEOGRAPH + 0xB86F: 0x7ADC, //CJK UNIFIED IDEOGRAPH + 0xB870: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xB871: 0x7AE1, //CJK UNIFIED IDEOGRAPH + 0xB872: 0x7AE2, //CJK UNIFIED IDEOGRAPH + 0xB873: 0x7AE4, //CJK UNIFIED IDEOGRAPH + 0xB874: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xB875: 0x7AE8, //CJK UNIFIED IDEOGRAPH + 0xB876: 0x7AE9, //CJK UNIFIED IDEOGRAPH + 0xB877: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0xB878: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xB879: 0x7AEC, //CJK UNIFIED IDEOGRAPH + 0xB87A: 0x7AEE, //CJK UNIFIED IDEOGRAPH + 0xB87B: 0x7AF0, //CJK UNIFIED IDEOGRAPH + 0xB87C: 0x7AF1, //CJK UNIFIED IDEOGRAPH + 0xB87D: 0x7AF2, //CJK UNIFIED IDEOGRAPH + 0xB87E: 0x7AF3, //CJK UNIFIED IDEOGRAPH + 0xB880: 0x7AF4, //CJK UNIFIED IDEOGRAPH + 0xB881: 0x7AF5, //CJK UNIFIED IDEOGRAPH + 0xB882: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xB883: 0x7AF7, //CJK UNIFIED IDEOGRAPH + 0xB884: 0x7AF8, //CJK UNIFIED IDEOGRAPH + 0xB885: 0x7AFB, //CJK UNIFIED IDEOGRAPH + 0xB886: 0x7AFC, //CJK UNIFIED IDEOGRAPH + 0xB887: 0x7AFE, //CJK UNIFIED IDEOGRAPH + 0xB888: 0x7B00, //CJK UNIFIED IDEOGRAPH + 0xB889: 0x7B01, //CJK UNIFIED IDEOGRAPH + 0xB88A: 0x7B02, //CJK UNIFIED IDEOGRAPH + 0xB88B: 0x7B05, //CJK UNIFIED IDEOGRAPH + 0xB88C: 0x7B07, //CJK UNIFIED IDEOGRAPH + 0xB88D: 0x7B09, //CJK UNIFIED IDEOGRAPH + 0xB88E: 0x7B0C, //CJK UNIFIED IDEOGRAPH + 0xB88F: 0x7B0D, //CJK UNIFIED IDEOGRAPH + 0xB890: 0x7B0E, //CJK UNIFIED IDEOGRAPH + 0xB891: 0x7B10, //CJK UNIFIED IDEOGRAPH + 0xB892: 0x7B12, //CJK UNIFIED IDEOGRAPH + 0xB893: 0x7B13, //CJK UNIFIED IDEOGRAPH + 0xB894: 0x7B16, //CJK UNIFIED IDEOGRAPH + 0xB895: 0x7B17, //CJK UNIFIED IDEOGRAPH + 0xB896: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xB897: 0x7B1A, //CJK UNIFIED IDEOGRAPH + 0xB898: 0x7B1C, //CJK UNIFIED IDEOGRAPH + 0xB899: 0x7B1D, //CJK UNIFIED IDEOGRAPH + 0xB89A: 0x7B1F, //CJK UNIFIED IDEOGRAPH + 0xB89B: 0x7B21, //CJK UNIFIED IDEOGRAPH + 0xB89C: 0x7B22, //CJK UNIFIED IDEOGRAPH + 0xB89D: 0x7B23, //CJK UNIFIED IDEOGRAPH + 0xB89E: 0x7B27, //CJK UNIFIED IDEOGRAPH + 0xB89F: 0x7B29, //CJK UNIFIED IDEOGRAPH + 0xB8A0: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xB8A1: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xB8A2: 0x6DAA, //CJK UNIFIED IDEOGRAPH + 0xB8A3: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xB8A4: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xB8A5: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xB8A6: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xB8A7: 0x629A, //CJK UNIFIED IDEOGRAPH + 0xB8A8: 0x8F85, //CJK UNIFIED IDEOGRAPH + 0xB8A9: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xB8AA: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xB8AB: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xB8AC: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xB8AD: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xB8AE: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xB8AF: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xB8B0: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xB8B1: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xB8B2: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xB8B3: 0x8D4B, //CJK UNIFIED IDEOGRAPH + 0xB8B4: 0x590D, //CJK UNIFIED IDEOGRAPH + 0xB8B5: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xB8B6: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xB8B7: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xB8B8: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xB8B9: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xB8BA: 0x8D1F, //CJK UNIFIED IDEOGRAPH + 0xB8BB: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xB8BC: 0x8BA3, //CJK UNIFIED IDEOGRAPH + 0xB8BD: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xB8BE: 0x5987, //CJK UNIFIED IDEOGRAPH + 0xB8BF: 0x7F1A, //CJK UNIFIED IDEOGRAPH + 0xB8C0: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xB8C1: 0x5676, //CJK UNIFIED IDEOGRAPH + 0xB8C2: 0x560E, //CJK UNIFIED IDEOGRAPH + 0xB8C3: 0x8BE5, //CJK UNIFIED IDEOGRAPH + 0xB8C4: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xB8C5: 0x6982, //CJK UNIFIED IDEOGRAPH + 0xB8C6: 0x9499, //CJK UNIFIED IDEOGRAPH + 0xB8C7: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xB8C8: 0x6E89, //CJK UNIFIED IDEOGRAPH + 0xB8C9: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xB8CA: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xB8CB: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xB8CC: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xB8CD: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xB8CE: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xB8CF: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xB8D0: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xB8D1: 0x79C6, //CJK UNIFIED IDEOGRAPH + 0xB8D2: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xB8D3: 0x8D63, //CJK UNIFIED IDEOGRAPH + 0xB8D4: 0x5188, //CJK UNIFIED IDEOGRAPH + 0xB8D5: 0x521A, //CJK UNIFIED IDEOGRAPH + 0xB8D6: 0x94A2, //CJK UNIFIED IDEOGRAPH + 0xB8D7: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xB8D8: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xB8D9: 0x7EB2, //CJK UNIFIED IDEOGRAPH + 0xB8DA: 0x5C97, //CJK UNIFIED IDEOGRAPH + 0xB8DB: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xB8DC: 0x6760, //CJK UNIFIED IDEOGRAPH + 0xB8DD: 0x7BD9, //CJK UNIFIED IDEOGRAPH + 0xB8DE: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xB8DF: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xB8E0: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xB8E1: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xB8E2: 0x7CD5, //CJK UNIFIED IDEOGRAPH + 0xB8E3: 0x641E, //CJK UNIFIED IDEOGRAPH + 0xB8E4: 0x9550, //CJK UNIFIED IDEOGRAPH + 0xB8E5: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xB8E6: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xB8E7: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xB8E8: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xB8E9: 0x6401, //CJK UNIFIED IDEOGRAPH + 0xB8EA: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xB8EB: 0x9E3D, //CJK UNIFIED IDEOGRAPH + 0xB8EC: 0x80F3, //CJK UNIFIED IDEOGRAPH + 0xB8ED: 0x7599, //CJK UNIFIED IDEOGRAPH + 0xB8EE: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xB8EF: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xB8F0: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xB8F1: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xB8F2: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xB8F3: 0x9601, //CJK UNIFIED IDEOGRAPH + 0xB8F4: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xB8F5: 0x94EC, //CJK UNIFIED IDEOGRAPH + 0xB8F6: 0x4E2A, //CJK UNIFIED IDEOGRAPH + 0xB8F7: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xB8F8: 0x7ED9, //CJK UNIFIED IDEOGRAPH + 0xB8F9: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xB8FA: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xB8FB: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xB8FC: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xB8FD: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xB8FE: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xB940: 0x7B2F, //CJK UNIFIED IDEOGRAPH + 0xB941: 0x7B30, //CJK UNIFIED IDEOGRAPH + 0xB942: 0x7B32, //CJK UNIFIED IDEOGRAPH + 0xB943: 0x7B34, //CJK UNIFIED IDEOGRAPH + 0xB944: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xB945: 0x7B36, //CJK UNIFIED IDEOGRAPH + 0xB946: 0x7B37, //CJK UNIFIED IDEOGRAPH + 0xB947: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0xB948: 0x7B3B, //CJK UNIFIED IDEOGRAPH + 0xB949: 0x7B3D, //CJK UNIFIED IDEOGRAPH + 0xB94A: 0x7B3F, //CJK UNIFIED IDEOGRAPH + 0xB94B: 0x7B40, //CJK UNIFIED IDEOGRAPH + 0xB94C: 0x7B41, //CJK UNIFIED IDEOGRAPH + 0xB94D: 0x7B42, //CJK UNIFIED IDEOGRAPH + 0xB94E: 0x7B43, //CJK UNIFIED IDEOGRAPH + 0xB94F: 0x7B44, //CJK UNIFIED IDEOGRAPH + 0xB950: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xB951: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0xB952: 0x7B4A, //CJK UNIFIED IDEOGRAPH + 0xB953: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xB954: 0x7B4E, //CJK UNIFIED IDEOGRAPH + 0xB955: 0x7B53, //CJK UNIFIED IDEOGRAPH + 0xB956: 0x7B55, //CJK UNIFIED IDEOGRAPH + 0xB957: 0x7B57, //CJK UNIFIED IDEOGRAPH + 0xB958: 0x7B59, //CJK UNIFIED IDEOGRAPH + 0xB959: 0x7B5C, //CJK UNIFIED IDEOGRAPH + 0xB95A: 0x7B5E, //CJK UNIFIED IDEOGRAPH + 0xB95B: 0x7B5F, //CJK UNIFIED IDEOGRAPH + 0xB95C: 0x7B61, //CJK UNIFIED IDEOGRAPH + 0xB95D: 0x7B63, //CJK UNIFIED IDEOGRAPH + 0xB95E: 0x7B64, //CJK UNIFIED IDEOGRAPH + 0xB95F: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xB960: 0x7B66, //CJK UNIFIED IDEOGRAPH + 0xB961: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xB962: 0x7B68, //CJK UNIFIED IDEOGRAPH + 0xB963: 0x7B69, //CJK UNIFIED IDEOGRAPH + 0xB964: 0x7B6A, //CJK UNIFIED IDEOGRAPH + 0xB965: 0x7B6B, //CJK UNIFIED IDEOGRAPH + 0xB966: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xB967: 0x7B6D, //CJK UNIFIED IDEOGRAPH + 0xB968: 0x7B6F, //CJK UNIFIED IDEOGRAPH + 0xB969: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xB96A: 0x7B73, //CJK UNIFIED IDEOGRAPH + 0xB96B: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xB96C: 0x7B76, //CJK UNIFIED IDEOGRAPH + 0xB96D: 0x7B78, //CJK UNIFIED IDEOGRAPH + 0xB96E: 0x7B7A, //CJK UNIFIED IDEOGRAPH + 0xB96F: 0x7B7C, //CJK UNIFIED IDEOGRAPH + 0xB970: 0x7B7D, //CJK UNIFIED IDEOGRAPH + 0xB971: 0x7B7F, //CJK UNIFIED IDEOGRAPH + 0xB972: 0x7B81, //CJK UNIFIED IDEOGRAPH + 0xB973: 0x7B82, //CJK UNIFIED IDEOGRAPH + 0xB974: 0x7B83, //CJK UNIFIED IDEOGRAPH + 0xB975: 0x7B84, //CJK UNIFIED IDEOGRAPH + 0xB976: 0x7B86, //CJK UNIFIED IDEOGRAPH + 0xB977: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xB978: 0x7B88, //CJK UNIFIED IDEOGRAPH + 0xB979: 0x7B89, //CJK UNIFIED IDEOGRAPH + 0xB97A: 0x7B8A, //CJK UNIFIED IDEOGRAPH + 0xB97B: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xB97C: 0x7B8C, //CJK UNIFIED IDEOGRAPH + 0xB97D: 0x7B8E, //CJK UNIFIED IDEOGRAPH + 0xB97E: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xB980: 0x7B91, //CJK UNIFIED IDEOGRAPH + 0xB981: 0x7B92, //CJK UNIFIED IDEOGRAPH + 0xB982: 0x7B93, //CJK UNIFIED IDEOGRAPH + 0xB983: 0x7B96, //CJK UNIFIED IDEOGRAPH + 0xB984: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xB985: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xB986: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xB987: 0x7B9B, //CJK UNIFIED IDEOGRAPH + 0xB988: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xB989: 0x7B9F, //CJK UNIFIED IDEOGRAPH + 0xB98A: 0x7BA0, //CJK UNIFIED IDEOGRAPH + 0xB98B: 0x7BA3, //CJK UNIFIED IDEOGRAPH + 0xB98C: 0x7BA4, //CJK UNIFIED IDEOGRAPH + 0xB98D: 0x7BA5, //CJK UNIFIED IDEOGRAPH + 0xB98E: 0x7BAE, //CJK UNIFIED IDEOGRAPH + 0xB98F: 0x7BAF, //CJK UNIFIED IDEOGRAPH + 0xB990: 0x7BB0, //CJK UNIFIED IDEOGRAPH + 0xB991: 0x7BB2, //CJK UNIFIED IDEOGRAPH + 0xB992: 0x7BB3, //CJK UNIFIED IDEOGRAPH + 0xB993: 0x7BB5, //CJK UNIFIED IDEOGRAPH + 0xB994: 0x7BB6, //CJK UNIFIED IDEOGRAPH + 0xB995: 0x7BB7, //CJK UNIFIED IDEOGRAPH + 0xB996: 0x7BB9, //CJK UNIFIED IDEOGRAPH + 0xB997: 0x7BBA, //CJK UNIFIED IDEOGRAPH + 0xB998: 0x7BBB, //CJK UNIFIED IDEOGRAPH + 0xB999: 0x7BBC, //CJK UNIFIED IDEOGRAPH + 0xB99A: 0x7BBD, //CJK UNIFIED IDEOGRAPH + 0xB99B: 0x7BBE, //CJK UNIFIED IDEOGRAPH + 0xB99C: 0x7BBF, //CJK UNIFIED IDEOGRAPH + 0xB99D: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xB99E: 0x7BC2, //CJK UNIFIED IDEOGRAPH + 0xB99F: 0x7BC3, //CJK UNIFIED IDEOGRAPH + 0xB9A0: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xB9A1: 0x57C2, //CJK UNIFIED IDEOGRAPH + 0xB9A2: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xB9A3: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xB9A4: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xB9A5: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xB9A6: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xB9A7: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xB9A8: 0x9F9A, //CJK UNIFIED IDEOGRAPH + 0xB9A9: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xB9AA: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xB9AB: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xB9AC: 0x5BAB, //CJK UNIFIED IDEOGRAPH + 0xB9AD: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xB9AE: 0x5DE9, //CJK UNIFIED IDEOGRAPH + 0xB9AF: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xB9B0: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xB9B1: 0x8D21, //CJK UNIFIED IDEOGRAPH + 0xB9B2: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xB9B3: 0x94A9, //CJK UNIFIED IDEOGRAPH + 0xB9B4: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xB9B5: 0x6C9F, //CJK UNIFIED IDEOGRAPH + 0xB9B6: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xB9B7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xB9B8: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xB9B9: 0x6784, //CJK UNIFIED IDEOGRAPH + 0xB9BA: 0x8D2D, //CJK UNIFIED IDEOGRAPH + 0xB9BB: 0x591F, //CJK UNIFIED IDEOGRAPH + 0xB9BC: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xB9BD: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xB9BE: 0x5495, //CJK UNIFIED IDEOGRAPH + 0xB9BF: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xB9C0: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0xB9C1: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xB9C2: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xB9C3: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xB9C4: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xB9C5: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xB9C6: 0x86CA, //CJK UNIFIED IDEOGRAPH + 0xB9C7: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xB9C8: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xB9C9: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xB9CA: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xB9CB: 0x987E, //CJK UNIFIED IDEOGRAPH + 0xB9CC: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xB9CD: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xB9CE: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xB9CF: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xB9D0: 0x5250, //CJK UNIFIED IDEOGRAPH + 0xB9D1: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xB9D2: 0x6302, //CJK UNIFIED IDEOGRAPH + 0xB9D3: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xB9D4: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xB9D5: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xB9D6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xB9D7: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xB9D8: 0x5173, //CJK UNIFIED IDEOGRAPH + 0xB9D9: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xB9DA: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xB9DB: 0x89C2, //CJK UNIFIED IDEOGRAPH + 0xB9DC: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xB9DD: 0x9986, //CJK UNIFIED IDEOGRAPH + 0xB9DE: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xB9DF: 0x60EF, //CJK UNIFIED IDEOGRAPH + 0xB9E0: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xB9E1: 0x8D2F, //CJK UNIFIED IDEOGRAPH + 0xB9E2: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xB9E3: 0x5E7F, //CJK UNIFIED IDEOGRAPH + 0xB9E4: 0x901B, //CJK UNIFIED IDEOGRAPH + 0xB9E5: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xB9E6: 0x89C4, //CJK UNIFIED IDEOGRAPH + 0xB9E7: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xB9E8: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xB9E9: 0x5F52, //CJK UNIFIED IDEOGRAPH + 0xB9EA: 0x9F9F, //CJK UNIFIED IDEOGRAPH + 0xB9EB: 0x95FA, //CJK UNIFIED IDEOGRAPH + 0xB9EC: 0x8F68, //CJK UNIFIED IDEOGRAPH + 0xB9ED: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xB9EE: 0x8BE1, //CJK UNIFIED IDEOGRAPH + 0xB9EF: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xB9F0: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xB9F1: 0x67DC, //CJK UNIFIED IDEOGRAPH + 0xB9F2: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xB9F3: 0x8D35, //CJK UNIFIED IDEOGRAPH + 0xB9F4: 0x523D, //CJK UNIFIED IDEOGRAPH + 0xB9F5: 0x8F8A, //CJK UNIFIED IDEOGRAPH + 0xB9F6: 0x6EDA, //CJK UNIFIED IDEOGRAPH + 0xB9F7: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xB9F8: 0x9505, //CJK UNIFIED IDEOGRAPH + 0xB9F9: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xB9FA: 0x56FD, //CJK UNIFIED IDEOGRAPH + 0xB9FB: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xB9FC: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xB9FD: 0x8FC7, //CJK UNIFIED IDEOGRAPH + 0xB9FE: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xBA40: 0x7BC5, //CJK UNIFIED IDEOGRAPH + 0xBA41: 0x7BC8, //CJK UNIFIED IDEOGRAPH + 0xBA42: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xBA43: 0x7BCA, //CJK UNIFIED IDEOGRAPH + 0xBA44: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xBA45: 0x7BCD, //CJK UNIFIED IDEOGRAPH + 0xBA46: 0x7BCE, //CJK UNIFIED IDEOGRAPH + 0xBA47: 0x7BCF, //CJK UNIFIED IDEOGRAPH + 0xBA48: 0x7BD0, //CJK UNIFIED IDEOGRAPH + 0xBA49: 0x7BD2, //CJK UNIFIED IDEOGRAPH + 0xBA4A: 0x7BD4, //CJK UNIFIED IDEOGRAPH + 0xBA4B: 0x7BD5, //CJK UNIFIED IDEOGRAPH + 0xBA4C: 0x7BD6, //CJK UNIFIED IDEOGRAPH + 0xBA4D: 0x7BD7, //CJK UNIFIED IDEOGRAPH + 0xBA4E: 0x7BD8, //CJK UNIFIED IDEOGRAPH + 0xBA4F: 0x7BDB, //CJK UNIFIED IDEOGRAPH + 0xBA50: 0x7BDC, //CJK UNIFIED IDEOGRAPH + 0xBA51: 0x7BDE, //CJK UNIFIED IDEOGRAPH + 0xBA52: 0x7BDF, //CJK UNIFIED IDEOGRAPH + 0xBA53: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xBA54: 0x7BE2, //CJK UNIFIED IDEOGRAPH + 0xBA55: 0x7BE3, //CJK UNIFIED IDEOGRAPH + 0xBA56: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xBA57: 0x7BE7, //CJK UNIFIED IDEOGRAPH + 0xBA58: 0x7BE8, //CJK UNIFIED IDEOGRAPH + 0xBA59: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xBA5A: 0x7BEB, //CJK UNIFIED IDEOGRAPH + 0xBA5B: 0x7BEC, //CJK UNIFIED IDEOGRAPH + 0xBA5C: 0x7BED, //CJK UNIFIED IDEOGRAPH + 0xBA5D: 0x7BEF, //CJK UNIFIED IDEOGRAPH + 0xBA5E: 0x7BF0, //CJK UNIFIED IDEOGRAPH + 0xBA5F: 0x7BF2, //CJK UNIFIED IDEOGRAPH + 0xBA60: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xBA61: 0x7BF4, //CJK UNIFIED IDEOGRAPH + 0xBA62: 0x7BF5, //CJK UNIFIED IDEOGRAPH + 0xBA63: 0x7BF6, //CJK UNIFIED IDEOGRAPH + 0xBA64: 0x7BF8, //CJK UNIFIED IDEOGRAPH + 0xBA65: 0x7BF9, //CJK UNIFIED IDEOGRAPH + 0xBA66: 0x7BFA, //CJK UNIFIED IDEOGRAPH + 0xBA67: 0x7BFB, //CJK UNIFIED IDEOGRAPH + 0xBA68: 0x7BFD, //CJK UNIFIED IDEOGRAPH + 0xBA69: 0x7BFF, //CJK UNIFIED IDEOGRAPH + 0xBA6A: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xBA6B: 0x7C01, //CJK UNIFIED IDEOGRAPH + 0xBA6C: 0x7C02, //CJK UNIFIED IDEOGRAPH + 0xBA6D: 0x7C03, //CJK UNIFIED IDEOGRAPH + 0xBA6E: 0x7C04, //CJK UNIFIED IDEOGRAPH + 0xBA6F: 0x7C05, //CJK UNIFIED IDEOGRAPH + 0xBA70: 0x7C06, //CJK UNIFIED IDEOGRAPH + 0xBA71: 0x7C08, //CJK UNIFIED IDEOGRAPH + 0xBA72: 0x7C09, //CJK UNIFIED IDEOGRAPH + 0xBA73: 0x7C0A, //CJK UNIFIED IDEOGRAPH + 0xBA74: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xBA75: 0x7C0E, //CJK UNIFIED IDEOGRAPH + 0xBA76: 0x7C10, //CJK UNIFIED IDEOGRAPH + 0xBA77: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xBA78: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0xBA79: 0x7C13, //CJK UNIFIED IDEOGRAPH + 0xBA7A: 0x7C14, //CJK UNIFIED IDEOGRAPH + 0xBA7B: 0x7C15, //CJK UNIFIED IDEOGRAPH + 0xBA7C: 0x7C17, //CJK UNIFIED IDEOGRAPH + 0xBA7D: 0x7C18, //CJK UNIFIED IDEOGRAPH + 0xBA7E: 0x7C19, //CJK UNIFIED IDEOGRAPH + 0xBA80: 0x7C1A, //CJK UNIFIED IDEOGRAPH + 0xBA81: 0x7C1B, //CJK UNIFIED IDEOGRAPH + 0xBA82: 0x7C1C, //CJK UNIFIED IDEOGRAPH + 0xBA83: 0x7C1D, //CJK UNIFIED IDEOGRAPH + 0xBA84: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xBA85: 0x7C20, //CJK UNIFIED IDEOGRAPH + 0xBA86: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xBA87: 0x7C22, //CJK UNIFIED IDEOGRAPH + 0xBA88: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xBA89: 0x7C24, //CJK UNIFIED IDEOGRAPH + 0xBA8A: 0x7C25, //CJK UNIFIED IDEOGRAPH + 0xBA8B: 0x7C28, //CJK UNIFIED IDEOGRAPH + 0xBA8C: 0x7C29, //CJK UNIFIED IDEOGRAPH + 0xBA8D: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xBA8E: 0x7C2C, //CJK UNIFIED IDEOGRAPH + 0xBA8F: 0x7C2D, //CJK UNIFIED IDEOGRAPH + 0xBA90: 0x7C2E, //CJK UNIFIED IDEOGRAPH + 0xBA91: 0x7C2F, //CJK UNIFIED IDEOGRAPH + 0xBA92: 0x7C30, //CJK UNIFIED IDEOGRAPH + 0xBA93: 0x7C31, //CJK UNIFIED IDEOGRAPH + 0xBA94: 0x7C32, //CJK UNIFIED IDEOGRAPH + 0xBA95: 0x7C33, //CJK UNIFIED IDEOGRAPH + 0xBA96: 0x7C34, //CJK UNIFIED IDEOGRAPH + 0xBA97: 0x7C35, //CJK UNIFIED IDEOGRAPH + 0xBA98: 0x7C36, //CJK UNIFIED IDEOGRAPH + 0xBA99: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xBA9A: 0x7C39, //CJK UNIFIED IDEOGRAPH + 0xBA9B: 0x7C3A, //CJK UNIFIED IDEOGRAPH + 0xBA9C: 0x7C3B, //CJK UNIFIED IDEOGRAPH + 0xBA9D: 0x7C3C, //CJK UNIFIED IDEOGRAPH + 0xBA9E: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xBA9F: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xBAA0: 0x7C42, //CJK UNIFIED IDEOGRAPH + 0xBAA1: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xBAA2: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xBAA3: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xBAA4: 0x6C26, //CJK UNIFIED IDEOGRAPH + 0xBAA5: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xBAA6: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xBAA7: 0x9A87, //CJK UNIFIED IDEOGRAPH + 0xBAA8: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xBAA9: 0x61A8, //CJK UNIFIED IDEOGRAPH + 0xBAAA: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xBAAB: 0x97E9, //CJK UNIFIED IDEOGRAPH + 0xBAAC: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xBAAD: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xBAAE: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xBAAF: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xBAB0: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xBAB1: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xBAB2: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xBAB3: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0xBAB4: 0x634D, //CJK UNIFIED IDEOGRAPH + 0xBAB5: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xBAB6: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xBAB7: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xBAB8: 0x710A, //CJK UNIFIED IDEOGRAPH + 0xBAB9: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xBABA: 0x6C49, //CJK UNIFIED IDEOGRAPH + 0xBABB: 0x592F, //CJK UNIFIED IDEOGRAPH + 0xBABC: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xBABD: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xBABE: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xBABF: 0x568E, //CJK UNIFIED IDEOGRAPH + 0xBAC0: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xBAC1: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xBAC2: 0x90DD, //CJK UNIFIED IDEOGRAPH + 0xBAC3: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xBAC4: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xBAC5: 0x53F7, //CJK UNIFIED IDEOGRAPH + 0xBAC6: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xBAC7: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xBAC8: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xBAC9: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xBACA: 0x83CF, //CJK UNIFIED IDEOGRAPH + 0xBACB: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xBACC: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xBACD: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xBACE: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xBACF: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xBAD0: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xBAD1: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xBAD2: 0x9602, //CJK UNIFIED IDEOGRAPH + 0xBAD3: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xBAD4: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0xBAD5: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xBAD6: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xBAD7: 0x9E64, //CJK UNIFIED IDEOGRAPH + 0xBAD8: 0x8D3A, //CJK UNIFIED IDEOGRAPH + 0xBAD9: 0x563F, //CJK UNIFIED IDEOGRAPH + 0xBADA: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xBADB: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xBADC: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0xBADD: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xBADE: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xBADF: 0x54FC, //CJK UNIFIED IDEOGRAPH + 0xBAE0: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xBAE1: 0x6A2A, //CJK UNIFIED IDEOGRAPH + 0xBAE2: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xBAE3: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xBAE4: 0x8F70, //CJK UNIFIED IDEOGRAPH + 0xBAE5: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xBAE6: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xBAE7: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xBAE8: 0x9E3F, //CJK UNIFIED IDEOGRAPH + 0xBAE9: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xBAEA: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xBAEB: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xBAEC: 0x7EA2, //CJK UNIFIED IDEOGRAPH + 0xBAED: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xBAEE: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xBAEF: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xBAF0: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xBAF1: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xBAF2: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xBAF3: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xBAF4: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xBAF5: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xBAF6: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xBAF7: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xBAF8: 0x58F6, //CJK UNIFIED IDEOGRAPH + 0xBAF9: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xBAFA: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xBAFB: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xBAFC: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xBAFD: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xBAFE: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xBB40: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xBB41: 0x7C44, //CJK UNIFIED IDEOGRAPH + 0xBB42: 0x7C45, //CJK UNIFIED IDEOGRAPH + 0xBB43: 0x7C46, //CJK UNIFIED IDEOGRAPH + 0xBB44: 0x7C47, //CJK UNIFIED IDEOGRAPH + 0xBB45: 0x7C48, //CJK UNIFIED IDEOGRAPH + 0xBB46: 0x7C49, //CJK UNIFIED IDEOGRAPH + 0xBB47: 0x7C4A, //CJK UNIFIED IDEOGRAPH + 0xBB48: 0x7C4B, //CJK UNIFIED IDEOGRAPH + 0xBB49: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xBB4A: 0x7C4E, //CJK UNIFIED IDEOGRAPH + 0xBB4B: 0x7C4F, //CJK UNIFIED IDEOGRAPH + 0xBB4C: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xBB4D: 0x7C51, //CJK UNIFIED IDEOGRAPH + 0xBB4E: 0x7C52, //CJK UNIFIED IDEOGRAPH + 0xBB4F: 0x7C53, //CJK UNIFIED IDEOGRAPH + 0xBB50: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xBB51: 0x7C55, //CJK UNIFIED IDEOGRAPH + 0xBB52: 0x7C56, //CJK UNIFIED IDEOGRAPH + 0xBB53: 0x7C57, //CJK UNIFIED IDEOGRAPH + 0xBB54: 0x7C58, //CJK UNIFIED IDEOGRAPH + 0xBB55: 0x7C59, //CJK UNIFIED IDEOGRAPH + 0xBB56: 0x7C5A, //CJK UNIFIED IDEOGRAPH + 0xBB57: 0x7C5B, //CJK UNIFIED IDEOGRAPH + 0xBB58: 0x7C5C, //CJK UNIFIED IDEOGRAPH + 0xBB59: 0x7C5D, //CJK UNIFIED IDEOGRAPH + 0xBB5A: 0x7C5E, //CJK UNIFIED IDEOGRAPH + 0xBB5B: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xBB5C: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xBB5D: 0x7C61, //CJK UNIFIED IDEOGRAPH + 0xBB5E: 0x7C62, //CJK UNIFIED IDEOGRAPH + 0xBB5F: 0x7C63, //CJK UNIFIED IDEOGRAPH + 0xBB60: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xBB61: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xBB62: 0x7C66, //CJK UNIFIED IDEOGRAPH + 0xBB63: 0x7C67, //CJK UNIFIED IDEOGRAPH + 0xBB64: 0x7C68, //CJK UNIFIED IDEOGRAPH + 0xBB65: 0x7C69, //CJK UNIFIED IDEOGRAPH + 0xBB66: 0x7C6A, //CJK UNIFIED IDEOGRAPH + 0xBB67: 0x7C6B, //CJK UNIFIED IDEOGRAPH + 0xBB68: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xBB69: 0x7C6D, //CJK UNIFIED IDEOGRAPH + 0xBB6A: 0x7C6E, //CJK UNIFIED IDEOGRAPH + 0xBB6B: 0x7C6F, //CJK UNIFIED IDEOGRAPH + 0xBB6C: 0x7C70, //CJK UNIFIED IDEOGRAPH + 0xBB6D: 0x7C71, //CJK UNIFIED IDEOGRAPH + 0xBB6E: 0x7C72, //CJK UNIFIED IDEOGRAPH + 0xBB6F: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xBB70: 0x7C76, //CJK UNIFIED IDEOGRAPH + 0xBB71: 0x7C77, //CJK UNIFIED IDEOGRAPH + 0xBB72: 0x7C78, //CJK UNIFIED IDEOGRAPH + 0xBB73: 0x7C79, //CJK UNIFIED IDEOGRAPH + 0xBB74: 0x7C7A, //CJK UNIFIED IDEOGRAPH + 0xBB75: 0x7C7E, //CJK UNIFIED IDEOGRAPH + 0xBB76: 0x7C7F, //CJK UNIFIED IDEOGRAPH + 0xBB77: 0x7C80, //CJK UNIFIED IDEOGRAPH + 0xBB78: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0xBB79: 0x7C82, //CJK UNIFIED IDEOGRAPH + 0xBB7A: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xBB7B: 0x7C84, //CJK UNIFIED IDEOGRAPH + 0xBB7C: 0x7C85, //CJK UNIFIED IDEOGRAPH + 0xBB7D: 0x7C86, //CJK UNIFIED IDEOGRAPH + 0xBB7E: 0x7C87, //CJK UNIFIED IDEOGRAPH + 0xBB80: 0x7C88, //CJK UNIFIED IDEOGRAPH + 0xBB81: 0x7C8A, //CJK UNIFIED IDEOGRAPH + 0xBB82: 0x7C8B, //CJK UNIFIED IDEOGRAPH + 0xBB83: 0x7C8C, //CJK UNIFIED IDEOGRAPH + 0xBB84: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0xBB85: 0x7C8E, //CJK UNIFIED IDEOGRAPH + 0xBB86: 0x7C8F, //CJK UNIFIED IDEOGRAPH + 0xBB87: 0x7C90, //CJK UNIFIED IDEOGRAPH + 0xBB88: 0x7C93, //CJK UNIFIED IDEOGRAPH + 0xBB89: 0x7C94, //CJK UNIFIED IDEOGRAPH + 0xBB8A: 0x7C96, //CJK UNIFIED IDEOGRAPH + 0xBB8B: 0x7C99, //CJK UNIFIED IDEOGRAPH + 0xBB8C: 0x7C9A, //CJK UNIFIED IDEOGRAPH + 0xBB8D: 0x7C9B, //CJK UNIFIED IDEOGRAPH + 0xBB8E: 0x7CA0, //CJK UNIFIED IDEOGRAPH + 0xBB8F: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xBB90: 0x7CA3, //CJK UNIFIED IDEOGRAPH + 0xBB91: 0x7CA6, //CJK UNIFIED IDEOGRAPH + 0xBB92: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xBB93: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xBB94: 0x7CA9, //CJK UNIFIED IDEOGRAPH + 0xBB95: 0x7CAB, //CJK UNIFIED IDEOGRAPH + 0xBB96: 0x7CAC, //CJK UNIFIED IDEOGRAPH + 0xBB97: 0x7CAD, //CJK UNIFIED IDEOGRAPH + 0xBB98: 0x7CAF, //CJK UNIFIED IDEOGRAPH + 0xBB99: 0x7CB0, //CJK UNIFIED IDEOGRAPH + 0xBB9A: 0x7CB4, //CJK UNIFIED IDEOGRAPH + 0xBB9B: 0x7CB5, //CJK UNIFIED IDEOGRAPH + 0xBB9C: 0x7CB6, //CJK UNIFIED IDEOGRAPH + 0xBB9D: 0x7CB7, //CJK UNIFIED IDEOGRAPH + 0xBB9E: 0x7CB8, //CJK UNIFIED IDEOGRAPH + 0xBB9F: 0x7CBA, //CJK UNIFIED IDEOGRAPH + 0xBBA0: 0x7CBB, //CJK UNIFIED IDEOGRAPH + 0xBBA1: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xBBA2: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xBBA3: 0x552C, //CJK UNIFIED IDEOGRAPH + 0xBBA4: 0x62A4, //CJK UNIFIED IDEOGRAPH + 0xBBA5: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xBBA6: 0x6CAA, //CJK UNIFIED IDEOGRAPH + 0xBBA7: 0x6237, //CJK UNIFIED IDEOGRAPH + 0xBBA8: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xBBA9: 0x54D7, //CJK UNIFIED IDEOGRAPH + 0xBBAA: 0x534E, //CJK UNIFIED IDEOGRAPH + 0xBBAB: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xBBAC: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xBBAD: 0x753B, //CJK UNIFIED IDEOGRAPH + 0xBBAE: 0x5212, //CJK UNIFIED IDEOGRAPH + 0xBBAF: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xBBB0: 0x8BDD, //CJK UNIFIED IDEOGRAPH + 0xBBB1: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xBBB2: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xBBB3: 0x6000, //CJK UNIFIED IDEOGRAPH + 0xBBB4: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xBBB5: 0x574F, //CJK UNIFIED IDEOGRAPH + 0xBBB6: 0x6B22, //CJK UNIFIED IDEOGRAPH + 0xBBB7: 0x73AF, //CJK UNIFIED IDEOGRAPH + 0xBBB8: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xBBB9: 0x8FD8, //CJK UNIFIED IDEOGRAPH + 0xBBBA: 0x7F13, //CJK UNIFIED IDEOGRAPH + 0xBBBB: 0x6362, //CJK UNIFIED IDEOGRAPH + 0xBBBC: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xBBBD: 0x5524, //CJK UNIFIED IDEOGRAPH + 0xBBBE: 0x75EA, //CJK UNIFIED IDEOGRAPH + 0xBBBF: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xBBC0: 0x7115, //CJK UNIFIED IDEOGRAPH + 0xBBC1: 0x6DA3, //CJK UNIFIED IDEOGRAPH + 0xBBC2: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xBBC3: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xBBC4: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xBBC5: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xBBC6: 0x9EC4, //CJK UNIFIED IDEOGRAPH + 0xBBC7: 0x78FA, //CJK UNIFIED IDEOGRAPH + 0xBBC8: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xBBC9: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xBBCA: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xBBCB: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xBBCC: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xBBCD: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xBBCE: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xBBCF: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xBBD0: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xBBD1: 0x8C0E, //CJK UNIFIED IDEOGRAPH + 0xBBD2: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xBBD3: 0x6325, //CJK UNIFIED IDEOGRAPH + 0xBBD4: 0x8F89, //CJK UNIFIED IDEOGRAPH + 0xBBD5: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xBBD6: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xBBD7: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xBBD8: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xBBD9: 0x6BC1, //CJK UNIFIED IDEOGRAPH + 0xBBDA: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xBBDB: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xBBDC: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xBBDD: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xBBDE: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xBBDF: 0x8D3F, //CJK UNIFIED IDEOGRAPH + 0xBBE0: 0x79FD, //CJK UNIFIED IDEOGRAPH + 0xBBE1: 0x4F1A, //CJK UNIFIED IDEOGRAPH + 0xBBE2: 0x70E9, //CJK UNIFIED IDEOGRAPH + 0xBBE3: 0x6C47, //CJK UNIFIED IDEOGRAPH + 0xBBE4: 0x8BB3, //CJK UNIFIED IDEOGRAPH + 0xBBE5: 0x8BF2, //CJK UNIFIED IDEOGRAPH + 0xBBE6: 0x7ED8, //CJK UNIFIED IDEOGRAPH + 0xBBE7: 0x8364, //CJK UNIFIED IDEOGRAPH + 0xBBE8: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xBBE9: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xBBEA: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xBBEB: 0x6D51, //CJK UNIFIED IDEOGRAPH + 0xBBEC: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xBBED: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xBBEE: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xBBEF: 0x4F19, //CJK UNIFIED IDEOGRAPH + 0xBBF0: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xBBF1: 0x83B7, //CJK UNIFIED IDEOGRAPH + 0xBBF2: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xBBF3: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xBBF4: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xBBF5: 0x8D27, //CJK UNIFIED IDEOGRAPH + 0xBBF6: 0x7978, //CJK UNIFIED IDEOGRAPH + 0xBBF7: 0x51FB, //CJK UNIFIED IDEOGRAPH + 0xBBF8: 0x573E, //CJK UNIFIED IDEOGRAPH + 0xBBF9: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xBBFA: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xBBFB: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xBBFC: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xBBFD: 0x79EF, //CJK UNIFIED IDEOGRAPH + 0xBBFE: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xBC40: 0x7CBF, //CJK UNIFIED IDEOGRAPH + 0xBC41: 0x7CC0, //CJK UNIFIED IDEOGRAPH + 0xBC42: 0x7CC2, //CJK UNIFIED IDEOGRAPH + 0xBC43: 0x7CC3, //CJK UNIFIED IDEOGRAPH + 0xBC44: 0x7CC4, //CJK UNIFIED IDEOGRAPH + 0xBC45: 0x7CC6, //CJK UNIFIED IDEOGRAPH + 0xBC46: 0x7CC9, //CJK UNIFIED IDEOGRAPH + 0xBC47: 0x7CCB, //CJK UNIFIED IDEOGRAPH + 0xBC48: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0xBC49: 0x7CCF, //CJK UNIFIED IDEOGRAPH + 0xBC4A: 0x7CD0, //CJK UNIFIED IDEOGRAPH + 0xBC4B: 0x7CD1, //CJK UNIFIED IDEOGRAPH + 0xBC4C: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xBC4D: 0x7CD3, //CJK UNIFIED IDEOGRAPH + 0xBC4E: 0x7CD4, //CJK UNIFIED IDEOGRAPH + 0xBC4F: 0x7CD8, //CJK UNIFIED IDEOGRAPH + 0xBC50: 0x7CDA, //CJK UNIFIED IDEOGRAPH + 0xBC51: 0x7CDB, //CJK UNIFIED IDEOGRAPH + 0xBC52: 0x7CDD, //CJK UNIFIED IDEOGRAPH + 0xBC53: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xBC54: 0x7CE1, //CJK UNIFIED IDEOGRAPH + 0xBC55: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xBC56: 0x7CE3, //CJK UNIFIED IDEOGRAPH + 0xBC57: 0x7CE4, //CJK UNIFIED IDEOGRAPH + 0xBC58: 0x7CE5, //CJK UNIFIED IDEOGRAPH + 0xBC59: 0x7CE6, //CJK UNIFIED IDEOGRAPH + 0xBC5A: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xBC5B: 0x7CE9, //CJK UNIFIED IDEOGRAPH + 0xBC5C: 0x7CEA, //CJK UNIFIED IDEOGRAPH + 0xBC5D: 0x7CEB, //CJK UNIFIED IDEOGRAPH + 0xBC5E: 0x7CEC, //CJK UNIFIED IDEOGRAPH + 0xBC5F: 0x7CED, //CJK UNIFIED IDEOGRAPH + 0xBC60: 0x7CEE, //CJK UNIFIED IDEOGRAPH + 0xBC61: 0x7CF0, //CJK UNIFIED IDEOGRAPH + 0xBC62: 0x7CF1, //CJK UNIFIED IDEOGRAPH + 0xBC63: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xBC64: 0x7CF3, //CJK UNIFIED IDEOGRAPH + 0xBC65: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xBC66: 0x7CF5, //CJK UNIFIED IDEOGRAPH + 0xBC67: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xBC68: 0x7CF7, //CJK UNIFIED IDEOGRAPH + 0xBC69: 0x7CF9, //CJK UNIFIED IDEOGRAPH + 0xBC6A: 0x7CFA, //CJK UNIFIED IDEOGRAPH + 0xBC6B: 0x7CFC, //CJK UNIFIED IDEOGRAPH + 0xBC6C: 0x7CFD, //CJK UNIFIED IDEOGRAPH + 0xBC6D: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xBC6E: 0x7CFF, //CJK UNIFIED IDEOGRAPH + 0xBC6F: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xBC70: 0x7D01, //CJK UNIFIED IDEOGRAPH + 0xBC71: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xBC72: 0x7D03, //CJK UNIFIED IDEOGRAPH + 0xBC73: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xBC74: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xBC75: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xBC76: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xBC77: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xBC78: 0x7D09, //CJK UNIFIED IDEOGRAPH + 0xBC79: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xBC7A: 0x7D0C, //CJK UNIFIED IDEOGRAPH + 0xBC7B: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xBC7C: 0x7D0E, //CJK UNIFIED IDEOGRAPH + 0xBC7D: 0x7D0F, //CJK UNIFIED IDEOGRAPH + 0xBC7E: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xBC80: 0x7D11, //CJK UNIFIED IDEOGRAPH + 0xBC81: 0x7D12, //CJK UNIFIED IDEOGRAPH + 0xBC82: 0x7D13, //CJK UNIFIED IDEOGRAPH + 0xBC83: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xBC84: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xBC85: 0x7D16, //CJK UNIFIED IDEOGRAPH + 0xBC86: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xBC87: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xBC88: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xBC89: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xBC8A: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xBC8B: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xBC8C: 0x7D1D, //CJK UNIFIED IDEOGRAPH + 0xBC8D: 0x7D1E, //CJK UNIFIED IDEOGRAPH + 0xBC8E: 0x7D1F, //CJK UNIFIED IDEOGRAPH + 0xBC8F: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xBC90: 0x7D23, //CJK UNIFIED IDEOGRAPH + 0xBC91: 0x7D24, //CJK UNIFIED IDEOGRAPH + 0xBC92: 0x7D25, //CJK UNIFIED IDEOGRAPH + 0xBC93: 0x7D26, //CJK UNIFIED IDEOGRAPH + 0xBC94: 0x7D28, //CJK UNIFIED IDEOGRAPH + 0xBC95: 0x7D29, //CJK UNIFIED IDEOGRAPH + 0xBC96: 0x7D2A, //CJK UNIFIED IDEOGRAPH + 0xBC97: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xBC98: 0x7D2D, //CJK UNIFIED IDEOGRAPH + 0xBC99: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xBC9A: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xBC9B: 0x7D31, //CJK UNIFIED IDEOGRAPH + 0xBC9C: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xBC9D: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xBC9E: 0x7D34, //CJK UNIFIED IDEOGRAPH + 0xBC9F: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xBCA0: 0x7D36, //CJK UNIFIED IDEOGRAPH + 0xBCA1: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xBCA2: 0x9965, //CJK UNIFIED IDEOGRAPH + 0xBCA3: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xBCA4: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xBCA5: 0x8BA5, //CJK UNIFIED IDEOGRAPH + 0xBCA6: 0x9E21, //CJK UNIFIED IDEOGRAPH + 0xBCA7: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xBCA8: 0x7EE9, //CJK UNIFIED IDEOGRAPH + 0xBCA9: 0x7F09, //CJK UNIFIED IDEOGRAPH + 0xBCAA: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xBCAB: 0x6781, //CJK UNIFIED IDEOGRAPH + 0xBCAC: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xBCAD: 0x8F91, //CJK UNIFIED IDEOGRAPH + 0xBCAE: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xBCAF: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xBCB0: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xBCB1: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xBCB2: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xBCB3: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xBCB4: 0x5373, //CJK UNIFIED IDEOGRAPH + 0xBCB5: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xBCB6: 0x7EA7, //CJK UNIFIED IDEOGRAPH + 0xBCB7: 0x6324, //CJK UNIFIED IDEOGRAPH + 0xBCB8: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0xBCB9: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xBCBA: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xBCBB: 0x84DF, //CJK UNIFIED IDEOGRAPH + 0xBCBC: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xBCBD: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xBCBE: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xBCBF: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xBCC0: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xBCC1: 0x5242, //CJK UNIFIED IDEOGRAPH + 0xBCC2: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xBCC3: 0x6D4E, //CJK UNIFIED IDEOGRAPH + 0xBCC4: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xBCC5: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xBCC6: 0x8BA1, //CJK UNIFIED IDEOGRAPH + 0xBCC7: 0x8BB0, //CJK UNIFIED IDEOGRAPH + 0xBCC8: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0xBCC9: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xBCCA: 0x9645, //CJK UNIFIED IDEOGRAPH + 0xBCCB: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xBCCC: 0x7EE7, //CJK UNIFIED IDEOGRAPH + 0xBCCD: 0x7EAA, //CJK UNIFIED IDEOGRAPH + 0xBCCE: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xBCCF: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xBCD0: 0x5939, //CJK UNIFIED IDEOGRAPH + 0xBCD1: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xBCD2: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xBCD3: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xBCD4: 0x835A, //CJK UNIFIED IDEOGRAPH + 0xBCD5: 0x988A, //CJK UNIFIED IDEOGRAPH + 0xBCD6: 0x8D3E, //CJK UNIFIED IDEOGRAPH + 0xBCD7: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xBCD8: 0x94BE, //CJK UNIFIED IDEOGRAPH + 0xBCD9: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xBCDA: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xBCDB: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xBCDC: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xBCDD: 0x9A7E, //CJK UNIFIED IDEOGRAPH + 0xBCDE: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xBCDF: 0x6B7C, //CJK UNIFIED IDEOGRAPH + 0xBCE0: 0x76D1, //CJK UNIFIED IDEOGRAPH + 0xBCE1: 0x575A, //CJK UNIFIED IDEOGRAPH + 0xBCE2: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xBCE3: 0x7B3A, //CJK UNIFIED IDEOGRAPH + 0xBCE4: 0x95F4, //CJK UNIFIED IDEOGRAPH + 0xBCE5: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xBCE6: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xBCE7: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xBCE8: 0x8270, //CJK UNIFIED IDEOGRAPH + 0xBCE9: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xBCEA: 0x7F04, //CJK UNIFIED IDEOGRAPH + 0xBCEB: 0x8327, //CJK UNIFIED IDEOGRAPH + 0xBCEC: 0x68C0, //CJK UNIFIED IDEOGRAPH + 0xBCED: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xBCEE: 0x78B1, //CJK UNIFIED IDEOGRAPH + 0xBCEF: 0x7877, //CJK UNIFIED IDEOGRAPH + 0xBCF0: 0x62E3, //CJK UNIFIED IDEOGRAPH + 0xBCF1: 0x6361, //CJK UNIFIED IDEOGRAPH + 0xBCF2: 0x7B80, //CJK UNIFIED IDEOGRAPH + 0xBCF3: 0x4FED, //CJK UNIFIED IDEOGRAPH + 0xBCF4: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xBCF5: 0x51CF, //CJK UNIFIED IDEOGRAPH + 0xBCF6: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xBCF7: 0x69DB, //CJK UNIFIED IDEOGRAPH + 0xBCF8: 0x9274, //CJK UNIFIED IDEOGRAPH + 0xBCF9: 0x8DF5, //CJK UNIFIED IDEOGRAPH + 0xBCFA: 0x8D31, //CJK UNIFIED IDEOGRAPH + 0xBCFB: 0x89C1, //CJK UNIFIED IDEOGRAPH + 0xBCFC: 0x952E, //CJK UNIFIED IDEOGRAPH + 0xBCFD: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xBCFE: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xBD40: 0x7D37, //CJK UNIFIED IDEOGRAPH + 0xBD41: 0x7D38, //CJK UNIFIED IDEOGRAPH + 0xBD42: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xBD43: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xBD44: 0x7D3B, //CJK UNIFIED IDEOGRAPH + 0xBD45: 0x7D3C, //CJK UNIFIED IDEOGRAPH + 0xBD46: 0x7D3D, //CJK UNIFIED IDEOGRAPH + 0xBD47: 0x7D3E, //CJK UNIFIED IDEOGRAPH + 0xBD48: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xBD49: 0x7D40, //CJK UNIFIED IDEOGRAPH + 0xBD4A: 0x7D41, //CJK UNIFIED IDEOGRAPH + 0xBD4B: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xBD4C: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xBD4D: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xBD4E: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xBD4F: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xBD50: 0x7D47, //CJK UNIFIED IDEOGRAPH + 0xBD51: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xBD52: 0x7D49, //CJK UNIFIED IDEOGRAPH + 0xBD53: 0x7D4A, //CJK UNIFIED IDEOGRAPH + 0xBD54: 0x7D4B, //CJK UNIFIED IDEOGRAPH + 0xBD55: 0x7D4C, //CJK UNIFIED IDEOGRAPH + 0xBD56: 0x7D4D, //CJK UNIFIED IDEOGRAPH + 0xBD57: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xBD58: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xBD59: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xBD5A: 0x7D51, //CJK UNIFIED IDEOGRAPH + 0xBD5B: 0x7D52, //CJK UNIFIED IDEOGRAPH + 0xBD5C: 0x7D53, //CJK UNIFIED IDEOGRAPH + 0xBD5D: 0x7D54, //CJK UNIFIED IDEOGRAPH + 0xBD5E: 0x7D55, //CJK UNIFIED IDEOGRAPH + 0xBD5F: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xBD60: 0x7D57, //CJK UNIFIED IDEOGRAPH + 0xBD61: 0x7D58, //CJK UNIFIED IDEOGRAPH + 0xBD62: 0x7D59, //CJK UNIFIED IDEOGRAPH + 0xBD63: 0x7D5A, //CJK UNIFIED IDEOGRAPH + 0xBD64: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xBD65: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xBD66: 0x7D5D, //CJK UNIFIED IDEOGRAPH + 0xBD67: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xBD68: 0x7D5F, //CJK UNIFIED IDEOGRAPH + 0xBD69: 0x7D60, //CJK UNIFIED IDEOGRAPH + 0xBD6A: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xBD6B: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xBD6C: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xBD6D: 0x7D64, //CJK UNIFIED IDEOGRAPH + 0xBD6E: 0x7D65, //CJK UNIFIED IDEOGRAPH + 0xBD6F: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xBD70: 0x7D67, //CJK UNIFIED IDEOGRAPH + 0xBD71: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xBD72: 0x7D69, //CJK UNIFIED IDEOGRAPH + 0xBD73: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xBD74: 0x7D6B, //CJK UNIFIED IDEOGRAPH + 0xBD75: 0x7D6C, //CJK UNIFIED IDEOGRAPH + 0xBD76: 0x7D6D, //CJK UNIFIED IDEOGRAPH + 0xBD77: 0x7D6F, //CJK UNIFIED IDEOGRAPH + 0xBD78: 0x7D70, //CJK UNIFIED IDEOGRAPH + 0xBD79: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xBD7A: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xBD7B: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xBD7C: 0x7D74, //CJK UNIFIED IDEOGRAPH + 0xBD7D: 0x7D75, //CJK UNIFIED IDEOGRAPH + 0xBD7E: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0xBD80: 0x7D78, //CJK UNIFIED IDEOGRAPH + 0xBD81: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xBD82: 0x7D7A, //CJK UNIFIED IDEOGRAPH + 0xBD83: 0x7D7B, //CJK UNIFIED IDEOGRAPH + 0xBD84: 0x7D7C, //CJK UNIFIED IDEOGRAPH + 0xBD85: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xBD86: 0x7D7E, //CJK UNIFIED IDEOGRAPH + 0xBD87: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xBD88: 0x7D80, //CJK UNIFIED IDEOGRAPH + 0xBD89: 0x7D81, //CJK UNIFIED IDEOGRAPH + 0xBD8A: 0x7D82, //CJK UNIFIED IDEOGRAPH + 0xBD8B: 0x7D83, //CJK UNIFIED IDEOGRAPH + 0xBD8C: 0x7D84, //CJK UNIFIED IDEOGRAPH + 0xBD8D: 0x7D85, //CJK UNIFIED IDEOGRAPH + 0xBD8E: 0x7D86, //CJK UNIFIED IDEOGRAPH + 0xBD8F: 0x7D87, //CJK UNIFIED IDEOGRAPH + 0xBD90: 0x7D88, //CJK UNIFIED IDEOGRAPH + 0xBD91: 0x7D89, //CJK UNIFIED IDEOGRAPH + 0xBD92: 0x7D8A, //CJK UNIFIED IDEOGRAPH + 0xBD93: 0x7D8B, //CJK UNIFIED IDEOGRAPH + 0xBD94: 0x7D8C, //CJK UNIFIED IDEOGRAPH + 0xBD95: 0x7D8D, //CJK UNIFIED IDEOGRAPH + 0xBD96: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xBD97: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xBD98: 0x7D90, //CJK UNIFIED IDEOGRAPH + 0xBD99: 0x7D91, //CJK UNIFIED IDEOGRAPH + 0xBD9A: 0x7D92, //CJK UNIFIED IDEOGRAPH + 0xBD9B: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xBD9C: 0x7D94, //CJK UNIFIED IDEOGRAPH + 0xBD9D: 0x7D95, //CJK UNIFIED IDEOGRAPH + 0xBD9E: 0x7D96, //CJK UNIFIED IDEOGRAPH + 0xBD9F: 0x7D97, //CJK UNIFIED IDEOGRAPH + 0xBDA0: 0x7D98, //CJK UNIFIED IDEOGRAPH + 0xBDA1: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xBDA2: 0x8230, //CJK UNIFIED IDEOGRAPH + 0xBDA3: 0x5251, //CJK UNIFIED IDEOGRAPH + 0xBDA4: 0x996F, //CJK UNIFIED IDEOGRAPH + 0xBDA5: 0x6E10, //CJK UNIFIED IDEOGRAPH + 0xBDA6: 0x6E85, //CJK UNIFIED IDEOGRAPH + 0xBDA7: 0x6DA7, //CJK UNIFIED IDEOGRAPH + 0xBDA8: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xBDA9: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0xBDAA: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xBDAB: 0x5C06, //CJK UNIFIED IDEOGRAPH + 0xBDAC: 0x6D46, //CJK UNIFIED IDEOGRAPH + 0xBDAD: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xBDAE: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xBDAF: 0x848B, //CJK UNIFIED IDEOGRAPH + 0xBDB0: 0x6868, //CJK UNIFIED IDEOGRAPH + 0xBDB1: 0x5956, //CJK UNIFIED IDEOGRAPH + 0xBDB2: 0x8BB2, //CJK UNIFIED IDEOGRAPH + 0xBDB3: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xBDB4: 0x9171, //CJK UNIFIED IDEOGRAPH + 0xBDB5: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xBDB6: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xBDB7: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xBDB8: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xBDB9: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xBDBA: 0x80F6, //CJK UNIFIED IDEOGRAPH + 0xBDBB: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xBDBC: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xBDBD: 0x6D47, //CJK UNIFIED IDEOGRAPH + 0xBDBE: 0x9A84, //CJK UNIFIED IDEOGRAPH + 0xBDBF: 0x5A07, //CJK UNIFIED IDEOGRAPH + 0xBDC0: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xBDC1: 0x6405, //CJK UNIFIED IDEOGRAPH + 0xBDC2: 0x94F0, //CJK UNIFIED IDEOGRAPH + 0xBDC3: 0x77EB, //CJK UNIFIED IDEOGRAPH + 0xBDC4: 0x4FA5, //CJK UNIFIED IDEOGRAPH + 0xBDC5: 0x811A, //CJK UNIFIED IDEOGRAPH + 0xBDC6: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xBDC7: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xBDC8: 0x997A, //CJK UNIFIED IDEOGRAPH + 0xBDC9: 0x7F34, //CJK UNIFIED IDEOGRAPH + 0xBDCA: 0x7EDE, //CJK UNIFIED IDEOGRAPH + 0xBDCB: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xBDCC: 0x6559, //CJK UNIFIED IDEOGRAPH + 0xBDCD: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xBDCE: 0x8F7F, //CJK UNIFIED IDEOGRAPH + 0xBDCF: 0x8F83, //CJK UNIFIED IDEOGRAPH + 0xBDD0: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xBDD1: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xBDD2: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xBDD3: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xBDD4: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xBDD5: 0x79F8, //CJK UNIFIED IDEOGRAPH + 0xBDD6: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xBDD7: 0x9636, //CJK UNIFIED IDEOGRAPH + 0xBDD8: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xBDD9: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xBDDA: 0x8282, //CJK UNIFIED IDEOGRAPH + 0xBDDB: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xBDDC: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xBDDD: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xBDDE: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xBDDF: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xBDE0: 0x6D01, //CJK UNIFIED IDEOGRAPH + 0xBDE1: 0x7ED3, //CJK UNIFIED IDEOGRAPH + 0xBDE2: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xBDE3: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xBDE4: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xBDE5: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xBDE6: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xBDE7: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xBDE8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xBDE9: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xBDEA: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xBDEB: 0x8BEB, //CJK UNIFIED IDEOGRAPH + 0xBDEC: 0x5C4A, //CJK UNIFIED IDEOGRAPH + 0xBDED: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xBDEE: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xBDEF: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xBDF0: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xBDF1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xBDF2: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xBDF3: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xBDF4: 0x7D27, //CJK UNIFIED IDEOGRAPH + 0xBDF5: 0x9526, //CJK UNIFIED IDEOGRAPH + 0xBDF6: 0x4EC5, //CJK UNIFIED IDEOGRAPH + 0xBDF7: 0x8C28, //CJK UNIFIED IDEOGRAPH + 0xBDF8: 0x8FDB, //CJK UNIFIED IDEOGRAPH + 0xBDF9: 0x9773, //CJK UNIFIED IDEOGRAPH + 0xBDFA: 0x664B, //CJK UNIFIED IDEOGRAPH + 0xBDFB: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xBDFC: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xBDFD: 0x70EC, //CJK UNIFIED IDEOGRAPH + 0xBDFE: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xBE40: 0x7D99, //CJK UNIFIED IDEOGRAPH + 0xBE41: 0x7D9A, //CJK UNIFIED IDEOGRAPH + 0xBE42: 0x7D9B, //CJK UNIFIED IDEOGRAPH + 0xBE43: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xBE44: 0x7D9D, //CJK UNIFIED IDEOGRAPH + 0xBE45: 0x7D9E, //CJK UNIFIED IDEOGRAPH + 0xBE46: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xBE47: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xBE48: 0x7DA1, //CJK UNIFIED IDEOGRAPH + 0xBE49: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xBE4A: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xBE4B: 0x7DA4, //CJK UNIFIED IDEOGRAPH + 0xBE4C: 0x7DA5, //CJK UNIFIED IDEOGRAPH + 0xBE4D: 0x7DA7, //CJK UNIFIED IDEOGRAPH + 0xBE4E: 0x7DA8, //CJK UNIFIED IDEOGRAPH + 0xBE4F: 0x7DA9, //CJK UNIFIED IDEOGRAPH + 0xBE50: 0x7DAA, //CJK UNIFIED IDEOGRAPH + 0xBE51: 0x7DAB, //CJK UNIFIED IDEOGRAPH + 0xBE52: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xBE53: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xBE54: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xBE55: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xBE56: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xBE57: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xBE58: 0x7DB3, //CJK UNIFIED IDEOGRAPH + 0xBE59: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xBE5A: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xBE5B: 0x7DB6, //CJK UNIFIED IDEOGRAPH + 0xBE5C: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xBE5D: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xBE5E: 0x7DB9, //CJK UNIFIED IDEOGRAPH + 0xBE5F: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xBE60: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xBE61: 0x7DBC, //CJK UNIFIED IDEOGRAPH + 0xBE62: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xBE63: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xBE64: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xBE65: 0x7DC0, //CJK UNIFIED IDEOGRAPH + 0xBE66: 0x7DC1, //CJK UNIFIED IDEOGRAPH + 0xBE67: 0x7DC2, //CJK UNIFIED IDEOGRAPH + 0xBE68: 0x7DC3, //CJK UNIFIED IDEOGRAPH + 0xBE69: 0x7DC4, //CJK UNIFIED IDEOGRAPH + 0xBE6A: 0x7DC5, //CJK UNIFIED IDEOGRAPH + 0xBE6B: 0x7DC6, //CJK UNIFIED IDEOGRAPH + 0xBE6C: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xBE6D: 0x7DC8, //CJK UNIFIED IDEOGRAPH + 0xBE6E: 0x7DC9, //CJK UNIFIED IDEOGRAPH + 0xBE6F: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xBE70: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xBE71: 0x7DCC, //CJK UNIFIED IDEOGRAPH + 0xBE72: 0x7DCD, //CJK UNIFIED IDEOGRAPH + 0xBE73: 0x7DCE, //CJK UNIFIED IDEOGRAPH + 0xBE74: 0x7DCF, //CJK UNIFIED IDEOGRAPH + 0xBE75: 0x7DD0, //CJK UNIFIED IDEOGRAPH + 0xBE76: 0x7DD1, //CJK UNIFIED IDEOGRAPH + 0xBE77: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0xBE78: 0x7DD3, //CJK UNIFIED IDEOGRAPH + 0xBE79: 0x7DD4, //CJK UNIFIED IDEOGRAPH + 0xBE7A: 0x7DD5, //CJK UNIFIED IDEOGRAPH + 0xBE7B: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xBE7C: 0x7DD7, //CJK UNIFIED IDEOGRAPH + 0xBE7D: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xBE7E: 0x7DD9, //CJK UNIFIED IDEOGRAPH + 0xBE80: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xBE81: 0x7DDB, //CJK UNIFIED IDEOGRAPH + 0xBE82: 0x7DDC, //CJK UNIFIED IDEOGRAPH + 0xBE83: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xBE84: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xBE85: 0x7DDF, //CJK UNIFIED IDEOGRAPH + 0xBE86: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xBE87: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xBE88: 0x7DE2, //CJK UNIFIED IDEOGRAPH + 0xBE89: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xBE8A: 0x7DE4, //CJK UNIFIED IDEOGRAPH + 0xBE8B: 0x7DE5, //CJK UNIFIED IDEOGRAPH + 0xBE8C: 0x7DE6, //CJK UNIFIED IDEOGRAPH + 0xBE8D: 0x7DE7, //CJK UNIFIED IDEOGRAPH + 0xBE8E: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xBE8F: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xBE90: 0x7DEA, //CJK UNIFIED IDEOGRAPH + 0xBE91: 0x7DEB, //CJK UNIFIED IDEOGRAPH + 0xBE92: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xBE93: 0x7DED, //CJK UNIFIED IDEOGRAPH + 0xBE94: 0x7DEE, //CJK UNIFIED IDEOGRAPH + 0xBE95: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xBE96: 0x7DF0, //CJK UNIFIED IDEOGRAPH + 0xBE97: 0x7DF1, //CJK UNIFIED IDEOGRAPH + 0xBE98: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xBE99: 0x7DF3, //CJK UNIFIED IDEOGRAPH + 0xBE9A: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xBE9B: 0x7DF5, //CJK UNIFIED IDEOGRAPH + 0xBE9C: 0x7DF6, //CJK UNIFIED IDEOGRAPH + 0xBE9D: 0x7DF7, //CJK UNIFIED IDEOGRAPH + 0xBE9E: 0x7DF8, //CJK UNIFIED IDEOGRAPH + 0xBE9F: 0x7DF9, //CJK UNIFIED IDEOGRAPH + 0xBEA0: 0x7DFA, //CJK UNIFIED IDEOGRAPH + 0xBEA1: 0x5C3D, //CJK UNIFIED IDEOGRAPH + 0xBEA2: 0x52B2, //CJK UNIFIED IDEOGRAPH + 0xBEA3: 0x8346, //CJK UNIFIED IDEOGRAPH + 0xBEA4: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xBEA5: 0x830E, //CJK UNIFIED IDEOGRAPH + 0xBEA6: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xBEA7: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xBEA8: 0x9CB8, //CJK UNIFIED IDEOGRAPH + 0xBEA9: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xBEAA: 0x60CA, //CJK UNIFIED IDEOGRAPH + 0xBEAB: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xBEAC: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xBEAD: 0x7ECF, //CJK UNIFIED IDEOGRAPH + 0xBEAE: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xBEAF: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xBEB0: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xBEB1: 0x9888, //CJK UNIFIED IDEOGRAPH + 0xBEB2: 0x9759, //CJK UNIFIED IDEOGRAPH + 0xBEB3: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xBEB4: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xBEB5: 0x955C, //CJK UNIFIED IDEOGRAPH + 0xBEB6: 0x5F84, //CJK UNIFIED IDEOGRAPH + 0xBEB7: 0x75C9, //CJK UNIFIED IDEOGRAPH + 0xBEB8: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xBEB9: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xBEBA: 0x7ADE, //CJK UNIFIED IDEOGRAPH + 0xBEBB: 0x51C0, //CJK UNIFIED IDEOGRAPH + 0xBEBC: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xBEBD: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xBEBE: 0x63EA, //CJK UNIFIED IDEOGRAPH + 0xBEBF: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xBEC0: 0x7EA0, //CJK UNIFIED IDEOGRAPH + 0xBEC1: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xBEC2: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xBEC3: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xBEC4: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xBEC5: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xBEC6: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xBEC7: 0x53A9, //CJK UNIFIED IDEOGRAPH + 0xBEC8: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xBEC9: 0x65E7, //CJK UNIFIED IDEOGRAPH + 0xBECA: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xBECB: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xBECC: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xBECD: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xBECE: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xBECF: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xBED0: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xBED1: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xBED2: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xBED3: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xBED4: 0x9A79, //CJK UNIFIED IDEOGRAPH + 0xBED5: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xBED6: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xBED7: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xBED8: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xBED9: 0x4E3E, //CJK UNIFIED IDEOGRAPH + 0xBEDA: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xBEDB: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xBEDC: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xBEDD: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xBEDE: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xBEDF: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xBEE0: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xBEE1: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xBEE2: 0x952F, //CJK UNIFIED IDEOGRAPH + 0xBEE3: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xBEE4: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xBEE5: 0x60E7, //CJK UNIFIED IDEOGRAPH + 0xBEE6: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xBEE7: 0x5267, //CJK UNIFIED IDEOGRAPH + 0xBEE8: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xBEE9: 0x9E43, //CJK UNIFIED IDEOGRAPH + 0xBEEA: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xBEEB: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xBEEC: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xBEED: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xBEEE: 0x7EE2, //CJK UNIFIED IDEOGRAPH + 0xBEEF: 0x6485, //CJK UNIFIED IDEOGRAPH + 0xBEF0: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xBEF1: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xBEF2: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xBEF3: 0x5014, //CJK UNIFIED IDEOGRAPH + 0xBEF4: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xBEF5: 0x89C9, //CJK UNIFIED IDEOGRAPH + 0xBEF6: 0x51B3, //CJK UNIFIED IDEOGRAPH + 0xBEF7: 0x8BC0, //CJK UNIFIED IDEOGRAPH + 0xBEF8: 0x7EDD, //CJK UNIFIED IDEOGRAPH + 0xBEF9: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xBEFA: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xBEFB: 0x94A7, //CJK UNIFIED IDEOGRAPH + 0xBEFC: 0x519B, //CJK UNIFIED IDEOGRAPH + 0xBEFD: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xBEFE: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xBF40: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xBF41: 0x7DFC, //CJK UNIFIED IDEOGRAPH + 0xBF42: 0x7DFD, //CJK UNIFIED IDEOGRAPH + 0xBF43: 0x7DFE, //CJK UNIFIED IDEOGRAPH + 0xBF44: 0x7DFF, //CJK UNIFIED IDEOGRAPH + 0xBF45: 0x7E00, //CJK UNIFIED IDEOGRAPH + 0xBF46: 0x7E01, //CJK UNIFIED IDEOGRAPH + 0xBF47: 0x7E02, //CJK UNIFIED IDEOGRAPH + 0xBF48: 0x7E03, //CJK UNIFIED IDEOGRAPH + 0xBF49: 0x7E04, //CJK UNIFIED IDEOGRAPH + 0xBF4A: 0x7E05, //CJK UNIFIED IDEOGRAPH + 0xBF4B: 0x7E06, //CJK UNIFIED IDEOGRAPH + 0xBF4C: 0x7E07, //CJK UNIFIED IDEOGRAPH + 0xBF4D: 0x7E08, //CJK UNIFIED IDEOGRAPH + 0xBF4E: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xBF4F: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xBF50: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xBF51: 0x7E0C, //CJK UNIFIED IDEOGRAPH + 0xBF52: 0x7E0D, //CJK UNIFIED IDEOGRAPH + 0xBF53: 0x7E0E, //CJK UNIFIED IDEOGRAPH + 0xBF54: 0x7E0F, //CJK UNIFIED IDEOGRAPH + 0xBF55: 0x7E10, //CJK UNIFIED IDEOGRAPH + 0xBF56: 0x7E11, //CJK UNIFIED IDEOGRAPH + 0xBF57: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xBF58: 0x7E13, //CJK UNIFIED IDEOGRAPH + 0xBF59: 0x7E14, //CJK UNIFIED IDEOGRAPH + 0xBF5A: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xBF5B: 0x7E16, //CJK UNIFIED IDEOGRAPH + 0xBF5C: 0x7E17, //CJK UNIFIED IDEOGRAPH + 0xBF5D: 0x7E18, //CJK UNIFIED IDEOGRAPH + 0xBF5E: 0x7E19, //CJK UNIFIED IDEOGRAPH + 0xBF5F: 0x7E1A, //CJK UNIFIED IDEOGRAPH + 0xBF60: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xBF61: 0x7E1C, //CJK UNIFIED IDEOGRAPH + 0xBF62: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xBF63: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xBF64: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xBF65: 0x7E20, //CJK UNIFIED IDEOGRAPH + 0xBF66: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xBF67: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xBF68: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xBF69: 0x7E24, //CJK UNIFIED IDEOGRAPH + 0xBF6A: 0x7E25, //CJK UNIFIED IDEOGRAPH + 0xBF6B: 0x7E26, //CJK UNIFIED IDEOGRAPH + 0xBF6C: 0x7E27, //CJK UNIFIED IDEOGRAPH + 0xBF6D: 0x7E28, //CJK UNIFIED IDEOGRAPH + 0xBF6E: 0x7E29, //CJK UNIFIED IDEOGRAPH + 0xBF6F: 0x7E2A, //CJK UNIFIED IDEOGRAPH + 0xBF70: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xBF71: 0x7E2C, //CJK UNIFIED IDEOGRAPH + 0xBF72: 0x7E2D, //CJK UNIFIED IDEOGRAPH + 0xBF73: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xBF74: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xBF75: 0x7E30, //CJK UNIFIED IDEOGRAPH + 0xBF76: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xBF77: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xBF78: 0x7E33, //CJK UNIFIED IDEOGRAPH + 0xBF79: 0x7E34, //CJK UNIFIED IDEOGRAPH + 0xBF7A: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xBF7B: 0x7E36, //CJK UNIFIED IDEOGRAPH + 0xBF7C: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xBF7D: 0x7E38, //CJK UNIFIED IDEOGRAPH + 0xBF7E: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xBF80: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xBF81: 0x7E3C, //CJK UNIFIED IDEOGRAPH + 0xBF82: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xBF83: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xBF84: 0x7E3F, //CJK UNIFIED IDEOGRAPH + 0xBF85: 0x7E40, //CJK UNIFIED IDEOGRAPH + 0xBF86: 0x7E42, //CJK UNIFIED IDEOGRAPH + 0xBF87: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xBF88: 0x7E44, //CJK UNIFIED IDEOGRAPH + 0xBF89: 0x7E45, //CJK UNIFIED IDEOGRAPH + 0xBF8A: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xBF8B: 0x7E48, //CJK UNIFIED IDEOGRAPH + 0xBF8C: 0x7E49, //CJK UNIFIED IDEOGRAPH + 0xBF8D: 0x7E4A, //CJK UNIFIED IDEOGRAPH + 0xBF8E: 0x7E4B, //CJK UNIFIED IDEOGRAPH + 0xBF8F: 0x7E4C, //CJK UNIFIED IDEOGRAPH + 0xBF90: 0x7E4D, //CJK UNIFIED IDEOGRAPH + 0xBF91: 0x7E4E, //CJK UNIFIED IDEOGRAPH + 0xBF92: 0x7E4F, //CJK UNIFIED IDEOGRAPH + 0xBF93: 0x7E50, //CJK UNIFIED IDEOGRAPH + 0xBF94: 0x7E51, //CJK UNIFIED IDEOGRAPH + 0xBF95: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xBF96: 0x7E53, //CJK UNIFIED IDEOGRAPH + 0xBF97: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xBF98: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xBF99: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xBF9A: 0x7E57, //CJK UNIFIED IDEOGRAPH + 0xBF9B: 0x7E58, //CJK UNIFIED IDEOGRAPH + 0xBF9C: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xBF9D: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xBF9E: 0x7E5B, //CJK UNIFIED IDEOGRAPH + 0xBF9F: 0x7E5C, //CJK UNIFIED IDEOGRAPH + 0xBFA0: 0x7E5D, //CJK UNIFIED IDEOGRAPH + 0xBFA1: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xBFA2: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xBFA3: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xBFA4: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xBFA5: 0x9A8F, //CJK UNIFIED IDEOGRAPH + 0xBFA6: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xBFA7: 0x5496, //CJK UNIFIED IDEOGRAPH + 0xBFA8: 0x5361, //CJK UNIFIED IDEOGRAPH + 0xBFA9: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0xBFAA: 0x5F00, //CJK UNIFIED IDEOGRAPH + 0xBFAB: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0xBFAC: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xBFAD: 0x51EF, //CJK UNIFIED IDEOGRAPH + 0xBFAE: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xBFAF: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xBFB0: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xBFB1: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xBFB2: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xBFB3: 0x780D, //CJK UNIFIED IDEOGRAPH + 0xBFB4: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xBFB5: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xBFB6: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xBFB7: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xBFB8: 0x625B, //CJK UNIFIED IDEOGRAPH + 0xBFB9: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xBFBA: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xBFBB: 0x7095, //CJK UNIFIED IDEOGRAPH + 0xBFBC: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xBFBD: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xBFBE: 0x70E4, //CJK UNIFIED IDEOGRAPH + 0xBFBF: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xBFC0: 0x5777, //CJK UNIFIED IDEOGRAPH + 0xBFC1: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xBFC2: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xBFC3: 0x68F5, //CJK UNIFIED IDEOGRAPH + 0xBFC4: 0x78D5, //CJK UNIFIED IDEOGRAPH + 0xBFC5: 0x9897, //CJK UNIFIED IDEOGRAPH + 0xBFC6: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xBFC7: 0x58F3, //CJK UNIFIED IDEOGRAPH + 0xBFC8: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xBFC9: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xBFCA: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xBFCB: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xBFCC: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xBFCD: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xBFCE: 0x8BFE, //CJK UNIFIED IDEOGRAPH + 0xBFCF: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xBFD0: 0x5543, //CJK UNIFIED IDEOGRAPH + 0xBFD1: 0x57A6, //CJK UNIFIED IDEOGRAPH + 0xBFD2: 0x6073, //CJK UNIFIED IDEOGRAPH + 0xBFD3: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xBFD4: 0x542D, //CJK UNIFIED IDEOGRAPH + 0xBFD5: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xBFD6: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xBFD7: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xBFD8: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xBFD9: 0x62A0, //CJK UNIFIED IDEOGRAPH + 0xBFDA: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xBFDB: 0x6263, //CJK UNIFIED IDEOGRAPH + 0xBFDC: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xBFDD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xBFDE: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xBFDF: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xBFE0: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xBFE1: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xBFE2: 0x5E93, //CJK UNIFIED IDEOGRAPH + 0xBFE3: 0x88E4, //CJK UNIFIED IDEOGRAPH + 0xBFE4: 0x5938, //CJK UNIFIED IDEOGRAPH + 0xBFE5: 0x57AE, //CJK UNIFIED IDEOGRAPH + 0xBFE6: 0x630E, //CJK UNIFIED IDEOGRAPH + 0xBFE7: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xBFE8: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xBFE9: 0x5757, //CJK UNIFIED IDEOGRAPH + 0xBFEA: 0x7B77, //CJK UNIFIED IDEOGRAPH + 0xBFEB: 0x4FA9, //CJK UNIFIED IDEOGRAPH + 0xBFEC: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xBFED: 0x5BBD, //CJK UNIFIED IDEOGRAPH + 0xBFEE: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xBFEF: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xBFF0: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xBFF1: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xBFF2: 0x6846, //CJK UNIFIED IDEOGRAPH + 0xBFF3: 0x77FF, //CJK UNIFIED IDEOGRAPH + 0xBFF4: 0x7736, //CJK UNIFIED IDEOGRAPH + 0xBFF5: 0x65F7, //CJK UNIFIED IDEOGRAPH + 0xBFF6: 0x51B5, //CJK UNIFIED IDEOGRAPH + 0xBFF7: 0x4E8F, //CJK UNIFIED IDEOGRAPH + 0xBFF8: 0x76D4, //CJK UNIFIED IDEOGRAPH + 0xBFF9: 0x5CBF, //CJK UNIFIED IDEOGRAPH + 0xBFFA: 0x7AA5, //CJK UNIFIED IDEOGRAPH + 0xBFFB: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xBFFC: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xBFFD: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xBFFE: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xC040: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xC041: 0x7E5F, //CJK UNIFIED IDEOGRAPH + 0xC042: 0x7E60, //CJK UNIFIED IDEOGRAPH + 0xC043: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xC044: 0x7E62, //CJK UNIFIED IDEOGRAPH + 0xC045: 0x7E63, //CJK UNIFIED IDEOGRAPH + 0xC046: 0x7E64, //CJK UNIFIED IDEOGRAPH + 0xC047: 0x7E65, //CJK UNIFIED IDEOGRAPH + 0xC048: 0x7E66, //CJK UNIFIED IDEOGRAPH + 0xC049: 0x7E67, //CJK UNIFIED IDEOGRAPH + 0xC04A: 0x7E68, //CJK UNIFIED IDEOGRAPH + 0xC04B: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xC04C: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xC04D: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xC04E: 0x7E6C, //CJK UNIFIED IDEOGRAPH + 0xC04F: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xC050: 0x7E6E, //CJK UNIFIED IDEOGRAPH + 0xC051: 0x7E6F, //CJK UNIFIED IDEOGRAPH + 0xC052: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xC053: 0x7E71, //CJK UNIFIED IDEOGRAPH + 0xC054: 0x7E72, //CJK UNIFIED IDEOGRAPH + 0xC055: 0x7E73, //CJK UNIFIED IDEOGRAPH + 0xC056: 0x7E74, //CJK UNIFIED IDEOGRAPH + 0xC057: 0x7E75, //CJK UNIFIED IDEOGRAPH + 0xC058: 0x7E76, //CJK UNIFIED IDEOGRAPH + 0xC059: 0x7E77, //CJK UNIFIED IDEOGRAPH + 0xC05A: 0x7E78, //CJK UNIFIED IDEOGRAPH + 0xC05B: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xC05C: 0x7E7A, //CJK UNIFIED IDEOGRAPH + 0xC05D: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xC05E: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xC05F: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xC060: 0x7E7E, //CJK UNIFIED IDEOGRAPH + 0xC061: 0x7E7F, //CJK UNIFIED IDEOGRAPH + 0xC062: 0x7E80, //CJK UNIFIED IDEOGRAPH + 0xC063: 0x7E81, //CJK UNIFIED IDEOGRAPH + 0xC064: 0x7E83, //CJK UNIFIED IDEOGRAPH + 0xC065: 0x7E84, //CJK UNIFIED IDEOGRAPH + 0xC066: 0x7E85, //CJK UNIFIED IDEOGRAPH + 0xC067: 0x7E86, //CJK UNIFIED IDEOGRAPH + 0xC068: 0x7E87, //CJK UNIFIED IDEOGRAPH + 0xC069: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xC06A: 0x7E89, //CJK UNIFIED IDEOGRAPH + 0xC06B: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xC06C: 0x7E8B, //CJK UNIFIED IDEOGRAPH + 0xC06D: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xC06E: 0x7E8D, //CJK UNIFIED IDEOGRAPH + 0xC06F: 0x7E8E, //CJK UNIFIED IDEOGRAPH + 0xC070: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xC071: 0x7E90, //CJK UNIFIED IDEOGRAPH + 0xC072: 0x7E91, //CJK UNIFIED IDEOGRAPH + 0xC073: 0x7E92, //CJK UNIFIED IDEOGRAPH + 0xC074: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xC075: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xC076: 0x7E95, //CJK UNIFIED IDEOGRAPH + 0xC077: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xC078: 0x7E97, //CJK UNIFIED IDEOGRAPH + 0xC079: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xC07A: 0x7E99, //CJK UNIFIED IDEOGRAPH + 0xC07B: 0x7E9A, //CJK UNIFIED IDEOGRAPH + 0xC07C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xC07D: 0x7E9D, //CJK UNIFIED IDEOGRAPH + 0xC07E: 0x7E9E, //CJK UNIFIED IDEOGRAPH + 0xC080: 0x7EAE, //CJK UNIFIED IDEOGRAPH + 0xC081: 0x7EB4, //CJK UNIFIED IDEOGRAPH + 0xC082: 0x7EBB, //CJK UNIFIED IDEOGRAPH + 0xC083: 0x7EBC, //CJK UNIFIED IDEOGRAPH + 0xC084: 0x7ED6, //CJK UNIFIED IDEOGRAPH + 0xC085: 0x7EE4, //CJK UNIFIED IDEOGRAPH + 0xC086: 0x7EEC, //CJK UNIFIED IDEOGRAPH + 0xC087: 0x7EF9, //CJK UNIFIED IDEOGRAPH + 0xC088: 0x7F0A, //CJK UNIFIED IDEOGRAPH + 0xC089: 0x7F10, //CJK UNIFIED IDEOGRAPH + 0xC08A: 0x7F1E, //CJK UNIFIED IDEOGRAPH + 0xC08B: 0x7F37, //CJK UNIFIED IDEOGRAPH + 0xC08C: 0x7F39, //CJK UNIFIED IDEOGRAPH + 0xC08D: 0x7F3B, //CJK UNIFIED IDEOGRAPH + 0xC08E: 0x7F3C, //CJK UNIFIED IDEOGRAPH + 0xC08F: 0x7F3D, //CJK UNIFIED IDEOGRAPH + 0xC090: 0x7F3E, //CJK UNIFIED IDEOGRAPH + 0xC091: 0x7F3F, //CJK UNIFIED IDEOGRAPH + 0xC092: 0x7F40, //CJK UNIFIED IDEOGRAPH + 0xC093: 0x7F41, //CJK UNIFIED IDEOGRAPH + 0xC094: 0x7F43, //CJK UNIFIED IDEOGRAPH + 0xC095: 0x7F46, //CJK UNIFIED IDEOGRAPH + 0xC096: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xC097: 0x7F48, //CJK UNIFIED IDEOGRAPH + 0xC098: 0x7F49, //CJK UNIFIED IDEOGRAPH + 0xC099: 0x7F4A, //CJK UNIFIED IDEOGRAPH + 0xC09A: 0x7F4B, //CJK UNIFIED IDEOGRAPH + 0xC09B: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xC09C: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xC09D: 0x7F4E, //CJK UNIFIED IDEOGRAPH + 0xC09E: 0x7F4F, //CJK UNIFIED IDEOGRAPH + 0xC09F: 0x7F52, //CJK UNIFIED IDEOGRAPH + 0xC0A0: 0x7F53, //CJK UNIFIED IDEOGRAPH + 0xC0A1: 0x9988, //CJK UNIFIED IDEOGRAPH + 0xC0A2: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xC0A3: 0x6E83, //CJK UNIFIED IDEOGRAPH + 0xC0A4: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xC0A5: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xC0A6: 0x6346, //CJK UNIFIED IDEOGRAPH + 0xC0A7: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xC0A8: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xC0A9: 0x6269, //CJK UNIFIED IDEOGRAPH + 0xC0AA: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xC0AB: 0x9614, //CJK UNIFIED IDEOGRAPH + 0xC0AC: 0x5783, //CJK UNIFIED IDEOGRAPH + 0xC0AD: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xC0AE: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xC0AF: 0x8721, //CJK UNIFIED IDEOGRAPH + 0xC0B0: 0x814A, //CJK UNIFIED IDEOGRAPH + 0xC0B1: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xC0B2: 0x5566, //CJK UNIFIED IDEOGRAPH + 0xC0B3: 0x83B1, //CJK UNIFIED IDEOGRAPH + 0xC0B4: 0x6765, //CJK UNIFIED IDEOGRAPH + 0xC0B5: 0x8D56, //CJK UNIFIED IDEOGRAPH + 0xC0B6: 0x84DD, //CJK UNIFIED IDEOGRAPH + 0xC0B7: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0xC0B8: 0x680F, //CJK UNIFIED IDEOGRAPH + 0xC0B9: 0x62E6, //CJK UNIFIED IDEOGRAPH + 0xC0BA: 0x7BEE, //CJK UNIFIED IDEOGRAPH + 0xC0BB: 0x9611, //CJK UNIFIED IDEOGRAPH + 0xC0BC: 0x5170, //CJK UNIFIED IDEOGRAPH + 0xC0BD: 0x6F9C, //CJK UNIFIED IDEOGRAPH + 0xC0BE: 0x8C30, //CJK UNIFIED IDEOGRAPH + 0xC0BF: 0x63FD, //CJK UNIFIED IDEOGRAPH + 0xC0C0: 0x89C8, //CJK UNIFIED IDEOGRAPH + 0xC0C1: 0x61D2, //CJK UNIFIED IDEOGRAPH + 0xC0C2: 0x7F06, //CJK UNIFIED IDEOGRAPH + 0xC0C3: 0x70C2, //CJK UNIFIED IDEOGRAPH + 0xC0C4: 0x6EE5, //CJK UNIFIED IDEOGRAPH + 0xC0C5: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xC0C6: 0x6994, //CJK UNIFIED IDEOGRAPH + 0xC0C7: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xC0C8: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xC0C9: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0xC0CA: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xC0CB: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xC0CC: 0x635E, //CJK UNIFIED IDEOGRAPH + 0xC0CD: 0x52B3, //CJK UNIFIED IDEOGRAPH + 0xC0CE: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xC0CF: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xC0D0: 0x4F6C, //CJK UNIFIED IDEOGRAPH + 0xC0D1: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0xC0D2: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xC0D3: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xC0D4: 0x6D9D, //CJK UNIFIED IDEOGRAPH + 0xC0D5: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xC0D6: 0x4E50, //CJK UNIFIED IDEOGRAPH + 0xC0D7: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xC0D8: 0x956D, //CJK UNIFIED IDEOGRAPH + 0xC0D9: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xC0DA: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xC0DB: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xC0DC: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xC0DD: 0x5792, //CJK UNIFIED IDEOGRAPH + 0xC0DE: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0xC0DF: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xC0E0: 0x7C7B, //CJK UNIFIED IDEOGRAPH + 0xC0E1: 0x6CEA, //CJK UNIFIED IDEOGRAPH + 0xC0E2: 0x68F1, //CJK UNIFIED IDEOGRAPH + 0xC0E3: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xC0E4: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xC0E5: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xC0E6: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xC0E7: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xC0E8: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xC0E9: 0x7BF1, //CJK UNIFIED IDEOGRAPH + 0xC0EA: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xC0EB: 0x79BB, //CJK UNIFIED IDEOGRAPH + 0xC0EC: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xC0ED: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xC0EE: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xC0EF: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xC0F0: 0x9CA4, //CJK UNIFIED IDEOGRAPH + 0xC0F1: 0x793C, //CJK UNIFIED IDEOGRAPH + 0xC0F2: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xC0F3: 0x8354, //CJK UNIFIED IDEOGRAPH + 0xC0F4: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xC0F5: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xC0F6: 0x4E3D, //CJK UNIFIED IDEOGRAPH + 0xC0F7: 0x5389, //CJK UNIFIED IDEOGRAPH + 0xC0F8: 0x52B1, //CJK UNIFIED IDEOGRAPH + 0xC0F9: 0x783E, //CJK UNIFIED IDEOGRAPH + 0xC0FA: 0x5386, //CJK UNIFIED IDEOGRAPH + 0xC0FB: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xC0FC: 0x5088, //CJK UNIFIED IDEOGRAPH + 0xC0FD: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xC0FE: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0xC140: 0x7F56, //CJK UNIFIED IDEOGRAPH + 0xC141: 0x7F59, //CJK UNIFIED IDEOGRAPH + 0xC142: 0x7F5B, //CJK UNIFIED IDEOGRAPH + 0xC143: 0x7F5C, //CJK UNIFIED IDEOGRAPH + 0xC144: 0x7F5D, //CJK UNIFIED IDEOGRAPH + 0xC145: 0x7F5E, //CJK UNIFIED IDEOGRAPH + 0xC146: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xC147: 0x7F63, //CJK UNIFIED IDEOGRAPH + 0xC148: 0x7F64, //CJK UNIFIED IDEOGRAPH + 0xC149: 0x7F65, //CJK UNIFIED IDEOGRAPH + 0xC14A: 0x7F66, //CJK UNIFIED IDEOGRAPH + 0xC14B: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xC14C: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xC14D: 0x7F6C, //CJK UNIFIED IDEOGRAPH + 0xC14E: 0x7F6D, //CJK UNIFIED IDEOGRAPH + 0xC14F: 0x7F6F, //CJK UNIFIED IDEOGRAPH + 0xC150: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xC151: 0x7F73, //CJK UNIFIED IDEOGRAPH + 0xC152: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xC153: 0x7F76, //CJK UNIFIED IDEOGRAPH + 0xC154: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xC155: 0x7F78, //CJK UNIFIED IDEOGRAPH + 0xC156: 0x7F7A, //CJK UNIFIED IDEOGRAPH + 0xC157: 0x7F7B, //CJK UNIFIED IDEOGRAPH + 0xC158: 0x7F7C, //CJK UNIFIED IDEOGRAPH + 0xC159: 0x7F7D, //CJK UNIFIED IDEOGRAPH + 0xC15A: 0x7F7F, //CJK UNIFIED IDEOGRAPH + 0xC15B: 0x7F80, //CJK UNIFIED IDEOGRAPH + 0xC15C: 0x7F82, //CJK UNIFIED IDEOGRAPH + 0xC15D: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xC15E: 0x7F84, //CJK UNIFIED IDEOGRAPH + 0xC15F: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xC160: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xC161: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xC162: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xC163: 0x7F89, //CJK UNIFIED IDEOGRAPH + 0xC164: 0x7F8B, //CJK UNIFIED IDEOGRAPH + 0xC165: 0x7F8D, //CJK UNIFIED IDEOGRAPH + 0xC166: 0x7F8F, //CJK UNIFIED IDEOGRAPH + 0xC167: 0x7F90, //CJK UNIFIED IDEOGRAPH + 0xC168: 0x7F91, //CJK UNIFIED IDEOGRAPH + 0xC169: 0x7F92, //CJK UNIFIED IDEOGRAPH + 0xC16A: 0x7F93, //CJK UNIFIED IDEOGRAPH + 0xC16B: 0x7F95, //CJK UNIFIED IDEOGRAPH + 0xC16C: 0x7F96, //CJK UNIFIED IDEOGRAPH + 0xC16D: 0x7F97, //CJK UNIFIED IDEOGRAPH + 0xC16E: 0x7F98, //CJK UNIFIED IDEOGRAPH + 0xC16F: 0x7F99, //CJK UNIFIED IDEOGRAPH + 0xC170: 0x7F9B, //CJK UNIFIED IDEOGRAPH + 0xC171: 0x7F9C, //CJK UNIFIED IDEOGRAPH + 0xC172: 0x7FA0, //CJK UNIFIED IDEOGRAPH + 0xC173: 0x7FA2, //CJK UNIFIED IDEOGRAPH + 0xC174: 0x7FA3, //CJK UNIFIED IDEOGRAPH + 0xC175: 0x7FA5, //CJK UNIFIED IDEOGRAPH + 0xC176: 0x7FA6, //CJK UNIFIED IDEOGRAPH + 0xC177: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xC178: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xC179: 0x7FAA, //CJK UNIFIED IDEOGRAPH + 0xC17A: 0x7FAB, //CJK UNIFIED IDEOGRAPH + 0xC17B: 0x7FAC, //CJK UNIFIED IDEOGRAPH + 0xC17C: 0x7FAD, //CJK UNIFIED IDEOGRAPH + 0xC17D: 0x7FAE, //CJK UNIFIED IDEOGRAPH + 0xC17E: 0x7FB1, //CJK UNIFIED IDEOGRAPH + 0xC180: 0x7FB3, //CJK UNIFIED IDEOGRAPH + 0xC181: 0x7FB4, //CJK UNIFIED IDEOGRAPH + 0xC182: 0x7FB5, //CJK UNIFIED IDEOGRAPH + 0xC183: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xC184: 0x7FB7, //CJK UNIFIED IDEOGRAPH + 0xC185: 0x7FBA, //CJK UNIFIED IDEOGRAPH + 0xC186: 0x7FBB, //CJK UNIFIED IDEOGRAPH + 0xC187: 0x7FBE, //CJK UNIFIED IDEOGRAPH + 0xC188: 0x7FC0, //CJK UNIFIED IDEOGRAPH + 0xC189: 0x7FC2, //CJK UNIFIED IDEOGRAPH + 0xC18A: 0x7FC3, //CJK UNIFIED IDEOGRAPH + 0xC18B: 0x7FC4, //CJK UNIFIED IDEOGRAPH + 0xC18C: 0x7FC6, //CJK UNIFIED IDEOGRAPH + 0xC18D: 0x7FC7, //CJK UNIFIED IDEOGRAPH + 0xC18E: 0x7FC8, //CJK UNIFIED IDEOGRAPH + 0xC18F: 0x7FC9, //CJK UNIFIED IDEOGRAPH + 0xC190: 0x7FCB, //CJK UNIFIED IDEOGRAPH + 0xC191: 0x7FCD, //CJK UNIFIED IDEOGRAPH + 0xC192: 0x7FCF, //CJK UNIFIED IDEOGRAPH + 0xC193: 0x7FD0, //CJK UNIFIED IDEOGRAPH + 0xC194: 0x7FD1, //CJK UNIFIED IDEOGRAPH + 0xC195: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xC196: 0x7FD3, //CJK UNIFIED IDEOGRAPH + 0xC197: 0x7FD6, //CJK UNIFIED IDEOGRAPH + 0xC198: 0x7FD7, //CJK UNIFIED IDEOGRAPH + 0xC199: 0x7FD9, //CJK UNIFIED IDEOGRAPH + 0xC19A: 0x7FDA, //CJK UNIFIED IDEOGRAPH + 0xC19B: 0x7FDB, //CJK UNIFIED IDEOGRAPH + 0xC19C: 0x7FDC, //CJK UNIFIED IDEOGRAPH + 0xC19D: 0x7FDD, //CJK UNIFIED IDEOGRAPH + 0xC19E: 0x7FDE, //CJK UNIFIED IDEOGRAPH + 0xC19F: 0x7FE2, //CJK UNIFIED IDEOGRAPH + 0xC1A0: 0x7FE3, //CJK UNIFIED IDEOGRAPH + 0xC1A1: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xC1A2: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xC1A3: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xC1A4: 0x6CA5, //CJK UNIFIED IDEOGRAPH + 0xC1A5: 0x96B6, //CJK UNIFIED IDEOGRAPH + 0xC1A6: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xC1A7: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xC1A8: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0xC1A9: 0x4FE9, //CJK UNIFIED IDEOGRAPH + 0xC1AA: 0x8054, //CJK UNIFIED IDEOGRAPH + 0xC1AB: 0x83B2, //CJK UNIFIED IDEOGRAPH + 0xC1AC: 0x8FDE, //CJK UNIFIED IDEOGRAPH + 0xC1AD: 0x9570, //CJK UNIFIED IDEOGRAPH + 0xC1AE: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xC1AF: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xC1B0: 0x6D9F, //CJK UNIFIED IDEOGRAPH + 0xC1B1: 0x5E18, //CJK UNIFIED IDEOGRAPH + 0xC1B2: 0x655B, //CJK UNIFIED IDEOGRAPH + 0xC1B3: 0x8138, //CJK UNIFIED IDEOGRAPH + 0xC1B4: 0x94FE, //CJK UNIFIED IDEOGRAPH + 0xC1B5: 0x604B, //CJK UNIFIED IDEOGRAPH + 0xC1B6: 0x70BC, //CJK UNIFIED IDEOGRAPH + 0xC1B7: 0x7EC3, //CJK UNIFIED IDEOGRAPH + 0xC1B8: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xC1B9: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0xC1BA: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xC1BB: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xC1BC: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xC1BD: 0x4E24, //CJK UNIFIED IDEOGRAPH + 0xC1BE: 0x8F86, //CJK UNIFIED IDEOGRAPH + 0xC1BF: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xC1C0: 0x667E, //CJK UNIFIED IDEOGRAPH + 0xC1C1: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xC1C2: 0x8C05, //CJK UNIFIED IDEOGRAPH + 0xC1C3: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0xC1C4: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xC1C5: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xC1C6: 0x7597, //CJK UNIFIED IDEOGRAPH + 0xC1C7: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xC1C8: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xC1C9: 0x8FBD, //CJK UNIFIED IDEOGRAPH + 0xC1CA: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xC1CB: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xC1CC: 0x6482, //CJK UNIFIED IDEOGRAPH + 0xC1CD: 0x9563, //CJK UNIFIED IDEOGRAPH + 0xC1CE: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xC1CF: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xC1D0: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xC1D1: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xC1D2: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xC1D3: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xC1D4: 0x730E, //CJK UNIFIED IDEOGRAPH + 0xC1D5: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xC1D6: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xC1D7: 0x78F7, //CJK UNIFIED IDEOGRAPH + 0xC1D8: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xC1D9: 0x4E34, //CJK UNIFIED IDEOGRAPH + 0xC1DA: 0x90BB, //CJK UNIFIED IDEOGRAPH + 0xC1DB: 0x9CDE, //CJK UNIFIED IDEOGRAPH + 0xC1DC: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xC1DD: 0x51DB, //CJK UNIFIED IDEOGRAPH + 0xC1DE: 0x8D41, //CJK UNIFIED IDEOGRAPH + 0xC1DF: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xC1E0: 0x62CE, //CJK UNIFIED IDEOGRAPH + 0xC1E1: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xC1E2: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xC1E3: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xC1E4: 0x9F84, //CJK UNIFIED IDEOGRAPH + 0xC1E5: 0x94C3, //CJK UNIFIED IDEOGRAPH + 0xC1E6: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xC1E7: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xC1E8: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xC1E9: 0x7075, //CJK UNIFIED IDEOGRAPH + 0xC1EA: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xC1EB: 0x5CAD, //CJK UNIFIED IDEOGRAPH + 0xC1EC: 0x9886, //CJK UNIFIED IDEOGRAPH + 0xC1ED: 0x53E6, //CJK UNIFIED IDEOGRAPH + 0xC1EE: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xC1EF: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xC1F0: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xC1F1: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xC1F2: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xC1F3: 0x998F, //CJK UNIFIED IDEOGRAPH + 0xC1F4: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xC1F5: 0x5218, //CJK UNIFIED IDEOGRAPH + 0xC1F6: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xC1F7: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xC1F8: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xC1F9: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xC1FA: 0x9F99, //CJK UNIFIED IDEOGRAPH + 0xC1FB: 0x804B, //CJK UNIFIED IDEOGRAPH + 0xC1FC: 0x5499, //CJK UNIFIED IDEOGRAPH + 0xC1FD: 0x7B3C, //CJK UNIFIED IDEOGRAPH + 0xC1FE: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xC240: 0x7FE4, //CJK UNIFIED IDEOGRAPH + 0xC241: 0x7FE7, //CJK UNIFIED IDEOGRAPH + 0xC242: 0x7FE8, //CJK UNIFIED IDEOGRAPH + 0xC243: 0x7FEA, //CJK UNIFIED IDEOGRAPH + 0xC244: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xC245: 0x7FEC, //CJK UNIFIED IDEOGRAPH + 0xC246: 0x7FED, //CJK UNIFIED IDEOGRAPH + 0xC247: 0x7FEF, //CJK UNIFIED IDEOGRAPH + 0xC248: 0x7FF2, //CJK UNIFIED IDEOGRAPH + 0xC249: 0x7FF4, //CJK UNIFIED IDEOGRAPH + 0xC24A: 0x7FF5, //CJK UNIFIED IDEOGRAPH + 0xC24B: 0x7FF6, //CJK UNIFIED IDEOGRAPH + 0xC24C: 0x7FF7, //CJK UNIFIED IDEOGRAPH + 0xC24D: 0x7FF8, //CJK UNIFIED IDEOGRAPH + 0xC24E: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xC24F: 0x7FFA, //CJK UNIFIED IDEOGRAPH + 0xC250: 0x7FFD, //CJK UNIFIED IDEOGRAPH + 0xC251: 0x7FFE, //CJK UNIFIED IDEOGRAPH + 0xC252: 0x7FFF, //CJK UNIFIED IDEOGRAPH + 0xC253: 0x8002, //CJK UNIFIED IDEOGRAPH + 0xC254: 0x8007, //CJK UNIFIED IDEOGRAPH + 0xC255: 0x8008, //CJK UNIFIED IDEOGRAPH + 0xC256: 0x8009, //CJK UNIFIED IDEOGRAPH + 0xC257: 0x800A, //CJK UNIFIED IDEOGRAPH + 0xC258: 0x800E, //CJK UNIFIED IDEOGRAPH + 0xC259: 0x800F, //CJK UNIFIED IDEOGRAPH + 0xC25A: 0x8011, //CJK UNIFIED IDEOGRAPH + 0xC25B: 0x8013, //CJK UNIFIED IDEOGRAPH + 0xC25C: 0x801A, //CJK UNIFIED IDEOGRAPH + 0xC25D: 0x801B, //CJK UNIFIED IDEOGRAPH + 0xC25E: 0x801D, //CJK UNIFIED IDEOGRAPH + 0xC25F: 0x801E, //CJK UNIFIED IDEOGRAPH + 0xC260: 0x801F, //CJK UNIFIED IDEOGRAPH + 0xC261: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xC262: 0x8023, //CJK UNIFIED IDEOGRAPH + 0xC263: 0x8024, //CJK UNIFIED IDEOGRAPH + 0xC264: 0x802B, //CJK UNIFIED IDEOGRAPH + 0xC265: 0x802C, //CJK UNIFIED IDEOGRAPH + 0xC266: 0x802D, //CJK UNIFIED IDEOGRAPH + 0xC267: 0x802E, //CJK UNIFIED IDEOGRAPH + 0xC268: 0x802F, //CJK UNIFIED IDEOGRAPH + 0xC269: 0x8030, //CJK UNIFIED IDEOGRAPH + 0xC26A: 0x8032, //CJK UNIFIED IDEOGRAPH + 0xC26B: 0x8034, //CJK UNIFIED IDEOGRAPH + 0xC26C: 0x8039, //CJK UNIFIED IDEOGRAPH + 0xC26D: 0x803A, //CJK UNIFIED IDEOGRAPH + 0xC26E: 0x803C, //CJK UNIFIED IDEOGRAPH + 0xC26F: 0x803E, //CJK UNIFIED IDEOGRAPH + 0xC270: 0x8040, //CJK UNIFIED IDEOGRAPH + 0xC271: 0x8041, //CJK UNIFIED IDEOGRAPH + 0xC272: 0x8044, //CJK UNIFIED IDEOGRAPH + 0xC273: 0x8045, //CJK UNIFIED IDEOGRAPH + 0xC274: 0x8047, //CJK UNIFIED IDEOGRAPH + 0xC275: 0x8048, //CJK UNIFIED IDEOGRAPH + 0xC276: 0x8049, //CJK UNIFIED IDEOGRAPH + 0xC277: 0x804E, //CJK UNIFIED IDEOGRAPH + 0xC278: 0x804F, //CJK UNIFIED IDEOGRAPH + 0xC279: 0x8050, //CJK UNIFIED IDEOGRAPH + 0xC27A: 0x8051, //CJK UNIFIED IDEOGRAPH + 0xC27B: 0x8053, //CJK UNIFIED IDEOGRAPH + 0xC27C: 0x8055, //CJK UNIFIED IDEOGRAPH + 0xC27D: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xC27E: 0x8057, //CJK UNIFIED IDEOGRAPH + 0xC280: 0x8059, //CJK UNIFIED IDEOGRAPH + 0xC281: 0x805B, //CJK UNIFIED IDEOGRAPH + 0xC282: 0x805C, //CJK UNIFIED IDEOGRAPH + 0xC283: 0x805D, //CJK UNIFIED IDEOGRAPH + 0xC284: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xC285: 0x805F, //CJK UNIFIED IDEOGRAPH + 0xC286: 0x8060, //CJK UNIFIED IDEOGRAPH + 0xC287: 0x8061, //CJK UNIFIED IDEOGRAPH + 0xC288: 0x8062, //CJK UNIFIED IDEOGRAPH + 0xC289: 0x8063, //CJK UNIFIED IDEOGRAPH + 0xC28A: 0x8064, //CJK UNIFIED IDEOGRAPH + 0xC28B: 0x8065, //CJK UNIFIED IDEOGRAPH + 0xC28C: 0x8066, //CJK UNIFIED IDEOGRAPH + 0xC28D: 0x8067, //CJK UNIFIED IDEOGRAPH + 0xC28E: 0x8068, //CJK UNIFIED IDEOGRAPH + 0xC28F: 0x806B, //CJK UNIFIED IDEOGRAPH + 0xC290: 0x806C, //CJK UNIFIED IDEOGRAPH + 0xC291: 0x806D, //CJK UNIFIED IDEOGRAPH + 0xC292: 0x806E, //CJK UNIFIED IDEOGRAPH + 0xC293: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xC294: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xC295: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xC296: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xC297: 0x8074, //CJK UNIFIED IDEOGRAPH + 0xC298: 0x8075, //CJK UNIFIED IDEOGRAPH + 0xC299: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xC29A: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xC29B: 0x8078, //CJK UNIFIED IDEOGRAPH + 0xC29C: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xC29D: 0x807A, //CJK UNIFIED IDEOGRAPH + 0xC29E: 0x807B, //CJK UNIFIED IDEOGRAPH + 0xC29F: 0x807C, //CJK UNIFIED IDEOGRAPH + 0xC2A0: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xC2A1: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xC2A2: 0x5784, //CJK UNIFIED IDEOGRAPH + 0xC2A3: 0x62E2, //CJK UNIFIED IDEOGRAPH + 0xC2A4: 0x9647, //CJK UNIFIED IDEOGRAPH + 0xC2A5: 0x697C, //CJK UNIFIED IDEOGRAPH + 0xC2A6: 0x5A04, //CJK UNIFIED IDEOGRAPH + 0xC2A7: 0x6402, //CJK UNIFIED IDEOGRAPH + 0xC2A8: 0x7BD3, //CJK UNIFIED IDEOGRAPH + 0xC2A9: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xC2AA: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xC2AB: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0xC2AC: 0x5362, //CJK UNIFIED IDEOGRAPH + 0xC2AD: 0x9885, //CJK UNIFIED IDEOGRAPH + 0xC2AE: 0x5E90, //CJK UNIFIED IDEOGRAPH + 0xC2AF: 0x7089, //CJK UNIFIED IDEOGRAPH + 0xC2B0: 0x63B3, //CJK UNIFIED IDEOGRAPH + 0xC2B1: 0x5364, //CJK UNIFIED IDEOGRAPH + 0xC2B2: 0x864F, //CJK UNIFIED IDEOGRAPH + 0xC2B3: 0x9C81, //CJK UNIFIED IDEOGRAPH + 0xC2B4: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xC2B5: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xC2B6: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xC2B7: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xC2B8: 0x8D42, //CJK UNIFIED IDEOGRAPH + 0xC2B9: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xC2BA: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xC2BB: 0x7984, //CJK UNIFIED IDEOGRAPH + 0xC2BC: 0x5F55, //CJK UNIFIED IDEOGRAPH + 0xC2BD: 0x9646, //CJK UNIFIED IDEOGRAPH + 0xC2BE: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xC2BF: 0x9A74, //CJK UNIFIED IDEOGRAPH + 0xC2C0: 0x5415, //CJK UNIFIED IDEOGRAPH + 0xC2C1: 0x94DD, //CJK UNIFIED IDEOGRAPH + 0xC2C2: 0x4FA3, //CJK UNIFIED IDEOGRAPH + 0xC2C3: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xC2C4: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xC2C5: 0x5C61, //CJK UNIFIED IDEOGRAPH + 0xC2C6: 0x7F15, //CJK UNIFIED IDEOGRAPH + 0xC2C7: 0x8651, //CJK UNIFIED IDEOGRAPH + 0xC2C8: 0x6C2F, //CJK UNIFIED IDEOGRAPH + 0xC2C9: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xC2CA: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xC2CB: 0x6EE4, //CJK UNIFIED IDEOGRAPH + 0xC2CC: 0x7EFF, //CJK UNIFIED IDEOGRAPH + 0xC2CD: 0x5CE6, //CJK UNIFIED IDEOGRAPH + 0xC2CE: 0x631B, //CJK UNIFIED IDEOGRAPH + 0xC2CF: 0x5B6A, //CJK UNIFIED IDEOGRAPH + 0xC2D0: 0x6EE6, //CJK UNIFIED IDEOGRAPH + 0xC2D1: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xC2D2: 0x4E71, //CJK UNIFIED IDEOGRAPH + 0xC2D3: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xC2D4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xC2D5: 0x62A1, //CJK UNIFIED IDEOGRAPH + 0xC2D6: 0x8F6E, //CJK UNIFIED IDEOGRAPH + 0xC2D7: 0x4F26, //CJK UNIFIED IDEOGRAPH + 0xC2D8: 0x4ED1, //CJK UNIFIED IDEOGRAPH + 0xC2D9: 0x6CA6, //CJK UNIFIED IDEOGRAPH + 0xC2DA: 0x7EB6, //CJK UNIFIED IDEOGRAPH + 0xC2DB: 0x8BBA, //CJK UNIFIED IDEOGRAPH + 0xC2DC: 0x841D, //CJK UNIFIED IDEOGRAPH + 0xC2DD: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xC2DE: 0x7F57, //CJK UNIFIED IDEOGRAPH + 0xC2DF: 0x903B, //CJK UNIFIED IDEOGRAPH + 0xC2E0: 0x9523, //CJK UNIFIED IDEOGRAPH + 0xC2E1: 0x7BA9, //CJK UNIFIED IDEOGRAPH + 0xC2E2: 0x9AA1, //CJK UNIFIED IDEOGRAPH + 0xC2E3: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xC2E4: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xC2E5: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xC2E6: 0x9A86, //CJK UNIFIED IDEOGRAPH + 0xC2E7: 0x7EDC, //CJK UNIFIED IDEOGRAPH + 0xC2E8: 0x5988, //CJK UNIFIED IDEOGRAPH + 0xC2E9: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xC2EA: 0x739B, //CJK UNIFIED IDEOGRAPH + 0xC2EB: 0x7801, //CJK UNIFIED IDEOGRAPH + 0xC2EC: 0x8682, //CJK UNIFIED IDEOGRAPH + 0xC2ED: 0x9A6C, //CJK UNIFIED IDEOGRAPH + 0xC2EE: 0x9A82, //CJK UNIFIED IDEOGRAPH + 0xC2EF: 0x561B, //CJK UNIFIED IDEOGRAPH + 0xC2F0: 0x5417, //CJK UNIFIED IDEOGRAPH + 0xC2F1: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xC2F2: 0x4E70, //CJK UNIFIED IDEOGRAPH + 0xC2F3: 0x9EA6, //CJK UNIFIED IDEOGRAPH + 0xC2F4: 0x5356, //CJK UNIFIED IDEOGRAPH + 0xC2F5: 0x8FC8, //CJK UNIFIED IDEOGRAPH + 0xC2F6: 0x8109, //CJK UNIFIED IDEOGRAPH + 0xC2F7: 0x7792, //CJK UNIFIED IDEOGRAPH + 0xC2F8: 0x9992, //CJK UNIFIED IDEOGRAPH + 0xC2F9: 0x86EE, //CJK UNIFIED IDEOGRAPH + 0xC2FA: 0x6EE1, //CJK UNIFIED IDEOGRAPH + 0xC2FB: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xC2FC: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xC2FD: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xC2FE: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xC340: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xC341: 0x8081, //CJK UNIFIED IDEOGRAPH + 0xC342: 0x8082, //CJK UNIFIED IDEOGRAPH + 0xC343: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xC344: 0x8088, //CJK UNIFIED IDEOGRAPH + 0xC345: 0x808A, //CJK UNIFIED IDEOGRAPH + 0xC346: 0x808D, //CJK UNIFIED IDEOGRAPH + 0xC347: 0x808E, //CJK UNIFIED IDEOGRAPH + 0xC348: 0x808F, //CJK UNIFIED IDEOGRAPH + 0xC349: 0x8090, //CJK UNIFIED IDEOGRAPH + 0xC34A: 0x8091, //CJK UNIFIED IDEOGRAPH + 0xC34B: 0x8092, //CJK UNIFIED IDEOGRAPH + 0xC34C: 0x8094, //CJK UNIFIED IDEOGRAPH + 0xC34D: 0x8095, //CJK UNIFIED IDEOGRAPH + 0xC34E: 0x8097, //CJK UNIFIED IDEOGRAPH + 0xC34F: 0x8099, //CJK UNIFIED IDEOGRAPH + 0xC350: 0x809E, //CJK UNIFIED IDEOGRAPH + 0xC351: 0x80A3, //CJK UNIFIED IDEOGRAPH + 0xC352: 0x80A6, //CJK UNIFIED IDEOGRAPH + 0xC353: 0x80A7, //CJK UNIFIED IDEOGRAPH + 0xC354: 0x80A8, //CJK UNIFIED IDEOGRAPH + 0xC355: 0x80AC, //CJK UNIFIED IDEOGRAPH + 0xC356: 0x80B0, //CJK UNIFIED IDEOGRAPH + 0xC357: 0x80B3, //CJK UNIFIED IDEOGRAPH + 0xC358: 0x80B5, //CJK UNIFIED IDEOGRAPH + 0xC359: 0x80B6, //CJK UNIFIED IDEOGRAPH + 0xC35A: 0x80B8, //CJK UNIFIED IDEOGRAPH + 0xC35B: 0x80B9, //CJK UNIFIED IDEOGRAPH + 0xC35C: 0x80BB, //CJK UNIFIED IDEOGRAPH + 0xC35D: 0x80C5, //CJK UNIFIED IDEOGRAPH + 0xC35E: 0x80C7, //CJK UNIFIED IDEOGRAPH + 0xC35F: 0x80C8, //CJK UNIFIED IDEOGRAPH + 0xC360: 0x80C9, //CJK UNIFIED IDEOGRAPH + 0xC361: 0x80CA, //CJK UNIFIED IDEOGRAPH + 0xC362: 0x80CB, //CJK UNIFIED IDEOGRAPH + 0xC363: 0x80CF, //CJK UNIFIED IDEOGRAPH + 0xC364: 0x80D0, //CJK UNIFIED IDEOGRAPH + 0xC365: 0x80D1, //CJK UNIFIED IDEOGRAPH + 0xC366: 0x80D2, //CJK UNIFIED IDEOGRAPH + 0xC367: 0x80D3, //CJK UNIFIED IDEOGRAPH + 0xC368: 0x80D4, //CJK UNIFIED IDEOGRAPH + 0xC369: 0x80D5, //CJK UNIFIED IDEOGRAPH + 0xC36A: 0x80D8, //CJK UNIFIED IDEOGRAPH + 0xC36B: 0x80DF, //CJK UNIFIED IDEOGRAPH + 0xC36C: 0x80E0, //CJK UNIFIED IDEOGRAPH + 0xC36D: 0x80E2, //CJK UNIFIED IDEOGRAPH + 0xC36E: 0x80E3, //CJK UNIFIED IDEOGRAPH + 0xC36F: 0x80E6, //CJK UNIFIED IDEOGRAPH + 0xC370: 0x80EE, //CJK UNIFIED IDEOGRAPH + 0xC371: 0x80F5, //CJK UNIFIED IDEOGRAPH + 0xC372: 0x80F7, //CJK UNIFIED IDEOGRAPH + 0xC373: 0x80F9, //CJK UNIFIED IDEOGRAPH + 0xC374: 0x80FB, //CJK UNIFIED IDEOGRAPH + 0xC375: 0x80FE, //CJK UNIFIED IDEOGRAPH + 0xC376: 0x80FF, //CJK UNIFIED IDEOGRAPH + 0xC377: 0x8100, //CJK UNIFIED IDEOGRAPH + 0xC378: 0x8101, //CJK UNIFIED IDEOGRAPH + 0xC379: 0x8103, //CJK UNIFIED IDEOGRAPH + 0xC37A: 0x8104, //CJK UNIFIED IDEOGRAPH + 0xC37B: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xC37C: 0x8107, //CJK UNIFIED IDEOGRAPH + 0xC37D: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xC37E: 0x810B, //CJK UNIFIED IDEOGRAPH + 0xC380: 0x810C, //CJK UNIFIED IDEOGRAPH + 0xC381: 0x8115, //CJK UNIFIED IDEOGRAPH + 0xC382: 0x8117, //CJK UNIFIED IDEOGRAPH + 0xC383: 0x8119, //CJK UNIFIED IDEOGRAPH + 0xC384: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xC385: 0x811C, //CJK UNIFIED IDEOGRAPH + 0xC386: 0x811D, //CJK UNIFIED IDEOGRAPH + 0xC387: 0x811F, //CJK UNIFIED IDEOGRAPH + 0xC388: 0x8120, //CJK UNIFIED IDEOGRAPH + 0xC389: 0x8121, //CJK UNIFIED IDEOGRAPH + 0xC38A: 0x8122, //CJK UNIFIED IDEOGRAPH + 0xC38B: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xC38C: 0x8124, //CJK UNIFIED IDEOGRAPH + 0xC38D: 0x8125, //CJK UNIFIED IDEOGRAPH + 0xC38E: 0x8126, //CJK UNIFIED IDEOGRAPH + 0xC38F: 0x8127, //CJK UNIFIED IDEOGRAPH + 0xC390: 0x8128, //CJK UNIFIED IDEOGRAPH + 0xC391: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xC392: 0x812A, //CJK UNIFIED IDEOGRAPH + 0xC393: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xC394: 0x812D, //CJK UNIFIED IDEOGRAPH + 0xC395: 0x812E, //CJK UNIFIED IDEOGRAPH + 0xC396: 0x8130, //CJK UNIFIED IDEOGRAPH + 0xC397: 0x8133, //CJK UNIFIED IDEOGRAPH + 0xC398: 0x8134, //CJK UNIFIED IDEOGRAPH + 0xC399: 0x8135, //CJK UNIFIED IDEOGRAPH + 0xC39A: 0x8137, //CJK UNIFIED IDEOGRAPH + 0xC39B: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xC39C: 0x813A, //CJK UNIFIED IDEOGRAPH + 0xC39D: 0x813B, //CJK UNIFIED IDEOGRAPH + 0xC39E: 0x813C, //CJK UNIFIED IDEOGRAPH + 0xC39F: 0x813D, //CJK UNIFIED IDEOGRAPH + 0xC3A0: 0x813F, //CJK UNIFIED IDEOGRAPH + 0xC3A1: 0x8C29, //CJK UNIFIED IDEOGRAPH + 0xC3A2: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xC3A3: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xC3A4: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xC3A5: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xC3A6: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xC3A7: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xC3A8: 0x732B, //CJK UNIFIED IDEOGRAPH + 0xC3A9: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xC3AA: 0x951A, //CJK UNIFIED IDEOGRAPH + 0xC3AB: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xC3AC: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xC3AD: 0x94C6, //CJK UNIFIED IDEOGRAPH + 0xC3AE: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xC3AF: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xC3B0: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xC3B1: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xC3B2: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xC3B3: 0x8D38, //CJK UNIFIED IDEOGRAPH + 0xC3B4: 0x4E48, //CJK UNIFIED IDEOGRAPH + 0xC3B5: 0x73AB, //CJK UNIFIED IDEOGRAPH + 0xC3B6: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xC3B7: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xC3B8: 0x9176, //CJK UNIFIED IDEOGRAPH + 0xC3B9: 0x9709, //CJK UNIFIED IDEOGRAPH + 0xC3BA: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xC3BB: 0x6CA1, //CJK UNIFIED IDEOGRAPH + 0xC3BC: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xC3BD: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xC3BE: 0x9541, //CJK UNIFIED IDEOGRAPH + 0xC3BF: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xC3C0: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xC3C1: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xC3C2: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xC3C3: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xC3C4: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xC3C5: 0x95E8, //CJK UNIFIED IDEOGRAPH + 0xC3C6: 0x95F7, //CJK UNIFIED IDEOGRAPH + 0xC3C7: 0x4EEC, //CJK UNIFIED IDEOGRAPH + 0xC3C8: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xC3C9: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xC3CA: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0xC3CB: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xC3CC: 0x9530, //CJK UNIFIED IDEOGRAPH + 0xC3CD: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xC3CE: 0x68A6, //CJK UNIFIED IDEOGRAPH + 0xC3CF: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xC3D0: 0x772F, //CJK UNIFIED IDEOGRAPH + 0xC3D1: 0x919A, //CJK UNIFIED IDEOGRAPH + 0xC3D2: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xC3D3: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xC3D4: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xC3D5: 0x8C1C, //CJK UNIFIED IDEOGRAPH + 0xC3D6: 0x5F25, //CJK UNIFIED IDEOGRAPH + 0xC3D7: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xC3D8: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xC3D9: 0x89C5, //CJK UNIFIED IDEOGRAPH + 0xC3DA: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xC3DB: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xC3DC: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xC3DD: 0x5E42, //CJK UNIFIED IDEOGRAPH + 0xC3DE: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xC3DF: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xC3E0: 0x7EF5, //CJK UNIFIED IDEOGRAPH + 0xC3E1: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xC3E2: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xC3E3: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xC3E4: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xC3E5: 0x7F05, //CJK UNIFIED IDEOGRAPH + 0xC3E6: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xC3E7: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xC3E8: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xC3E9: 0x7784, //CJK UNIFIED IDEOGRAPH + 0xC3EA: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xC3EB: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xC3EC: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xC3ED: 0x5E99, //CJK UNIFIED IDEOGRAPH + 0xC3EE: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xC3EF: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xC3F0: 0x706D, //CJK UNIFIED IDEOGRAPH + 0xC3F1: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xC3F2: 0x62BF, //CJK UNIFIED IDEOGRAPH + 0xC3F3: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xC3F4: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xC3F5: 0x60AF, //CJK UNIFIED IDEOGRAPH + 0xC3F6: 0x95FD, //CJK UNIFIED IDEOGRAPH + 0xC3F7: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xC3F8: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xC3F9: 0x9E23, //CJK UNIFIED IDEOGRAPH + 0xC3FA: 0x94ED, //CJK UNIFIED IDEOGRAPH + 0xC3FB: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xC3FC: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xC3FD: 0x8C2C, //CJK UNIFIED IDEOGRAPH + 0xC3FE: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xC440: 0x8140, //CJK UNIFIED IDEOGRAPH + 0xC441: 0x8141, //CJK UNIFIED IDEOGRAPH + 0xC442: 0x8142, //CJK UNIFIED IDEOGRAPH + 0xC443: 0x8143, //CJK UNIFIED IDEOGRAPH + 0xC444: 0x8144, //CJK UNIFIED IDEOGRAPH + 0xC445: 0x8145, //CJK UNIFIED IDEOGRAPH + 0xC446: 0x8147, //CJK UNIFIED IDEOGRAPH + 0xC447: 0x8149, //CJK UNIFIED IDEOGRAPH + 0xC448: 0x814D, //CJK UNIFIED IDEOGRAPH + 0xC449: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xC44A: 0x814F, //CJK UNIFIED IDEOGRAPH + 0xC44B: 0x8152, //CJK UNIFIED IDEOGRAPH + 0xC44C: 0x8156, //CJK UNIFIED IDEOGRAPH + 0xC44D: 0x8157, //CJK UNIFIED IDEOGRAPH + 0xC44E: 0x8158, //CJK UNIFIED IDEOGRAPH + 0xC44F: 0x815B, //CJK UNIFIED IDEOGRAPH + 0xC450: 0x815C, //CJK UNIFIED IDEOGRAPH + 0xC451: 0x815D, //CJK UNIFIED IDEOGRAPH + 0xC452: 0x815E, //CJK UNIFIED IDEOGRAPH + 0xC453: 0x815F, //CJK UNIFIED IDEOGRAPH + 0xC454: 0x8161, //CJK UNIFIED IDEOGRAPH + 0xC455: 0x8162, //CJK UNIFIED IDEOGRAPH + 0xC456: 0x8163, //CJK UNIFIED IDEOGRAPH + 0xC457: 0x8164, //CJK UNIFIED IDEOGRAPH + 0xC458: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xC459: 0x8168, //CJK UNIFIED IDEOGRAPH + 0xC45A: 0x816A, //CJK UNIFIED IDEOGRAPH + 0xC45B: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xC45C: 0x816C, //CJK UNIFIED IDEOGRAPH + 0xC45D: 0x816F, //CJK UNIFIED IDEOGRAPH + 0xC45E: 0x8172, //CJK UNIFIED IDEOGRAPH + 0xC45F: 0x8173, //CJK UNIFIED IDEOGRAPH + 0xC460: 0x8175, //CJK UNIFIED IDEOGRAPH + 0xC461: 0x8176, //CJK UNIFIED IDEOGRAPH + 0xC462: 0x8177, //CJK UNIFIED IDEOGRAPH + 0xC463: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xC464: 0x8181, //CJK UNIFIED IDEOGRAPH + 0xC465: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xC466: 0x8184, //CJK UNIFIED IDEOGRAPH + 0xC467: 0x8185, //CJK UNIFIED IDEOGRAPH + 0xC468: 0x8186, //CJK UNIFIED IDEOGRAPH + 0xC469: 0x8187, //CJK UNIFIED IDEOGRAPH + 0xC46A: 0x8189, //CJK UNIFIED IDEOGRAPH + 0xC46B: 0x818B, //CJK UNIFIED IDEOGRAPH + 0xC46C: 0x818C, //CJK UNIFIED IDEOGRAPH + 0xC46D: 0x818D, //CJK UNIFIED IDEOGRAPH + 0xC46E: 0x818E, //CJK UNIFIED IDEOGRAPH + 0xC46F: 0x8190, //CJK UNIFIED IDEOGRAPH + 0xC470: 0x8192, //CJK UNIFIED IDEOGRAPH + 0xC471: 0x8193, //CJK UNIFIED IDEOGRAPH + 0xC472: 0x8194, //CJK UNIFIED IDEOGRAPH + 0xC473: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xC474: 0x8196, //CJK UNIFIED IDEOGRAPH + 0xC475: 0x8197, //CJK UNIFIED IDEOGRAPH + 0xC476: 0x8199, //CJK UNIFIED IDEOGRAPH + 0xC477: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xC478: 0x819E, //CJK UNIFIED IDEOGRAPH + 0xC479: 0x819F, //CJK UNIFIED IDEOGRAPH + 0xC47A: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xC47B: 0x81A1, //CJK UNIFIED IDEOGRAPH + 0xC47C: 0x81A2, //CJK UNIFIED IDEOGRAPH + 0xC47D: 0x81A4, //CJK UNIFIED IDEOGRAPH + 0xC47E: 0x81A5, //CJK UNIFIED IDEOGRAPH + 0xC480: 0x81A7, //CJK UNIFIED IDEOGRAPH + 0xC481: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xC482: 0x81AB, //CJK UNIFIED IDEOGRAPH + 0xC483: 0x81AC, //CJK UNIFIED IDEOGRAPH + 0xC484: 0x81AD, //CJK UNIFIED IDEOGRAPH + 0xC485: 0x81AE, //CJK UNIFIED IDEOGRAPH + 0xC486: 0x81AF, //CJK UNIFIED IDEOGRAPH + 0xC487: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xC488: 0x81B1, //CJK UNIFIED IDEOGRAPH + 0xC489: 0x81B2, //CJK UNIFIED IDEOGRAPH + 0xC48A: 0x81B4, //CJK UNIFIED IDEOGRAPH + 0xC48B: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xC48C: 0x81B6, //CJK UNIFIED IDEOGRAPH + 0xC48D: 0x81B7, //CJK UNIFIED IDEOGRAPH + 0xC48E: 0x81B8, //CJK UNIFIED IDEOGRAPH + 0xC48F: 0x81B9, //CJK UNIFIED IDEOGRAPH + 0xC490: 0x81BC, //CJK UNIFIED IDEOGRAPH + 0xC491: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xC492: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xC493: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xC494: 0x81C4, //CJK UNIFIED IDEOGRAPH + 0xC495: 0x81C5, //CJK UNIFIED IDEOGRAPH + 0xC496: 0x81C7, //CJK UNIFIED IDEOGRAPH + 0xC497: 0x81C8, //CJK UNIFIED IDEOGRAPH + 0xC498: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xC499: 0x81CB, //CJK UNIFIED IDEOGRAPH + 0xC49A: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xC49B: 0x81CE, //CJK UNIFIED IDEOGRAPH + 0xC49C: 0x81CF, //CJK UNIFIED IDEOGRAPH + 0xC49D: 0x81D0, //CJK UNIFIED IDEOGRAPH + 0xC49E: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xC49F: 0x81D2, //CJK UNIFIED IDEOGRAPH + 0xC4A0: 0x81D3, //CJK UNIFIED IDEOGRAPH + 0xC4A1: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xC4A2: 0x8611, //CJK UNIFIED IDEOGRAPH + 0xC4A3: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xC4A4: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xC4A5: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xC4A6: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xC4A7: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xC4A8: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xC4A9: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xC4AA: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xC4AB: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xC4AC: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xC4AD: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xC4AE: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xC4AF: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xC4B0: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xC4B1: 0x8C0B, //CJK UNIFIED IDEOGRAPH + 0xC4B2: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xC4B3: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xC4B4: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xC4B5: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xC4B6: 0x4EA9, //CJK UNIFIED IDEOGRAPH + 0xC4B7: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xC4B8: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xC4B9: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xC4BA: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xC4BB: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xC4BC: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xC4BD: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xC4BE: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xC4BF: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xC4C0: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xC4C1: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xC4C2: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xC4C3: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xC4C4: 0x54EA, //CJK UNIFIED IDEOGRAPH + 0xC4C5: 0x5450, //CJK UNIFIED IDEOGRAPH + 0xC4C6: 0x94A0, //CJK UNIFIED IDEOGRAPH + 0xC4C7: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xC4C8: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xC4C9: 0x7EB3, //CJK UNIFIED IDEOGRAPH + 0xC4CA: 0x6C16, //CJK UNIFIED IDEOGRAPH + 0xC4CB: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xC4CC: 0x5976, //CJK UNIFIED IDEOGRAPH + 0xC4CD: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xC4CE: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xC4CF: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xC4D0: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xC4D1: 0x96BE, //CJK UNIFIED IDEOGRAPH + 0xC4D2: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xC4D3: 0x6320, //CJK UNIFIED IDEOGRAPH + 0xC4D4: 0x8111, //CJK UNIFIED IDEOGRAPH + 0xC4D5: 0x607C, //CJK UNIFIED IDEOGRAPH + 0xC4D6: 0x95F9, //CJK UNIFIED IDEOGRAPH + 0xC4D7: 0x6DD6, //CJK UNIFIED IDEOGRAPH + 0xC4D8: 0x5462, //CJK UNIFIED IDEOGRAPH + 0xC4D9: 0x9981, //CJK UNIFIED IDEOGRAPH + 0xC4DA: 0x5185, //CJK UNIFIED IDEOGRAPH + 0xC4DB: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xC4DC: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xC4DD: 0x59AE, //CJK UNIFIED IDEOGRAPH + 0xC4DE: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xC4DF: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xC4E0: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xC4E1: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xC4E2: 0x62DF, //CJK UNIFIED IDEOGRAPH + 0xC4E3: 0x4F60, //CJK UNIFIED IDEOGRAPH + 0xC4E4: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xC4E5: 0x817B, //CJK UNIFIED IDEOGRAPH + 0xC4E6: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xC4E7: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xC4E8: 0x852B, //CJK UNIFIED IDEOGRAPH + 0xC4E9: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xC4EA: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xC4EB: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xC4EC: 0x64B5, //CJK UNIFIED IDEOGRAPH + 0xC4ED: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xC4EE: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xC4EF: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xC4F0: 0x917F, //CJK UNIFIED IDEOGRAPH + 0xC4F1: 0x9E1F, //CJK UNIFIED IDEOGRAPH + 0xC4F2: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xC4F3: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xC4F4: 0x8042, //CJK UNIFIED IDEOGRAPH + 0xC4F5: 0x5B7D, //CJK UNIFIED IDEOGRAPH + 0xC4F6: 0x556E, //CJK UNIFIED IDEOGRAPH + 0xC4F7: 0x954A, //CJK UNIFIED IDEOGRAPH + 0xC4F8: 0x954D, //CJK UNIFIED IDEOGRAPH + 0xC4F9: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xC4FA: 0x60A8, //CJK UNIFIED IDEOGRAPH + 0xC4FB: 0x67E0, //CJK UNIFIED IDEOGRAPH + 0xC4FC: 0x72DE, //CJK UNIFIED IDEOGRAPH + 0xC4FD: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xC4FE: 0x5B81, //CJK UNIFIED IDEOGRAPH + 0xC540: 0x81D4, //CJK UNIFIED IDEOGRAPH + 0xC541: 0x81D5, //CJK UNIFIED IDEOGRAPH + 0xC542: 0x81D6, //CJK UNIFIED IDEOGRAPH + 0xC543: 0x81D7, //CJK UNIFIED IDEOGRAPH + 0xC544: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xC545: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xC546: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xC547: 0x81DB, //CJK UNIFIED IDEOGRAPH + 0xC548: 0x81DC, //CJK UNIFIED IDEOGRAPH + 0xC549: 0x81DD, //CJK UNIFIED IDEOGRAPH + 0xC54A: 0x81DE, //CJK UNIFIED IDEOGRAPH + 0xC54B: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xC54C: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xC54D: 0x81E1, //CJK UNIFIED IDEOGRAPH + 0xC54E: 0x81E2, //CJK UNIFIED IDEOGRAPH + 0xC54F: 0x81E4, //CJK UNIFIED IDEOGRAPH + 0xC550: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xC551: 0x81E6, //CJK UNIFIED IDEOGRAPH + 0xC552: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xC553: 0x81E9, //CJK UNIFIED IDEOGRAPH + 0xC554: 0x81EB, //CJK UNIFIED IDEOGRAPH + 0xC555: 0x81EE, //CJK UNIFIED IDEOGRAPH + 0xC556: 0x81EF, //CJK UNIFIED IDEOGRAPH + 0xC557: 0x81F0, //CJK UNIFIED IDEOGRAPH + 0xC558: 0x81F1, //CJK UNIFIED IDEOGRAPH + 0xC559: 0x81F2, //CJK UNIFIED IDEOGRAPH + 0xC55A: 0x81F5, //CJK UNIFIED IDEOGRAPH + 0xC55B: 0x81F6, //CJK UNIFIED IDEOGRAPH + 0xC55C: 0x81F7, //CJK UNIFIED IDEOGRAPH + 0xC55D: 0x81F8, //CJK UNIFIED IDEOGRAPH + 0xC55E: 0x81F9, //CJK UNIFIED IDEOGRAPH + 0xC55F: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xC560: 0x81FD, //CJK UNIFIED IDEOGRAPH + 0xC561: 0x81FF, //CJK UNIFIED IDEOGRAPH + 0xC562: 0x8203, //CJK UNIFIED IDEOGRAPH + 0xC563: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xC564: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xC565: 0x8209, //CJK UNIFIED IDEOGRAPH + 0xC566: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xC567: 0x820B, //CJK UNIFIED IDEOGRAPH + 0xC568: 0x820E, //CJK UNIFIED IDEOGRAPH + 0xC569: 0x820F, //CJK UNIFIED IDEOGRAPH + 0xC56A: 0x8211, //CJK UNIFIED IDEOGRAPH + 0xC56B: 0x8213, //CJK UNIFIED IDEOGRAPH + 0xC56C: 0x8215, //CJK UNIFIED IDEOGRAPH + 0xC56D: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xC56E: 0x8217, //CJK UNIFIED IDEOGRAPH + 0xC56F: 0x8218, //CJK UNIFIED IDEOGRAPH + 0xC570: 0x8219, //CJK UNIFIED IDEOGRAPH + 0xC571: 0x821A, //CJK UNIFIED IDEOGRAPH + 0xC572: 0x821D, //CJK UNIFIED IDEOGRAPH + 0xC573: 0x8220, //CJK UNIFIED IDEOGRAPH + 0xC574: 0x8224, //CJK UNIFIED IDEOGRAPH + 0xC575: 0x8225, //CJK UNIFIED IDEOGRAPH + 0xC576: 0x8226, //CJK UNIFIED IDEOGRAPH + 0xC577: 0x8227, //CJK UNIFIED IDEOGRAPH + 0xC578: 0x8229, //CJK UNIFIED IDEOGRAPH + 0xC579: 0x822E, //CJK UNIFIED IDEOGRAPH + 0xC57A: 0x8232, //CJK UNIFIED IDEOGRAPH + 0xC57B: 0x823A, //CJK UNIFIED IDEOGRAPH + 0xC57C: 0x823C, //CJK UNIFIED IDEOGRAPH + 0xC57D: 0x823D, //CJK UNIFIED IDEOGRAPH + 0xC57E: 0x823F, //CJK UNIFIED IDEOGRAPH + 0xC580: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xC581: 0x8241, //CJK UNIFIED IDEOGRAPH + 0xC582: 0x8242, //CJK UNIFIED IDEOGRAPH + 0xC583: 0x8243, //CJK UNIFIED IDEOGRAPH + 0xC584: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xC585: 0x8246, //CJK UNIFIED IDEOGRAPH + 0xC586: 0x8248, //CJK UNIFIED IDEOGRAPH + 0xC587: 0x824A, //CJK UNIFIED IDEOGRAPH + 0xC588: 0x824C, //CJK UNIFIED IDEOGRAPH + 0xC589: 0x824D, //CJK UNIFIED IDEOGRAPH + 0xC58A: 0x824E, //CJK UNIFIED IDEOGRAPH + 0xC58B: 0x8250, //CJK UNIFIED IDEOGRAPH + 0xC58C: 0x8251, //CJK UNIFIED IDEOGRAPH + 0xC58D: 0x8252, //CJK UNIFIED IDEOGRAPH + 0xC58E: 0x8253, //CJK UNIFIED IDEOGRAPH + 0xC58F: 0x8254, //CJK UNIFIED IDEOGRAPH + 0xC590: 0x8255, //CJK UNIFIED IDEOGRAPH + 0xC591: 0x8256, //CJK UNIFIED IDEOGRAPH + 0xC592: 0x8257, //CJK UNIFIED IDEOGRAPH + 0xC593: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xC594: 0x825B, //CJK UNIFIED IDEOGRAPH + 0xC595: 0x825C, //CJK UNIFIED IDEOGRAPH + 0xC596: 0x825D, //CJK UNIFIED IDEOGRAPH + 0xC597: 0x825E, //CJK UNIFIED IDEOGRAPH + 0xC598: 0x8260, //CJK UNIFIED IDEOGRAPH + 0xC599: 0x8261, //CJK UNIFIED IDEOGRAPH + 0xC59A: 0x8262, //CJK UNIFIED IDEOGRAPH + 0xC59B: 0x8263, //CJK UNIFIED IDEOGRAPH + 0xC59C: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xC59D: 0x8265, //CJK UNIFIED IDEOGRAPH + 0xC59E: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xC59F: 0x8267, //CJK UNIFIED IDEOGRAPH + 0xC5A0: 0x8269, //CJK UNIFIED IDEOGRAPH + 0xC5A1: 0x62E7, //CJK UNIFIED IDEOGRAPH + 0xC5A2: 0x6CDE, //CJK UNIFIED IDEOGRAPH + 0xC5A3: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xC5A4: 0x626D, //CJK UNIFIED IDEOGRAPH + 0xC5A5: 0x94AE, //CJK UNIFIED IDEOGRAPH + 0xC5A6: 0x7EBD, //CJK UNIFIED IDEOGRAPH + 0xC5A7: 0x8113, //CJK UNIFIED IDEOGRAPH + 0xC5A8: 0x6D53, //CJK UNIFIED IDEOGRAPH + 0xC5A9: 0x519C, //CJK UNIFIED IDEOGRAPH + 0xC5AA: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xC5AB: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xC5AC: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xC5AD: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xC5AE: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xC5AF: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xC5B0: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xC5B1: 0x759F, //CJK UNIFIED IDEOGRAPH + 0xC5B2: 0x632A, //CJK UNIFIED IDEOGRAPH + 0xC5B3: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xC5B4: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xC5B5: 0x8BFA, //CJK UNIFIED IDEOGRAPH + 0xC5B6: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0xC5B7: 0x6B27, //CJK UNIFIED IDEOGRAPH + 0xC5B8: 0x9E25, //CJK UNIFIED IDEOGRAPH + 0xC5B9: 0x6BB4, //CJK UNIFIED IDEOGRAPH + 0xC5BA: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xC5BB: 0x5455, //CJK UNIFIED IDEOGRAPH + 0xC5BC: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xC5BD: 0x6CA4, //CJK UNIFIED IDEOGRAPH + 0xC5BE: 0x556A, //CJK UNIFIED IDEOGRAPH + 0xC5BF: 0x8DB4, //CJK UNIFIED IDEOGRAPH + 0xC5C0: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xC5C1: 0x5E15, //CJK UNIFIED IDEOGRAPH + 0xC5C2: 0x6015, //CJK UNIFIED IDEOGRAPH + 0xC5C3: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xC5C4: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xC5C5: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xC5C6: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xC5C7: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xC5C8: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xC5C9: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xC5CA: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xC5CB: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xC5CC: 0x76D8, //CJK UNIFIED IDEOGRAPH + 0xC5CD: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xC5CE: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xC5CF: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xC5D0: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xC5D1: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xC5D2: 0x4E53, //CJK UNIFIED IDEOGRAPH + 0xC5D3: 0x5E9E, //CJK UNIFIED IDEOGRAPH + 0xC5D4: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xC5D5: 0x802A, //CJK UNIFIED IDEOGRAPH + 0xC5D6: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xC5D7: 0x629B, //CJK UNIFIED IDEOGRAPH + 0xC5D8: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xC5D9: 0x5228, //CJK UNIFIED IDEOGRAPH + 0xC5DA: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xC5DB: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xC5DC: 0x8DD1, //CJK UNIFIED IDEOGRAPH + 0xC5DD: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xC5DE: 0x5478, //CJK UNIFIED IDEOGRAPH + 0xC5DF: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xC5E0: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xC5E1: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xC5E2: 0x8D54, //CJK UNIFIED IDEOGRAPH + 0xC5E3: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xC5E4: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xC5E5: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xC5E6: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xC5E7: 0x55B7, //CJK UNIFIED IDEOGRAPH + 0xC5E8: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xC5E9: 0x7830, //CJK UNIFIED IDEOGRAPH + 0xC5EA: 0x62A8, //CJK UNIFIED IDEOGRAPH + 0xC5EB: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xC5EC: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xC5ED: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xC5EE: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xC5EF: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xC5F0: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xC5F1: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xC5F2: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xC5F3: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xC5F4: 0x9E4F, //CJK UNIFIED IDEOGRAPH + 0xC5F5: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xC5F6: 0x78B0, //CJK UNIFIED IDEOGRAPH + 0xC5F7: 0x576F, //CJK UNIFIED IDEOGRAPH + 0xC5F8: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xC5F9: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xC5FA: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xC5FB: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xC5FC: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xC5FD: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xC5FE: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xC640: 0x826A, //CJK UNIFIED IDEOGRAPH + 0xC641: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xC642: 0x826C, //CJK UNIFIED IDEOGRAPH + 0xC643: 0x826D, //CJK UNIFIED IDEOGRAPH + 0xC644: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xC645: 0x8275, //CJK UNIFIED IDEOGRAPH + 0xC646: 0x8276, //CJK UNIFIED IDEOGRAPH + 0xC647: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xC648: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xC649: 0x827B, //CJK UNIFIED IDEOGRAPH + 0xC64A: 0x827C, //CJK UNIFIED IDEOGRAPH + 0xC64B: 0x8280, //CJK UNIFIED IDEOGRAPH + 0xC64C: 0x8281, //CJK UNIFIED IDEOGRAPH + 0xC64D: 0x8283, //CJK UNIFIED IDEOGRAPH + 0xC64E: 0x8285, //CJK UNIFIED IDEOGRAPH + 0xC64F: 0x8286, //CJK UNIFIED IDEOGRAPH + 0xC650: 0x8287, //CJK UNIFIED IDEOGRAPH + 0xC651: 0x8289, //CJK UNIFIED IDEOGRAPH + 0xC652: 0x828C, //CJK UNIFIED IDEOGRAPH + 0xC653: 0x8290, //CJK UNIFIED IDEOGRAPH + 0xC654: 0x8293, //CJK UNIFIED IDEOGRAPH + 0xC655: 0x8294, //CJK UNIFIED IDEOGRAPH + 0xC656: 0x8295, //CJK UNIFIED IDEOGRAPH + 0xC657: 0x8296, //CJK UNIFIED IDEOGRAPH + 0xC658: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xC659: 0x829B, //CJK UNIFIED IDEOGRAPH + 0xC65A: 0x829E, //CJK UNIFIED IDEOGRAPH + 0xC65B: 0x82A0, //CJK UNIFIED IDEOGRAPH + 0xC65C: 0x82A2, //CJK UNIFIED IDEOGRAPH + 0xC65D: 0x82A3, //CJK UNIFIED IDEOGRAPH + 0xC65E: 0x82A7, //CJK UNIFIED IDEOGRAPH + 0xC65F: 0x82B2, //CJK UNIFIED IDEOGRAPH + 0xC660: 0x82B5, //CJK UNIFIED IDEOGRAPH + 0xC661: 0x82B6, //CJK UNIFIED IDEOGRAPH + 0xC662: 0x82BA, //CJK UNIFIED IDEOGRAPH + 0xC663: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xC664: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xC665: 0x82BF, //CJK UNIFIED IDEOGRAPH + 0xC666: 0x82C0, //CJK UNIFIED IDEOGRAPH + 0xC667: 0x82C2, //CJK UNIFIED IDEOGRAPH + 0xC668: 0x82C3, //CJK UNIFIED IDEOGRAPH + 0xC669: 0x82C5, //CJK UNIFIED IDEOGRAPH + 0xC66A: 0x82C6, //CJK UNIFIED IDEOGRAPH + 0xC66B: 0x82C9, //CJK UNIFIED IDEOGRAPH + 0xC66C: 0x82D0, //CJK UNIFIED IDEOGRAPH + 0xC66D: 0x82D6, //CJK UNIFIED IDEOGRAPH + 0xC66E: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xC66F: 0x82DA, //CJK UNIFIED IDEOGRAPH + 0xC670: 0x82DD, //CJK UNIFIED IDEOGRAPH + 0xC671: 0x82E2, //CJK UNIFIED IDEOGRAPH + 0xC672: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xC673: 0x82E8, //CJK UNIFIED IDEOGRAPH + 0xC674: 0x82E9, //CJK UNIFIED IDEOGRAPH + 0xC675: 0x82EA, //CJK UNIFIED IDEOGRAPH + 0xC676: 0x82EC, //CJK UNIFIED IDEOGRAPH + 0xC677: 0x82ED, //CJK UNIFIED IDEOGRAPH + 0xC678: 0x82EE, //CJK UNIFIED IDEOGRAPH + 0xC679: 0x82F0, //CJK UNIFIED IDEOGRAPH + 0xC67A: 0x82F2, //CJK UNIFIED IDEOGRAPH + 0xC67B: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xC67C: 0x82F5, //CJK UNIFIED IDEOGRAPH + 0xC67D: 0x82F6, //CJK UNIFIED IDEOGRAPH + 0xC67E: 0x82F8, //CJK UNIFIED IDEOGRAPH + 0xC680: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xC681: 0x82FC, //CJK UNIFIED IDEOGRAPH + 0xC682: 0x82FD, //CJK UNIFIED IDEOGRAPH + 0xC683: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xC684: 0x82FF, //CJK UNIFIED IDEOGRAPH + 0xC685: 0x8300, //CJK UNIFIED IDEOGRAPH + 0xC686: 0x830A, //CJK UNIFIED IDEOGRAPH + 0xC687: 0x830B, //CJK UNIFIED IDEOGRAPH + 0xC688: 0x830D, //CJK UNIFIED IDEOGRAPH + 0xC689: 0x8310, //CJK UNIFIED IDEOGRAPH + 0xC68A: 0x8312, //CJK UNIFIED IDEOGRAPH + 0xC68B: 0x8313, //CJK UNIFIED IDEOGRAPH + 0xC68C: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xC68D: 0x8318, //CJK UNIFIED IDEOGRAPH + 0xC68E: 0x8319, //CJK UNIFIED IDEOGRAPH + 0xC68F: 0x831D, //CJK UNIFIED IDEOGRAPH + 0xC690: 0x831E, //CJK UNIFIED IDEOGRAPH + 0xC691: 0x831F, //CJK UNIFIED IDEOGRAPH + 0xC692: 0x8320, //CJK UNIFIED IDEOGRAPH + 0xC693: 0x8321, //CJK UNIFIED IDEOGRAPH + 0xC694: 0x8322, //CJK UNIFIED IDEOGRAPH + 0xC695: 0x8323, //CJK UNIFIED IDEOGRAPH + 0xC696: 0x8324, //CJK UNIFIED IDEOGRAPH + 0xC697: 0x8325, //CJK UNIFIED IDEOGRAPH + 0xC698: 0x8326, //CJK UNIFIED IDEOGRAPH + 0xC699: 0x8329, //CJK UNIFIED IDEOGRAPH + 0xC69A: 0x832A, //CJK UNIFIED IDEOGRAPH + 0xC69B: 0x832E, //CJK UNIFIED IDEOGRAPH + 0xC69C: 0x8330, //CJK UNIFIED IDEOGRAPH + 0xC69D: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xC69E: 0x8337, //CJK UNIFIED IDEOGRAPH + 0xC69F: 0x833B, //CJK UNIFIED IDEOGRAPH + 0xC6A0: 0x833D, //CJK UNIFIED IDEOGRAPH + 0xC6A1: 0x5564, //CJK UNIFIED IDEOGRAPH + 0xC6A2: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xC6A3: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xC6A4: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xC6A5: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xC6A6: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xC6A7: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xC6A8: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0xC6A9: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xC6AA: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xC6AB: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xC6AC: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xC6AD: 0x9A97, //CJK UNIFIED IDEOGRAPH + 0xC6AE: 0x98D8, //CJK UNIFIED IDEOGRAPH + 0xC6AF: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xC6B0: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xC6B1: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xC6B2: 0x6487, //CJK UNIFIED IDEOGRAPH + 0xC6B3: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xC6B4: 0x62FC, //CJK UNIFIED IDEOGRAPH + 0xC6B5: 0x9891, //CJK UNIFIED IDEOGRAPH + 0xC6B6: 0x8D2B, //CJK UNIFIED IDEOGRAPH + 0xC6B7: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xC6B8: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xC6B9: 0x4E52, //CJK UNIFIED IDEOGRAPH + 0xC6BA: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xC6BB: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xC6BC: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xC6BD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xC6BE: 0x51ED, //CJK UNIFIED IDEOGRAPH + 0xC6BF: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0xC6C0: 0x8BC4, //CJK UNIFIED IDEOGRAPH + 0xC6C1: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0xC6C2: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xC6C3: 0x6CFC, //CJK UNIFIED IDEOGRAPH + 0xC6C4: 0x9887, //CJK UNIFIED IDEOGRAPH + 0xC6C5: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xC6C6: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xC6C7: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xC6C8: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xC6C9: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xC6CA: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xC6CB: 0x6251, //CJK UNIFIED IDEOGRAPH + 0xC6CC: 0x94FA, //CJK UNIFIED IDEOGRAPH + 0xC6CD: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0xC6CE: 0x8386, //CJK UNIFIED IDEOGRAPH + 0xC6CF: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xC6D0: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xC6D1: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xC6D2: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0xC6D3: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xC6D4: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xC6D5: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xC6D6: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xC6D7: 0x8C31, //CJK UNIFIED IDEOGRAPH + 0xC6D8: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xC6D9: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xC6DA: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xC6DB: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xC6DC: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xC6DD: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xC6DE: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xC6DF: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xC6E0: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xC6E1: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xC6E2: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xC6E3: 0x6C8F, //CJK UNIFIED IDEOGRAPH + 0xC6E4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xC6E5: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xC6E6: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xC6E7: 0x6B67, //CJK UNIFIED IDEOGRAPH + 0xC6E8: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xC6E9: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xC6EA: 0x8110, //CJK UNIFIED IDEOGRAPH + 0xC6EB: 0x9F50, //CJK UNIFIED IDEOGRAPH + 0xC6EC: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xC6ED: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xC6EE: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xC6EF: 0x9A91, //CJK UNIFIED IDEOGRAPH + 0xC6F0: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xC6F1: 0x5C82, //CJK UNIFIED IDEOGRAPH + 0xC6F2: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xC6F3: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xC6F4: 0x542F, //CJK UNIFIED IDEOGRAPH + 0xC6F5: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xC6F6: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xC6F7: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xC6F8: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0xC6F9: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0xC6FA: 0x5F03, //CJK UNIFIED IDEOGRAPH + 0xC6FB: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xC6FC: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xC6FD: 0x8BAB, //CJK UNIFIED IDEOGRAPH + 0xC6FE: 0x6390, //CJK UNIFIED IDEOGRAPH + 0xC740: 0x833E, //CJK UNIFIED IDEOGRAPH + 0xC741: 0x833F, //CJK UNIFIED IDEOGRAPH + 0xC742: 0x8341, //CJK UNIFIED IDEOGRAPH + 0xC743: 0x8342, //CJK UNIFIED IDEOGRAPH + 0xC744: 0x8344, //CJK UNIFIED IDEOGRAPH + 0xC745: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xC746: 0x8348, //CJK UNIFIED IDEOGRAPH + 0xC747: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xC748: 0x834B, //CJK UNIFIED IDEOGRAPH + 0xC749: 0x834C, //CJK UNIFIED IDEOGRAPH + 0xC74A: 0x834D, //CJK UNIFIED IDEOGRAPH + 0xC74B: 0x834E, //CJK UNIFIED IDEOGRAPH + 0xC74C: 0x8353, //CJK UNIFIED IDEOGRAPH + 0xC74D: 0x8355, //CJK UNIFIED IDEOGRAPH + 0xC74E: 0x8356, //CJK UNIFIED IDEOGRAPH + 0xC74F: 0x8357, //CJK UNIFIED IDEOGRAPH + 0xC750: 0x8358, //CJK UNIFIED IDEOGRAPH + 0xC751: 0x8359, //CJK UNIFIED IDEOGRAPH + 0xC752: 0x835D, //CJK UNIFIED IDEOGRAPH + 0xC753: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xC754: 0x8370, //CJK UNIFIED IDEOGRAPH + 0xC755: 0x8371, //CJK UNIFIED IDEOGRAPH + 0xC756: 0x8372, //CJK UNIFIED IDEOGRAPH + 0xC757: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xC758: 0x8374, //CJK UNIFIED IDEOGRAPH + 0xC759: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xC75A: 0x8376, //CJK UNIFIED IDEOGRAPH + 0xC75B: 0x8379, //CJK UNIFIED IDEOGRAPH + 0xC75C: 0x837A, //CJK UNIFIED IDEOGRAPH + 0xC75D: 0x837E, //CJK UNIFIED IDEOGRAPH + 0xC75E: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xC75F: 0x8380, //CJK UNIFIED IDEOGRAPH + 0xC760: 0x8381, //CJK UNIFIED IDEOGRAPH + 0xC761: 0x8382, //CJK UNIFIED IDEOGRAPH + 0xC762: 0x8383, //CJK UNIFIED IDEOGRAPH + 0xC763: 0x8384, //CJK UNIFIED IDEOGRAPH + 0xC764: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xC765: 0x8388, //CJK UNIFIED IDEOGRAPH + 0xC766: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xC767: 0x838B, //CJK UNIFIED IDEOGRAPH + 0xC768: 0x838C, //CJK UNIFIED IDEOGRAPH + 0xC769: 0x838D, //CJK UNIFIED IDEOGRAPH + 0xC76A: 0x838F, //CJK UNIFIED IDEOGRAPH + 0xC76B: 0x8390, //CJK UNIFIED IDEOGRAPH + 0xC76C: 0x8391, //CJK UNIFIED IDEOGRAPH + 0xC76D: 0x8394, //CJK UNIFIED IDEOGRAPH + 0xC76E: 0x8395, //CJK UNIFIED IDEOGRAPH + 0xC76F: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xC770: 0x8397, //CJK UNIFIED IDEOGRAPH + 0xC771: 0x8399, //CJK UNIFIED IDEOGRAPH + 0xC772: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xC773: 0x839D, //CJK UNIFIED IDEOGRAPH + 0xC774: 0x839F, //CJK UNIFIED IDEOGRAPH + 0xC775: 0x83A1, //CJK UNIFIED IDEOGRAPH + 0xC776: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xC777: 0x83A3, //CJK UNIFIED IDEOGRAPH + 0xC778: 0x83A4, //CJK UNIFIED IDEOGRAPH + 0xC779: 0x83A5, //CJK UNIFIED IDEOGRAPH + 0xC77A: 0x83A6, //CJK UNIFIED IDEOGRAPH + 0xC77B: 0x83A7, //CJK UNIFIED IDEOGRAPH + 0xC77C: 0x83AC, //CJK UNIFIED IDEOGRAPH + 0xC77D: 0x83AD, //CJK UNIFIED IDEOGRAPH + 0xC77E: 0x83AE, //CJK UNIFIED IDEOGRAPH + 0xC780: 0x83AF, //CJK UNIFIED IDEOGRAPH + 0xC781: 0x83B5, //CJK UNIFIED IDEOGRAPH + 0xC782: 0x83BB, //CJK UNIFIED IDEOGRAPH + 0xC783: 0x83BE, //CJK UNIFIED IDEOGRAPH + 0xC784: 0x83BF, //CJK UNIFIED IDEOGRAPH + 0xC785: 0x83C2, //CJK UNIFIED IDEOGRAPH + 0xC786: 0x83C3, //CJK UNIFIED IDEOGRAPH + 0xC787: 0x83C4, //CJK UNIFIED IDEOGRAPH + 0xC788: 0x83C6, //CJK UNIFIED IDEOGRAPH + 0xC789: 0x83C8, //CJK UNIFIED IDEOGRAPH + 0xC78A: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xC78B: 0x83CB, //CJK UNIFIED IDEOGRAPH + 0xC78C: 0x83CD, //CJK UNIFIED IDEOGRAPH + 0xC78D: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xC78E: 0x83D0, //CJK UNIFIED IDEOGRAPH + 0xC78F: 0x83D1, //CJK UNIFIED IDEOGRAPH + 0xC790: 0x83D2, //CJK UNIFIED IDEOGRAPH + 0xC791: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0xC792: 0x83D5, //CJK UNIFIED IDEOGRAPH + 0xC793: 0x83D7, //CJK UNIFIED IDEOGRAPH + 0xC794: 0x83D9, //CJK UNIFIED IDEOGRAPH + 0xC795: 0x83DA, //CJK UNIFIED IDEOGRAPH + 0xC796: 0x83DB, //CJK UNIFIED IDEOGRAPH + 0xC797: 0x83DE, //CJK UNIFIED IDEOGRAPH + 0xC798: 0x83E2, //CJK UNIFIED IDEOGRAPH + 0xC799: 0x83E3, //CJK UNIFIED IDEOGRAPH + 0xC79A: 0x83E4, //CJK UNIFIED IDEOGRAPH + 0xC79B: 0x83E6, //CJK UNIFIED IDEOGRAPH + 0xC79C: 0x83E7, //CJK UNIFIED IDEOGRAPH + 0xC79D: 0x83E8, //CJK UNIFIED IDEOGRAPH + 0xC79E: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xC79F: 0x83EC, //CJK UNIFIED IDEOGRAPH + 0xC7A0: 0x83ED, //CJK UNIFIED IDEOGRAPH + 0xC7A1: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xC7A2: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xC7A3: 0x7275, //CJK UNIFIED IDEOGRAPH + 0xC7A4: 0x6266, //CJK UNIFIED IDEOGRAPH + 0xC7A5: 0x948E, //CJK UNIFIED IDEOGRAPH + 0xC7A6: 0x94C5, //CJK UNIFIED IDEOGRAPH + 0xC7A7: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xC7A8: 0x8FC1, //CJK UNIFIED IDEOGRAPH + 0xC7A9: 0x7B7E, //CJK UNIFIED IDEOGRAPH + 0xC7AA: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xC7AB: 0x8C26, //CJK UNIFIED IDEOGRAPH + 0xC7AC: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xC7AD: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xC7AE: 0x94B1, //CJK UNIFIED IDEOGRAPH + 0xC7AF: 0x94B3, //CJK UNIFIED IDEOGRAPH + 0xC7B0: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xC7B1: 0x6F5C, //CJK UNIFIED IDEOGRAPH + 0xC7B2: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xC7B3: 0x6D45, //CJK UNIFIED IDEOGRAPH + 0xC7B4: 0x8C34, //CJK UNIFIED IDEOGRAPH + 0xC7B5: 0x5811, //CJK UNIFIED IDEOGRAPH + 0xC7B6: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xC7B7: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xC7B8: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0xC7B9: 0x67AA, //CJK UNIFIED IDEOGRAPH + 0xC7BA: 0x545B, //CJK UNIFIED IDEOGRAPH + 0xC7BB: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xC7BC: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xC7BD: 0x5899, //CJK UNIFIED IDEOGRAPH + 0xC7BE: 0x8537, //CJK UNIFIED IDEOGRAPH + 0xC7BF: 0x5F3A, //CJK UNIFIED IDEOGRAPH + 0xC7C0: 0x62A2, //CJK UNIFIED IDEOGRAPH + 0xC7C1: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0xC7C2: 0x9539, //CJK UNIFIED IDEOGRAPH + 0xC7C3: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xC7C4: 0x6084, //CJK UNIFIED IDEOGRAPH + 0xC7C5: 0x6865, //CJK UNIFIED IDEOGRAPH + 0xC7C6: 0x77A7, //CJK UNIFIED IDEOGRAPH + 0xC7C7: 0x4E54, //CJK UNIFIED IDEOGRAPH + 0xC7C8: 0x4FA8, //CJK UNIFIED IDEOGRAPH + 0xC7C9: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xC7CA: 0x9798, //CJK UNIFIED IDEOGRAPH + 0xC7CB: 0x64AC, //CJK UNIFIED IDEOGRAPH + 0xC7CC: 0x7FD8, //CJK UNIFIED IDEOGRAPH + 0xC7CD: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0xC7CE: 0x4FCF, //CJK UNIFIED IDEOGRAPH + 0xC7CF: 0x7A8D, //CJK UNIFIED IDEOGRAPH + 0xC7D0: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xC7D1: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xC7D2: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xC7D3: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xC7D4: 0x7A83, //CJK UNIFIED IDEOGRAPH + 0xC7D5: 0x94A6, //CJK UNIFIED IDEOGRAPH + 0xC7D6: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xC7D7: 0x4EB2, //CJK UNIFIED IDEOGRAPH + 0xC7D8: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xC7D9: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xC7DA: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xC7DB: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xC7DC: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xC7DD: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xC7DE: 0x5BDD, //CJK UNIFIED IDEOGRAPH + 0xC7DF: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xC7E0: 0x9752, //CJK UNIFIED IDEOGRAPH + 0xC7E1: 0x8F7B, //CJK UNIFIED IDEOGRAPH + 0xC7E2: 0x6C22, //CJK UNIFIED IDEOGRAPH + 0xC7E3: 0x503E, //CJK UNIFIED IDEOGRAPH + 0xC7E4: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xC7E5: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0xC7E6: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xC7E7: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xC7E8: 0x6C30, //CJK UNIFIED IDEOGRAPH + 0xC7E9: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xC7EA: 0x9877, //CJK UNIFIED IDEOGRAPH + 0xC7EB: 0x8BF7, //CJK UNIFIED IDEOGRAPH + 0xC7EC: 0x5E86, //CJK UNIFIED IDEOGRAPH + 0xC7ED: 0x743C, //CJK UNIFIED IDEOGRAPH + 0xC7EE: 0x7A77, //CJK UNIFIED IDEOGRAPH + 0xC7EF: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xC7F0: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xC7F1: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xC7F2: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xC7F3: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xC7F4: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xC7F5: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xC7F6: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0xC7F7: 0x8D8B, //CJK UNIFIED IDEOGRAPH + 0xC7F8: 0x533A, //CJK UNIFIED IDEOGRAPH + 0xC7F9: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xC7FA: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xC7FB: 0x8EAF, //CJK UNIFIED IDEOGRAPH + 0xC7FC: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xC7FD: 0x9A71, //CJK UNIFIED IDEOGRAPH + 0xC7FE: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xC840: 0x83EE, //CJK UNIFIED IDEOGRAPH + 0xC841: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xC842: 0x83F3, //CJK UNIFIED IDEOGRAPH + 0xC843: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xC844: 0x83F5, //CJK UNIFIED IDEOGRAPH + 0xC845: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xC846: 0x83F7, //CJK UNIFIED IDEOGRAPH + 0xC847: 0x83FA, //CJK UNIFIED IDEOGRAPH + 0xC848: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xC849: 0x83FC, //CJK UNIFIED IDEOGRAPH + 0xC84A: 0x83FE, //CJK UNIFIED IDEOGRAPH + 0xC84B: 0x83FF, //CJK UNIFIED IDEOGRAPH + 0xC84C: 0x8400, //CJK UNIFIED IDEOGRAPH + 0xC84D: 0x8402, //CJK UNIFIED IDEOGRAPH + 0xC84E: 0x8405, //CJK UNIFIED IDEOGRAPH + 0xC84F: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xC850: 0x8408, //CJK UNIFIED IDEOGRAPH + 0xC851: 0x8409, //CJK UNIFIED IDEOGRAPH + 0xC852: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xC853: 0x8410, //CJK UNIFIED IDEOGRAPH + 0xC854: 0x8412, //CJK UNIFIED IDEOGRAPH + 0xC855: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xC856: 0x8414, //CJK UNIFIED IDEOGRAPH + 0xC857: 0x8415, //CJK UNIFIED IDEOGRAPH + 0xC858: 0x8416, //CJK UNIFIED IDEOGRAPH + 0xC859: 0x8417, //CJK UNIFIED IDEOGRAPH + 0xC85A: 0x8419, //CJK UNIFIED IDEOGRAPH + 0xC85B: 0x841A, //CJK UNIFIED IDEOGRAPH + 0xC85C: 0x841B, //CJK UNIFIED IDEOGRAPH + 0xC85D: 0x841E, //CJK UNIFIED IDEOGRAPH + 0xC85E: 0x841F, //CJK UNIFIED IDEOGRAPH + 0xC85F: 0x8420, //CJK UNIFIED IDEOGRAPH + 0xC860: 0x8421, //CJK UNIFIED IDEOGRAPH + 0xC861: 0x8422, //CJK UNIFIED IDEOGRAPH + 0xC862: 0x8423, //CJK UNIFIED IDEOGRAPH + 0xC863: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xC864: 0x842A, //CJK UNIFIED IDEOGRAPH + 0xC865: 0x842B, //CJK UNIFIED IDEOGRAPH + 0xC866: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xC867: 0x842D, //CJK UNIFIED IDEOGRAPH + 0xC868: 0x842E, //CJK UNIFIED IDEOGRAPH + 0xC869: 0x842F, //CJK UNIFIED IDEOGRAPH + 0xC86A: 0x8430, //CJK UNIFIED IDEOGRAPH + 0xC86B: 0x8432, //CJK UNIFIED IDEOGRAPH + 0xC86C: 0x8433, //CJK UNIFIED IDEOGRAPH + 0xC86D: 0x8434, //CJK UNIFIED IDEOGRAPH + 0xC86E: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xC86F: 0x8436, //CJK UNIFIED IDEOGRAPH + 0xC870: 0x8437, //CJK UNIFIED IDEOGRAPH + 0xC871: 0x8439, //CJK UNIFIED IDEOGRAPH + 0xC872: 0x843A, //CJK UNIFIED IDEOGRAPH + 0xC873: 0x843B, //CJK UNIFIED IDEOGRAPH + 0xC874: 0x843E, //CJK UNIFIED IDEOGRAPH + 0xC875: 0x843F, //CJK UNIFIED IDEOGRAPH + 0xC876: 0x8440, //CJK UNIFIED IDEOGRAPH + 0xC877: 0x8441, //CJK UNIFIED IDEOGRAPH + 0xC878: 0x8442, //CJK UNIFIED IDEOGRAPH + 0xC879: 0x8443, //CJK UNIFIED IDEOGRAPH + 0xC87A: 0x8444, //CJK UNIFIED IDEOGRAPH + 0xC87B: 0x8445, //CJK UNIFIED IDEOGRAPH + 0xC87C: 0x8447, //CJK UNIFIED IDEOGRAPH + 0xC87D: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xC87E: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xC880: 0x844A, //CJK UNIFIED IDEOGRAPH + 0xC881: 0x844B, //CJK UNIFIED IDEOGRAPH + 0xC882: 0x844C, //CJK UNIFIED IDEOGRAPH + 0xC883: 0x844D, //CJK UNIFIED IDEOGRAPH + 0xC884: 0x844E, //CJK UNIFIED IDEOGRAPH + 0xC885: 0x844F, //CJK UNIFIED IDEOGRAPH + 0xC886: 0x8450, //CJK UNIFIED IDEOGRAPH + 0xC887: 0x8452, //CJK UNIFIED IDEOGRAPH + 0xC888: 0x8453, //CJK UNIFIED IDEOGRAPH + 0xC889: 0x8454, //CJK UNIFIED IDEOGRAPH + 0xC88A: 0x8455, //CJK UNIFIED IDEOGRAPH + 0xC88B: 0x8456, //CJK UNIFIED IDEOGRAPH + 0xC88C: 0x8458, //CJK UNIFIED IDEOGRAPH + 0xC88D: 0x845D, //CJK UNIFIED IDEOGRAPH + 0xC88E: 0x845E, //CJK UNIFIED IDEOGRAPH + 0xC88F: 0x845F, //CJK UNIFIED IDEOGRAPH + 0xC890: 0x8460, //CJK UNIFIED IDEOGRAPH + 0xC891: 0x8462, //CJK UNIFIED IDEOGRAPH + 0xC892: 0x8464, //CJK UNIFIED IDEOGRAPH + 0xC893: 0x8465, //CJK UNIFIED IDEOGRAPH + 0xC894: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xC895: 0x8467, //CJK UNIFIED IDEOGRAPH + 0xC896: 0x8468, //CJK UNIFIED IDEOGRAPH + 0xC897: 0x846A, //CJK UNIFIED IDEOGRAPH + 0xC898: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xC899: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xC89A: 0x8470, //CJK UNIFIED IDEOGRAPH + 0xC89B: 0x8472, //CJK UNIFIED IDEOGRAPH + 0xC89C: 0x8474, //CJK UNIFIED IDEOGRAPH + 0xC89D: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xC89E: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xC89F: 0x847B, //CJK UNIFIED IDEOGRAPH + 0xC8A0: 0x847C, //CJK UNIFIED IDEOGRAPH + 0xC8A1: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xC8A2: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xC8A3: 0x9F8B, //CJK UNIFIED IDEOGRAPH + 0xC8A4: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xC8A5: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xC8A6: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xC8A7: 0x98A7, //CJK UNIFIED IDEOGRAPH + 0xC8A8: 0x6743, //CJK UNIFIED IDEOGRAPH + 0xC8A9: 0x919B, //CJK UNIFIED IDEOGRAPH + 0xC8AA: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xC8AB: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xC8AC: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xC8AD: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xC8AE: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xC8AF: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xC8B0: 0x529D, //CJK UNIFIED IDEOGRAPH + 0xC8B1: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xC8B2: 0x7094, //CJK UNIFIED IDEOGRAPH + 0xC8B3: 0x7638, //CJK UNIFIED IDEOGRAPH + 0xC8B4: 0x5374, //CJK UNIFIED IDEOGRAPH + 0xC8B5: 0x9E4A, //CJK UNIFIED IDEOGRAPH + 0xC8B6: 0x69B7, //CJK UNIFIED IDEOGRAPH + 0xC8B7: 0x786E, //CJK UNIFIED IDEOGRAPH + 0xC8B8: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xC8B9: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xC8BA: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xC8BB: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xC8BC: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xC8BD: 0x5189, //CJK UNIFIED IDEOGRAPH + 0xC8BE: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xC8BF: 0x74E4, //CJK UNIFIED IDEOGRAPH + 0xC8C0: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xC8C1: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xC8C2: 0x56B7, //CJK UNIFIED IDEOGRAPH + 0xC8C3: 0x8BA9, //CJK UNIFIED IDEOGRAPH + 0xC8C4: 0x9976, //CJK UNIFIED IDEOGRAPH + 0xC8C5: 0x6270, //CJK UNIFIED IDEOGRAPH + 0xC8C6: 0x7ED5, //CJK UNIFIED IDEOGRAPH + 0xC8C7: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xC8C8: 0x70ED, //CJK UNIFIED IDEOGRAPH + 0xC8C9: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xC8CA: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xC8CB: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xC8CC: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xC8CD: 0x97E7, //CJK UNIFIED IDEOGRAPH + 0xC8CE: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xC8CF: 0x8BA4, //CJK UNIFIED IDEOGRAPH + 0xC8D0: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xC8D1: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xC8D2: 0x7EAB, //CJK UNIFIED IDEOGRAPH + 0xC8D3: 0x6254, //CJK UNIFIED IDEOGRAPH + 0xC8D4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xC8D5: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xC8D6: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xC8D7: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xC8D8: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xC8D9: 0x8363, //CJK UNIFIED IDEOGRAPH + 0xC8DA: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xC8DB: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xC8DC: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xC8DD: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xC8DE: 0x7ED2, //CJK UNIFIED IDEOGRAPH + 0xC8DF: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xC8E0: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0xC8E1: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xC8E2: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xC8E3: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xC8E4: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xC8E5: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xC8E6: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xC8E7: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xC8E8: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xC8E9: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xC8EA: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xC8EB: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xC8EC: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xC8ED: 0x8F6F, //CJK UNIFIED IDEOGRAPH + 0xC8EE: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xC8EF: 0x854A, //CJK UNIFIED IDEOGRAPH + 0xC8F0: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xC8F1: 0x9510, //CJK UNIFIED IDEOGRAPH + 0xC8F2: 0x95F0, //CJK UNIFIED IDEOGRAPH + 0xC8F3: 0x6DA6, //CJK UNIFIED IDEOGRAPH + 0xC8F4: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xC8F5: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xC8F6: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xC8F7: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0xC8F8: 0x8428, //CJK UNIFIED IDEOGRAPH + 0xC8F9: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xC8FA: 0x9CC3, //CJK UNIFIED IDEOGRAPH + 0xC8FB: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xC8FC: 0x8D5B, //CJK UNIFIED IDEOGRAPH + 0xC8FD: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xC8FE: 0x53C1, //CJK UNIFIED IDEOGRAPH + 0xC940: 0x847D, //CJK UNIFIED IDEOGRAPH + 0xC941: 0x847E, //CJK UNIFIED IDEOGRAPH + 0xC942: 0x847F, //CJK UNIFIED IDEOGRAPH + 0xC943: 0x8480, //CJK UNIFIED IDEOGRAPH + 0xC944: 0x8481, //CJK UNIFIED IDEOGRAPH + 0xC945: 0x8483, //CJK UNIFIED IDEOGRAPH + 0xC946: 0x8484, //CJK UNIFIED IDEOGRAPH + 0xC947: 0x8485, //CJK UNIFIED IDEOGRAPH + 0xC948: 0x8486, //CJK UNIFIED IDEOGRAPH + 0xC949: 0x848A, //CJK UNIFIED IDEOGRAPH + 0xC94A: 0x848D, //CJK UNIFIED IDEOGRAPH + 0xC94B: 0x848F, //CJK UNIFIED IDEOGRAPH + 0xC94C: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xC94D: 0x8491, //CJK UNIFIED IDEOGRAPH + 0xC94E: 0x8492, //CJK UNIFIED IDEOGRAPH + 0xC94F: 0x8493, //CJK UNIFIED IDEOGRAPH + 0xC950: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xC951: 0x8495, //CJK UNIFIED IDEOGRAPH + 0xC952: 0x8496, //CJK UNIFIED IDEOGRAPH + 0xC953: 0x8498, //CJK UNIFIED IDEOGRAPH + 0xC954: 0x849A, //CJK UNIFIED IDEOGRAPH + 0xC955: 0x849B, //CJK UNIFIED IDEOGRAPH + 0xC956: 0x849D, //CJK UNIFIED IDEOGRAPH + 0xC957: 0x849E, //CJK UNIFIED IDEOGRAPH + 0xC958: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xC959: 0x84A0, //CJK UNIFIED IDEOGRAPH + 0xC95A: 0x84A2, //CJK UNIFIED IDEOGRAPH + 0xC95B: 0x84A3, //CJK UNIFIED IDEOGRAPH + 0xC95C: 0x84A4, //CJK UNIFIED IDEOGRAPH + 0xC95D: 0x84A5, //CJK UNIFIED IDEOGRAPH + 0xC95E: 0x84A6, //CJK UNIFIED IDEOGRAPH + 0xC95F: 0x84A7, //CJK UNIFIED IDEOGRAPH + 0xC960: 0x84A8, //CJK UNIFIED IDEOGRAPH + 0xC961: 0x84A9, //CJK UNIFIED IDEOGRAPH + 0xC962: 0x84AA, //CJK UNIFIED IDEOGRAPH + 0xC963: 0x84AB, //CJK UNIFIED IDEOGRAPH + 0xC964: 0x84AC, //CJK UNIFIED IDEOGRAPH + 0xC965: 0x84AD, //CJK UNIFIED IDEOGRAPH + 0xC966: 0x84AE, //CJK UNIFIED IDEOGRAPH + 0xC967: 0x84B0, //CJK UNIFIED IDEOGRAPH + 0xC968: 0x84B1, //CJK UNIFIED IDEOGRAPH + 0xC969: 0x84B3, //CJK UNIFIED IDEOGRAPH + 0xC96A: 0x84B5, //CJK UNIFIED IDEOGRAPH + 0xC96B: 0x84B6, //CJK UNIFIED IDEOGRAPH + 0xC96C: 0x84B7, //CJK UNIFIED IDEOGRAPH + 0xC96D: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xC96E: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xC96F: 0x84BE, //CJK UNIFIED IDEOGRAPH + 0xC970: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xC971: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xC972: 0x84C3, //CJK UNIFIED IDEOGRAPH + 0xC973: 0x84C5, //CJK UNIFIED IDEOGRAPH + 0xC974: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xC975: 0x84C7, //CJK UNIFIED IDEOGRAPH + 0xC976: 0x84C8, //CJK UNIFIED IDEOGRAPH + 0xC977: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xC978: 0x84CC, //CJK UNIFIED IDEOGRAPH + 0xC979: 0x84CE, //CJK UNIFIED IDEOGRAPH + 0xC97A: 0x84CF, //CJK UNIFIED IDEOGRAPH + 0xC97B: 0x84D2, //CJK UNIFIED IDEOGRAPH + 0xC97C: 0x84D4, //CJK UNIFIED IDEOGRAPH + 0xC97D: 0x84D5, //CJK UNIFIED IDEOGRAPH + 0xC97E: 0x84D7, //CJK UNIFIED IDEOGRAPH + 0xC980: 0x84D8, //CJK UNIFIED IDEOGRAPH + 0xC981: 0x84D9, //CJK UNIFIED IDEOGRAPH + 0xC982: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xC983: 0x84DB, //CJK UNIFIED IDEOGRAPH + 0xC984: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xC985: 0x84DE, //CJK UNIFIED IDEOGRAPH + 0xC986: 0x84E1, //CJK UNIFIED IDEOGRAPH + 0xC987: 0x84E2, //CJK UNIFIED IDEOGRAPH + 0xC988: 0x84E4, //CJK UNIFIED IDEOGRAPH + 0xC989: 0x84E7, //CJK UNIFIED IDEOGRAPH + 0xC98A: 0x84E8, //CJK UNIFIED IDEOGRAPH + 0xC98B: 0x84E9, //CJK UNIFIED IDEOGRAPH + 0xC98C: 0x84EA, //CJK UNIFIED IDEOGRAPH + 0xC98D: 0x84EB, //CJK UNIFIED IDEOGRAPH + 0xC98E: 0x84ED, //CJK UNIFIED IDEOGRAPH + 0xC98F: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xC990: 0x84EF, //CJK UNIFIED IDEOGRAPH + 0xC991: 0x84F1, //CJK UNIFIED IDEOGRAPH + 0xC992: 0x84F2, //CJK UNIFIED IDEOGRAPH + 0xC993: 0x84F3, //CJK UNIFIED IDEOGRAPH + 0xC994: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xC995: 0x84F5, //CJK UNIFIED IDEOGRAPH + 0xC996: 0x84F6, //CJK UNIFIED IDEOGRAPH + 0xC997: 0x84F7, //CJK UNIFIED IDEOGRAPH + 0xC998: 0x84F8, //CJK UNIFIED IDEOGRAPH + 0xC999: 0x84F9, //CJK UNIFIED IDEOGRAPH + 0xC99A: 0x84FA, //CJK UNIFIED IDEOGRAPH + 0xC99B: 0x84FB, //CJK UNIFIED IDEOGRAPH + 0xC99C: 0x84FD, //CJK UNIFIED IDEOGRAPH + 0xC99D: 0x84FE, //CJK UNIFIED IDEOGRAPH + 0xC99E: 0x8500, //CJK UNIFIED IDEOGRAPH + 0xC99F: 0x8501, //CJK UNIFIED IDEOGRAPH + 0xC9A0: 0x8502, //CJK UNIFIED IDEOGRAPH + 0xC9A1: 0x4F1E, //CJK UNIFIED IDEOGRAPH + 0xC9A2: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xC9A3: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xC9A4: 0x55D3, //CJK UNIFIED IDEOGRAPH + 0xC9A5: 0x4E27, //CJK UNIFIED IDEOGRAPH + 0xC9A6: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xC9A7: 0x9A9A, //CJK UNIFIED IDEOGRAPH + 0xC9A8: 0x626B, //CJK UNIFIED IDEOGRAPH + 0xC9A9: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xC9AA: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xC9AB: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xC9AC: 0x6DA9, //CJK UNIFIED IDEOGRAPH + 0xC9AD: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xC9AE: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xC9AF: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xC9B0: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xC9B1: 0x6740, //CJK UNIFIED IDEOGRAPH + 0xC9B2: 0x5239, //CJK UNIFIED IDEOGRAPH + 0xC9B3: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xC9B4: 0x7EB1, //CJK UNIFIED IDEOGRAPH + 0xC9B5: 0x50BB, //CJK UNIFIED IDEOGRAPH + 0xC9B6: 0x5565, //CJK UNIFIED IDEOGRAPH + 0xC9B7: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xC9B8: 0x7B5B, //CJK UNIFIED IDEOGRAPH + 0xC9B9: 0x6652, //CJK UNIFIED IDEOGRAPH + 0xC9BA: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xC9BB: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0xC9BC: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xC9BD: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xC9BE: 0x5220, //CJK UNIFIED IDEOGRAPH + 0xC9BF: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xC9C0: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xC9C1: 0x95EA, //CJK UNIFIED IDEOGRAPH + 0xC9C2: 0x9655, //CJK UNIFIED IDEOGRAPH + 0xC9C3: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xC9C4: 0x8D61, //CJK UNIFIED IDEOGRAPH + 0xC9C5: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xC9C6: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xC9C7: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xC9C8: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xC9C9: 0x7F2E, //CJK UNIFIED IDEOGRAPH + 0xC9CA: 0x5892, //CJK UNIFIED IDEOGRAPH + 0xC9CB: 0x4F24, //CJK UNIFIED IDEOGRAPH + 0xC9CC: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xC9CD: 0x8D4F, //CJK UNIFIED IDEOGRAPH + 0xC9CE: 0x664C, //CJK UNIFIED IDEOGRAPH + 0xC9CF: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xC9D0: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0xC9D1: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xC9D2: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xC9D3: 0x634E, //CJK UNIFIED IDEOGRAPH + 0xC9D4: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xC9D5: 0x70E7, //CJK UNIFIED IDEOGRAPH + 0xC9D6: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xC9D7: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xC9D8: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xC9D9: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xC9DA: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xC9DB: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xC9DC: 0x7ECD, //CJK UNIFIED IDEOGRAPH + 0xC9DD: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xC9DE: 0x8D4A, //CJK UNIFIED IDEOGRAPH + 0xC9DF: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xC9E0: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xC9E1: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xC9E2: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xC9E3: 0x6444, //CJK UNIFIED IDEOGRAPH + 0xC9E4: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xC9E5: 0x6151, //CJK UNIFIED IDEOGRAPH + 0xC9E6: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xC9E7: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xC9E8: 0x8BBE, //CJK UNIFIED IDEOGRAPH + 0xC9E9: 0x7837, //CJK UNIFIED IDEOGRAPH + 0xC9EA: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xC9EB: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xC9EC: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xC9ED: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xC9EE: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xC9EF: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xC9F0: 0x7EC5, //CJK UNIFIED IDEOGRAPH + 0xC9F1: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xC9F2: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xC9F3: 0x5BA1, //CJK UNIFIED IDEOGRAPH + 0xC9F4: 0x5A76, //CJK UNIFIED IDEOGRAPH + 0xC9F5: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xC9F6: 0x80BE, //CJK UNIFIED IDEOGRAPH + 0xC9F7: 0x614E, //CJK UNIFIED IDEOGRAPH + 0xC9F8: 0x6E17, //CJK UNIFIED IDEOGRAPH + 0xC9F9: 0x58F0, //CJK UNIFIED IDEOGRAPH + 0xC9FA: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xC9FB: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xC9FC: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xC9FD: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xC9FE: 0x7EF3, //CJK UNIFIED IDEOGRAPH + 0xCA40: 0x8503, //CJK UNIFIED IDEOGRAPH + 0xCA41: 0x8504, //CJK UNIFIED IDEOGRAPH + 0xCA42: 0x8505, //CJK UNIFIED IDEOGRAPH + 0xCA43: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xCA44: 0x8507, //CJK UNIFIED IDEOGRAPH + 0xCA45: 0x8508, //CJK UNIFIED IDEOGRAPH + 0xCA46: 0x8509, //CJK UNIFIED IDEOGRAPH + 0xCA47: 0x850A, //CJK UNIFIED IDEOGRAPH + 0xCA48: 0x850B, //CJK UNIFIED IDEOGRAPH + 0xCA49: 0x850D, //CJK UNIFIED IDEOGRAPH + 0xCA4A: 0x850E, //CJK UNIFIED IDEOGRAPH + 0xCA4B: 0x850F, //CJK UNIFIED IDEOGRAPH + 0xCA4C: 0x8510, //CJK UNIFIED IDEOGRAPH + 0xCA4D: 0x8512, //CJK UNIFIED IDEOGRAPH + 0xCA4E: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xCA4F: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xCA50: 0x8516, //CJK UNIFIED IDEOGRAPH + 0xCA51: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xCA52: 0x8519, //CJK UNIFIED IDEOGRAPH + 0xCA53: 0x851B, //CJK UNIFIED IDEOGRAPH + 0xCA54: 0x851C, //CJK UNIFIED IDEOGRAPH + 0xCA55: 0x851D, //CJK UNIFIED IDEOGRAPH + 0xCA56: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xCA57: 0x8520, //CJK UNIFIED IDEOGRAPH + 0xCA58: 0x8522, //CJK UNIFIED IDEOGRAPH + 0xCA59: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xCA5A: 0x8524, //CJK UNIFIED IDEOGRAPH + 0xCA5B: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xCA5C: 0x8526, //CJK UNIFIED IDEOGRAPH + 0xCA5D: 0x8527, //CJK UNIFIED IDEOGRAPH + 0xCA5E: 0x8528, //CJK UNIFIED IDEOGRAPH + 0xCA5F: 0x8529, //CJK UNIFIED IDEOGRAPH + 0xCA60: 0x852A, //CJK UNIFIED IDEOGRAPH + 0xCA61: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xCA62: 0x852E, //CJK UNIFIED IDEOGRAPH + 0xCA63: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xCA64: 0x8530, //CJK UNIFIED IDEOGRAPH + 0xCA65: 0x8531, //CJK UNIFIED IDEOGRAPH + 0xCA66: 0x8532, //CJK UNIFIED IDEOGRAPH + 0xCA67: 0x8533, //CJK UNIFIED IDEOGRAPH + 0xCA68: 0x8534, //CJK UNIFIED IDEOGRAPH + 0xCA69: 0x8535, //CJK UNIFIED IDEOGRAPH + 0xCA6A: 0x8536, //CJK UNIFIED IDEOGRAPH + 0xCA6B: 0x853E, //CJK UNIFIED IDEOGRAPH + 0xCA6C: 0x853F, //CJK UNIFIED IDEOGRAPH + 0xCA6D: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xCA6E: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xCA6F: 0x8542, //CJK UNIFIED IDEOGRAPH + 0xCA70: 0x8544, //CJK UNIFIED IDEOGRAPH + 0xCA71: 0x8545, //CJK UNIFIED IDEOGRAPH + 0xCA72: 0x8546, //CJK UNIFIED IDEOGRAPH + 0xCA73: 0x8547, //CJK UNIFIED IDEOGRAPH + 0xCA74: 0x854B, //CJK UNIFIED IDEOGRAPH + 0xCA75: 0x854C, //CJK UNIFIED IDEOGRAPH + 0xCA76: 0x854D, //CJK UNIFIED IDEOGRAPH + 0xCA77: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xCA78: 0x854F, //CJK UNIFIED IDEOGRAPH + 0xCA79: 0x8550, //CJK UNIFIED IDEOGRAPH + 0xCA7A: 0x8551, //CJK UNIFIED IDEOGRAPH + 0xCA7B: 0x8552, //CJK UNIFIED IDEOGRAPH + 0xCA7C: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xCA7D: 0x8554, //CJK UNIFIED IDEOGRAPH + 0xCA7E: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xCA80: 0x8557, //CJK UNIFIED IDEOGRAPH + 0xCA81: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xCA82: 0x855A, //CJK UNIFIED IDEOGRAPH + 0xCA83: 0x855B, //CJK UNIFIED IDEOGRAPH + 0xCA84: 0x855C, //CJK UNIFIED IDEOGRAPH + 0xCA85: 0x855D, //CJK UNIFIED IDEOGRAPH + 0xCA86: 0x855F, //CJK UNIFIED IDEOGRAPH + 0xCA87: 0x8560, //CJK UNIFIED IDEOGRAPH + 0xCA88: 0x8561, //CJK UNIFIED IDEOGRAPH + 0xCA89: 0x8562, //CJK UNIFIED IDEOGRAPH + 0xCA8A: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xCA8B: 0x8565, //CJK UNIFIED IDEOGRAPH + 0xCA8C: 0x8566, //CJK UNIFIED IDEOGRAPH + 0xCA8D: 0x8567, //CJK UNIFIED IDEOGRAPH + 0xCA8E: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xCA8F: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xCA90: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xCA91: 0x856C, //CJK UNIFIED IDEOGRAPH + 0xCA92: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xCA93: 0x856E, //CJK UNIFIED IDEOGRAPH + 0xCA94: 0x856F, //CJK UNIFIED IDEOGRAPH + 0xCA95: 0x8570, //CJK UNIFIED IDEOGRAPH + 0xCA96: 0x8571, //CJK UNIFIED IDEOGRAPH + 0xCA97: 0x8573, //CJK UNIFIED IDEOGRAPH + 0xCA98: 0x8575, //CJK UNIFIED IDEOGRAPH + 0xCA99: 0x8576, //CJK UNIFIED IDEOGRAPH + 0xCA9A: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xCA9B: 0x8578, //CJK UNIFIED IDEOGRAPH + 0xCA9C: 0x857C, //CJK UNIFIED IDEOGRAPH + 0xCA9D: 0x857D, //CJK UNIFIED IDEOGRAPH + 0xCA9E: 0x857F, //CJK UNIFIED IDEOGRAPH + 0xCA9F: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xCAA0: 0x8581, //CJK UNIFIED IDEOGRAPH + 0xCAA1: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x80DC, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x5723, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x5E08, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x72EE, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x6E7F, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x8BD7, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x65F6, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x8680, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x5B9E, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x8BC6, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x9A76, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x52BF, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x566C, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x91CA, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x9970, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x89C6, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x8BD5, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x5BFF, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x552E, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x517D, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x67A2, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x8F93, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x4E66, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x8D4E, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x5C5E, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x672F, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x6811, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x7AD6, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x6570, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xCB40: 0x8582, //CJK UNIFIED IDEOGRAPH + 0xCB41: 0x8583, //CJK UNIFIED IDEOGRAPH + 0xCB42: 0x8586, //CJK UNIFIED IDEOGRAPH + 0xCB43: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xCB44: 0x8589, //CJK UNIFIED IDEOGRAPH + 0xCB45: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xCB46: 0x858B, //CJK UNIFIED IDEOGRAPH + 0xCB47: 0x858C, //CJK UNIFIED IDEOGRAPH + 0xCB48: 0x858D, //CJK UNIFIED IDEOGRAPH + 0xCB49: 0x858E, //CJK UNIFIED IDEOGRAPH + 0xCB4A: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xCB4B: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xCB4C: 0x8592, //CJK UNIFIED IDEOGRAPH + 0xCB4D: 0x8593, //CJK UNIFIED IDEOGRAPH + 0xCB4E: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xCB4F: 0x8595, //CJK UNIFIED IDEOGRAPH + 0xCB50: 0x8596, //CJK UNIFIED IDEOGRAPH + 0xCB51: 0x8597, //CJK UNIFIED IDEOGRAPH + 0xCB52: 0x8598, //CJK UNIFIED IDEOGRAPH + 0xCB53: 0x8599, //CJK UNIFIED IDEOGRAPH + 0xCB54: 0x859A, //CJK UNIFIED IDEOGRAPH + 0xCB55: 0x859D, //CJK UNIFIED IDEOGRAPH + 0xCB56: 0x859E, //CJK UNIFIED IDEOGRAPH + 0xCB57: 0x859F, //CJK UNIFIED IDEOGRAPH + 0xCB58: 0x85A0, //CJK UNIFIED IDEOGRAPH + 0xCB59: 0x85A1, //CJK UNIFIED IDEOGRAPH + 0xCB5A: 0x85A2, //CJK UNIFIED IDEOGRAPH + 0xCB5B: 0x85A3, //CJK UNIFIED IDEOGRAPH + 0xCB5C: 0x85A5, //CJK UNIFIED IDEOGRAPH + 0xCB5D: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xCB5E: 0x85A7, //CJK UNIFIED IDEOGRAPH + 0xCB5F: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xCB60: 0x85AB, //CJK UNIFIED IDEOGRAPH + 0xCB61: 0x85AC, //CJK UNIFIED IDEOGRAPH + 0xCB62: 0x85AD, //CJK UNIFIED IDEOGRAPH + 0xCB63: 0x85B1, //CJK UNIFIED IDEOGRAPH + 0xCB64: 0x85B2, //CJK UNIFIED IDEOGRAPH + 0xCB65: 0x85B3, //CJK UNIFIED IDEOGRAPH + 0xCB66: 0x85B4, //CJK UNIFIED IDEOGRAPH + 0xCB67: 0x85B5, //CJK UNIFIED IDEOGRAPH + 0xCB68: 0x85B6, //CJK UNIFIED IDEOGRAPH + 0xCB69: 0x85B8, //CJK UNIFIED IDEOGRAPH + 0xCB6A: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xCB6B: 0x85BB, //CJK UNIFIED IDEOGRAPH + 0xCB6C: 0x85BC, //CJK UNIFIED IDEOGRAPH + 0xCB6D: 0x85BD, //CJK UNIFIED IDEOGRAPH + 0xCB6E: 0x85BE, //CJK UNIFIED IDEOGRAPH + 0xCB6F: 0x85BF, //CJK UNIFIED IDEOGRAPH + 0xCB70: 0x85C0, //CJK UNIFIED IDEOGRAPH + 0xCB71: 0x85C2, //CJK UNIFIED IDEOGRAPH + 0xCB72: 0x85C3, //CJK UNIFIED IDEOGRAPH + 0xCB73: 0x85C4, //CJK UNIFIED IDEOGRAPH + 0xCB74: 0x85C5, //CJK UNIFIED IDEOGRAPH + 0xCB75: 0x85C6, //CJK UNIFIED IDEOGRAPH + 0xCB76: 0x85C7, //CJK UNIFIED IDEOGRAPH + 0xCB77: 0x85C8, //CJK UNIFIED IDEOGRAPH + 0xCB78: 0x85CA, //CJK UNIFIED IDEOGRAPH + 0xCB79: 0x85CB, //CJK UNIFIED IDEOGRAPH + 0xCB7A: 0x85CC, //CJK UNIFIED IDEOGRAPH + 0xCB7B: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xCB7C: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xCB7D: 0x85D1, //CJK UNIFIED IDEOGRAPH + 0xCB7E: 0x85D2, //CJK UNIFIED IDEOGRAPH + 0xCB80: 0x85D4, //CJK UNIFIED IDEOGRAPH + 0xCB81: 0x85D6, //CJK UNIFIED IDEOGRAPH + 0xCB82: 0x85D7, //CJK UNIFIED IDEOGRAPH + 0xCB83: 0x85D8, //CJK UNIFIED IDEOGRAPH + 0xCB84: 0x85D9, //CJK UNIFIED IDEOGRAPH + 0xCB85: 0x85DA, //CJK UNIFIED IDEOGRAPH + 0xCB86: 0x85DB, //CJK UNIFIED IDEOGRAPH + 0xCB87: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xCB88: 0x85DE, //CJK UNIFIED IDEOGRAPH + 0xCB89: 0x85DF, //CJK UNIFIED IDEOGRAPH + 0xCB8A: 0x85E0, //CJK UNIFIED IDEOGRAPH + 0xCB8B: 0x85E1, //CJK UNIFIED IDEOGRAPH + 0xCB8C: 0x85E2, //CJK UNIFIED IDEOGRAPH + 0xCB8D: 0x85E3, //CJK UNIFIED IDEOGRAPH + 0xCB8E: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xCB8F: 0x85E6, //CJK UNIFIED IDEOGRAPH + 0xCB90: 0x85E7, //CJK UNIFIED IDEOGRAPH + 0xCB91: 0x85E8, //CJK UNIFIED IDEOGRAPH + 0xCB92: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xCB93: 0x85EB, //CJK UNIFIED IDEOGRAPH + 0xCB94: 0x85EC, //CJK UNIFIED IDEOGRAPH + 0xCB95: 0x85ED, //CJK UNIFIED IDEOGRAPH + 0xCB96: 0x85EE, //CJK UNIFIED IDEOGRAPH + 0xCB97: 0x85EF, //CJK UNIFIED IDEOGRAPH + 0xCB98: 0x85F0, //CJK UNIFIED IDEOGRAPH + 0xCB99: 0x85F1, //CJK UNIFIED IDEOGRAPH + 0xCB9A: 0x85F2, //CJK UNIFIED IDEOGRAPH + 0xCB9B: 0x85F3, //CJK UNIFIED IDEOGRAPH + 0xCB9C: 0x85F4, //CJK UNIFIED IDEOGRAPH + 0xCB9D: 0x85F5, //CJK UNIFIED IDEOGRAPH + 0xCB9E: 0x85F6, //CJK UNIFIED IDEOGRAPH + 0xCB9F: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xCBA0: 0x85F8, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x800D, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x6454, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x7529, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x5E05, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x62F4, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x53CC, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x8C01, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x7A0E, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x542E, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x987A, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x8BF4, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x7855, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x70C1, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x6495, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4E1D, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x9972, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x8038, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x6002, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x9882, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x8BBC, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0x8BF5, //CJK UNIFIED IDEOGRAPH + 0xCBD1: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x64DE, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x82CF, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xCBD7: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x50F3, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x8BC9, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x8083, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x867D, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x968F, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0x7EE5, //CJK UNIFIED IDEOGRAPH + 0xCBE8: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x5C81, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5B59, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x635F, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x7B0B, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x7F29, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x7410, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x9501, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x584C, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5979, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xCC40: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xCC41: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xCC42: 0x85FC, //CJK UNIFIED IDEOGRAPH + 0xCC43: 0x85FD, //CJK UNIFIED IDEOGRAPH + 0xCC44: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xCC45: 0x8600, //CJK UNIFIED IDEOGRAPH + 0xCC46: 0x8601, //CJK UNIFIED IDEOGRAPH + 0xCC47: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xCC48: 0x8603, //CJK UNIFIED IDEOGRAPH + 0xCC49: 0x8604, //CJK UNIFIED IDEOGRAPH + 0xCC4A: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xCC4B: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xCC4C: 0x8608, //CJK UNIFIED IDEOGRAPH + 0xCC4D: 0x8609, //CJK UNIFIED IDEOGRAPH + 0xCC4E: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xCC4F: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xCC50: 0x860C, //CJK UNIFIED IDEOGRAPH + 0xCC51: 0x860D, //CJK UNIFIED IDEOGRAPH + 0xCC52: 0x860E, //CJK UNIFIED IDEOGRAPH + 0xCC53: 0x860F, //CJK UNIFIED IDEOGRAPH + 0xCC54: 0x8610, //CJK UNIFIED IDEOGRAPH + 0xCC55: 0x8612, //CJK UNIFIED IDEOGRAPH + 0xCC56: 0x8613, //CJK UNIFIED IDEOGRAPH + 0xCC57: 0x8614, //CJK UNIFIED IDEOGRAPH + 0xCC58: 0x8615, //CJK UNIFIED IDEOGRAPH + 0xCC59: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xCC5A: 0x8618, //CJK UNIFIED IDEOGRAPH + 0xCC5B: 0x8619, //CJK UNIFIED IDEOGRAPH + 0xCC5C: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xCC5D: 0x861B, //CJK UNIFIED IDEOGRAPH + 0xCC5E: 0x861C, //CJK UNIFIED IDEOGRAPH + 0xCC5F: 0x861D, //CJK UNIFIED IDEOGRAPH + 0xCC60: 0x861E, //CJK UNIFIED IDEOGRAPH + 0xCC61: 0x861F, //CJK UNIFIED IDEOGRAPH + 0xCC62: 0x8620, //CJK UNIFIED IDEOGRAPH + 0xCC63: 0x8621, //CJK UNIFIED IDEOGRAPH + 0xCC64: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xCC65: 0x8623, //CJK UNIFIED IDEOGRAPH + 0xCC66: 0x8624, //CJK UNIFIED IDEOGRAPH + 0xCC67: 0x8625, //CJK UNIFIED IDEOGRAPH + 0xCC68: 0x8626, //CJK UNIFIED IDEOGRAPH + 0xCC69: 0x8628, //CJK UNIFIED IDEOGRAPH + 0xCC6A: 0x862A, //CJK UNIFIED IDEOGRAPH + 0xCC6B: 0x862B, //CJK UNIFIED IDEOGRAPH + 0xCC6C: 0x862C, //CJK UNIFIED IDEOGRAPH + 0xCC6D: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xCC6E: 0x862E, //CJK UNIFIED IDEOGRAPH + 0xCC6F: 0x862F, //CJK UNIFIED IDEOGRAPH + 0xCC70: 0x8630, //CJK UNIFIED IDEOGRAPH + 0xCC71: 0x8631, //CJK UNIFIED IDEOGRAPH + 0xCC72: 0x8632, //CJK UNIFIED IDEOGRAPH + 0xCC73: 0x8633, //CJK UNIFIED IDEOGRAPH + 0xCC74: 0x8634, //CJK UNIFIED IDEOGRAPH + 0xCC75: 0x8635, //CJK UNIFIED IDEOGRAPH + 0xCC76: 0x8636, //CJK UNIFIED IDEOGRAPH + 0xCC77: 0x8637, //CJK UNIFIED IDEOGRAPH + 0xCC78: 0x8639, //CJK UNIFIED IDEOGRAPH + 0xCC79: 0x863A, //CJK UNIFIED IDEOGRAPH + 0xCC7A: 0x863B, //CJK UNIFIED IDEOGRAPH + 0xCC7B: 0x863D, //CJK UNIFIED IDEOGRAPH + 0xCC7C: 0x863E, //CJK UNIFIED IDEOGRAPH + 0xCC7D: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xCC7E: 0x8640, //CJK UNIFIED IDEOGRAPH + 0xCC80: 0x8641, //CJK UNIFIED IDEOGRAPH + 0xCC81: 0x8642, //CJK UNIFIED IDEOGRAPH + 0xCC82: 0x8643, //CJK UNIFIED IDEOGRAPH + 0xCC83: 0x8644, //CJK UNIFIED IDEOGRAPH + 0xCC84: 0x8645, //CJK UNIFIED IDEOGRAPH + 0xCC85: 0x8646, //CJK UNIFIED IDEOGRAPH + 0xCC86: 0x8647, //CJK UNIFIED IDEOGRAPH + 0xCC87: 0x8648, //CJK UNIFIED IDEOGRAPH + 0xCC88: 0x8649, //CJK UNIFIED IDEOGRAPH + 0xCC89: 0x864A, //CJK UNIFIED IDEOGRAPH + 0xCC8A: 0x864B, //CJK UNIFIED IDEOGRAPH + 0xCC8B: 0x864C, //CJK UNIFIED IDEOGRAPH + 0xCC8C: 0x8652, //CJK UNIFIED IDEOGRAPH + 0xCC8D: 0x8653, //CJK UNIFIED IDEOGRAPH + 0xCC8E: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xCC8F: 0x8656, //CJK UNIFIED IDEOGRAPH + 0xCC90: 0x8657, //CJK UNIFIED IDEOGRAPH + 0xCC91: 0x8658, //CJK UNIFIED IDEOGRAPH + 0xCC92: 0x8659, //CJK UNIFIED IDEOGRAPH + 0xCC93: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xCC94: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xCC95: 0x865D, //CJK UNIFIED IDEOGRAPH + 0xCC96: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xCC97: 0x8660, //CJK UNIFIED IDEOGRAPH + 0xCC98: 0x8661, //CJK UNIFIED IDEOGRAPH + 0xCC99: 0x8663, //CJK UNIFIED IDEOGRAPH + 0xCC9A: 0x8664, //CJK UNIFIED IDEOGRAPH + 0xCC9B: 0x8665, //CJK UNIFIED IDEOGRAPH + 0xCC9C: 0x8666, //CJK UNIFIED IDEOGRAPH + 0xCC9D: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xCC9E: 0x8668, //CJK UNIFIED IDEOGRAPH + 0xCC9F: 0x8669, //CJK UNIFIED IDEOGRAPH + 0xCCA0: 0x866A, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x736D, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x631E, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x8E4B, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x915E, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6001, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x644A, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x8D2A, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x762B, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x6EE9, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x575B, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x8C2D, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x8C08, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x78B3, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x53F9, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x6C64, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x642A, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x819B, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x5018, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x8EBA, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x8D9F, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x70EB, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x638F, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x6D9B, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x7EE6, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x8BA8, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x817E, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x8A8A, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x8E22, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x9511, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x9898, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x568F, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x5C49, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x586B, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x751C, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x8214, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x6761, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x8D34, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x94C1, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x5385, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x542C, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x70C3, //CJK UNIFIED IDEOGRAPH + 0xCD40: 0x866D, //CJK UNIFIED IDEOGRAPH + 0xCD41: 0x866F, //CJK UNIFIED IDEOGRAPH + 0xCD42: 0x8670, //CJK UNIFIED IDEOGRAPH + 0xCD43: 0x8672, //CJK UNIFIED IDEOGRAPH + 0xCD44: 0x8673, //CJK UNIFIED IDEOGRAPH + 0xCD45: 0x8674, //CJK UNIFIED IDEOGRAPH + 0xCD46: 0x8675, //CJK UNIFIED IDEOGRAPH + 0xCD47: 0x8676, //CJK UNIFIED IDEOGRAPH + 0xCD48: 0x8677, //CJK UNIFIED IDEOGRAPH + 0xCD49: 0x8678, //CJK UNIFIED IDEOGRAPH + 0xCD4A: 0x8683, //CJK UNIFIED IDEOGRAPH + 0xCD4B: 0x8684, //CJK UNIFIED IDEOGRAPH + 0xCD4C: 0x8685, //CJK UNIFIED IDEOGRAPH + 0xCD4D: 0x8686, //CJK UNIFIED IDEOGRAPH + 0xCD4E: 0x8687, //CJK UNIFIED IDEOGRAPH + 0xCD4F: 0x8688, //CJK UNIFIED IDEOGRAPH + 0xCD50: 0x8689, //CJK UNIFIED IDEOGRAPH + 0xCD51: 0x868E, //CJK UNIFIED IDEOGRAPH + 0xCD52: 0x868F, //CJK UNIFIED IDEOGRAPH + 0xCD53: 0x8690, //CJK UNIFIED IDEOGRAPH + 0xCD54: 0x8691, //CJK UNIFIED IDEOGRAPH + 0xCD55: 0x8692, //CJK UNIFIED IDEOGRAPH + 0xCD56: 0x8694, //CJK UNIFIED IDEOGRAPH + 0xCD57: 0x8696, //CJK UNIFIED IDEOGRAPH + 0xCD58: 0x8697, //CJK UNIFIED IDEOGRAPH + 0xCD59: 0x8698, //CJK UNIFIED IDEOGRAPH + 0xCD5A: 0x8699, //CJK UNIFIED IDEOGRAPH + 0xCD5B: 0x869A, //CJK UNIFIED IDEOGRAPH + 0xCD5C: 0x869B, //CJK UNIFIED IDEOGRAPH + 0xCD5D: 0x869E, //CJK UNIFIED IDEOGRAPH + 0xCD5E: 0x869F, //CJK UNIFIED IDEOGRAPH + 0xCD5F: 0x86A0, //CJK UNIFIED IDEOGRAPH + 0xCD60: 0x86A1, //CJK UNIFIED IDEOGRAPH + 0xCD61: 0x86A2, //CJK UNIFIED IDEOGRAPH + 0xCD62: 0x86A5, //CJK UNIFIED IDEOGRAPH + 0xCD63: 0x86A6, //CJK UNIFIED IDEOGRAPH + 0xCD64: 0x86AB, //CJK UNIFIED IDEOGRAPH + 0xCD65: 0x86AD, //CJK UNIFIED IDEOGRAPH + 0xCD66: 0x86AE, //CJK UNIFIED IDEOGRAPH + 0xCD67: 0x86B2, //CJK UNIFIED IDEOGRAPH + 0xCD68: 0x86B3, //CJK UNIFIED IDEOGRAPH + 0xCD69: 0x86B7, //CJK UNIFIED IDEOGRAPH + 0xCD6A: 0x86B8, //CJK UNIFIED IDEOGRAPH + 0xCD6B: 0x86B9, //CJK UNIFIED IDEOGRAPH + 0xCD6C: 0x86BB, //CJK UNIFIED IDEOGRAPH + 0xCD6D: 0x86BC, //CJK UNIFIED IDEOGRAPH + 0xCD6E: 0x86BD, //CJK UNIFIED IDEOGRAPH + 0xCD6F: 0x86BE, //CJK UNIFIED IDEOGRAPH + 0xCD70: 0x86BF, //CJK UNIFIED IDEOGRAPH + 0xCD71: 0x86C1, //CJK UNIFIED IDEOGRAPH + 0xCD72: 0x86C2, //CJK UNIFIED IDEOGRAPH + 0xCD73: 0x86C3, //CJK UNIFIED IDEOGRAPH + 0xCD74: 0x86C5, //CJK UNIFIED IDEOGRAPH + 0xCD75: 0x86C8, //CJK UNIFIED IDEOGRAPH + 0xCD76: 0x86CC, //CJK UNIFIED IDEOGRAPH + 0xCD77: 0x86CD, //CJK UNIFIED IDEOGRAPH + 0xCD78: 0x86D2, //CJK UNIFIED IDEOGRAPH + 0xCD79: 0x86D3, //CJK UNIFIED IDEOGRAPH + 0xCD7A: 0x86D5, //CJK UNIFIED IDEOGRAPH + 0xCD7B: 0x86D6, //CJK UNIFIED IDEOGRAPH + 0xCD7C: 0x86D7, //CJK UNIFIED IDEOGRAPH + 0xCD7D: 0x86DA, //CJK UNIFIED IDEOGRAPH + 0xCD7E: 0x86DC, //CJK UNIFIED IDEOGRAPH + 0xCD80: 0x86DD, //CJK UNIFIED IDEOGRAPH + 0xCD81: 0x86E0, //CJK UNIFIED IDEOGRAPH + 0xCD82: 0x86E1, //CJK UNIFIED IDEOGRAPH + 0xCD83: 0x86E2, //CJK UNIFIED IDEOGRAPH + 0xCD84: 0x86E3, //CJK UNIFIED IDEOGRAPH + 0xCD85: 0x86E5, //CJK UNIFIED IDEOGRAPH + 0xCD86: 0x86E6, //CJK UNIFIED IDEOGRAPH + 0xCD87: 0x86E7, //CJK UNIFIED IDEOGRAPH + 0xCD88: 0x86E8, //CJK UNIFIED IDEOGRAPH + 0xCD89: 0x86EA, //CJK UNIFIED IDEOGRAPH + 0xCD8A: 0x86EB, //CJK UNIFIED IDEOGRAPH + 0xCD8B: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xCD8C: 0x86EF, //CJK UNIFIED IDEOGRAPH + 0xCD8D: 0x86F5, //CJK UNIFIED IDEOGRAPH + 0xCD8E: 0x86F6, //CJK UNIFIED IDEOGRAPH + 0xCD8F: 0x86F7, //CJK UNIFIED IDEOGRAPH + 0xCD90: 0x86FA, //CJK UNIFIED IDEOGRAPH + 0xCD91: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xCD92: 0x86FC, //CJK UNIFIED IDEOGRAPH + 0xCD93: 0x86FD, //CJK UNIFIED IDEOGRAPH + 0xCD94: 0x86FF, //CJK UNIFIED IDEOGRAPH + 0xCD95: 0x8701, //CJK UNIFIED IDEOGRAPH + 0xCD96: 0x8704, //CJK UNIFIED IDEOGRAPH + 0xCD97: 0x8705, //CJK UNIFIED IDEOGRAPH + 0xCD98: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xCD99: 0x870B, //CJK UNIFIED IDEOGRAPH + 0xCD9A: 0x870C, //CJK UNIFIED IDEOGRAPH + 0xCD9B: 0x870E, //CJK UNIFIED IDEOGRAPH + 0xCD9C: 0x870F, //CJK UNIFIED IDEOGRAPH + 0xCD9D: 0x8710, //CJK UNIFIED IDEOGRAPH + 0xCD9E: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xCD9F: 0x8714, //CJK UNIFIED IDEOGRAPH + 0xCDA0: 0x8716, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x916E, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x94DC, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x5F64, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x6345, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x7EDF, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x5077, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x5934, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x79C3, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x56FE, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x6D82, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x5154, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x56E2, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x9893, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x8715, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x541E, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xCDD0: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x8131, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x9E35, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x9A6E, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x9A7C, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x692D, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x6316, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x6D3C, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x889C, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x5F2F, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x6E7E, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x987D, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xCDE9: 0x70F7, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x665A, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x60CB, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xCE40: 0x8719, //CJK UNIFIED IDEOGRAPH + 0xCE41: 0x871B, //CJK UNIFIED IDEOGRAPH + 0xCE42: 0x871D, //CJK UNIFIED IDEOGRAPH + 0xCE43: 0x871F, //CJK UNIFIED IDEOGRAPH + 0xCE44: 0x8720, //CJK UNIFIED IDEOGRAPH + 0xCE45: 0x8724, //CJK UNIFIED IDEOGRAPH + 0xCE46: 0x8726, //CJK UNIFIED IDEOGRAPH + 0xCE47: 0x8727, //CJK UNIFIED IDEOGRAPH + 0xCE48: 0x8728, //CJK UNIFIED IDEOGRAPH + 0xCE49: 0x872A, //CJK UNIFIED IDEOGRAPH + 0xCE4A: 0x872B, //CJK UNIFIED IDEOGRAPH + 0xCE4B: 0x872C, //CJK UNIFIED IDEOGRAPH + 0xCE4C: 0x872D, //CJK UNIFIED IDEOGRAPH + 0xCE4D: 0x872F, //CJK UNIFIED IDEOGRAPH + 0xCE4E: 0x8730, //CJK UNIFIED IDEOGRAPH + 0xCE4F: 0x8732, //CJK UNIFIED IDEOGRAPH + 0xCE50: 0x8733, //CJK UNIFIED IDEOGRAPH + 0xCE51: 0x8735, //CJK UNIFIED IDEOGRAPH + 0xCE52: 0x8736, //CJK UNIFIED IDEOGRAPH + 0xCE53: 0x8738, //CJK UNIFIED IDEOGRAPH + 0xCE54: 0x8739, //CJK UNIFIED IDEOGRAPH + 0xCE55: 0x873A, //CJK UNIFIED IDEOGRAPH + 0xCE56: 0x873C, //CJK UNIFIED IDEOGRAPH + 0xCE57: 0x873D, //CJK UNIFIED IDEOGRAPH + 0xCE58: 0x8740, //CJK UNIFIED IDEOGRAPH + 0xCE59: 0x8741, //CJK UNIFIED IDEOGRAPH + 0xCE5A: 0x8742, //CJK UNIFIED IDEOGRAPH + 0xCE5B: 0x8743, //CJK UNIFIED IDEOGRAPH + 0xCE5C: 0x8744, //CJK UNIFIED IDEOGRAPH + 0xCE5D: 0x8745, //CJK UNIFIED IDEOGRAPH + 0xCE5E: 0x8746, //CJK UNIFIED IDEOGRAPH + 0xCE5F: 0x874A, //CJK UNIFIED IDEOGRAPH + 0xCE60: 0x874B, //CJK UNIFIED IDEOGRAPH + 0xCE61: 0x874D, //CJK UNIFIED IDEOGRAPH + 0xCE62: 0x874F, //CJK UNIFIED IDEOGRAPH + 0xCE63: 0x8750, //CJK UNIFIED IDEOGRAPH + 0xCE64: 0x8751, //CJK UNIFIED IDEOGRAPH + 0xCE65: 0x8752, //CJK UNIFIED IDEOGRAPH + 0xCE66: 0x8754, //CJK UNIFIED IDEOGRAPH + 0xCE67: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xCE68: 0x8756, //CJK UNIFIED IDEOGRAPH + 0xCE69: 0x8758, //CJK UNIFIED IDEOGRAPH + 0xCE6A: 0x875A, //CJK UNIFIED IDEOGRAPH + 0xCE6B: 0x875B, //CJK UNIFIED IDEOGRAPH + 0xCE6C: 0x875C, //CJK UNIFIED IDEOGRAPH + 0xCE6D: 0x875D, //CJK UNIFIED IDEOGRAPH + 0xCE6E: 0x875E, //CJK UNIFIED IDEOGRAPH + 0xCE6F: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xCE70: 0x8761, //CJK UNIFIED IDEOGRAPH + 0xCE71: 0x8762, //CJK UNIFIED IDEOGRAPH + 0xCE72: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xCE73: 0x8767, //CJK UNIFIED IDEOGRAPH + 0xCE74: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xCE75: 0x8769, //CJK UNIFIED IDEOGRAPH + 0xCE76: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xCE77: 0x876B, //CJK UNIFIED IDEOGRAPH + 0xCE78: 0x876C, //CJK UNIFIED IDEOGRAPH + 0xCE79: 0x876D, //CJK UNIFIED IDEOGRAPH + 0xCE7A: 0x876F, //CJK UNIFIED IDEOGRAPH + 0xCE7B: 0x8771, //CJK UNIFIED IDEOGRAPH + 0xCE7C: 0x8772, //CJK UNIFIED IDEOGRAPH + 0xCE7D: 0x8773, //CJK UNIFIED IDEOGRAPH + 0xCE7E: 0x8775, //CJK UNIFIED IDEOGRAPH + 0xCE80: 0x8777, //CJK UNIFIED IDEOGRAPH + 0xCE81: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xCE82: 0x8779, //CJK UNIFIED IDEOGRAPH + 0xCE83: 0x877A, //CJK UNIFIED IDEOGRAPH + 0xCE84: 0x877F, //CJK UNIFIED IDEOGRAPH + 0xCE85: 0x8780, //CJK UNIFIED IDEOGRAPH + 0xCE86: 0x8781, //CJK UNIFIED IDEOGRAPH + 0xCE87: 0x8784, //CJK UNIFIED IDEOGRAPH + 0xCE88: 0x8786, //CJK UNIFIED IDEOGRAPH + 0xCE89: 0x8787, //CJK UNIFIED IDEOGRAPH + 0xCE8A: 0x8789, //CJK UNIFIED IDEOGRAPH + 0xCE8B: 0x878A, //CJK UNIFIED IDEOGRAPH + 0xCE8C: 0x878C, //CJK UNIFIED IDEOGRAPH + 0xCE8D: 0x878E, //CJK UNIFIED IDEOGRAPH + 0xCE8E: 0x878F, //CJK UNIFIED IDEOGRAPH + 0xCE8F: 0x8790, //CJK UNIFIED IDEOGRAPH + 0xCE90: 0x8791, //CJK UNIFIED IDEOGRAPH + 0xCE91: 0x8792, //CJK UNIFIED IDEOGRAPH + 0xCE92: 0x8794, //CJK UNIFIED IDEOGRAPH + 0xCE93: 0x8795, //CJK UNIFIED IDEOGRAPH + 0xCE94: 0x8796, //CJK UNIFIED IDEOGRAPH + 0xCE95: 0x8798, //CJK UNIFIED IDEOGRAPH + 0xCE96: 0x8799, //CJK UNIFIED IDEOGRAPH + 0xCE97: 0x879A, //CJK UNIFIED IDEOGRAPH + 0xCE98: 0x879B, //CJK UNIFIED IDEOGRAPH + 0xCE99: 0x879C, //CJK UNIFIED IDEOGRAPH + 0xCE9A: 0x879D, //CJK UNIFIED IDEOGRAPH + 0xCE9B: 0x879E, //CJK UNIFIED IDEOGRAPH + 0xCE9C: 0x87A0, //CJK UNIFIED IDEOGRAPH + 0xCE9D: 0x87A1, //CJK UNIFIED IDEOGRAPH + 0xCE9E: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xCE9F: 0x87A3, //CJK UNIFIED IDEOGRAPH + 0xCEA0: 0x87A4, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x97E6, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x8FDD, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x6845, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x56F4, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x4E3A, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x6F4D, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x7EF4, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0x82C7, //CJK UNIFIED IDEOGRAPH + 0xCEAE: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x4F1F, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x4F2A, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x7EAC, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x5582, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x8C13, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x536B, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x6E29, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x95FB, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x7EB9, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x7A33, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x95EE, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x55E1, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x631D, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x8717, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x6DA1, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x7A9D, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x5367, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x545C, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x94A8, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x4E4C, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x6C61, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x8BEC, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x829C, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x5434, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x6342, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x575E, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x96FE, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x52A1, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x8BEF, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x7852, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x77FD, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x6670, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x563B, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x9521, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x727A, //CJK UNIFIED IDEOGRAPH + 0xCF40: 0x87A5, //CJK UNIFIED IDEOGRAPH + 0xCF41: 0x87A6, //CJK UNIFIED IDEOGRAPH + 0xCF42: 0x87A7, //CJK UNIFIED IDEOGRAPH + 0xCF43: 0x87A9, //CJK UNIFIED IDEOGRAPH + 0xCF44: 0x87AA, //CJK UNIFIED IDEOGRAPH + 0xCF45: 0x87AE, //CJK UNIFIED IDEOGRAPH + 0xCF46: 0x87B0, //CJK UNIFIED IDEOGRAPH + 0xCF47: 0x87B1, //CJK UNIFIED IDEOGRAPH + 0xCF48: 0x87B2, //CJK UNIFIED IDEOGRAPH + 0xCF49: 0x87B4, //CJK UNIFIED IDEOGRAPH + 0xCF4A: 0x87B6, //CJK UNIFIED IDEOGRAPH + 0xCF4B: 0x87B7, //CJK UNIFIED IDEOGRAPH + 0xCF4C: 0x87B8, //CJK UNIFIED IDEOGRAPH + 0xCF4D: 0x87B9, //CJK UNIFIED IDEOGRAPH + 0xCF4E: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xCF4F: 0x87BC, //CJK UNIFIED IDEOGRAPH + 0xCF50: 0x87BE, //CJK UNIFIED IDEOGRAPH + 0xCF51: 0x87BF, //CJK UNIFIED IDEOGRAPH + 0xCF52: 0x87C1, //CJK UNIFIED IDEOGRAPH + 0xCF53: 0x87C2, //CJK UNIFIED IDEOGRAPH + 0xCF54: 0x87C3, //CJK UNIFIED IDEOGRAPH + 0xCF55: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xCF56: 0x87C5, //CJK UNIFIED IDEOGRAPH + 0xCF57: 0x87C7, //CJK UNIFIED IDEOGRAPH + 0xCF58: 0x87C8, //CJK UNIFIED IDEOGRAPH + 0xCF59: 0x87C9, //CJK UNIFIED IDEOGRAPH + 0xCF5A: 0x87CC, //CJK UNIFIED IDEOGRAPH + 0xCF5B: 0x87CD, //CJK UNIFIED IDEOGRAPH + 0xCF5C: 0x87CE, //CJK UNIFIED IDEOGRAPH + 0xCF5D: 0x87CF, //CJK UNIFIED IDEOGRAPH + 0xCF5E: 0x87D0, //CJK UNIFIED IDEOGRAPH + 0xCF5F: 0x87D4, //CJK UNIFIED IDEOGRAPH + 0xCF60: 0x87D5, //CJK UNIFIED IDEOGRAPH + 0xCF61: 0x87D6, //CJK UNIFIED IDEOGRAPH + 0xCF62: 0x87D7, //CJK UNIFIED IDEOGRAPH + 0xCF63: 0x87D8, //CJK UNIFIED IDEOGRAPH + 0xCF64: 0x87D9, //CJK UNIFIED IDEOGRAPH + 0xCF65: 0x87DA, //CJK UNIFIED IDEOGRAPH + 0xCF66: 0x87DC, //CJK UNIFIED IDEOGRAPH + 0xCF67: 0x87DD, //CJK UNIFIED IDEOGRAPH + 0xCF68: 0x87DE, //CJK UNIFIED IDEOGRAPH + 0xCF69: 0x87DF, //CJK UNIFIED IDEOGRAPH + 0xCF6A: 0x87E1, //CJK UNIFIED IDEOGRAPH + 0xCF6B: 0x87E2, //CJK UNIFIED IDEOGRAPH + 0xCF6C: 0x87E3, //CJK UNIFIED IDEOGRAPH + 0xCF6D: 0x87E4, //CJK UNIFIED IDEOGRAPH + 0xCF6E: 0x87E6, //CJK UNIFIED IDEOGRAPH + 0xCF6F: 0x87E7, //CJK UNIFIED IDEOGRAPH + 0xCF70: 0x87E8, //CJK UNIFIED IDEOGRAPH + 0xCF71: 0x87E9, //CJK UNIFIED IDEOGRAPH + 0xCF72: 0x87EB, //CJK UNIFIED IDEOGRAPH + 0xCF73: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xCF74: 0x87ED, //CJK UNIFIED IDEOGRAPH + 0xCF75: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xCF76: 0x87F0, //CJK UNIFIED IDEOGRAPH + 0xCF77: 0x87F1, //CJK UNIFIED IDEOGRAPH + 0xCF78: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xCF79: 0x87F3, //CJK UNIFIED IDEOGRAPH + 0xCF7A: 0x87F4, //CJK UNIFIED IDEOGRAPH + 0xCF7B: 0x87F5, //CJK UNIFIED IDEOGRAPH + 0xCF7C: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xCF7D: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xCF7E: 0x87F8, //CJK UNIFIED IDEOGRAPH + 0xCF80: 0x87FA, //CJK UNIFIED IDEOGRAPH + 0xCF81: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xCF82: 0x87FC, //CJK UNIFIED IDEOGRAPH + 0xCF83: 0x87FD, //CJK UNIFIED IDEOGRAPH + 0xCF84: 0x87FF, //CJK UNIFIED IDEOGRAPH + 0xCF85: 0x8800, //CJK UNIFIED IDEOGRAPH + 0xCF86: 0x8801, //CJK UNIFIED IDEOGRAPH + 0xCF87: 0x8802, //CJK UNIFIED IDEOGRAPH + 0xCF88: 0x8804, //CJK UNIFIED IDEOGRAPH + 0xCF89: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xCF8A: 0x8806, //CJK UNIFIED IDEOGRAPH + 0xCF8B: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xCF8C: 0x8808, //CJK UNIFIED IDEOGRAPH + 0xCF8D: 0x8809, //CJK UNIFIED IDEOGRAPH + 0xCF8E: 0x880B, //CJK UNIFIED IDEOGRAPH + 0xCF8F: 0x880C, //CJK UNIFIED IDEOGRAPH + 0xCF90: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xCF91: 0x880E, //CJK UNIFIED IDEOGRAPH + 0xCF92: 0x880F, //CJK UNIFIED IDEOGRAPH + 0xCF93: 0x8810, //CJK UNIFIED IDEOGRAPH + 0xCF94: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xCF95: 0x8812, //CJK UNIFIED IDEOGRAPH + 0xCF96: 0x8814, //CJK UNIFIED IDEOGRAPH + 0xCF97: 0x8817, //CJK UNIFIED IDEOGRAPH + 0xCF98: 0x8818, //CJK UNIFIED IDEOGRAPH + 0xCF99: 0x8819, //CJK UNIFIED IDEOGRAPH + 0xCF9A: 0x881A, //CJK UNIFIED IDEOGRAPH + 0xCF9B: 0x881C, //CJK UNIFIED IDEOGRAPH + 0xCF9C: 0x881D, //CJK UNIFIED IDEOGRAPH + 0xCF9D: 0x881E, //CJK UNIFIED IDEOGRAPH + 0xCF9E: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xCF9F: 0x8820, //CJK UNIFIED IDEOGRAPH + 0xCFA0: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x70EF, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x88AD, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x4E60, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x5AB3, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x94E3, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x620F, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7EC6, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x867E, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x8F96, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x5CE1, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x4FA0, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x72ED, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x5413, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x6380, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x9528, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x9C9C, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x7EA4, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x8D24, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x8854, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x95F2, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x663E, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x9669, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x73B0, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x732E, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x53BF, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x9985, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x5BAA, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x7EBF, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x53A2, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x9576, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x4E61, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x8BE6, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x54CD, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x9879, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x8427, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x56A3, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x9500, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xCFFC: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x6653, //CJK UNIFIED IDEOGRAPH + 0xD040: 0x8824, //CJK UNIFIED IDEOGRAPH + 0xD041: 0x8825, //CJK UNIFIED IDEOGRAPH + 0xD042: 0x8826, //CJK UNIFIED IDEOGRAPH + 0xD043: 0x8827, //CJK UNIFIED IDEOGRAPH + 0xD044: 0x8828, //CJK UNIFIED IDEOGRAPH + 0xD045: 0x8829, //CJK UNIFIED IDEOGRAPH + 0xD046: 0x882A, //CJK UNIFIED IDEOGRAPH + 0xD047: 0x882B, //CJK UNIFIED IDEOGRAPH + 0xD048: 0x882C, //CJK UNIFIED IDEOGRAPH + 0xD049: 0x882D, //CJK UNIFIED IDEOGRAPH + 0xD04A: 0x882E, //CJK UNIFIED IDEOGRAPH + 0xD04B: 0x882F, //CJK UNIFIED IDEOGRAPH + 0xD04C: 0x8830, //CJK UNIFIED IDEOGRAPH + 0xD04D: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xD04E: 0x8833, //CJK UNIFIED IDEOGRAPH + 0xD04F: 0x8834, //CJK UNIFIED IDEOGRAPH + 0xD050: 0x8835, //CJK UNIFIED IDEOGRAPH + 0xD051: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xD052: 0x8837, //CJK UNIFIED IDEOGRAPH + 0xD053: 0x8838, //CJK UNIFIED IDEOGRAPH + 0xD054: 0x883A, //CJK UNIFIED IDEOGRAPH + 0xD055: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xD056: 0x883D, //CJK UNIFIED IDEOGRAPH + 0xD057: 0x883E, //CJK UNIFIED IDEOGRAPH + 0xD058: 0x883F, //CJK UNIFIED IDEOGRAPH + 0xD059: 0x8841, //CJK UNIFIED IDEOGRAPH + 0xD05A: 0x8842, //CJK UNIFIED IDEOGRAPH + 0xD05B: 0x8843, //CJK UNIFIED IDEOGRAPH + 0xD05C: 0x8846, //CJK UNIFIED IDEOGRAPH + 0xD05D: 0x8847, //CJK UNIFIED IDEOGRAPH + 0xD05E: 0x8848, //CJK UNIFIED IDEOGRAPH + 0xD05F: 0x8849, //CJK UNIFIED IDEOGRAPH + 0xD060: 0x884A, //CJK UNIFIED IDEOGRAPH + 0xD061: 0x884B, //CJK UNIFIED IDEOGRAPH + 0xD062: 0x884E, //CJK UNIFIED IDEOGRAPH + 0xD063: 0x884F, //CJK UNIFIED IDEOGRAPH + 0xD064: 0x8850, //CJK UNIFIED IDEOGRAPH + 0xD065: 0x8851, //CJK UNIFIED IDEOGRAPH + 0xD066: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xD067: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xD068: 0x8855, //CJK UNIFIED IDEOGRAPH + 0xD069: 0x8856, //CJK UNIFIED IDEOGRAPH + 0xD06A: 0x8858, //CJK UNIFIED IDEOGRAPH + 0xD06B: 0x885A, //CJK UNIFIED IDEOGRAPH + 0xD06C: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xD06D: 0x885C, //CJK UNIFIED IDEOGRAPH + 0xD06E: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xD06F: 0x885E, //CJK UNIFIED IDEOGRAPH + 0xD070: 0x885F, //CJK UNIFIED IDEOGRAPH + 0xD071: 0x8860, //CJK UNIFIED IDEOGRAPH + 0xD072: 0x8866, //CJK UNIFIED IDEOGRAPH + 0xD073: 0x8867, //CJK UNIFIED IDEOGRAPH + 0xD074: 0x886A, //CJK UNIFIED IDEOGRAPH + 0xD075: 0x886D, //CJK UNIFIED IDEOGRAPH + 0xD076: 0x886F, //CJK UNIFIED IDEOGRAPH + 0xD077: 0x8871, //CJK UNIFIED IDEOGRAPH + 0xD078: 0x8873, //CJK UNIFIED IDEOGRAPH + 0xD079: 0x8874, //CJK UNIFIED IDEOGRAPH + 0xD07A: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xD07B: 0x8876, //CJK UNIFIED IDEOGRAPH + 0xD07C: 0x8878, //CJK UNIFIED IDEOGRAPH + 0xD07D: 0x8879, //CJK UNIFIED IDEOGRAPH + 0xD07E: 0x887A, //CJK UNIFIED IDEOGRAPH + 0xD080: 0x887B, //CJK UNIFIED IDEOGRAPH + 0xD081: 0x887C, //CJK UNIFIED IDEOGRAPH + 0xD082: 0x8880, //CJK UNIFIED IDEOGRAPH + 0xD083: 0x8883, //CJK UNIFIED IDEOGRAPH + 0xD084: 0x8886, //CJK UNIFIED IDEOGRAPH + 0xD085: 0x8887, //CJK UNIFIED IDEOGRAPH + 0xD086: 0x8889, //CJK UNIFIED IDEOGRAPH + 0xD087: 0x888A, //CJK UNIFIED IDEOGRAPH + 0xD088: 0x888C, //CJK UNIFIED IDEOGRAPH + 0xD089: 0x888E, //CJK UNIFIED IDEOGRAPH + 0xD08A: 0x888F, //CJK UNIFIED IDEOGRAPH + 0xD08B: 0x8890, //CJK UNIFIED IDEOGRAPH + 0xD08C: 0x8891, //CJK UNIFIED IDEOGRAPH + 0xD08D: 0x8893, //CJK UNIFIED IDEOGRAPH + 0xD08E: 0x8894, //CJK UNIFIED IDEOGRAPH + 0xD08F: 0x8895, //CJK UNIFIED IDEOGRAPH + 0xD090: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xD091: 0x8898, //CJK UNIFIED IDEOGRAPH + 0xD092: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xD093: 0x889A, //CJK UNIFIED IDEOGRAPH + 0xD094: 0x889B, //CJK UNIFIED IDEOGRAPH + 0xD095: 0x889D, //CJK UNIFIED IDEOGRAPH + 0xD096: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xD097: 0x889F, //CJK UNIFIED IDEOGRAPH + 0xD098: 0x88A0, //CJK UNIFIED IDEOGRAPH + 0xD099: 0x88A1, //CJK UNIFIED IDEOGRAPH + 0xD09A: 0x88A3, //CJK UNIFIED IDEOGRAPH + 0xD09B: 0x88A5, //CJK UNIFIED IDEOGRAPH + 0xD09C: 0x88A6, //CJK UNIFIED IDEOGRAPH + 0xD09D: 0x88A7, //CJK UNIFIED IDEOGRAPH + 0xD09E: 0x88A8, //CJK UNIFIED IDEOGRAPH + 0xD09F: 0x88A9, //CJK UNIFIED IDEOGRAPH + 0xD0A0: 0x88AA, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xD0A3: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x5578, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x534F, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x631F, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x643A, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x80C1, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x8C10, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x5199, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x5378, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xD0B9: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x6CFB, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x8C22, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x950C, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x8845, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x5174, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xD0D1: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x6C79, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xD0DE: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x9508, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x7EE3, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x865A, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x5618, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x987B, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x8BB8, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x9157, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x53D9, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x7EEA, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x7EED, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x8F69, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x60AC, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xD140: 0x88AC, //CJK UNIFIED IDEOGRAPH + 0xD141: 0x88AE, //CJK UNIFIED IDEOGRAPH + 0xD142: 0x88AF, //CJK UNIFIED IDEOGRAPH + 0xD143: 0x88B0, //CJK UNIFIED IDEOGRAPH + 0xD144: 0x88B2, //CJK UNIFIED IDEOGRAPH + 0xD145: 0x88B3, //CJK UNIFIED IDEOGRAPH + 0xD146: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0xD147: 0x88B5, //CJK UNIFIED IDEOGRAPH + 0xD148: 0x88B6, //CJK UNIFIED IDEOGRAPH + 0xD149: 0x88B8, //CJK UNIFIED IDEOGRAPH + 0xD14A: 0x88B9, //CJK UNIFIED IDEOGRAPH + 0xD14B: 0x88BA, //CJK UNIFIED IDEOGRAPH + 0xD14C: 0x88BB, //CJK UNIFIED IDEOGRAPH + 0xD14D: 0x88BD, //CJK UNIFIED IDEOGRAPH + 0xD14E: 0x88BE, //CJK UNIFIED IDEOGRAPH + 0xD14F: 0x88BF, //CJK UNIFIED IDEOGRAPH + 0xD150: 0x88C0, //CJK UNIFIED IDEOGRAPH + 0xD151: 0x88C3, //CJK UNIFIED IDEOGRAPH + 0xD152: 0x88C4, //CJK UNIFIED IDEOGRAPH + 0xD153: 0x88C7, //CJK UNIFIED IDEOGRAPH + 0xD154: 0x88C8, //CJK UNIFIED IDEOGRAPH + 0xD155: 0x88CA, //CJK UNIFIED IDEOGRAPH + 0xD156: 0x88CB, //CJK UNIFIED IDEOGRAPH + 0xD157: 0x88CC, //CJK UNIFIED IDEOGRAPH + 0xD158: 0x88CD, //CJK UNIFIED IDEOGRAPH + 0xD159: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xD15A: 0x88D0, //CJK UNIFIED IDEOGRAPH + 0xD15B: 0x88D1, //CJK UNIFIED IDEOGRAPH + 0xD15C: 0x88D3, //CJK UNIFIED IDEOGRAPH + 0xD15D: 0x88D6, //CJK UNIFIED IDEOGRAPH + 0xD15E: 0x88D7, //CJK UNIFIED IDEOGRAPH + 0xD15F: 0x88DA, //CJK UNIFIED IDEOGRAPH + 0xD160: 0x88DB, //CJK UNIFIED IDEOGRAPH + 0xD161: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xD162: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xD163: 0x88DE, //CJK UNIFIED IDEOGRAPH + 0xD164: 0x88E0, //CJK UNIFIED IDEOGRAPH + 0xD165: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xD166: 0x88E6, //CJK UNIFIED IDEOGRAPH + 0xD167: 0x88E7, //CJK UNIFIED IDEOGRAPH + 0xD168: 0x88E9, //CJK UNIFIED IDEOGRAPH + 0xD169: 0x88EA, //CJK UNIFIED IDEOGRAPH + 0xD16A: 0x88EB, //CJK UNIFIED IDEOGRAPH + 0xD16B: 0x88EC, //CJK UNIFIED IDEOGRAPH + 0xD16C: 0x88ED, //CJK UNIFIED IDEOGRAPH + 0xD16D: 0x88EE, //CJK UNIFIED IDEOGRAPH + 0xD16E: 0x88EF, //CJK UNIFIED IDEOGRAPH + 0xD16F: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xD170: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xD171: 0x88F6, //CJK UNIFIED IDEOGRAPH + 0xD172: 0x88F7, //CJK UNIFIED IDEOGRAPH + 0xD173: 0x88FA, //CJK UNIFIED IDEOGRAPH + 0xD174: 0x88FB, //CJK UNIFIED IDEOGRAPH + 0xD175: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xD176: 0x88FF, //CJK UNIFIED IDEOGRAPH + 0xD177: 0x8900, //CJK UNIFIED IDEOGRAPH + 0xD178: 0x8901, //CJK UNIFIED IDEOGRAPH + 0xD179: 0x8903, //CJK UNIFIED IDEOGRAPH + 0xD17A: 0x8904, //CJK UNIFIED IDEOGRAPH + 0xD17B: 0x8905, //CJK UNIFIED IDEOGRAPH + 0xD17C: 0x8906, //CJK UNIFIED IDEOGRAPH + 0xD17D: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xD17E: 0x8908, //CJK UNIFIED IDEOGRAPH + 0xD180: 0x8909, //CJK UNIFIED IDEOGRAPH + 0xD181: 0x890B, //CJK UNIFIED IDEOGRAPH + 0xD182: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xD183: 0x890D, //CJK UNIFIED IDEOGRAPH + 0xD184: 0x890E, //CJK UNIFIED IDEOGRAPH + 0xD185: 0x890F, //CJK UNIFIED IDEOGRAPH + 0xD186: 0x8911, //CJK UNIFIED IDEOGRAPH + 0xD187: 0x8914, //CJK UNIFIED IDEOGRAPH + 0xD188: 0x8915, //CJK UNIFIED IDEOGRAPH + 0xD189: 0x8916, //CJK UNIFIED IDEOGRAPH + 0xD18A: 0x8917, //CJK UNIFIED IDEOGRAPH + 0xD18B: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xD18C: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xD18D: 0x891D, //CJK UNIFIED IDEOGRAPH + 0xD18E: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xD18F: 0x891F, //CJK UNIFIED IDEOGRAPH + 0xD190: 0x8920, //CJK UNIFIED IDEOGRAPH + 0xD191: 0x8922, //CJK UNIFIED IDEOGRAPH + 0xD192: 0x8923, //CJK UNIFIED IDEOGRAPH + 0xD193: 0x8924, //CJK UNIFIED IDEOGRAPH + 0xD194: 0x8926, //CJK UNIFIED IDEOGRAPH + 0xD195: 0x8927, //CJK UNIFIED IDEOGRAPH + 0xD196: 0x8928, //CJK UNIFIED IDEOGRAPH + 0xD197: 0x8929, //CJK UNIFIED IDEOGRAPH + 0xD198: 0x892C, //CJK UNIFIED IDEOGRAPH + 0xD199: 0x892D, //CJK UNIFIED IDEOGRAPH + 0xD19A: 0x892E, //CJK UNIFIED IDEOGRAPH + 0xD19B: 0x892F, //CJK UNIFIED IDEOGRAPH + 0xD19C: 0x8931, //CJK UNIFIED IDEOGRAPH + 0xD19D: 0x8932, //CJK UNIFIED IDEOGRAPH + 0xD19E: 0x8933, //CJK UNIFIED IDEOGRAPH + 0xD19F: 0x8935, //CJK UNIFIED IDEOGRAPH + 0xD1A0: 0x8937, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x9009, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x7663, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x7EDA, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x5B66, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x52CB, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x8BE2, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x5BFB, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x9A6F, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x6C5B, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x8BAD, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x8BAF, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x900A, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x538B, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x9E26, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x9E2D, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x5440, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x4E2B, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x869C, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x54D1, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x4E9A, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x8BB6, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x9609, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x76D0, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x4E25, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x7814, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xD1D5: 0x989C, //CJK UNIFIED IDEOGRAPH + 0xD1D6: 0x960E, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xD1D9: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xD1DC: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xD1DD: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xD1DE: 0x8273, //CJK UNIFIED IDEOGRAPH + 0xD1DF: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xD1E0: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xD1E1: 0x538C, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0x781A, //CJK UNIFIED IDEOGRAPH + 0xD1E3: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xD1E4: 0x5501, //CJK UNIFIED IDEOGRAPH + 0xD1E5: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0xD1E6: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xD1E7: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0x8C1A, //CJK UNIFIED IDEOGRAPH + 0xD1E9: 0x9A8C, //CJK UNIFIED IDEOGRAPH + 0xD1EA: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xD1EB: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xD1EC: 0x9E2F, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xD1EE: 0x6768, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0x626C, //CJK UNIFIED IDEOGRAPH + 0xD1F0: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xD1F1: 0x75A1, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xD1F3: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x9633, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x6C27, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xD1F7: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x517B, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6837, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xD1FB: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xD1FD: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xD1FE: 0x7476, //CJK UNIFIED IDEOGRAPH + 0xD240: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xD241: 0x8939, //CJK UNIFIED IDEOGRAPH + 0xD242: 0x893A, //CJK UNIFIED IDEOGRAPH + 0xD243: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xD244: 0x893C, //CJK UNIFIED IDEOGRAPH + 0xD245: 0x893D, //CJK UNIFIED IDEOGRAPH + 0xD246: 0x893E, //CJK UNIFIED IDEOGRAPH + 0xD247: 0x893F, //CJK UNIFIED IDEOGRAPH + 0xD248: 0x8940, //CJK UNIFIED IDEOGRAPH + 0xD249: 0x8942, //CJK UNIFIED IDEOGRAPH + 0xD24A: 0x8943, //CJK UNIFIED IDEOGRAPH + 0xD24B: 0x8945, //CJK UNIFIED IDEOGRAPH + 0xD24C: 0x8946, //CJK UNIFIED IDEOGRAPH + 0xD24D: 0x8947, //CJK UNIFIED IDEOGRAPH + 0xD24E: 0x8948, //CJK UNIFIED IDEOGRAPH + 0xD24F: 0x8949, //CJK UNIFIED IDEOGRAPH + 0xD250: 0x894A, //CJK UNIFIED IDEOGRAPH + 0xD251: 0x894B, //CJK UNIFIED IDEOGRAPH + 0xD252: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xD253: 0x894D, //CJK UNIFIED IDEOGRAPH + 0xD254: 0x894E, //CJK UNIFIED IDEOGRAPH + 0xD255: 0x894F, //CJK UNIFIED IDEOGRAPH + 0xD256: 0x8950, //CJK UNIFIED IDEOGRAPH + 0xD257: 0x8951, //CJK UNIFIED IDEOGRAPH + 0xD258: 0x8952, //CJK UNIFIED IDEOGRAPH + 0xD259: 0x8953, //CJK UNIFIED IDEOGRAPH + 0xD25A: 0x8954, //CJK UNIFIED IDEOGRAPH + 0xD25B: 0x8955, //CJK UNIFIED IDEOGRAPH + 0xD25C: 0x8956, //CJK UNIFIED IDEOGRAPH + 0xD25D: 0x8957, //CJK UNIFIED IDEOGRAPH + 0xD25E: 0x8958, //CJK UNIFIED IDEOGRAPH + 0xD25F: 0x8959, //CJK UNIFIED IDEOGRAPH + 0xD260: 0x895A, //CJK UNIFIED IDEOGRAPH + 0xD261: 0x895B, //CJK UNIFIED IDEOGRAPH + 0xD262: 0x895C, //CJK UNIFIED IDEOGRAPH + 0xD263: 0x895D, //CJK UNIFIED IDEOGRAPH + 0xD264: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xD265: 0x8961, //CJK UNIFIED IDEOGRAPH + 0xD266: 0x8962, //CJK UNIFIED IDEOGRAPH + 0xD267: 0x8963, //CJK UNIFIED IDEOGRAPH + 0xD268: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xD269: 0x8965, //CJK UNIFIED IDEOGRAPH + 0xD26A: 0x8967, //CJK UNIFIED IDEOGRAPH + 0xD26B: 0x8968, //CJK UNIFIED IDEOGRAPH + 0xD26C: 0x8969, //CJK UNIFIED IDEOGRAPH + 0xD26D: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xD26E: 0x896B, //CJK UNIFIED IDEOGRAPH + 0xD26F: 0x896C, //CJK UNIFIED IDEOGRAPH + 0xD270: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xD271: 0x896E, //CJK UNIFIED IDEOGRAPH + 0xD272: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xD273: 0x8970, //CJK UNIFIED IDEOGRAPH + 0xD274: 0x8971, //CJK UNIFIED IDEOGRAPH + 0xD275: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xD276: 0x8973, //CJK UNIFIED IDEOGRAPH + 0xD277: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xD278: 0x8975, //CJK UNIFIED IDEOGRAPH + 0xD279: 0x8976, //CJK UNIFIED IDEOGRAPH + 0xD27A: 0x8977, //CJK UNIFIED IDEOGRAPH + 0xD27B: 0x8978, //CJK UNIFIED IDEOGRAPH + 0xD27C: 0x8979, //CJK UNIFIED IDEOGRAPH + 0xD27D: 0x897A, //CJK UNIFIED IDEOGRAPH + 0xD27E: 0x897C, //CJK UNIFIED IDEOGRAPH + 0xD280: 0x897D, //CJK UNIFIED IDEOGRAPH + 0xD281: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xD282: 0x8980, //CJK UNIFIED IDEOGRAPH + 0xD283: 0x8982, //CJK UNIFIED IDEOGRAPH + 0xD284: 0x8984, //CJK UNIFIED IDEOGRAPH + 0xD285: 0x8985, //CJK UNIFIED IDEOGRAPH + 0xD286: 0x8987, //CJK UNIFIED IDEOGRAPH + 0xD287: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xD288: 0x8989, //CJK UNIFIED IDEOGRAPH + 0xD289: 0x898A, //CJK UNIFIED IDEOGRAPH + 0xD28A: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xD28B: 0x898C, //CJK UNIFIED IDEOGRAPH + 0xD28C: 0x898D, //CJK UNIFIED IDEOGRAPH + 0xD28D: 0x898E, //CJK UNIFIED IDEOGRAPH + 0xD28E: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xD28F: 0x8990, //CJK UNIFIED IDEOGRAPH + 0xD290: 0x8991, //CJK UNIFIED IDEOGRAPH + 0xD291: 0x8992, //CJK UNIFIED IDEOGRAPH + 0xD292: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xD293: 0x8994, //CJK UNIFIED IDEOGRAPH + 0xD294: 0x8995, //CJK UNIFIED IDEOGRAPH + 0xD295: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xD296: 0x8997, //CJK UNIFIED IDEOGRAPH + 0xD297: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xD298: 0x8999, //CJK UNIFIED IDEOGRAPH + 0xD299: 0x899A, //CJK UNIFIED IDEOGRAPH + 0xD29A: 0x899B, //CJK UNIFIED IDEOGRAPH + 0xD29B: 0x899C, //CJK UNIFIED IDEOGRAPH + 0xD29C: 0x899D, //CJK UNIFIED IDEOGRAPH + 0xD29D: 0x899E, //CJK UNIFIED IDEOGRAPH + 0xD29E: 0x899F, //CJK UNIFIED IDEOGRAPH + 0xD29F: 0x89A0, //CJK UNIFIED IDEOGRAPH + 0xD2A0: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xD2A1: 0x6447, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0x5C27, //CJK UNIFIED IDEOGRAPH + 0xD2A3: 0x9065, //CJK UNIFIED IDEOGRAPH + 0xD2A4: 0x7A91, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x8C23, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xD2A8: 0x8200, //CJK UNIFIED IDEOGRAPH + 0xD2A9: 0x836F, //CJK UNIFIED IDEOGRAPH + 0xD2AA: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xD2AB: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xD2AC: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0x564E, //CJK UNIFIED IDEOGRAPH + 0xD2AE: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x7237, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xD2B3: 0x9875, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x4E1A, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x53F6, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x533B, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xD2BF: 0x94F1, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xD2C3: 0x9890, //CJK UNIFIED IDEOGRAPH + 0xD2C4: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xD2C5: 0x9057, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xD2C7: 0x4EEA, //CJK UNIFIED IDEOGRAPH + 0xD2C8: 0x80F0, //CJK UNIFIED IDEOGRAPH + 0xD2C9: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xD2CA: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xD2CB: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xD2CC: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0xD2CE: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xD2CF: 0x8681, //CJK UNIFIED IDEOGRAPH + 0xD2D0: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xD2D1: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xD2D2: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xD2D3: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xD2D4: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xD2D5: 0x827A, //CJK UNIFIED IDEOGRAPH + 0xD2D6: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xD2D7: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xD2D8: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xD2DA: 0x4EBF, //CJK UNIFIED IDEOGRAPH + 0xD2DB: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xD2DF: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xD2E0: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xD2E2: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xD2E3: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0x5FC6, //CJK UNIFIED IDEOGRAPH + 0xD2E5: 0x4E49, //CJK UNIFIED IDEOGRAPH + 0xD2E6: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xD2E7: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xD2E8: 0x8BE3, //CJK UNIFIED IDEOGRAPH + 0xD2E9: 0x8BAE, //CJK UNIFIED IDEOGRAPH + 0xD2EA: 0x8C0A, //CJK UNIFIED IDEOGRAPH + 0xD2EB: 0x8BD1, //CJK UNIFIED IDEOGRAPH + 0xD2EC: 0x5F02, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x7ECE, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xD2F1: 0x836B, //CJK UNIFIED IDEOGRAPH + 0xD2F2: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xD2F3: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xD2F4: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xD2F5: 0x9634, //CJK UNIFIED IDEOGRAPH + 0xD2F6: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xD2F8: 0x94F6, //CJK UNIFIED IDEOGRAPH + 0xD2F9: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x996E, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x9690, //CJK UNIFIED IDEOGRAPH + 0xD340: 0x89A2, //CJK UNIFIED IDEOGRAPH + 0xD341: 0x89A3, //CJK UNIFIED IDEOGRAPH + 0xD342: 0x89A4, //CJK UNIFIED IDEOGRAPH + 0xD343: 0x89A5, //CJK UNIFIED IDEOGRAPH + 0xD344: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xD345: 0x89A7, //CJK UNIFIED IDEOGRAPH + 0xD346: 0x89A8, //CJK UNIFIED IDEOGRAPH + 0xD347: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xD348: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xD349: 0x89AB, //CJK UNIFIED IDEOGRAPH + 0xD34A: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xD34B: 0x89AD, //CJK UNIFIED IDEOGRAPH + 0xD34C: 0x89AE, //CJK UNIFIED IDEOGRAPH + 0xD34D: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xD34E: 0x89B0, //CJK UNIFIED IDEOGRAPH + 0xD34F: 0x89B1, //CJK UNIFIED IDEOGRAPH + 0xD350: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xD351: 0x89B3, //CJK UNIFIED IDEOGRAPH + 0xD352: 0x89B4, //CJK UNIFIED IDEOGRAPH + 0xD353: 0x89B5, //CJK UNIFIED IDEOGRAPH + 0xD354: 0x89B6, //CJK UNIFIED IDEOGRAPH + 0xD355: 0x89B7, //CJK UNIFIED IDEOGRAPH + 0xD356: 0x89B8, //CJK UNIFIED IDEOGRAPH + 0xD357: 0x89B9, //CJK UNIFIED IDEOGRAPH + 0xD358: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xD359: 0x89BB, //CJK UNIFIED IDEOGRAPH + 0xD35A: 0x89BC, //CJK UNIFIED IDEOGRAPH + 0xD35B: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xD35C: 0x89BE, //CJK UNIFIED IDEOGRAPH + 0xD35D: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xD35E: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xD35F: 0x89C3, //CJK UNIFIED IDEOGRAPH + 0xD360: 0x89CD, //CJK UNIFIED IDEOGRAPH + 0xD361: 0x89D3, //CJK UNIFIED IDEOGRAPH + 0xD362: 0x89D4, //CJK UNIFIED IDEOGRAPH + 0xD363: 0x89D5, //CJK UNIFIED IDEOGRAPH + 0xD364: 0x89D7, //CJK UNIFIED IDEOGRAPH + 0xD365: 0x89D8, //CJK UNIFIED IDEOGRAPH + 0xD366: 0x89D9, //CJK UNIFIED IDEOGRAPH + 0xD367: 0x89DB, //CJK UNIFIED IDEOGRAPH + 0xD368: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xD369: 0x89DF, //CJK UNIFIED IDEOGRAPH + 0xD36A: 0x89E0, //CJK UNIFIED IDEOGRAPH + 0xD36B: 0x89E1, //CJK UNIFIED IDEOGRAPH + 0xD36C: 0x89E2, //CJK UNIFIED IDEOGRAPH + 0xD36D: 0x89E4, //CJK UNIFIED IDEOGRAPH + 0xD36E: 0x89E7, //CJK UNIFIED IDEOGRAPH + 0xD36F: 0x89E8, //CJK UNIFIED IDEOGRAPH + 0xD370: 0x89E9, //CJK UNIFIED IDEOGRAPH + 0xD371: 0x89EA, //CJK UNIFIED IDEOGRAPH + 0xD372: 0x89EC, //CJK UNIFIED IDEOGRAPH + 0xD373: 0x89ED, //CJK UNIFIED IDEOGRAPH + 0xD374: 0x89EE, //CJK UNIFIED IDEOGRAPH + 0xD375: 0x89F0, //CJK UNIFIED IDEOGRAPH + 0xD376: 0x89F1, //CJK UNIFIED IDEOGRAPH + 0xD377: 0x89F2, //CJK UNIFIED IDEOGRAPH + 0xD378: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xD379: 0x89F5, //CJK UNIFIED IDEOGRAPH + 0xD37A: 0x89F6, //CJK UNIFIED IDEOGRAPH + 0xD37B: 0x89F7, //CJK UNIFIED IDEOGRAPH + 0xD37C: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xD37D: 0x89F9, //CJK UNIFIED IDEOGRAPH + 0xD37E: 0x89FA, //CJK UNIFIED IDEOGRAPH + 0xD380: 0x89FB, //CJK UNIFIED IDEOGRAPH + 0xD381: 0x89FC, //CJK UNIFIED IDEOGRAPH + 0xD382: 0x89FD, //CJK UNIFIED IDEOGRAPH + 0xD383: 0x89FE, //CJK UNIFIED IDEOGRAPH + 0xD384: 0x89FF, //CJK UNIFIED IDEOGRAPH + 0xD385: 0x8A01, //CJK UNIFIED IDEOGRAPH + 0xD386: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xD387: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xD388: 0x8A04, //CJK UNIFIED IDEOGRAPH + 0xD389: 0x8A05, //CJK UNIFIED IDEOGRAPH + 0xD38A: 0x8A06, //CJK UNIFIED IDEOGRAPH + 0xD38B: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xD38C: 0x8A09, //CJK UNIFIED IDEOGRAPH + 0xD38D: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xD38E: 0x8A0B, //CJK UNIFIED IDEOGRAPH + 0xD38F: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xD390: 0x8A0D, //CJK UNIFIED IDEOGRAPH + 0xD391: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xD392: 0x8A0F, //CJK UNIFIED IDEOGRAPH + 0xD393: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xD394: 0x8A11, //CJK UNIFIED IDEOGRAPH + 0xD395: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xD396: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xD397: 0x8A14, //CJK UNIFIED IDEOGRAPH + 0xD398: 0x8A15, //CJK UNIFIED IDEOGRAPH + 0xD399: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xD39A: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xD39B: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xD39C: 0x8A19, //CJK UNIFIED IDEOGRAPH + 0xD39D: 0x8A1A, //CJK UNIFIED IDEOGRAPH + 0xD39E: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xD39F: 0x8A1C, //CJK UNIFIED IDEOGRAPH + 0xD3A0: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x6A31, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x5A74, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x9E70, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x5E94, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x7F28, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x83B9, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x8424, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x8425, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x8367, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x8747, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x8D62, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x9896, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x54DF, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x62E5, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x4F63, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x81C3, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x75C8, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x548F, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x607F, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x4F18, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x5FE7, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x90AE, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x94C0, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x72B9, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x8BF1, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x6986, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x8206, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x4FDE, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x9C7C, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x6E14, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x5A31, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x5C7F, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x8BED, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x5401, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x55BB, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x72F1, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x8A89, //CJK UNIFIED IDEOGRAPH + 0xD440: 0x8A1E, //CJK UNIFIED IDEOGRAPH + 0xD441: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xD442: 0x8A20, //CJK UNIFIED IDEOGRAPH + 0xD443: 0x8A21, //CJK UNIFIED IDEOGRAPH + 0xD444: 0x8A22, //CJK UNIFIED IDEOGRAPH + 0xD445: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xD446: 0x8A24, //CJK UNIFIED IDEOGRAPH + 0xD447: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xD448: 0x8A26, //CJK UNIFIED IDEOGRAPH + 0xD449: 0x8A27, //CJK UNIFIED IDEOGRAPH + 0xD44A: 0x8A28, //CJK UNIFIED IDEOGRAPH + 0xD44B: 0x8A29, //CJK UNIFIED IDEOGRAPH + 0xD44C: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xD44D: 0x8A2B, //CJK UNIFIED IDEOGRAPH + 0xD44E: 0x8A2C, //CJK UNIFIED IDEOGRAPH + 0xD44F: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xD450: 0x8A2E, //CJK UNIFIED IDEOGRAPH + 0xD451: 0x8A2F, //CJK UNIFIED IDEOGRAPH + 0xD452: 0x8A30, //CJK UNIFIED IDEOGRAPH + 0xD453: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xD454: 0x8A32, //CJK UNIFIED IDEOGRAPH + 0xD455: 0x8A33, //CJK UNIFIED IDEOGRAPH + 0xD456: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xD457: 0x8A35, //CJK UNIFIED IDEOGRAPH + 0xD458: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xD459: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xD45A: 0x8A38, //CJK UNIFIED IDEOGRAPH + 0xD45B: 0x8A39, //CJK UNIFIED IDEOGRAPH + 0xD45C: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xD45D: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xD45E: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0xD45F: 0x8A3D, //CJK UNIFIED IDEOGRAPH + 0xD460: 0x8A3F, //CJK UNIFIED IDEOGRAPH + 0xD461: 0x8A40, //CJK UNIFIED IDEOGRAPH + 0xD462: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xD463: 0x8A42, //CJK UNIFIED IDEOGRAPH + 0xD464: 0x8A43, //CJK UNIFIED IDEOGRAPH + 0xD465: 0x8A44, //CJK UNIFIED IDEOGRAPH + 0xD466: 0x8A45, //CJK UNIFIED IDEOGRAPH + 0xD467: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xD468: 0x8A47, //CJK UNIFIED IDEOGRAPH + 0xD469: 0x8A49, //CJK UNIFIED IDEOGRAPH + 0xD46A: 0x8A4A, //CJK UNIFIED IDEOGRAPH + 0xD46B: 0x8A4B, //CJK UNIFIED IDEOGRAPH + 0xD46C: 0x8A4C, //CJK UNIFIED IDEOGRAPH + 0xD46D: 0x8A4D, //CJK UNIFIED IDEOGRAPH + 0xD46E: 0x8A4E, //CJK UNIFIED IDEOGRAPH + 0xD46F: 0x8A4F, //CJK UNIFIED IDEOGRAPH + 0xD470: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xD471: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0xD472: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xD473: 0x8A53, //CJK UNIFIED IDEOGRAPH + 0xD474: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xD475: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xD476: 0x8A56, //CJK UNIFIED IDEOGRAPH + 0xD477: 0x8A57, //CJK UNIFIED IDEOGRAPH + 0xD478: 0x8A58, //CJK UNIFIED IDEOGRAPH + 0xD479: 0x8A59, //CJK UNIFIED IDEOGRAPH + 0xD47A: 0x8A5A, //CJK UNIFIED IDEOGRAPH + 0xD47B: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xD47C: 0x8A5C, //CJK UNIFIED IDEOGRAPH + 0xD47D: 0x8A5D, //CJK UNIFIED IDEOGRAPH + 0xD47E: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xD480: 0x8A5F, //CJK UNIFIED IDEOGRAPH + 0xD481: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xD482: 0x8A61, //CJK UNIFIED IDEOGRAPH + 0xD483: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xD484: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xD485: 0x8A64, //CJK UNIFIED IDEOGRAPH + 0xD486: 0x8A65, //CJK UNIFIED IDEOGRAPH + 0xD487: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xD488: 0x8A67, //CJK UNIFIED IDEOGRAPH + 0xD489: 0x8A68, //CJK UNIFIED IDEOGRAPH + 0xD48A: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xD48B: 0x8A6A, //CJK UNIFIED IDEOGRAPH + 0xD48C: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0xD48D: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xD48E: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xD48F: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xD490: 0x8A6F, //CJK UNIFIED IDEOGRAPH + 0xD491: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0xD492: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xD493: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xD494: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xD495: 0x8A74, //CJK UNIFIED IDEOGRAPH + 0xD496: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xD497: 0x8A76, //CJK UNIFIED IDEOGRAPH + 0xD498: 0x8A77, //CJK UNIFIED IDEOGRAPH + 0xD499: 0x8A78, //CJK UNIFIED IDEOGRAPH + 0xD49A: 0x8A7A, //CJK UNIFIED IDEOGRAPH + 0xD49B: 0x8A7B, //CJK UNIFIED IDEOGRAPH + 0xD49C: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xD49D: 0x8A7D, //CJK UNIFIED IDEOGRAPH + 0xD49E: 0x8A7E, //CJK UNIFIED IDEOGRAPH + 0xD49F: 0x8A7F, //CJK UNIFIED IDEOGRAPH + 0xD4A0: 0x8A80, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x9884, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x9A6D, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x9E33, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x6E0A, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x8F95, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x56ED, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x5458, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x5706, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x7F18, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x8FDC, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x7EA6, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x8DC3, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x94A5, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x7CA4, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x60A6, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x9605, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x90E7, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x9668, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x8FD0, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x8574, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x915D, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x6655, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x97F5, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x531D, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x7838, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x6742, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x707E, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x8F7D, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x54B1, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x6512, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x6682, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x8D5E, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x8D43, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x810F, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x51FF, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0x67A3, //CJK UNIFIED IDEOGRAPH + 0xD4E7: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x566A, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x7076, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x8D23, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x62E9, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x5219, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x6CFD, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x8D3C, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x600E, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x8D60, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x624E, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x55B3, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xD4FD: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x8F67, //CJK UNIFIED IDEOGRAPH + 0xD540: 0x8A81, //CJK UNIFIED IDEOGRAPH + 0xD541: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xD542: 0x8A83, //CJK UNIFIED IDEOGRAPH + 0xD543: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xD544: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xD545: 0x8A86, //CJK UNIFIED IDEOGRAPH + 0xD546: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xD547: 0x8A88, //CJK UNIFIED IDEOGRAPH + 0xD548: 0x8A8B, //CJK UNIFIED IDEOGRAPH + 0xD549: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xD54A: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xD54B: 0x8A8E, //CJK UNIFIED IDEOGRAPH + 0xD54C: 0x8A8F, //CJK UNIFIED IDEOGRAPH + 0xD54D: 0x8A90, //CJK UNIFIED IDEOGRAPH + 0xD54E: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xD54F: 0x8A92, //CJK UNIFIED IDEOGRAPH + 0xD550: 0x8A94, //CJK UNIFIED IDEOGRAPH + 0xD551: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xD552: 0x8A96, //CJK UNIFIED IDEOGRAPH + 0xD553: 0x8A97, //CJK UNIFIED IDEOGRAPH + 0xD554: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xD555: 0x8A99, //CJK UNIFIED IDEOGRAPH + 0xD556: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xD557: 0x8A9B, //CJK UNIFIED IDEOGRAPH + 0xD558: 0x8A9C, //CJK UNIFIED IDEOGRAPH + 0xD559: 0x8A9D, //CJK UNIFIED IDEOGRAPH + 0xD55A: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xD55B: 0x8A9F, //CJK UNIFIED IDEOGRAPH + 0xD55C: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xD55D: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xD55E: 0x8AA2, //CJK UNIFIED IDEOGRAPH + 0xD55F: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xD560: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xD561: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xD562: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xD563: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xD564: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xD565: 0x8AA9, //CJK UNIFIED IDEOGRAPH + 0xD566: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xD567: 0x8AAB, //CJK UNIFIED IDEOGRAPH + 0xD568: 0x8AAC, //CJK UNIFIED IDEOGRAPH + 0xD569: 0x8AAD, //CJK UNIFIED IDEOGRAPH + 0xD56A: 0x8AAE, //CJK UNIFIED IDEOGRAPH + 0xD56B: 0x8AAF, //CJK UNIFIED IDEOGRAPH + 0xD56C: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xD56D: 0x8AB1, //CJK UNIFIED IDEOGRAPH + 0xD56E: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xD56F: 0x8AB3, //CJK UNIFIED IDEOGRAPH + 0xD570: 0x8AB4, //CJK UNIFIED IDEOGRAPH + 0xD571: 0x8AB5, //CJK UNIFIED IDEOGRAPH + 0xD572: 0x8AB6, //CJK UNIFIED IDEOGRAPH + 0xD573: 0x8AB7, //CJK UNIFIED IDEOGRAPH + 0xD574: 0x8AB8, //CJK UNIFIED IDEOGRAPH + 0xD575: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xD576: 0x8ABA, //CJK UNIFIED IDEOGRAPH + 0xD577: 0x8ABB, //CJK UNIFIED IDEOGRAPH + 0xD578: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xD579: 0x8ABD, //CJK UNIFIED IDEOGRAPH + 0xD57A: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xD57B: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xD57C: 0x8AC0, //CJK UNIFIED IDEOGRAPH + 0xD57D: 0x8AC1, //CJK UNIFIED IDEOGRAPH + 0xD57E: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xD580: 0x8AC3, //CJK UNIFIED IDEOGRAPH + 0xD581: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xD582: 0x8AC5, //CJK UNIFIED IDEOGRAPH + 0xD583: 0x8AC6, //CJK UNIFIED IDEOGRAPH + 0xD584: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xD585: 0x8AC8, //CJK UNIFIED IDEOGRAPH + 0xD586: 0x8AC9, //CJK UNIFIED IDEOGRAPH + 0xD587: 0x8ACA, //CJK UNIFIED IDEOGRAPH + 0xD588: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xD589: 0x8ACC, //CJK UNIFIED IDEOGRAPH + 0xD58A: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xD58B: 0x8ACE, //CJK UNIFIED IDEOGRAPH + 0xD58C: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xD58D: 0x8AD0, //CJK UNIFIED IDEOGRAPH + 0xD58E: 0x8AD1, //CJK UNIFIED IDEOGRAPH + 0xD58F: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xD590: 0x8AD3, //CJK UNIFIED IDEOGRAPH + 0xD591: 0x8AD4, //CJK UNIFIED IDEOGRAPH + 0xD592: 0x8AD5, //CJK UNIFIED IDEOGRAPH + 0xD593: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xD594: 0x8AD7, //CJK UNIFIED IDEOGRAPH + 0xD595: 0x8AD8, //CJK UNIFIED IDEOGRAPH + 0xD596: 0x8AD9, //CJK UNIFIED IDEOGRAPH + 0xD597: 0x8ADA, //CJK UNIFIED IDEOGRAPH + 0xD598: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xD599: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xD59A: 0x8ADD, //CJK UNIFIED IDEOGRAPH + 0xD59B: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xD59C: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xD59D: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xD59E: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xD59F: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xD5A0: 0x8AE3, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x94E1, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x95F8, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x7728, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x6805, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0x69A8, //CJK UNIFIED IDEOGRAPH + 0xD5A6: 0x548B, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x8BC8, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0x658B, //CJK UNIFIED IDEOGRAPH + 0xD5AC: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0x503A, //CJK UNIFIED IDEOGRAPH + 0xD5AF: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6BE1, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x76CF, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x65A9, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x8F97, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x5D2D, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x8638, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x6808, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6218, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x7EFD, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x6F33, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x5F20, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6DA8, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x5E10, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x8D26, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x80C0, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x627E, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x8D75, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x86F0, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x8F99, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x9517, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x8FD9, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x771F, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x8D1E, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x9488, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x4FA6, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x8BCA, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x9547, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x9635, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x6323, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x7741, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x72F0, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x4E89, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x6014, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xD640: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xD641: 0x8AE5, //CJK UNIFIED IDEOGRAPH + 0xD642: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xD643: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xD644: 0x8AE8, //CJK UNIFIED IDEOGRAPH + 0xD645: 0x8AE9, //CJK UNIFIED IDEOGRAPH + 0xD646: 0x8AEA, //CJK UNIFIED IDEOGRAPH + 0xD647: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xD648: 0x8AEC, //CJK UNIFIED IDEOGRAPH + 0xD649: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xD64A: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xD64B: 0x8AEF, //CJK UNIFIED IDEOGRAPH + 0xD64C: 0x8AF0, //CJK UNIFIED IDEOGRAPH + 0xD64D: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xD64E: 0x8AF2, //CJK UNIFIED IDEOGRAPH + 0xD64F: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xD650: 0x8AF4, //CJK UNIFIED IDEOGRAPH + 0xD651: 0x8AF5, //CJK UNIFIED IDEOGRAPH + 0xD652: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xD653: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xD654: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xD655: 0x8AF9, //CJK UNIFIED IDEOGRAPH + 0xD656: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xD657: 0x8AFB, //CJK UNIFIED IDEOGRAPH + 0xD658: 0x8AFC, //CJK UNIFIED IDEOGRAPH + 0xD659: 0x8AFD, //CJK UNIFIED IDEOGRAPH + 0xD65A: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xD65B: 0x8AFF, //CJK UNIFIED IDEOGRAPH + 0xD65C: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xD65D: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xD65E: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xD65F: 0x8B03, //CJK UNIFIED IDEOGRAPH + 0xD660: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xD661: 0x8B05, //CJK UNIFIED IDEOGRAPH + 0xD662: 0x8B06, //CJK UNIFIED IDEOGRAPH + 0xD663: 0x8B08, //CJK UNIFIED IDEOGRAPH + 0xD664: 0x8B09, //CJK UNIFIED IDEOGRAPH + 0xD665: 0x8B0A, //CJK UNIFIED IDEOGRAPH + 0xD666: 0x8B0B, //CJK UNIFIED IDEOGRAPH + 0xD667: 0x8B0C, //CJK UNIFIED IDEOGRAPH + 0xD668: 0x8B0D, //CJK UNIFIED IDEOGRAPH + 0xD669: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xD66A: 0x8B0F, //CJK UNIFIED IDEOGRAPH + 0xD66B: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xD66C: 0x8B11, //CJK UNIFIED IDEOGRAPH + 0xD66D: 0x8B12, //CJK UNIFIED IDEOGRAPH + 0xD66E: 0x8B13, //CJK UNIFIED IDEOGRAPH + 0xD66F: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xD670: 0x8B15, //CJK UNIFIED IDEOGRAPH + 0xD671: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xD672: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xD673: 0x8B18, //CJK UNIFIED IDEOGRAPH + 0xD674: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xD675: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xD676: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xD677: 0x8B1C, //CJK UNIFIED IDEOGRAPH + 0xD678: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xD679: 0x8B1E, //CJK UNIFIED IDEOGRAPH + 0xD67A: 0x8B1F, //CJK UNIFIED IDEOGRAPH + 0xD67B: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xD67C: 0x8B21, //CJK UNIFIED IDEOGRAPH + 0xD67D: 0x8B22, //CJK UNIFIED IDEOGRAPH + 0xD67E: 0x8B23, //CJK UNIFIED IDEOGRAPH + 0xD680: 0x8B24, //CJK UNIFIED IDEOGRAPH + 0xD681: 0x8B25, //CJK UNIFIED IDEOGRAPH + 0xD682: 0x8B27, //CJK UNIFIED IDEOGRAPH + 0xD683: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xD684: 0x8B29, //CJK UNIFIED IDEOGRAPH + 0xD685: 0x8B2A, //CJK UNIFIED IDEOGRAPH + 0xD686: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xD687: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xD688: 0x8B2D, //CJK UNIFIED IDEOGRAPH + 0xD689: 0x8B2E, //CJK UNIFIED IDEOGRAPH + 0xD68A: 0x8B2F, //CJK UNIFIED IDEOGRAPH + 0xD68B: 0x8B30, //CJK UNIFIED IDEOGRAPH + 0xD68C: 0x8B31, //CJK UNIFIED IDEOGRAPH + 0xD68D: 0x8B32, //CJK UNIFIED IDEOGRAPH + 0xD68E: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xD68F: 0x8B34, //CJK UNIFIED IDEOGRAPH + 0xD690: 0x8B35, //CJK UNIFIED IDEOGRAPH + 0xD691: 0x8B36, //CJK UNIFIED IDEOGRAPH + 0xD692: 0x8B37, //CJK UNIFIED IDEOGRAPH + 0xD693: 0x8B38, //CJK UNIFIED IDEOGRAPH + 0xD694: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xD695: 0x8B3A, //CJK UNIFIED IDEOGRAPH + 0xD696: 0x8B3B, //CJK UNIFIED IDEOGRAPH + 0xD697: 0x8B3C, //CJK UNIFIED IDEOGRAPH + 0xD698: 0x8B3D, //CJK UNIFIED IDEOGRAPH + 0xD699: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xD69A: 0x8B3F, //CJK UNIFIED IDEOGRAPH + 0xD69B: 0x8B40, //CJK UNIFIED IDEOGRAPH + 0xD69C: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xD69D: 0x8B42, //CJK UNIFIED IDEOGRAPH + 0xD69E: 0x8B43, //CJK UNIFIED IDEOGRAPH + 0xD69F: 0x8B44, //CJK UNIFIED IDEOGRAPH + 0xD6A0: 0x8B45, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x5E27, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x90D1, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x8BC1, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x5431, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x7EC7, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x804C, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x6267, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x503C, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xD6B9: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7EB8, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x631A, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x63B7, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x5E1C, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x8D28, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0x6EDE, //CJK UNIFIED IDEOGRAPH + 0xD6CE: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x76C5, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x949F, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x7EC8, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x79CD, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x80BF, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x4F17, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x8BCC, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x8F74, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x8098, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x5492, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x76B1, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x663C, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x9AA4, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x732A, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x8BF8, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x8BDB, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x70DB, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x62C4, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x77A9, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x5631, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x86C0, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x8D2E, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x94F8, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xD740: 0x8B46, //CJK UNIFIED IDEOGRAPH + 0xD741: 0x8B47, //CJK UNIFIED IDEOGRAPH + 0xD742: 0x8B48, //CJK UNIFIED IDEOGRAPH + 0xD743: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xD744: 0x8B4A, //CJK UNIFIED IDEOGRAPH + 0xD745: 0x8B4B, //CJK UNIFIED IDEOGRAPH + 0xD746: 0x8B4C, //CJK UNIFIED IDEOGRAPH + 0xD747: 0x8B4D, //CJK UNIFIED IDEOGRAPH + 0xD748: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xD749: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xD74A: 0x8B50, //CJK UNIFIED IDEOGRAPH + 0xD74B: 0x8B51, //CJK UNIFIED IDEOGRAPH + 0xD74C: 0x8B52, //CJK UNIFIED IDEOGRAPH + 0xD74D: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xD74E: 0x8B54, //CJK UNIFIED IDEOGRAPH + 0xD74F: 0x8B55, //CJK UNIFIED IDEOGRAPH + 0xD750: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xD751: 0x8B57, //CJK UNIFIED IDEOGRAPH + 0xD752: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xD753: 0x8B59, //CJK UNIFIED IDEOGRAPH + 0xD754: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xD755: 0x8B5B, //CJK UNIFIED IDEOGRAPH + 0xD756: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xD757: 0x8B5D, //CJK UNIFIED IDEOGRAPH + 0xD758: 0x8B5E, //CJK UNIFIED IDEOGRAPH + 0xD759: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xD75A: 0x8B60, //CJK UNIFIED IDEOGRAPH + 0xD75B: 0x8B61, //CJK UNIFIED IDEOGRAPH + 0xD75C: 0x8B62, //CJK UNIFIED IDEOGRAPH + 0xD75D: 0x8B63, //CJK UNIFIED IDEOGRAPH + 0xD75E: 0x8B64, //CJK UNIFIED IDEOGRAPH + 0xD75F: 0x8B65, //CJK UNIFIED IDEOGRAPH + 0xD760: 0x8B67, //CJK UNIFIED IDEOGRAPH + 0xD761: 0x8B68, //CJK UNIFIED IDEOGRAPH + 0xD762: 0x8B69, //CJK UNIFIED IDEOGRAPH + 0xD763: 0x8B6A, //CJK UNIFIED IDEOGRAPH + 0xD764: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xD765: 0x8B6D, //CJK UNIFIED IDEOGRAPH + 0xD766: 0x8B6E, //CJK UNIFIED IDEOGRAPH + 0xD767: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xD768: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xD769: 0x8B71, //CJK UNIFIED IDEOGRAPH + 0xD76A: 0x8B72, //CJK UNIFIED IDEOGRAPH + 0xD76B: 0x8B73, //CJK UNIFIED IDEOGRAPH + 0xD76C: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xD76D: 0x8B75, //CJK UNIFIED IDEOGRAPH + 0xD76E: 0x8B76, //CJK UNIFIED IDEOGRAPH + 0xD76F: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xD770: 0x8B78, //CJK UNIFIED IDEOGRAPH + 0xD771: 0x8B79, //CJK UNIFIED IDEOGRAPH + 0xD772: 0x8B7A, //CJK UNIFIED IDEOGRAPH + 0xD773: 0x8B7B, //CJK UNIFIED IDEOGRAPH + 0xD774: 0x8B7C, //CJK UNIFIED IDEOGRAPH + 0xD775: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xD776: 0x8B7E, //CJK UNIFIED IDEOGRAPH + 0xD777: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xD778: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xD779: 0x8B81, //CJK UNIFIED IDEOGRAPH + 0xD77A: 0x8B82, //CJK UNIFIED IDEOGRAPH + 0xD77B: 0x8B83, //CJK UNIFIED IDEOGRAPH + 0xD77C: 0x8B84, //CJK UNIFIED IDEOGRAPH + 0xD77D: 0x8B85, //CJK UNIFIED IDEOGRAPH + 0xD77E: 0x8B86, //CJK UNIFIED IDEOGRAPH + 0xD780: 0x8B87, //CJK UNIFIED IDEOGRAPH + 0xD781: 0x8B88, //CJK UNIFIED IDEOGRAPH + 0xD782: 0x8B89, //CJK UNIFIED IDEOGRAPH + 0xD783: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xD784: 0x8B8B, //CJK UNIFIED IDEOGRAPH + 0xD785: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xD786: 0x8B8D, //CJK UNIFIED IDEOGRAPH + 0xD787: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xD788: 0x8B8F, //CJK UNIFIED IDEOGRAPH + 0xD789: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0xD78A: 0x8B91, //CJK UNIFIED IDEOGRAPH + 0xD78B: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xD78C: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xD78D: 0x8B94, //CJK UNIFIED IDEOGRAPH + 0xD78E: 0x8B95, //CJK UNIFIED IDEOGRAPH + 0xD78F: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xD790: 0x8B97, //CJK UNIFIED IDEOGRAPH + 0xD791: 0x8B98, //CJK UNIFIED IDEOGRAPH + 0xD792: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xD793: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xD794: 0x8B9B, //CJK UNIFIED IDEOGRAPH + 0xD795: 0x8B9C, //CJK UNIFIED IDEOGRAPH + 0xD796: 0x8B9D, //CJK UNIFIED IDEOGRAPH + 0xD797: 0x8B9E, //CJK UNIFIED IDEOGRAPH + 0xD798: 0x8B9F, //CJK UNIFIED IDEOGRAPH + 0xD799: 0x8BAC, //CJK UNIFIED IDEOGRAPH + 0xD79A: 0x8BB1, //CJK UNIFIED IDEOGRAPH + 0xD79B: 0x8BBB, //CJK UNIFIED IDEOGRAPH + 0xD79C: 0x8BC7, //CJK UNIFIED IDEOGRAPH + 0xD79D: 0x8BD0, //CJK UNIFIED IDEOGRAPH + 0xD79E: 0x8BEA, //CJK UNIFIED IDEOGRAPH + 0xD79F: 0x8C09, //CJK UNIFIED IDEOGRAPH + 0xD7A0: 0x8C1E, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x9A7B, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x6293, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x62FD, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x4E13, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x7816, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x8F6C, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x8D5A, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x6869, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x88C5, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x5986, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x58EE, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x72B6, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x9525, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x8D58, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x5760, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x7F00, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x8C06, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x684C, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x7740, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x6D4A, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x5179, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x8D44, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xD7CC: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x7C7D, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x6E0D, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x9B03, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x7EFC, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x603B, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x7EB5, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x90B9, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x63CD, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xD7E5: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x8BC5, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x7EC4, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x94BB, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xD840: 0x8C38, //CJK UNIFIED IDEOGRAPH + 0xD841: 0x8C39, //CJK UNIFIED IDEOGRAPH + 0xD842: 0x8C3A, //CJK UNIFIED IDEOGRAPH + 0xD843: 0x8C3B, //CJK UNIFIED IDEOGRAPH + 0xD844: 0x8C3C, //CJK UNIFIED IDEOGRAPH + 0xD845: 0x8C3D, //CJK UNIFIED IDEOGRAPH + 0xD846: 0x8C3E, //CJK UNIFIED IDEOGRAPH + 0xD847: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xD848: 0x8C40, //CJK UNIFIED IDEOGRAPH + 0xD849: 0x8C42, //CJK UNIFIED IDEOGRAPH + 0xD84A: 0x8C43, //CJK UNIFIED IDEOGRAPH + 0xD84B: 0x8C44, //CJK UNIFIED IDEOGRAPH + 0xD84C: 0x8C45, //CJK UNIFIED IDEOGRAPH + 0xD84D: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xD84E: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xD84F: 0x8C4B, //CJK UNIFIED IDEOGRAPH + 0xD850: 0x8C4D, //CJK UNIFIED IDEOGRAPH + 0xD851: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xD852: 0x8C4F, //CJK UNIFIED IDEOGRAPH + 0xD853: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xD854: 0x8C51, //CJK UNIFIED IDEOGRAPH + 0xD855: 0x8C52, //CJK UNIFIED IDEOGRAPH + 0xD856: 0x8C53, //CJK UNIFIED IDEOGRAPH + 0xD857: 0x8C54, //CJK UNIFIED IDEOGRAPH + 0xD858: 0x8C56, //CJK UNIFIED IDEOGRAPH + 0xD859: 0x8C57, //CJK UNIFIED IDEOGRAPH + 0xD85A: 0x8C58, //CJK UNIFIED IDEOGRAPH + 0xD85B: 0x8C59, //CJK UNIFIED IDEOGRAPH + 0xD85C: 0x8C5B, //CJK UNIFIED IDEOGRAPH + 0xD85D: 0x8C5C, //CJK UNIFIED IDEOGRAPH + 0xD85E: 0x8C5D, //CJK UNIFIED IDEOGRAPH + 0xD85F: 0x8C5E, //CJK UNIFIED IDEOGRAPH + 0xD860: 0x8C5F, //CJK UNIFIED IDEOGRAPH + 0xD861: 0x8C60, //CJK UNIFIED IDEOGRAPH + 0xD862: 0x8C63, //CJK UNIFIED IDEOGRAPH + 0xD863: 0x8C64, //CJK UNIFIED IDEOGRAPH + 0xD864: 0x8C65, //CJK UNIFIED IDEOGRAPH + 0xD865: 0x8C66, //CJK UNIFIED IDEOGRAPH + 0xD866: 0x8C67, //CJK UNIFIED IDEOGRAPH + 0xD867: 0x8C68, //CJK UNIFIED IDEOGRAPH + 0xD868: 0x8C69, //CJK UNIFIED IDEOGRAPH + 0xD869: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xD86A: 0x8C6D, //CJK UNIFIED IDEOGRAPH + 0xD86B: 0x8C6E, //CJK UNIFIED IDEOGRAPH + 0xD86C: 0x8C6F, //CJK UNIFIED IDEOGRAPH + 0xD86D: 0x8C70, //CJK UNIFIED IDEOGRAPH + 0xD86E: 0x8C71, //CJK UNIFIED IDEOGRAPH + 0xD86F: 0x8C72, //CJK UNIFIED IDEOGRAPH + 0xD870: 0x8C74, //CJK UNIFIED IDEOGRAPH + 0xD871: 0x8C75, //CJK UNIFIED IDEOGRAPH + 0xD872: 0x8C76, //CJK UNIFIED IDEOGRAPH + 0xD873: 0x8C77, //CJK UNIFIED IDEOGRAPH + 0xD874: 0x8C7B, //CJK UNIFIED IDEOGRAPH + 0xD875: 0x8C7C, //CJK UNIFIED IDEOGRAPH + 0xD876: 0x8C7D, //CJK UNIFIED IDEOGRAPH + 0xD877: 0x8C7E, //CJK UNIFIED IDEOGRAPH + 0xD878: 0x8C7F, //CJK UNIFIED IDEOGRAPH + 0xD879: 0x8C80, //CJK UNIFIED IDEOGRAPH + 0xD87A: 0x8C81, //CJK UNIFIED IDEOGRAPH + 0xD87B: 0x8C83, //CJK UNIFIED IDEOGRAPH + 0xD87C: 0x8C84, //CJK UNIFIED IDEOGRAPH + 0xD87D: 0x8C86, //CJK UNIFIED IDEOGRAPH + 0xD87E: 0x8C87, //CJK UNIFIED IDEOGRAPH + 0xD880: 0x8C88, //CJK UNIFIED IDEOGRAPH + 0xD881: 0x8C8B, //CJK UNIFIED IDEOGRAPH + 0xD882: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xD883: 0x8C8E, //CJK UNIFIED IDEOGRAPH + 0xD884: 0x8C8F, //CJK UNIFIED IDEOGRAPH + 0xD885: 0x8C90, //CJK UNIFIED IDEOGRAPH + 0xD886: 0x8C91, //CJK UNIFIED IDEOGRAPH + 0xD887: 0x8C92, //CJK UNIFIED IDEOGRAPH + 0xD888: 0x8C93, //CJK UNIFIED IDEOGRAPH + 0xD889: 0x8C95, //CJK UNIFIED IDEOGRAPH + 0xD88A: 0x8C96, //CJK UNIFIED IDEOGRAPH + 0xD88B: 0x8C97, //CJK UNIFIED IDEOGRAPH + 0xD88C: 0x8C99, //CJK UNIFIED IDEOGRAPH + 0xD88D: 0x8C9A, //CJK UNIFIED IDEOGRAPH + 0xD88E: 0x8C9B, //CJK UNIFIED IDEOGRAPH + 0xD88F: 0x8C9C, //CJK UNIFIED IDEOGRAPH + 0xD890: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xD891: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xD892: 0x8C9F, //CJK UNIFIED IDEOGRAPH + 0xD893: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xD894: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xD895: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xD896: 0x8CA3, //CJK UNIFIED IDEOGRAPH + 0xD897: 0x8CA4, //CJK UNIFIED IDEOGRAPH + 0xD898: 0x8CA5, //CJK UNIFIED IDEOGRAPH + 0xD899: 0x8CA6, //CJK UNIFIED IDEOGRAPH + 0xD89A: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xD89B: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xD89C: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xD89D: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xD89E: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xD89F: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xD8A0: 0x8CAD, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x4E8D, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x4E0C, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x5B6C, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x5669, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x4E3F, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x4E47, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x536E, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x6C10, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x56DF, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x9F17, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x4E36, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x9F10, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x4E5C, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x4E69, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x4E93, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x8288, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x556C, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x560F, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x538D, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x539D, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x53A3, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x53AE, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x9765, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x8D5D, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x531A, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x53F5, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x5326, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x532E, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x533E, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x8D5C, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x5363, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x5202, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x522D, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5233, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x523F, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x5240, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x525E, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x525C, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x84AF, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x5282, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x5281, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x5290, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x5293, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x5182, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x4EBB, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x4EC3, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x4EC9, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x4EE8, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x4EEB, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x4F1B, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x4EF3, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x4F22, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x4F64, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x4EF5, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x4F25, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x4F27, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x4F2B, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x4F67, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0xD940: 0x8CAE, //CJK UNIFIED IDEOGRAPH + 0xD941: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xD942: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xD943: 0x8CB1, //CJK UNIFIED IDEOGRAPH + 0xD944: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xD945: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xD946: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xD947: 0x8CB5, //CJK UNIFIED IDEOGRAPH + 0xD948: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xD949: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xD94A: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xD94B: 0x8CB9, //CJK UNIFIED IDEOGRAPH + 0xD94C: 0x8CBA, //CJK UNIFIED IDEOGRAPH + 0xD94D: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xD94E: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xD94F: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xD950: 0x8CBE, //CJK UNIFIED IDEOGRAPH + 0xD951: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xD952: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xD953: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xD954: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xD955: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xD956: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xD957: 0x8CC5, //CJK UNIFIED IDEOGRAPH + 0xD958: 0x8CC6, //CJK UNIFIED IDEOGRAPH + 0xD959: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xD95A: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xD95B: 0x8CC9, //CJK UNIFIED IDEOGRAPH + 0xD95C: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xD95D: 0x8CCB, //CJK UNIFIED IDEOGRAPH + 0xD95E: 0x8CCC, //CJK UNIFIED IDEOGRAPH + 0xD95F: 0x8CCD, //CJK UNIFIED IDEOGRAPH + 0xD960: 0x8CCE, //CJK UNIFIED IDEOGRAPH + 0xD961: 0x8CCF, //CJK UNIFIED IDEOGRAPH + 0xD962: 0x8CD0, //CJK UNIFIED IDEOGRAPH + 0xD963: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xD964: 0x8CD2, //CJK UNIFIED IDEOGRAPH + 0xD965: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xD966: 0x8CD4, //CJK UNIFIED IDEOGRAPH + 0xD967: 0x8CD5, //CJK UNIFIED IDEOGRAPH + 0xD968: 0x8CD6, //CJK UNIFIED IDEOGRAPH + 0xD969: 0x8CD7, //CJK UNIFIED IDEOGRAPH + 0xD96A: 0x8CD8, //CJK UNIFIED IDEOGRAPH + 0xD96B: 0x8CD9, //CJK UNIFIED IDEOGRAPH + 0xD96C: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xD96D: 0x8CDB, //CJK UNIFIED IDEOGRAPH + 0xD96E: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xD96F: 0x8CDD, //CJK UNIFIED IDEOGRAPH + 0xD970: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xD971: 0x8CDF, //CJK UNIFIED IDEOGRAPH + 0xD972: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xD973: 0x8CE1, //CJK UNIFIED IDEOGRAPH + 0xD974: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xD975: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xD976: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xD977: 0x8CE5, //CJK UNIFIED IDEOGRAPH + 0xD978: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xD979: 0x8CE7, //CJK UNIFIED IDEOGRAPH + 0xD97A: 0x8CE8, //CJK UNIFIED IDEOGRAPH + 0xD97B: 0x8CE9, //CJK UNIFIED IDEOGRAPH + 0xD97C: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xD97D: 0x8CEB, //CJK UNIFIED IDEOGRAPH + 0xD97E: 0x8CEC, //CJK UNIFIED IDEOGRAPH + 0xD980: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xD981: 0x8CEE, //CJK UNIFIED IDEOGRAPH + 0xD982: 0x8CEF, //CJK UNIFIED IDEOGRAPH + 0xD983: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xD984: 0x8CF1, //CJK UNIFIED IDEOGRAPH + 0xD985: 0x8CF2, //CJK UNIFIED IDEOGRAPH + 0xD986: 0x8CF3, //CJK UNIFIED IDEOGRAPH + 0xD987: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xD988: 0x8CF5, //CJK UNIFIED IDEOGRAPH + 0xD989: 0x8CF6, //CJK UNIFIED IDEOGRAPH + 0xD98A: 0x8CF7, //CJK UNIFIED IDEOGRAPH + 0xD98B: 0x8CF8, //CJK UNIFIED IDEOGRAPH + 0xD98C: 0x8CF9, //CJK UNIFIED IDEOGRAPH + 0xD98D: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xD98E: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xD98F: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xD990: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xD991: 0x8CFE, //CJK UNIFIED IDEOGRAPH + 0xD992: 0x8CFF, //CJK UNIFIED IDEOGRAPH + 0xD993: 0x8D00, //CJK UNIFIED IDEOGRAPH + 0xD994: 0x8D01, //CJK UNIFIED IDEOGRAPH + 0xD995: 0x8D02, //CJK UNIFIED IDEOGRAPH + 0xD996: 0x8D03, //CJK UNIFIED IDEOGRAPH + 0xD997: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xD998: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xD999: 0x8D06, //CJK UNIFIED IDEOGRAPH + 0xD99A: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xD99B: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xD99C: 0x8D09, //CJK UNIFIED IDEOGRAPH + 0xD99D: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xD99E: 0x8D0B, //CJK UNIFIED IDEOGRAPH + 0xD99F: 0x8D0C, //CJK UNIFIED IDEOGRAPH + 0xD9A0: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x4F5F, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x4F32, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x4F74, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x4F89, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x4FAA, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x4FAC, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x4FE6, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x4FE8, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x4FEA, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x4FC5, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x4FE3, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x4FDC, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x5029, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x504C, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x502E, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x500C, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x5025, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x507E, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x504E, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x506C, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x507B, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x50A5, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x50A7, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x50A9, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x50BA, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x50EC, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x50E6, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x5107, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x510B, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6C3D, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x4F58, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x4F65, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x6C46, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x7C74, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x9EC9, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x5181, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x52F9, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x8A07, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x51EB, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x5155, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x4EA0, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x5156, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x886E, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x4EB5, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x8114, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x88D2, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x7980, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x5B34, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x8803, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x51AB, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x51BC, //CJK UNIFIED IDEOGRAPH + 0xDA40: 0x8D0E, //CJK UNIFIED IDEOGRAPH + 0xDA41: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xDA42: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xDA43: 0x8D11, //CJK UNIFIED IDEOGRAPH + 0xDA44: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xDA45: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xDA46: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xDA47: 0x8D15, //CJK UNIFIED IDEOGRAPH + 0xDA48: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xDA49: 0x8D17, //CJK UNIFIED IDEOGRAPH + 0xDA4A: 0x8D18, //CJK UNIFIED IDEOGRAPH + 0xDA4B: 0x8D19, //CJK UNIFIED IDEOGRAPH + 0xDA4C: 0x8D1A, //CJK UNIFIED IDEOGRAPH + 0xDA4D: 0x8D1B, //CJK UNIFIED IDEOGRAPH + 0xDA4E: 0x8D1C, //CJK UNIFIED IDEOGRAPH + 0xDA4F: 0x8D20, //CJK UNIFIED IDEOGRAPH + 0xDA50: 0x8D51, //CJK UNIFIED IDEOGRAPH + 0xDA51: 0x8D52, //CJK UNIFIED IDEOGRAPH + 0xDA52: 0x8D57, //CJK UNIFIED IDEOGRAPH + 0xDA53: 0x8D5F, //CJK UNIFIED IDEOGRAPH + 0xDA54: 0x8D65, //CJK UNIFIED IDEOGRAPH + 0xDA55: 0x8D68, //CJK UNIFIED IDEOGRAPH + 0xDA56: 0x8D69, //CJK UNIFIED IDEOGRAPH + 0xDA57: 0x8D6A, //CJK UNIFIED IDEOGRAPH + 0xDA58: 0x8D6C, //CJK UNIFIED IDEOGRAPH + 0xDA59: 0x8D6E, //CJK UNIFIED IDEOGRAPH + 0xDA5A: 0x8D6F, //CJK UNIFIED IDEOGRAPH + 0xDA5B: 0x8D71, //CJK UNIFIED IDEOGRAPH + 0xDA5C: 0x8D72, //CJK UNIFIED IDEOGRAPH + 0xDA5D: 0x8D78, //CJK UNIFIED IDEOGRAPH + 0xDA5E: 0x8D79, //CJK UNIFIED IDEOGRAPH + 0xDA5F: 0x8D7A, //CJK UNIFIED IDEOGRAPH + 0xDA60: 0x8D7B, //CJK UNIFIED IDEOGRAPH + 0xDA61: 0x8D7C, //CJK UNIFIED IDEOGRAPH + 0xDA62: 0x8D7D, //CJK UNIFIED IDEOGRAPH + 0xDA63: 0x8D7E, //CJK UNIFIED IDEOGRAPH + 0xDA64: 0x8D7F, //CJK UNIFIED IDEOGRAPH + 0xDA65: 0x8D80, //CJK UNIFIED IDEOGRAPH + 0xDA66: 0x8D82, //CJK UNIFIED IDEOGRAPH + 0xDA67: 0x8D83, //CJK UNIFIED IDEOGRAPH + 0xDA68: 0x8D86, //CJK UNIFIED IDEOGRAPH + 0xDA69: 0x8D87, //CJK UNIFIED IDEOGRAPH + 0xDA6A: 0x8D88, //CJK UNIFIED IDEOGRAPH + 0xDA6B: 0x8D89, //CJK UNIFIED IDEOGRAPH + 0xDA6C: 0x8D8C, //CJK UNIFIED IDEOGRAPH + 0xDA6D: 0x8D8D, //CJK UNIFIED IDEOGRAPH + 0xDA6E: 0x8D8E, //CJK UNIFIED IDEOGRAPH + 0xDA6F: 0x8D8F, //CJK UNIFIED IDEOGRAPH + 0xDA70: 0x8D90, //CJK UNIFIED IDEOGRAPH + 0xDA71: 0x8D92, //CJK UNIFIED IDEOGRAPH + 0xDA72: 0x8D93, //CJK UNIFIED IDEOGRAPH + 0xDA73: 0x8D95, //CJK UNIFIED IDEOGRAPH + 0xDA74: 0x8D96, //CJK UNIFIED IDEOGRAPH + 0xDA75: 0x8D97, //CJK UNIFIED IDEOGRAPH + 0xDA76: 0x8D98, //CJK UNIFIED IDEOGRAPH + 0xDA77: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xDA78: 0x8D9A, //CJK UNIFIED IDEOGRAPH + 0xDA79: 0x8D9B, //CJK UNIFIED IDEOGRAPH + 0xDA7A: 0x8D9C, //CJK UNIFIED IDEOGRAPH + 0xDA7B: 0x8D9D, //CJK UNIFIED IDEOGRAPH + 0xDA7C: 0x8D9E, //CJK UNIFIED IDEOGRAPH + 0xDA7D: 0x8DA0, //CJK UNIFIED IDEOGRAPH + 0xDA7E: 0x8DA1, //CJK UNIFIED IDEOGRAPH + 0xDA80: 0x8DA2, //CJK UNIFIED IDEOGRAPH + 0xDA81: 0x8DA4, //CJK UNIFIED IDEOGRAPH + 0xDA82: 0x8DA5, //CJK UNIFIED IDEOGRAPH + 0xDA83: 0x8DA6, //CJK UNIFIED IDEOGRAPH + 0xDA84: 0x8DA7, //CJK UNIFIED IDEOGRAPH + 0xDA85: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xDA86: 0x8DA9, //CJK UNIFIED IDEOGRAPH + 0xDA87: 0x8DAA, //CJK UNIFIED IDEOGRAPH + 0xDA88: 0x8DAB, //CJK UNIFIED IDEOGRAPH + 0xDA89: 0x8DAC, //CJK UNIFIED IDEOGRAPH + 0xDA8A: 0x8DAD, //CJK UNIFIED IDEOGRAPH + 0xDA8B: 0x8DAE, //CJK UNIFIED IDEOGRAPH + 0xDA8C: 0x8DAF, //CJK UNIFIED IDEOGRAPH + 0xDA8D: 0x8DB0, //CJK UNIFIED IDEOGRAPH + 0xDA8E: 0x8DB2, //CJK UNIFIED IDEOGRAPH + 0xDA8F: 0x8DB6, //CJK UNIFIED IDEOGRAPH + 0xDA90: 0x8DB7, //CJK UNIFIED IDEOGRAPH + 0xDA91: 0x8DB9, //CJK UNIFIED IDEOGRAPH + 0xDA92: 0x8DBB, //CJK UNIFIED IDEOGRAPH + 0xDA93: 0x8DBD, //CJK UNIFIED IDEOGRAPH + 0xDA94: 0x8DC0, //CJK UNIFIED IDEOGRAPH + 0xDA95: 0x8DC1, //CJK UNIFIED IDEOGRAPH + 0xDA96: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xDA97: 0x8DC5, //CJK UNIFIED IDEOGRAPH + 0xDA98: 0x8DC7, //CJK UNIFIED IDEOGRAPH + 0xDA99: 0x8DC8, //CJK UNIFIED IDEOGRAPH + 0xDA9A: 0x8DC9, //CJK UNIFIED IDEOGRAPH + 0xDA9B: 0x8DCA, //CJK UNIFIED IDEOGRAPH + 0xDA9C: 0x8DCD, //CJK UNIFIED IDEOGRAPH + 0xDA9D: 0x8DD0, //CJK UNIFIED IDEOGRAPH + 0xDA9E: 0x8DD2, //CJK UNIFIED IDEOGRAPH + 0xDA9F: 0x8DD3, //CJK UNIFIED IDEOGRAPH + 0xDAA0: 0x8DD4, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x51C7, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x5196, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x8BA0, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x8BA6, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x8BA7, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x8BAA, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x8BB4, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x8BB5, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x8BB7, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x8BC2, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x8BC3, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x8BCB, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x8BCF, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x8BCE, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x8BD2, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x8BD3, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x8BD4, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x8BD6, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x8BD8, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x8BD9, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x8BDC, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x8BDF, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x8BE0, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x8BE4, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x8BE8, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x8BE9, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x8BEE, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x8BF0, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x8BF3, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x8BF6, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x8BF9, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x8BFC, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x8BFF, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x8C00, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x8C02, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x8C04, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x8C07, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x8C0C, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x8C0F, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x8C11, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x8C12, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x8C14, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x8C15, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x8C16, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x8C19, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x8C1B, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x8C18, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x8C1D, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x8C1F, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x8C20, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x8C21, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x8C25, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x8C27, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x8C2A, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x8C2B, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x8C2E, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x8C2F, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x8C32, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x8C33, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x8C35, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x8C36, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x5369, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x537A, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x961D, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x9622, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x9631, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x963D, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x963C, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x9649, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x9654, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x9667, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x9674, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x9688, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x9097, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x909B, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x909D, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x90AC, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x90A1, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x90B4, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x90B3, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x90B6, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x90BA, //CJK UNIFIED IDEOGRAPH + 0xDB40: 0x8DD5, //CJK UNIFIED IDEOGRAPH + 0xDB41: 0x8DD8, //CJK UNIFIED IDEOGRAPH + 0xDB42: 0x8DD9, //CJK UNIFIED IDEOGRAPH + 0xDB43: 0x8DDC, //CJK UNIFIED IDEOGRAPH + 0xDB44: 0x8DE0, //CJK UNIFIED IDEOGRAPH + 0xDB45: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xDB46: 0x8DE2, //CJK UNIFIED IDEOGRAPH + 0xDB47: 0x8DE5, //CJK UNIFIED IDEOGRAPH + 0xDB48: 0x8DE6, //CJK UNIFIED IDEOGRAPH + 0xDB49: 0x8DE7, //CJK UNIFIED IDEOGRAPH + 0xDB4A: 0x8DE9, //CJK UNIFIED IDEOGRAPH + 0xDB4B: 0x8DED, //CJK UNIFIED IDEOGRAPH + 0xDB4C: 0x8DEE, //CJK UNIFIED IDEOGRAPH + 0xDB4D: 0x8DF0, //CJK UNIFIED IDEOGRAPH + 0xDB4E: 0x8DF1, //CJK UNIFIED IDEOGRAPH + 0xDB4F: 0x8DF2, //CJK UNIFIED IDEOGRAPH + 0xDB50: 0x8DF4, //CJK UNIFIED IDEOGRAPH + 0xDB51: 0x8DF6, //CJK UNIFIED IDEOGRAPH + 0xDB52: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xDB53: 0x8DFE, //CJK UNIFIED IDEOGRAPH + 0xDB54: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xDB55: 0x8E00, //CJK UNIFIED IDEOGRAPH + 0xDB56: 0x8E01, //CJK UNIFIED IDEOGRAPH + 0xDB57: 0x8E02, //CJK UNIFIED IDEOGRAPH + 0xDB58: 0x8E03, //CJK UNIFIED IDEOGRAPH + 0xDB59: 0x8E04, //CJK UNIFIED IDEOGRAPH + 0xDB5A: 0x8E06, //CJK UNIFIED IDEOGRAPH + 0xDB5B: 0x8E07, //CJK UNIFIED IDEOGRAPH + 0xDB5C: 0x8E08, //CJK UNIFIED IDEOGRAPH + 0xDB5D: 0x8E0B, //CJK UNIFIED IDEOGRAPH + 0xDB5E: 0x8E0D, //CJK UNIFIED IDEOGRAPH + 0xDB5F: 0x8E0E, //CJK UNIFIED IDEOGRAPH + 0xDB60: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xDB61: 0x8E11, //CJK UNIFIED IDEOGRAPH + 0xDB62: 0x8E12, //CJK UNIFIED IDEOGRAPH + 0xDB63: 0x8E13, //CJK UNIFIED IDEOGRAPH + 0xDB64: 0x8E15, //CJK UNIFIED IDEOGRAPH + 0xDB65: 0x8E16, //CJK UNIFIED IDEOGRAPH + 0xDB66: 0x8E17, //CJK UNIFIED IDEOGRAPH + 0xDB67: 0x8E18, //CJK UNIFIED IDEOGRAPH + 0xDB68: 0x8E19, //CJK UNIFIED IDEOGRAPH + 0xDB69: 0x8E1A, //CJK UNIFIED IDEOGRAPH + 0xDB6A: 0x8E1B, //CJK UNIFIED IDEOGRAPH + 0xDB6B: 0x8E1C, //CJK UNIFIED IDEOGRAPH + 0xDB6C: 0x8E20, //CJK UNIFIED IDEOGRAPH + 0xDB6D: 0x8E21, //CJK UNIFIED IDEOGRAPH + 0xDB6E: 0x8E24, //CJK UNIFIED IDEOGRAPH + 0xDB6F: 0x8E25, //CJK UNIFIED IDEOGRAPH + 0xDB70: 0x8E26, //CJK UNIFIED IDEOGRAPH + 0xDB71: 0x8E27, //CJK UNIFIED IDEOGRAPH + 0xDB72: 0x8E28, //CJK UNIFIED IDEOGRAPH + 0xDB73: 0x8E2B, //CJK UNIFIED IDEOGRAPH + 0xDB74: 0x8E2D, //CJK UNIFIED IDEOGRAPH + 0xDB75: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xDB76: 0x8E32, //CJK UNIFIED IDEOGRAPH + 0xDB77: 0x8E33, //CJK UNIFIED IDEOGRAPH + 0xDB78: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xDB79: 0x8E36, //CJK UNIFIED IDEOGRAPH + 0xDB7A: 0x8E37, //CJK UNIFIED IDEOGRAPH + 0xDB7B: 0x8E38, //CJK UNIFIED IDEOGRAPH + 0xDB7C: 0x8E3B, //CJK UNIFIED IDEOGRAPH + 0xDB7D: 0x8E3C, //CJK UNIFIED IDEOGRAPH + 0xDB7E: 0x8E3E, //CJK UNIFIED IDEOGRAPH + 0xDB80: 0x8E3F, //CJK UNIFIED IDEOGRAPH + 0xDB81: 0x8E43, //CJK UNIFIED IDEOGRAPH + 0xDB82: 0x8E45, //CJK UNIFIED IDEOGRAPH + 0xDB83: 0x8E46, //CJK UNIFIED IDEOGRAPH + 0xDB84: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xDB85: 0x8E4D, //CJK UNIFIED IDEOGRAPH + 0xDB86: 0x8E4E, //CJK UNIFIED IDEOGRAPH + 0xDB87: 0x8E4F, //CJK UNIFIED IDEOGRAPH + 0xDB88: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xDB89: 0x8E53, //CJK UNIFIED IDEOGRAPH + 0xDB8A: 0x8E54, //CJK UNIFIED IDEOGRAPH + 0xDB8B: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xDB8C: 0x8E56, //CJK UNIFIED IDEOGRAPH + 0xDB8D: 0x8E57, //CJK UNIFIED IDEOGRAPH + 0xDB8E: 0x8E58, //CJK UNIFIED IDEOGRAPH + 0xDB8F: 0x8E5A, //CJK UNIFIED IDEOGRAPH + 0xDB90: 0x8E5B, //CJK UNIFIED IDEOGRAPH + 0xDB91: 0x8E5C, //CJK UNIFIED IDEOGRAPH + 0xDB92: 0x8E5D, //CJK UNIFIED IDEOGRAPH + 0xDB93: 0x8E5E, //CJK UNIFIED IDEOGRAPH + 0xDB94: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xDB95: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xDB96: 0x8E61, //CJK UNIFIED IDEOGRAPH + 0xDB97: 0x8E62, //CJK UNIFIED IDEOGRAPH + 0xDB98: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xDB99: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xDB9A: 0x8E65, //CJK UNIFIED IDEOGRAPH + 0xDB9B: 0x8E67, //CJK UNIFIED IDEOGRAPH + 0xDB9C: 0x8E68, //CJK UNIFIED IDEOGRAPH + 0xDB9D: 0x8E6A, //CJK UNIFIED IDEOGRAPH + 0xDB9E: 0x8E6B, //CJK UNIFIED IDEOGRAPH + 0xDB9F: 0x8E6E, //CJK UNIFIED IDEOGRAPH + 0xDBA0: 0x8E71, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x90CF, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x90C5, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x90BE, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x90D0, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x90C4, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x90C7, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x90D3, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x90E6, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x90DC, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x90D7, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x90EB, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x90EF, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x90FE, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x9104, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x9122, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x911E, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x9123, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x9131, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x912F, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x9139, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x9143, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x9146, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x520D, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x5942, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x52A2, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x52D0, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x52F0, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0xDBC6: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x5EF4, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x51FC, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x53B6, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x5DEF, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x574C, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x57A9, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x57A1, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x58BC, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x5729, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x572C, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x572A, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x5733, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x5739, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x572E, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x572F, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x575C, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x5742, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x5769, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x5785, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x576B, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0x5786, //CJK UNIFIED IDEOGRAPH + 0xDBE5: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x577B, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x5768, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x576D, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x5776, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x5773, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x57AD, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x578C, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x57B2, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x57CF, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x57A7, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x57B4, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x57D5, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x57D8, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x57DA, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x57D9, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x57B8, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x57EF, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x57F8, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x57E4, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x57DD, //CJK UNIFIED IDEOGRAPH + 0xDC40: 0x8E73, //CJK UNIFIED IDEOGRAPH + 0xDC41: 0x8E75, //CJK UNIFIED IDEOGRAPH + 0xDC42: 0x8E77, //CJK UNIFIED IDEOGRAPH + 0xDC43: 0x8E78, //CJK UNIFIED IDEOGRAPH + 0xDC44: 0x8E79, //CJK UNIFIED IDEOGRAPH + 0xDC45: 0x8E7A, //CJK UNIFIED IDEOGRAPH + 0xDC46: 0x8E7B, //CJK UNIFIED IDEOGRAPH + 0xDC47: 0x8E7D, //CJK UNIFIED IDEOGRAPH + 0xDC48: 0x8E7E, //CJK UNIFIED IDEOGRAPH + 0xDC49: 0x8E80, //CJK UNIFIED IDEOGRAPH + 0xDC4A: 0x8E82, //CJK UNIFIED IDEOGRAPH + 0xDC4B: 0x8E83, //CJK UNIFIED IDEOGRAPH + 0xDC4C: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xDC4D: 0x8E86, //CJK UNIFIED IDEOGRAPH + 0xDC4E: 0x8E88, //CJK UNIFIED IDEOGRAPH + 0xDC4F: 0x8E89, //CJK UNIFIED IDEOGRAPH + 0xDC50: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xDC51: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xDC52: 0x8E8C, //CJK UNIFIED IDEOGRAPH + 0xDC53: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xDC54: 0x8E8E, //CJK UNIFIED IDEOGRAPH + 0xDC55: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xDC56: 0x8E92, //CJK UNIFIED IDEOGRAPH + 0xDC57: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xDC58: 0x8E95, //CJK UNIFIED IDEOGRAPH + 0xDC59: 0x8E96, //CJK UNIFIED IDEOGRAPH + 0xDC5A: 0x8E97, //CJK UNIFIED IDEOGRAPH + 0xDC5B: 0x8E98, //CJK UNIFIED IDEOGRAPH + 0xDC5C: 0x8E99, //CJK UNIFIED IDEOGRAPH + 0xDC5D: 0x8E9A, //CJK UNIFIED IDEOGRAPH + 0xDC5E: 0x8E9B, //CJK UNIFIED IDEOGRAPH + 0xDC5F: 0x8E9D, //CJK UNIFIED IDEOGRAPH + 0xDC60: 0x8E9F, //CJK UNIFIED IDEOGRAPH + 0xDC61: 0x8EA0, //CJK UNIFIED IDEOGRAPH + 0xDC62: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xDC63: 0x8EA2, //CJK UNIFIED IDEOGRAPH + 0xDC64: 0x8EA3, //CJK UNIFIED IDEOGRAPH + 0xDC65: 0x8EA4, //CJK UNIFIED IDEOGRAPH + 0xDC66: 0x8EA5, //CJK UNIFIED IDEOGRAPH + 0xDC67: 0x8EA6, //CJK UNIFIED IDEOGRAPH + 0xDC68: 0x8EA7, //CJK UNIFIED IDEOGRAPH + 0xDC69: 0x8EA8, //CJK UNIFIED IDEOGRAPH + 0xDC6A: 0x8EA9, //CJK UNIFIED IDEOGRAPH + 0xDC6B: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xDC6C: 0x8EAD, //CJK UNIFIED IDEOGRAPH + 0xDC6D: 0x8EAE, //CJK UNIFIED IDEOGRAPH + 0xDC6E: 0x8EB0, //CJK UNIFIED IDEOGRAPH + 0xDC6F: 0x8EB1, //CJK UNIFIED IDEOGRAPH + 0xDC70: 0x8EB3, //CJK UNIFIED IDEOGRAPH + 0xDC71: 0x8EB4, //CJK UNIFIED IDEOGRAPH + 0xDC72: 0x8EB5, //CJK UNIFIED IDEOGRAPH + 0xDC73: 0x8EB6, //CJK UNIFIED IDEOGRAPH + 0xDC74: 0x8EB7, //CJK UNIFIED IDEOGRAPH + 0xDC75: 0x8EB8, //CJK UNIFIED IDEOGRAPH + 0xDC76: 0x8EB9, //CJK UNIFIED IDEOGRAPH + 0xDC77: 0x8EBB, //CJK UNIFIED IDEOGRAPH + 0xDC78: 0x8EBC, //CJK UNIFIED IDEOGRAPH + 0xDC79: 0x8EBD, //CJK UNIFIED IDEOGRAPH + 0xDC7A: 0x8EBE, //CJK UNIFIED IDEOGRAPH + 0xDC7B: 0x8EBF, //CJK UNIFIED IDEOGRAPH + 0xDC7C: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xDC7D: 0x8EC1, //CJK UNIFIED IDEOGRAPH + 0xDC7E: 0x8EC2, //CJK UNIFIED IDEOGRAPH + 0xDC80: 0x8EC3, //CJK UNIFIED IDEOGRAPH + 0xDC81: 0x8EC4, //CJK UNIFIED IDEOGRAPH + 0xDC82: 0x8EC5, //CJK UNIFIED IDEOGRAPH + 0xDC83: 0x8EC6, //CJK UNIFIED IDEOGRAPH + 0xDC84: 0x8EC7, //CJK UNIFIED IDEOGRAPH + 0xDC85: 0x8EC8, //CJK UNIFIED IDEOGRAPH + 0xDC86: 0x8EC9, //CJK UNIFIED IDEOGRAPH + 0xDC87: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xDC88: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xDC89: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xDC8A: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xDC8B: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xDC8C: 0x8ED0, //CJK UNIFIED IDEOGRAPH + 0xDC8D: 0x8ED1, //CJK UNIFIED IDEOGRAPH + 0xDC8E: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xDC8F: 0x8ED3, //CJK UNIFIED IDEOGRAPH + 0xDC90: 0x8ED4, //CJK UNIFIED IDEOGRAPH + 0xDC91: 0x8ED5, //CJK UNIFIED IDEOGRAPH + 0xDC92: 0x8ED6, //CJK UNIFIED IDEOGRAPH + 0xDC93: 0x8ED7, //CJK UNIFIED IDEOGRAPH + 0xDC94: 0x8ED8, //CJK UNIFIED IDEOGRAPH + 0xDC95: 0x8ED9, //CJK UNIFIED IDEOGRAPH + 0xDC96: 0x8EDA, //CJK UNIFIED IDEOGRAPH + 0xDC97: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xDC98: 0x8EDC, //CJK UNIFIED IDEOGRAPH + 0xDC99: 0x8EDD, //CJK UNIFIED IDEOGRAPH + 0xDC9A: 0x8EDE, //CJK UNIFIED IDEOGRAPH + 0xDC9B: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xDC9C: 0x8EE0, //CJK UNIFIED IDEOGRAPH + 0xDC9D: 0x8EE1, //CJK UNIFIED IDEOGRAPH + 0xDC9E: 0x8EE2, //CJK UNIFIED IDEOGRAPH + 0xDC9F: 0x8EE3, //CJK UNIFIED IDEOGRAPH + 0xDCA0: 0x8EE4, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x580B, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x580D, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x57FD, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x57ED, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xDCA6: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x5819, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x5844, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x5820, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x5865, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x586C, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x5881, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x589A, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x5880, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x9F19, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x8279, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x827D, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x827F, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x828F, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x828A, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x82A8, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x8284, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x8291, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x8297, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x82BE, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x82B0, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x82C8, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x82CA, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x8298, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x82CB, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x82CC, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x82C1, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x82B4, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x82A1, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x82AA, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x82C4, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x82CE, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x82A4, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x82F7, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x82E4, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x830F, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x8307, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x82D8, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x830C, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x8311, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x831A, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x8314, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x8315, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x82E0, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x831C, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x835B, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x835C, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x8308, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x8392, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x833C, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x839B, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x835E, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x8343, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x835F, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x8360, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x832D, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x833A, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x8333, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x8366, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x8365, //CJK UNIFIED IDEOGRAPH + 0xDD40: 0x8EE5, //CJK UNIFIED IDEOGRAPH + 0xDD41: 0x8EE6, //CJK UNIFIED IDEOGRAPH + 0xDD42: 0x8EE7, //CJK UNIFIED IDEOGRAPH + 0xDD43: 0x8EE8, //CJK UNIFIED IDEOGRAPH + 0xDD44: 0x8EE9, //CJK UNIFIED IDEOGRAPH + 0xDD45: 0x8EEA, //CJK UNIFIED IDEOGRAPH + 0xDD46: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xDD47: 0x8EEC, //CJK UNIFIED IDEOGRAPH + 0xDD48: 0x8EED, //CJK UNIFIED IDEOGRAPH + 0xDD49: 0x8EEE, //CJK UNIFIED IDEOGRAPH + 0xDD4A: 0x8EEF, //CJK UNIFIED IDEOGRAPH + 0xDD4B: 0x8EF0, //CJK UNIFIED IDEOGRAPH + 0xDD4C: 0x8EF1, //CJK UNIFIED IDEOGRAPH + 0xDD4D: 0x8EF2, //CJK UNIFIED IDEOGRAPH + 0xDD4E: 0x8EF3, //CJK UNIFIED IDEOGRAPH + 0xDD4F: 0x8EF4, //CJK UNIFIED IDEOGRAPH + 0xDD50: 0x8EF5, //CJK UNIFIED IDEOGRAPH + 0xDD51: 0x8EF6, //CJK UNIFIED IDEOGRAPH + 0xDD52: 0x8EF7, //CJK UNIFIED IDEOGRAPH + 0xDD53: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xDD54: 0x8EF9, //CJK UNIFIED IDEOGRAPH + 0xDD55: 0x8EFA, //CJK UNIFIED IDEOGRAPH + 0xDD56: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xDD57: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xDD58: 0x8EFD, //CJK UNIFIED IDEOGRAPH + 0xDD59: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xDD5A: 0x8EFF, //CJK UNIFIED IDEOGRAPH + 0xDD5B: 0x8F00, //CJK UNIFIED IDEOGRAPH + 0xDD5C: 0x8F01, //CJK UNIFIED IDEOGRAPH + 0xDD5D: 0x8F02, //CJK UNIFIED IDEOGRAPH + 0xDD5E: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xDD5F: 0x8F04, //CJK UNIFIED IDEOGRAPH + 0xDD60: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xDD61: 0x8F06, //CJK UNIFIED IDEOGRAPH + 0xDD62: 0x8F07, //CJK UNIFIED IDEOGRAPH + 0xDD63: 0x8F08, //CJK UNIFIED IDEOGRAPH + 0xDD64: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xDD65: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xDD66: 0x8F0B, //CJK UNIFIED IDEOGRAPH + 0xDD67: 0x8F0C, //CJK UNIFIED IDEOGRAPH + 0xDD68: 0x8F0D, //CJK UNIFIED IDEOGRAPH + 0xDD69: 0x8F0E, //CJK UNIFIED IDEOGRAPH + 0xDD6A: 0x8F0F, //CJK UNIFIED IDEOGRAPH + 0xDD6B: 0x8F10, //CJK UNIFIED IDEOGRAPH + 0xDD6C: 0x8F11, //CJK UNIFIED IDEOGRAPH + 0xDD6D: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xDD6E: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xDD6F: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xDD70: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xDD71: 0x8F16, //CJK UNIFIED IDEOGRAPH + 0xDD72: 0x8F17, //CJK UNIFIED IDEOGRAPH + 0xDD73: 0x8F18, //CJK UNIFIED IDEOGRAPH + 0xDD74: 0x8F19, //CJK UNIFIED IDEOGRAPH + 0xDD75: 0x8F1A, //CJK UNIFIED IDEOGRAPH + 0xDD76: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xDD77: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xDD78: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xDD79: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xDD7A: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xDD7B: 0x8F20, //CJK UNIFIED IDEOGRAPH + 0xDD7C: 0x8F21, //CJK UNIFIED IDEOGRAPH + 0xDD7D: 0x8F22, //CJK UNIFIED IDEOGRAPH + 0xDD7E: 0x8F23, //CJK UNIFIED IDEOGRAPH + 0xDD80: 0x8F24, //CJK UNIFIED IDEOGRAPH + 0xDD81: 0x8F25, //CJK UNIFIED IDEOGRAPH + 0xDD82: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xDD83: 0x8F27, //CJK UNIFIED IDEOGRAPH + 0xDD84: 0x8F28, //CJK UNIFIED IDEOGRAPH + 0xDD85: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xDD86: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xDD87: 0x8F2B, //CJK UNIFIED IDEOGRAPH + 0xDD88: 0x8F2C, //CJK UNIFIED IDEOGRAPH + 0xDD89: 0x8F2D, //CJK UNIFIED IDEOGRAPH + 0xDD8A: 0x8F2E, //CJK UNIFIED IDEOGRAPH + 0xDD8B: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xDD8C: 0x8F30, //CJK UNIFIED IDEOGRAPH + 0xDD8D: 0x8F31, //CJK UNIFIED IDEOGRAPH + 0xDD8E: 0x8F32, //CJK UNIFIED IDEOGRAPH + 0xDD8F: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xDD90: 0x8F34, //CJK UNIFIED IDEOGRAPH + 0xDD91: 0x8F35, //CJK UNIFIED IDEOGRAPH + 0xDD92: 0x8F36, //CJK UNIFIED IDEOGRAPH + 0xDD93: 0x8F37, //CJK UNIFIED IDEOGRAPH + 0xDD94: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xDD95: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xDD96: 0x8F3A, //CJK UNIFIED IDEOGRAPH + 0xDD97: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xDD98: 0x8F3C, //CJK UNIFIED IDEOGRAPH + 0xDD99: 0x8F3D, //CJK UNIFIED IDEOGRAPH + 0xDD9A: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xDD9B: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xDD9C: 0x8F40, //CJK UNIFIED IDEOGRAPH + 0xDD9D: 0x8F41, //CJK UNIFIED IDEOGRAPH + 0xDD9E: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xDD9F: 0x8F43, //CJK UNIFIED IDEOGRAPH + 0xDDA0: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x8368, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x831B, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x8369, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x836C, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0x836A, //CJK UNIFIED IDEOGRAPH + 0xDDA6: 0x836D, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x836E, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x83B0, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x8378, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x83B3, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x83B4, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x839C, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x8385, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x83B6, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x837D, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x83B8, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x83BA, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x83BC, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x8401, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x83E5, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x5807, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x8418, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x83DD, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x841C, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x8411, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x8406, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x83D4, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x840F, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x83F8, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x83EA, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x83C0, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x8426, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0x83E1, //CJK UNIFIED IDEOGRAPH + 0xDDD6: 0x845C, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x8451, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x845A, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x8459, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x8473, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x8487, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x8488, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x8489, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x8478, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x8476, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x848C, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x848E, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x84E6, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x84BD, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x84D3, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x84BA, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x84E0, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xDDF5: 0x8497, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x84E5, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x84E3, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x850C, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x8538, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x84F0, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0x8539, //CJK UNIFIED IDEOGRAPH + 0xDDFD: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x853A, //CJK UNIFIED IDEOGRAPH + 0xDE40: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xDE41: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xDE42: 0x8F47, //CJK UNIFIED IDEOGRAPH + 0xDE43: 0x8F48, //CJK UNIFIED IDEOGRAPH + 0xDE44: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xDE45: 0x8F4A, //CJK UNIFIED IDEOGRAPH + 0xDE46: 0x8F4B, //CJK UNIFIED IDEOGRAPH + 0xDE47: 0x8F4C, //CJK UNIFIED IDEOGRAPH + 0xDE48: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xDE49: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xDE4A: 0x8F4F, //CJK UNIFIED IDEOGRAPH + 0xDE4B: 0x8F50, //CJK UNIFIED IDEOGRAPH + 0xDE4C: 0x8F51, //CJK UNIFIED IDEOGRAPH + 0xDE4D: 0x8F52, //CJK UNIFIED IDEOGRAPH + 0xDE4E: 0x8F53, //CJK UNIFIED IDEOGRAPH + 0xDE4F: 0x8F54, //CJK UNIFIED IDEOGRAPH + 0xDE50: 0x8F55, //CJK UNIFIED IDEOGRAPH + 0xDE51: 0x8F56, //CJK UNIFIED IDEOGRAPH + 0xDE52: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xDE53: 0x8F58, //CJK UNIFIED IDEOGRAPH + 0xDE54: 0x8F59, //CJK UNIFIED IDEOGRAPH + 0xDE55: 0x8F5A, //CJK UNIFIED IDEOGRAPH + 0xDE56: 0x8F5B, //CJK UNIFIED IDEOGRAPH + 0xDE57: 0x8F5C, //CJK UNIFIED IDEOGRAPH + 0xDE58: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xDE59: 0x8F5E, //CJK UNIFIED IDEOGRAPH + 0xDE5A: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xDE5B: 0x8F60, //CJK UNIFIED IDEOGRAPH + 0xDE5C: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0xDE5D: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xDE5E: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xDE5F: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xDE60: 0x8F65, //CJK UNIFIED IDEOGRAPH + 0xDE61: 0x8F6A, //CJK UNIFIED IDEOGRAPH + 0xDE62: 0x8F80, //CJK UNIFIED IDEOGRAPH + 0xDE63: 0x8F8C, //CJK UNIFIED IDEOGRAPH + 0xDE64: 0x8F92, //CJK UNIFIED IDEOGRAPH + 0xDE65: 0x8F9D, //CJK UNIFIED IDEOGRAPH + 0xDE66: 0x8FA0, //CJK UNIFIED IDEOGRAPH + 0xDE67: 0x8FA1, //CJK UNIFIED IDEOGRAPH + 0xDE68: 0x8FA2, //CJK UNIFIED IDEOGRAPH + 0xDE69: 0x8FA4, //CJK UNIFIED IDEOGRAPH + 0xDE6A: 0x8FA5, //CJK UNIFIED IDEOGRAPH + 0xDE6B: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xDE6C: 0x8FA7, //CJK UNIFIED IDEOGRAPH + 0xDE6D: 0x8FAA, //CJK UNIFIED IDEOGRAPH + 0xDE6E: 0x8FAC, //CJK UNIFIED IDEOGRAPH + 0xDE6F: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xDE70: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xDE71: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xDE72: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xDE73: 0x8FB3, //CJK UNIFIED IDEOGRAPH + 0xDE74: 0x8FB4, //CJK UNIFIED IDEOGRAPH + 0xDE75: 0x8FB5, //CJK UNIFIED IDEOGRAPH + 0xDE76: 0x8FB7, //CJK UNIFIED IDEOGRAPH + 0xDE77: 0x8FB8, //CJK UNIFIED IDEOGRAPH + 0xDE78: 0x8FBA, //CJK UNIFIED IDEOGRAPH + 0xDE79: 0x8FBB, //CJK UNIFIED IDEOGRAPH + 0xDE7A: 0x8FBC, //CJK UNIFIED IDEOGRAPH + 0xDE7B: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0xDE7C: 0x8FC0, //CJK UNIFIED IDEOGRAPH + 0xDE7D: 0x8FC3, //CJK UNIFIED IDEOGRAPH + 0xDE7E: 0x8FC6, //CJK UNIFIED IDEOGRAPH + 0xDE80: 0x8FC9, //CJK UNIFIED IDEOGRAPH + 0xDE81: 0x8FCA, //CJK UNIFIED IDEOGRAPH + 0xDE82: 0x8FCB, //CJK UNIFIED IDEOGRAPH + 0xDE83: 0x8FCC, //CJK UNIFIED IDEOGRAPH + 0xDE84: 0x8FCD, //CJK UNIFIED IDEOGRAPH + 0xDE85: 0x8FCF, //CJK UNIFIED IDEOGRAPH + 0xDE86: 0x8FD2, //CJK UNIFIED IDEOGRAPH + 0xDE87: 0x8FD6, //CJK UNIFIED IDEOGRAPH + 0xDE88: 0x8FD7, //CJK UNIFIED IDEOGRAPH + 0xDE89: 0x8FDA, //CJK UNIFIED IDEOGRAPH + 0xDE8A: 0x8FE0, //CJK UNIFIED IDEOGRAPH + 0xDE8B: 0x8FE1, //CJK UNIFIED IDEOGRAPH + 0xDE8C: 0x8FE3, //CJK UNIFIED IDEOGRAPH + 0xDE8D: 0x8FE7, //CJK UNIFIED IDEOGRAPH + 0xDE8E: 0x8FEC, //CJK UNIFIED IDEOGRAPH + 0xDE8F: 0x8FEF, //CJK UNIFIED IDEOGRAPH + 0xDE90: 0x8FF1, //CJK UNIFIED IDEOGRAPH + 0xDE91: 0x8FF2, //CJK UNIFIED IDEOGRAPH + 0xDE92: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xDE93: 0x8FF5, //CJK UNIFIED IDEOGRAPH + 0xDE94: 0x8FF6, //CJK UNIFIED IDEOGRAPH + 0xDE95: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xDE96: 0x8FFB, //CJK UNIFIED IDEOGRAPH + 0xDE97: 0x8FFC, //CJK UNIFIED IDEOGRAPH + 0xDE98: 0x8FFE, //CJK UNIFIED IDEOGRAPH + 0xDE99: 0x8FFF, //CJK UNIFIED IDEOGRAPH + 0xDE9A: 0x9007, //CJK UNIFIED IDEOGRAPH + 0xDE9B: 0x9008, //CJK UNIFIED IDEOGRAPH + 0xDE9C: 0x900C, //CJK UNIFIED IDEOGRAPH + 0xDE9D: 0x900E, //CJK UNIFIED IDEOGRAPH + 0xDE9E: 0x9013, //CJK UNIFIED IDEOGRAPH + 0xDE9F: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xDEA0: 0x9018, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x8556, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x853B, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x8564, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x855E, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x857A, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x77A2, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x8572, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x857B, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x8579, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x85AE, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x8585, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x85B7, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x85D3, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x8627, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x8605, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x8629, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x8616, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x863C, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x5F08, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x593C, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x5941, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x8037, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x5958, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x5C25, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x5C2C, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x5C34, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x624C, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x626A, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x629F, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x62DA, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x6322, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x6339, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x634B, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x6343, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x63AD, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x6371, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x638E, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x63B4, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x636D, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x638A, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x6369, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x63AE, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x63BC, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x63F2, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x63F8, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x63E0, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x63FF, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x63DE, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x63CE, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x6452, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x6445, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x6441, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x640B, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x641B, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x6420, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x640C, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x6426, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x6421, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x645E, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0x6484, //CJK UNIFIED IDEOGRAPH + 0xDEFD: 0x646D, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0x6496, //CJK UNIFIED IDEOGRAPH + 0xDF40: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xDF41: 0x901C, //CJK UNIFIED IDEOGRAPH + 0xDF42: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xDF43: 0x9024, //CJK UNIFIED IDEOGRAPH + 0xDF44: 0x9025, //CJK UNIFIED IDEOGRAPH + 0xDF45: 0x9027, //CJK UNIFIED IDEOGRAPH + 0xDF46: 0x9028, //CJK UNIFIED IDEOGRAPH + 0xDF47: 0x9029, //CJK UNIFIED IDEOGRAPH + 0xDF48: 0x902A, //CJK UNIFIED IDEOGRAPH + 0xDF49: 0x902B, //CJK UNIFIED IDEOGRAPH + 0xDF4A: 0x902C, //CJK UNIFIED IDEOGRAPH + 0xDF4B: 0x9030, //CJK UNIFIED IDEOGRAPH + 0xDF4C: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xDF4D: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xDF4E: 0x9033, //CJK UNIFIED IDEOGRAPH + 0xDF4F: 0x9034, //CJK UNIFIED IDEOGRAPH + 0xDF50: 0x9037, //CJK UNIFIED IDEOGRAPH + 0xDF51: 0x9039, //CJK UNIFIED IDEOGRAPH + 0xDF52: 0x903A, //CJK UNIFIED IDEOGRAPH + 0xDF53: 0x903D, //CJK UNIFIED IDEOGRAPH + 0xDF54: 0x903F, //CJK UNIFIED IDEOGRAPH + 0xDF55: 0x9040, //CJK UNIFIED IDEOGRAPH + 0xDF56: 0x9043, //CJK UNIFIED IDEOGRAPH + 0xDF57: 0x9045, //CJK UNIFIED IDEOGRAPH + 0xDF58: 0x9046, //CJK UNIFIED IDEOGRAPH + 0xDF59: 0x9048, //CJK UNIFIED IDEOGRAPH + 0xDF5A: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xDF5B: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xDF5C: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xDF5D: 0x904C, //CJK UNIFIED IDEOGRAPH + 0xDF5E: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xDF5F: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xDF60: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xDF61: 0x9056, //CJK UNIFIED IDEOGRAPH + 0xDF62: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xDF63: 0x905A, //CJK UNIFIED IDEOGRAPH + 0xDF64: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xDF65: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xDF66: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xDF67: 0x905F, //CJK UNIFIED IDEOGRAPH + 0xDF68: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xDF69: 0x9061, //CJK UNIFIED IDEOGRAPH + 0xDF6A: 0x9064, //CJK UNIFIED IDEOGRAPH + 0xDF6B: 0x9066, //CJK UNIFIED IDEOGRAPH + 0xDF6C: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xDF6D: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xDF6E: 0x906A, //CJK UNIFIED IDEOGRAPH + 0xDF6F: 0x906B, //CJK UNIFIED IDEOGRAPH + 0xDF70: 0x906C, //CJK UNIFIED IDEOGRAPH + 0xDF71: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xDF72: 0x9070, //CJK UNIFIED IDEOGRAPH + 0xDF73: 0x9071, //CJK UNIFIED IDEOGRAPH + 0xDF74: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xDF75: 0x9073, //CJK UNIFIED IDEOGRAPH + 0xDF76: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xDF77: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xDF78: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xDF79: 0x9079, //CJK UNIFIED IDEOGRAPH + 0xDF7A: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xDF7B: 0x907B, //CJK UNIFIED IDEOGRAPH + 0xDF7C: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xDF7D: 0x907E, //CJK UNIFIED IDEOGRAPH + 0xDF7E: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xDF80: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xDF81: 0x9085, //CJK UNIFIED IDEOGRAPH + 0xDF82: 0x9086, //CJK UNIFIED IDEOGRAPH + 0xDF83: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xDF84: 0x9089, //CJK UNIFIED IDEOGRAPH + 0xDF85: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xDF86: 0x908C, //CJK UNIFIED IDEOGRAPH + 0xDF87: 0x908D, //CJK UNIFIED IDEOGRAPH + 0xDF88: 0x908E, //CJK UNIFIED IDEOGRAPH + 0xDF89: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xDF8A: 0x9090, //CJK UNIFIED IDEOGRAPH + 0xDF8B: 0x9092, //CJK UNIFIED IDEOGRAPH + 0xDF8C: 0x9094, //CJK UNIFIED IDEOGRAPH + 0xDF8D: 0x9096, //CJK UNIFIED IDEOGRAPH + 0xDF8E: 0x9098, //CJK UNIFIED IDEOGRAPH + 0xDF8F: 0x909A, //CJK UNIFIED IDEOGRAPH + 0xDF90: 0x909C, //CJK UNIFIED IDEOGRAPH + 0xDF91: 0x909E, //CJK UNIFIED IDEOGRAPH + 0xDF92: 0x909F, //CJK UNIFIED IDEOGRAPH + 0xDF93: 0x90A0, //CJK UNIFIED IDEOGRAPH + 0xDF94: 0x90A4, //CJK UNIFIED IDEOGRAPH + 0xDF95: 0x90A5, //CJK UNIFIED IDEOGRAPH + 0xDF96: 0x90A7, //CJK UNIFIED IDEOGRAPH + 0xDF97: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xDF98: 0x90A9, //CJK UNIFIED IDEOGRAPH + 0xDF99: 0x90AB, //CJK UNIFIED IDEOGRAPH + 0xDF9A: 0x90AD, //CJK UNIFIED IDEOGRAPH + 0xDF9B: 0x90B2, //CJK UNIFIED IDEOGRAPH + 0xDF9C: 0x90B7, //CJK UNIFIED IDEOGRAPH + 0xDF9D: 0x90BC, //CJK UNIFIED IDEOGRAPH + 0xDF9E: 0x90BD, //CJK UNIFIED IDEOGRAPH + 0xDF9F: 0x90BF, //CJK UNIFIED IDEOGRAPH + 0xDFA0: 0x90C0, //CJK UNIFIED IDEOGRAPH + 0xDFA1: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x64B7, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x64B8, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x6499, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x64BA, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x64C0, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x64D0, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x64D7, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x64E4, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x6509, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x6525, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x652E, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x5FD2, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x7519, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x535F, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xDFB4: 0x53FD, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x53FB, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x5412, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x5416, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x5406, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x544B, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x5452, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x5453, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x5454, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x5456, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x5443, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x5421, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x5457, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x5459, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x5423, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x5432, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x5482, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x5494, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x5477, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x5464, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x549A, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x549B, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x5484, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x5476, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x5466, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x549D, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x54D0, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x54AD, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x54B4, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x54D2, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x54A7, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x54A6, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x54D3, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x54D4, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x5472, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x54A3, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x54D5, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x54BB, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x54BF, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x54CC, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x54D9, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0x54DA, //CJK UNIFIED IDEOGRAPH + 0xDFE2: 0x54DC, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x54AA, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x54DD, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x54CF, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0x54DE, //CJK UNIFIED IDEOGRAPH + 0xDFE9: 0x551B, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x54E7, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x5520, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x5514, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x54F3, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x5522, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x5523, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x550F, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x5511, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x5527, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x552A, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x5567, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x558F, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x55B5, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x5549, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x556D, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x5541, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x5555, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x553F, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x5550, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x553C, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x90C2, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x90C3, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x90C6, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x90C8, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x90C9, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x90CB, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x90CC, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x90CD, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x90D2, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x90D4, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x90D5, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x90D6, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x90D8, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x90D9, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x90DA, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x90DF, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x90E0, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x90E3, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x90E5, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x90E9, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x90EA, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x90EC, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x90EE, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x90F0, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x90F1, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x90F2, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x90F3, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x90F6, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x90F7, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x90F9, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x90FA, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x90FB, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x90FC, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x90FF, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x9100, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x9101, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x9103, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x9105, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x9106, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x9107, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x9108, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x9109, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x910A, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x910B, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x910C, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x910D, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x910E, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x910F, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x9110, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x9111, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x9113, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x9114, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x9116, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x9117, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x9118, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x911A, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x911B, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x911C, //CJK UNIFIED IDEOGRAPH + 0xE080: 0x911D, //CJK UNIFIED IDEOGRAPH + 0xE081: 0x911F, //CJK UNIFIED IDEOGRAPH + 0xE082: 0x9120, //CJK UNIFIED IDEOGRAPH + 0xE083: 0x9121, //CJK UNIFIED IDEOGRAPH + 0xE084: 0x9124, //CJK UNIFIED IDEOGRAPH + 0xE085: 0x9125, //CJK UNIFIED IDEOGRAPH + 0xE086: 0x9126, //CJK UNIFIED IDEOGRAPH + 0xE087: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xE088: 0x9128, //CJK UNIFIED IDEOGRAPH + 0xE089: 0x9129, //CJK UNIFIED IDEOGRAPH + 0xE08A: 0x912A, //CJK UNIFIED IDEOGRAPH + 0xE08B: 0x912B, //CJK UNIFIED IDEOGRAPH + 0xE08C: 0x912C, //CJK UNIFIED IDEOGRAPH + 0xE08D: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xE08E: 0x912E, //CJK UNIFIED IDEOGRAPH + 0xE08F: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xE090: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE091: 0x9133, //CJK UNIFIED IDEOGRAPH + 0xE092: 0x9134, //CJK UNIFIED IDEOGRAPH + 0xE093: 0x9135, //CJK UNIFIED IDEOGRAPH + 0xE094: 0x9136, //CJK UNIFIED IDEOGRAPH + 0xE095: 0x9137, //CJK UNIFIED IDEOGRAPH + 0xE096: 0x9138, //CJK UNIFIED IDEOGRAPH + 0xE097: 0x913A, //CJK UNIFIED IDEOGRAPH + 0xE098: 0x913B, //CJK UNIFIED IDEOGRAPH + 0xE099: 0x913C, //CJK UNIFIED IDEOGRAPH + 0xE09A: 0x913D, //CJK UNIFIED IDEOGRAPH + 0xE09B: 0x913E, //CJK UNIFIED IDEOGRAPH + 0xE09C: 0x913F, //CJK UNIFIED IDEOGRAPH + 0xE09D: 0x9140, //CJK UNIFIED IDEOGRAPH + 0xE09E: 0x9141, //CJK UNIFIED IDEOGRAPH + 0xE09F: 0x9142, //CJK UNIFIED IDEOGRAPH + 0xE0A0: 0x9144, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x5537, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x5575, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x5576, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x5577, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x5533, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x5530, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x555C, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x558B, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x55D2, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x5583, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x55B1, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x55B9, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x5588, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x5581, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x559F, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x557E, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x55D6, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x5591, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x557B, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x55BD, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x55BE, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x5594, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x55EA, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x55C9, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x561F, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x55D1, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x55EB, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x55EC, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x55E6, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x55DD, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x55EF, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x55E5, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x55F2, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x55F3, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x55CC, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x55CD, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x55E8, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x55F5, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x8F94, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x561E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x5608, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x560C, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x5601, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x5624, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x5623, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x5600, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x5627, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x562D, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x5658, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x5639, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x5657, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x562C, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x564D, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x5662, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x5659, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x565C, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x564C, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x5654, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x5664, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x5671, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x567B, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x567C, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x5685, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x5693, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x56AF, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x56D4, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x56DD, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x56E1, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x56F5, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x56EB, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x570A, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x5709, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x571C, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x5E0F, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x5E14, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x5E31, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x5E3B, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x5E3C, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x9145, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x9147, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x9148, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x9151, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x9153, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x9154, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x9155, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x9159, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x915B, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x915C, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x915F, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x9160, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x9166, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x9167, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x9168, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x916B, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x916D, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x917A, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x917B, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x917C, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x9180, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x9181, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x9183, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x9184, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x9186, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x9188, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x918A, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x918E, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x918F, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x9193, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x9194, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x9195, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x9196, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x9197, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x9198, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x9199, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x919D, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x919E, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x919F, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x91A0, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x91A1, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x91A4, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x91A5, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x91A6, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x91A7, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x91A8, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x91A9, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x91B0, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x91B2, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x91B3, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x91B6, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x91B7, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x91B8, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x91B9, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x91BB, //CJK UNIFIED IDEOGRAPH + 0xE180: 0x91BC, //CJK UNIFIED IDEOGRAPH + 0xE181: 0x91BD, //CJK UNIFIED IDEOGRAPH + 0xE182: 0x91BE, //CJK UNIFIED IDEOGRAPH + 0xE183: 0x91BF, //CJK UNIFIED IDEOGRAPH + 0xE184: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE185: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xE186: 0x91C2, //CJK UNIFIED IDEOGRAPH + 0xE187: 0x91C3, //CJK UNIFIED IDEOGRAPH + 0xE188: 0x91C4, //CJK UNIFIED IDEOGRAPH + 0xE189: 0x91C5, //CJK UNIFIED IDEOGRAPH + 0xE18A: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0xE18B: 0x91C8, //CJK UNIFIED IDEOGRAPH + 0xE18C: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE18D: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xE18E: 0x91D2, //CJK UNIFIED IDEOGRAPH + 0xE18F: 0x91D3, //CJK UNIFIED IDEOGRAPH + 0xE190: 0x91D4, //CJK UNIFIED IDEOGRAPH + 0xE191: 0x91D5, //CJK UNIFIED IDEOGRAPH + 0xE192: 0x91D6, //CJK UNIFIED IDEOGRAPH + 0xE193: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xE194: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xE195: 0x91D9, //CJK UNIFIED IDEOGRAPH + 0xE196: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xE197: 0x91DB, //CJK UNIFIED IDEOGRAPH + 0xE198: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xE199: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xE19A: 0x91DF, //CJK UNIFIED IDEOGRAPH + 0xE19B: 0x91E0, //CJK UNIFIED IDEOGRAPH + 0xE19C: 0x91E1, //CJK UNIFIED IDEOGRAPH + 0xE19D: 0x91E2, //CJK UNIFIED IDEOGRAPH + 0xE19E: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xE19F: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xE1A0: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x5E5B, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x5E5E, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x5C7A, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x5C8D, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x5C96, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x5C88, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x5C98, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x5C99, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x5C9A, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5C9C, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5CA2, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5CBD, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x5CA3, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x5CC1, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x5CC4, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x5CD2, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x5CE4, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x5CCB, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x5CE5, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x5D02, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x5D03, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x5D26, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x5D2E, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x5D24, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x5D1E, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x5D06, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x5D58, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x5D3E, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x5D34, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x5D3D, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x5D5B, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x5D5D, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x5D6B, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x5D4A, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x5D74, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x5D99, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x8C73, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x5DC5, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x5F89, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x5F95, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x5F9C, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x5F61, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x72AD, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x72B0, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x72B4, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x72B7, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x72B8, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x72C1, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x72CD, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x72E8, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x72EF, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x72F2, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x72F4, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x7301, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x72F3, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x7303, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x72FA, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x91E8, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x91E9, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x91EB, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x91EC, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x91EF, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x91F0, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x91F1, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x91F2, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x91F3, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x91F4, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x91F6, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x91F7, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x91F8, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x91F9, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x91FA, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x91FB, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x91FC, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x91FD, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x91FE, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x9200, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x9201, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x9202, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x9203, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x9204, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x9205, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x9207, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x9208, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x9209, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x920B, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x920C, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x920E, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x920F, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x9213, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x9216, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x9218, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x9219, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x921A, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x921B, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x921C, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x921D, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x921F, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x9220, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x9221, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x9222, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x9223, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x9224, //CJK UNIFIED IDEOGRAPH + 0xE280: 0x9225, //CJK UNIFIED IDEOGRAPH + 0xE281: 0x9226, //CJK UNIFIED IDEOGRAPH + 0xE282: 0x9227, //CJK UNIFIED IDEOGRAPH + 0xE283: 0x9228, //CJK UNIFIED IDEOGRAPH + 0xE284: 0x9229, //CJK UNIFIED IDEOGRAPH + 0xE285: 0x922A, //CJK UNIFIED IDEOGRAPH + 0xE286: 0x922B, //CJK UNIFIED IDEOGRAPH + 0xE287: 0x922C, //CJK UNIFIED IDEOGRAPH + 0xE288: 0x922D, //CJK UNIFIED IDEOGRAPH + 0xE289: 0x922E, //CJK UNIFIED IDEOGRAPH + 0xE28A: 0x922F, //CJK UNIFIED IDEOGRAPH + 0xE28B: 0x9230, //CJK UNIFIED IDEOGRAPH + 0xE28C: 0x9231, //CJK UNIFIED IDEOGRAPH + 0xE28D: 0x9232, //CJK UNIFIED IDEOGRAPH + 0xE28E: 0x9233, //CJK UNIFIED IDEOGRAPH + 0xE28F: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xE290: 0x9235, //CJK UNIFIED IDEOGRAPH + 0xE291: 0x9236, //CJK UNIFIED IDEOGRAPH + 0xE292: 0x9237, //CJK UNIFIED IDEOGRAPH + 0xE293: 0x9238, //CJK UNIFIED IDEOGRAPH + 0xE294: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xE295: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE296: 0x923B, //CJK UNIFIED IDEOGRAPH + 0xE297: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xE298: 0x923D, //CJK UNIFIED IDEOGRAPH + 0xE299: 0x923E, //CJK UNIFIED IDEOGRAPH + 0xE29A: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xE29B: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xE29C: 0x9241, //CJK UNIFIED IDEOGRAPH + 0xE29D: 0x9242, //CJK UNIFIED IDEOGRAPH + 0xE29E: 0x9243, //CJK UNIFIED IDEOGRAPH + 0xE29F: 0x9244, //CJK UNIFIED IDEOGRAPH + 0xE2A0: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x72FB, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x7313, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x7321, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x731E, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x7315, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x7322, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x7339, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x732C, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x7338, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7331, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x734D, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7360, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x736C, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x736F, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x737E, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x5925, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x98E7, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x5924, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x5902, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x9963, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x9967, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x9968, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x9969, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x996A, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x996B, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x996C, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x9974, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x9977, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x997D, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x9980, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x9984, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x9987, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x998A, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x998D, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x9990, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x9991, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x9993, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x9994, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x9995, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x5E80, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x5E91, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x5E8B, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x5EA5, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x5EB9, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x5EB3, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x8D53, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x5ED2, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x5ED1, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x5EEA, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x5FC4, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x5FC9, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x5FCF, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x6003, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x5FEE, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x6004, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x5FE1, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x5FFE, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x6005, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x6006, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x5FEA, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x5FED, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x6019, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x6035, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x6026, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x601B, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x600D, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x6029, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x602B, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x600A, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x603F, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x6078, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x6079, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x607B, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x607A, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x9246, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x9247, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x924A, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x924C, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x924D, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x924F, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x9252, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x9253, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x9254, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x9255, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x9256, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x9258, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x925C, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x925D, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x925F, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x9260, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x9261, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x9262, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x9263, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x9268, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x9269, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x926A, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x926B, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x926C, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x926D, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x926E, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x926F, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x9270, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x9271, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x9272, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x9273, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x9275, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x9276, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x9279, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x927A, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x927B, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x927C, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x927D, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x927E, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x927F, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x9281, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x9282, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x9284, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xE380: 0x9286, //CJK UNIFIED IDEOGRAPH + 0xE381: 0x9287, //CJK UNIFIED IDEOGRAPH + 0xE382: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xE383: 0x9289, //CJK UNIFIED IDEOGRAPH + 0xE384: 0x928A, //CJK UNIFIED IDEOGRAPH + 0xE385: 0x928B, //CJK UNIFIED IDEOGRAPH + 0xE386: 0x928C, //CJK UNIFIED IDEOGRAPH + 0xE387: 0x928D, //CJK UNIFIED IDEOGRAPH + 0xE388: 0x928F, //CJK UNIFIED IDEOGRAPH + 0xE389: 0x9290, //CJK UNIFIED IDEOGRAPH + 0xE38A: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xE38B: 0x9292, //CJK UNIFIED IDEOGRAPH + 0xE38C: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xE38D: 0x9294, //CJK UNIFIED IDEOGRAPH + 0xE38E: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE38F: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE390: 0x9297, //CJK UNIFIED IDEOGRAPH + 0xE391: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xE392: 0x9299, //CJK UNIFIED IDEOGRAPH + 0xE393: 0x929A, //CJK UNIFIED IDEOGRAPH + 0xE394: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE395: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xE396: 0x929D, //CJK UNIFIED IDEOGRAPH + 0xE397: 0x929E, //CJK UNIFIED IDEOGRAPH + 0xE398: 0x929F, //CJK UNIFIED IDEOGRAPH + 0xE399: 0x92A0, //CJK UNIFIED IDEOGRAPH + 0xE39A: 0x92A1, //CJK UNIFIED IDEOGRAPH + 0xE39B: 0x92A2, //CJK UNIFIED IDEOGRAPH + 0xE39C: 0x92A3, //CJK UNIFIED IDEOGRAPH + 0xE39D: 0x92A4, //CJK UNIFIED IDEOGRAPH + 0xE39E: 0x92A5, //CJK UNIFIED IDEOGRAPH + 0xE39F: 0x92A6, //CJK UNIFIED IDEOGRAPH + 0xE3A0: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x607D, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x60AD, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x609D, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x6083, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x6092, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x60EC, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x60BB, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x60B1, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x60DD, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x6126, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x6123, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x6100, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x612B, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x6175, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x61B7, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x61D4, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x61F5, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x96B3, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x95E9, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x95EB, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x95F1, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x95F3, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x95F5, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x95F6, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x95FC, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x95FE, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x9603, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x9604, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x9606, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x9608, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x960A, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x960B, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x960C, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x960D, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x960F, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x9612, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x9615, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x9616, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x9617, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x9619, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x961A, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x4E2C, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x6215, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x6C35, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x6C54, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x6C4A, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x6CA3, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x6C69, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x6C74, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x6CA9, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x6CD0, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x6CD4, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x6CAD, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x6CF7, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x6CF8, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x6CB2, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x6CE0, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x6CD6, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x6CFA, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x6CFE, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x92A8, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x92A9, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x92AA, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x92AB, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x92AC, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x92AD, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x92AF, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x92B0, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x92B1, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x92B2, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x92B4, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x92B5, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x92B8, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x92BA, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x92BB, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x92BC, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x92BD, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x92BE, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x92BF, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x92C0, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x92C1, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x92C2, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x92C3, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x92C4, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x92C5, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x92C6, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x92C7, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x92C9, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x92CA, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x92CB, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x92CD, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x92CE, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x92D1, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x92D4, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x92D6, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x92D8, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x92DA, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x92DB, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x92DC, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x92DD, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x92DE, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x92DF, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x92E1, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x92E2, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x92E3, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x92E5, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x92E6, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x92E8, //CJK UNIFIED IDEOGRAPH + 0xE480: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE481: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xE482: 0x92EB, //CJK UNIFIED IDEOGRAPH + 0xE483: 0x92EC, //CJK UNIFIED IDEOGRAPH + 0xE484: 0x92ED, //CJK UNIFIED IDEOGRAPH + 0xE485: 0x92EE, //CJK UNIFIED IDEOGRAPH + 0xE486: 0x92EF, //CJK UNIFIED IDEOGRAPH + 0xE487: 0x92F0, //CJK UNIFIED IDEOGRAPH + 0xE488: 0x92F1, //CJK UNIFIED IDEOGRAPH + 0xE489: 0x92F2, //CJK UNIFIED IDEOGRAPH + 0xE48A: 0x92F3, //CJK UNIFIED IDEOGRAPH + 0xE48B: 0x92F4, //CJK UNIFIED IDEOGRAPH + 0xE48C: 0x92F5, //CJK UNIFIED IDEOGRAPH + 0xE48D: 0x92F6, //CJK UNIFIED IDEOGRAPH + 0xE48E: 0x92F7, //CJK UNIFIED IDEOGRAPH + 0xE48F: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xE490: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xE491: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xE492: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xE493: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xE494: 0x92FD, //CJK UNIFIED IDEOGRAPH + 0xE495: 0x92FE, //CJK UNIFIED IDEOGRAPH + 0xE496: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xE497: 0x9300, //CJK UNIFIED IDEOGRAPH + 0xE498: 0x9301, //CJK UNIFIED IDEOGRAPH + 0xE499: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xE49A: 0x9303, //CJK UNIFIED IDEOGRAPH + 0xE49B: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xE49C: 0x9305, //CJK UNIFIED IDEOGRAPH + 0xE49D: 0x9306, //CJK UNIFIED IDEOGRAPH + 0xE49E: 0x9307, //CJK UNIFIED IDEOGRAPH + 0xE49F: 0x9308, //CJK UNIFIED IDEOGRAPH + 0xE4A0: 0x9309, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x6D43, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x6D48, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x6D07, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x6D0E, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x6D4D, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x6D2E, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x6D1A, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x6D4F, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x6D52, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x6D54, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x6D9E, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x6DA0, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x6D5E, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x6D94, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x6D60, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x6D7C, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x6E0E, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x6DBF, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x6DE0, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x6E11, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x6DDD, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x6E16, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x6DAB, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x6E0C, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x6DAE, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x6E86, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x6E53, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x6E54, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x6EDF, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x6EE0, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x6F2D, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x6EE2, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x6EA7, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x6EBB, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x6ED7, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x6EB4, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x6ECF, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x6F46, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x6F47, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x6F24, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x6EF9, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x6F2F, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x6F36, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x6F4B, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x6F74, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x6F2A, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x6F29, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x6F89, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x6F8C, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x6F72, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x6FD1, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x930A, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x930B, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x930C, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x930D, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x930E, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x9311, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x9312, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x9313, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x9314, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x9315, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x9316, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x9317, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x931B, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x931C, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x9327, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x9329, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x932A, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x932C, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x932D, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x9330, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x9331, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x9332, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x9333, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x9334, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x9336, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x9337, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x9338, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x9339, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x933A, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x933B, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x933C, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x933D, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x933F, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x9340, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x9341, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x9342, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x9343, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x9344, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x9345, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x9346, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x9347, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x9349, //CJK UNIFIED IDEOGRAPH + 0xE580: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xE581: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xE582: 0x934C, //CJK UNIFIED IDEOGRAPH + 0xE583: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xE584: 0x934E, //CJK UNIFIED IDEOGRAPH + 0xE585: 0x934F, //CJK UNIFIED IDEOGRAPH + 0xE586: 0x9350, //CJK UNIFIED IDEOGRAPH + 0xE587: 0x9351, //CJK UNIFIED IDEOGRAPH + 0xE588: 0x9352, //CJK UNIFIED IDEOGRAPH + 0xE589: 0x9353, //CJK UNIFIED IDEOGRAPH + 0xE58A: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xE58B: 0x9355, //CJK UNIFIED IDEOGRAPH + 0xE58C: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xE58D: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xE58E: 0x9358, //CJK UNIFIED IDEOGRAPH + 0xE58F: 0x9359, //CJK UNIFIED IDEOGRAPH + 0xE590: 0x935A, //CJK UNIFIED IDEOGRAPH + 0xE591: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xE592: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xE593: 0x935D, //CJK UNIFIED IDEOGRAPH + 0xE594: 0x935E, //CJK UNIFIED IDEOGRAPH + 0xE595: 0x935F, //CJK UNIFIED IDEOGRAPH + 0xE596: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xE597: 0x9361, //CJK UNIFIED IDEOGRAPH + 0xE598: 0x9362, //CJK UNIFIED IDEOGRAPH + 0xE599: 0x9363, //CJK UNIFIED IDEOGRAPH + 0xE59A: 0x9364, //CJK UNIFIED IDEOGRAPH + 0xE59B: 0x9365, //CJK UNIFIED IDEOGRAPH + 0xE59C: 0x9366, //CJK UNIFIED IDEOGRAPH + 0xE59D: 0x9367, //CJK UNIFIED IDEOGRAPH + 0xE59E: 0x9368, //CJK UNIFIED IDEOGRAPH + 0xE59F: 0x9369, //CJK UNIFIED IDEOGRAPH + 0xE5A0: 0x936B, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x6FC9, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x6FB6, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x6FDE, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x7039, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x7035, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x704F, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x705E, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x5B80, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x5B84, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x9A9E, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x6434, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x8930, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x8FB6, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x8FD3, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x8FD5, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x8FEE, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x8FE4, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x8FE9, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x8FF3, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x8FE8, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x9004, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x9026, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x902D, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x902F, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x9044, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x9062, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x905B, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x9074, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x908B, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x5F50, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x5F58, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x5C59, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x5C63, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x5C66, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x7FBC, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x5F2A, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x8274, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x5981, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x598D, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x59A9, //CJK UNIFIED IDEOGRAPH + 0xE5FD: 0x59AA, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x936C, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x936D, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x936F, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x9371, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x9372, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x9373, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x9374, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x9376, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x9377, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x9378, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x9379, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x937A, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x937B, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x937D, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x937F, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x9380, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x9381, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x9382, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x9383, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x9384, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x9385, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x9386, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x9387, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x9388, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x9389, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x938A, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x938B, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x938D, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x938E, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x9390, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x9391, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x9392, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x9393, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x9395, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x9397, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x9398, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x9399, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x939B, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x939C, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x939D, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x939E, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x939F, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x93A0, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x93A1, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x93A2, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x93A5, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x93A6, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x93A8, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x93A9, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x93AA, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x93AB, //CJK UNIFIED IDEOGRAPH + 0xE680: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xE681: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xE682: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0xE683: 0x93AF, //CJK UNIFIED IDEOGRAPH + 0xE684: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xE685: 0x93B1, //CJK UNIFIED IDEOGRAPH + 0xE686: 0x93B2, //CJK UNIFIED IDEOGRAPH + 0xE687: 0x93B3, //CJK UNIFIED IDEOGRAPH + 0xE688: 0x93B4, //CJK UNIFIED IDEOGRAPH + 0xE689: 0x93B5, //CJK UNIFIED IDEOGRAPH + 0xE68A: 0x93B6, //CJK UNIFIED IDEOGRAPH + 0xE68B: 0x93B7, //CJK UNIFIED IDEOGRAPH + 0xE68C: 0x93B8, //CJK UNIFIED IDEOGRAPH + 0xE68D: 0x93B9, //CJK UNIFIED IDEOGRAPH + 0xE68E: 0x93BA, //CJK UNIFIED IDEOGRAPH + 0xE68F: 0x93BB, //CJK UNIFIED IDEOGRAPH + 0xE690: 0x93BC, //CJK UNIFIED IDEOGRAPH + 0xE691: 0x93BD, //CJK UNIFIED IDEOGRAPH + 0xE692: 0x93BE, //CJK UNIFIED IDEOGRAPH + 0xE693: 0x93BF, //CJK UNIFIED IDEOGRAPH + 0xE694: 0x93C0, //CJK UNIFIED IDEOGRAPH + 0xE695: 0x93C1, //CJK UNIFIED IDEOGRAPH + 0xE696: 0x93C2, //CJK UNIFIED IDEOGRAPH + 0xE697: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xE698: 0x93C4, //CJK UNIFIED IDEOGRAPH + 0xE699: 0x93C5, //CJK UNIFIED IDEOGRAPH + 0xE69A: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xE69B: 0x93C7, //CJK UNIFIED IDEOGRAPH + 0xE69C: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xE69D: 0x93C9, //CJK UNIFIED IDEOGRAPH + 0xE69E: 0x93CB, //CJK UNIFIED IDEOGRAPH + 0xE69F: 0x93CC, //CJK UNIFIED IDEOGRAPH + 0xE6A0: 0x93CD, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x59CA, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x59AB, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x599E, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x59D2, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x59AF, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x59D7, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x5A05, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x5A06, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x5A08, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x59E3, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x59D8, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x59F9, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x5A0C, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x5A32, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x5A34, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x5A23, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x5A13, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x5A67, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x5A4A, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x5A55, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x5A75, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x80EC, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x5AAA, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x5A77, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x5A7A, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x5AEB, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x5AB2, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x5AD2, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x5AD4, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x5AB8, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x5AE0, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x5AF1, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x5AD8, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x5ADC, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x5B17, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x5B37, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x5C15, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x5C1C, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x5B53, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x5B62, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x9A75, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x9A77, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x9A78, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x9A7A, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x9A7F, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x9A7D, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x9A80, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x9A81, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x9A85, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x9A88, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x9A8A, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x9A90, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x9A92, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x9A93, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x9A96, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x9A98, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x9A9B, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x9A9C, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x9A9D, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x9A9F, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x9AA0, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x9AA2, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x9AA3, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x9AA5, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x9AA7, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x7E9F, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x7EA1, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x7EA3, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x7EA5, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x7EA8, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x7EA9, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x93CE, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x93CF, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x93D2, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x93D3, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x93D4, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x93D5, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x93D9, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x93DA, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x93DB, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x93DC, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x93DF, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x93E0, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x93E2, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x93E3, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x93E5, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x93E6, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x93E7, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x93E9, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x93EA, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x93EB, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x93EC, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x93ED, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x93EE, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x93EF, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x93F0, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x93F1, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x93F2, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x93F3, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x93F4, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x93F5, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x93F7, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x93F9, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x93FA, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x93FB, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x93FC, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x93FD, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x93FE, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x93FF, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x9400, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x9401, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x9402, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x9404, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x9405, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x9406, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x9408, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x9409, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x940A, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x940B, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x940C, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x940D, //CJK UNIFIED IDEOGRAPH + 0xE780: 0x940E, //CJK UNIFIED IDEOGRAPH + 0xE781: 0x940F, //CJK UNIFIED IDEOGRAPH + 0xE782: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xE783: 0x9411, //CJK UNIFIED IDEOGRAPH + 0xE784: 0x9412, //CJK UNIFIED IDEOGRAPH + 0xE785: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xE786: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xE787: 0x9415, //CJK UNIFIED IDEOGRAPH + 0xE788: 0x9416, //CJK UNIFIED IDEOGRAPH + 0xE789: 0x9417, //CJK UNIFIED IDEOGRAPH + 0xE78A: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xE78B: 0x9419, //CJK UNIFIED IDEOGRAPH + 0xE78C: 0x941A, //CJK UNIFIED IDEOGRAPH + 0xE78D: 0x941B, //CJK UNIFIED IDEOGRAPH + 0xE78E: 0x941C, //CJK UNIFIED IDEOGRAPH + 0xE78F: 0x941D, //CJK UNIFIED IDEOGRAPH + 0xE790: 0x941E, //CJK UNIFIED IDEOGRAPH + 0xE791: 0x941F, //CJK UNIFIED IDEOGRAPH + 0xE792: 0x9420, //CJK UNIFIED IDEOGRAPH + 0xE793: 0x9421, //CJK UNIFIED IDEOGRAPH + 0xE794: 0x9422, //CJK UNIFIED IDEOGRAPH + 0xE795: 0x9423, //CJK UNIFIED IDEOGRAPH + 0xE796: 0x9424, //CJK UNIFIED IDEOGRAPH + 0xE797: 0x9425, //CJK UNIFIED IDEOGRAPH + 0xE798: 0x9426, //CJK UNIFIED IDEOGRAPH + 0xE799: 0x9427, //CJK UNIFIED IDEOGRAPH + 0xE79A: 0x9428, //CJK UNIFIED IDEOGRAPH + 0xE79B: 0x9429, //CJK UNIFIED IDEOGRAPH + 0xE79C: 0x942A, //CJK UNIFIED IDEOGRAPH + 0xE79D: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xE79E: 0x942C, //CJK UNIFIED IDEOGRAPH + 0xE79F: 0x942D, //CJK UNIFIED IDEOGRAPH + 0xE7A0: 0x942E, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x7EAD, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x7EB0, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x7EBE, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x7EC0, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x7EC1, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x7EC2, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x7EC9, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x7ECB, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x7ECC, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x7ED0, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x7ED4, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x7ED7, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x7EDB, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x7EE0, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x7EE1, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x7EE8, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x7EEB, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x7EEE, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x7EEF, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x7EF1, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x7EF2, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x7F0D, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x7EF6, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x7EFA, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x7EFB, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x7EFE, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x7F01, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x7F02, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x7F03, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x7F07, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x7F08, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x7F0B, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x7F0C, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x7F0F, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x7F11, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x7F12, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x7F17, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x7F19, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x7F1C, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x7F1B, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x7F1F, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x7F21, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x7F22, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x7F23, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x7F24, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x7F25, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x7F26, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x7F27, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x7F2A, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x7F2B, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x7F2C, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x7F2D, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x7F2F, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x7F30, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x7F31, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x7F32, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x7F33, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x7F35, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x5E7A, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x5DDB, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x753E, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x7391, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x73AE, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x73A2, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x73CF, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x73D1, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x73B7, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x987C, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x740A, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x73E7, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x73BA, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x73F2, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x740F, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x942F, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x9430, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x9432, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x9433, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x9434, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x9437, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x9439, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x943B, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x943C, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x943D, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x943F, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x9440, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x9441, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x9442, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x9443, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x9446, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x9447, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x9449, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x944A, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x944B, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x944C, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x944D, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x944E, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x944F, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9450, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x9453, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x9454, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x9455, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x9456, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x9457, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x9458, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x9459, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x945A, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x945C, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x945D, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x945F, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x9461, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x9463, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x9464, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x9465, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x9466, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x9467, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x9468, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x9469, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x946C, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x946D, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x946E, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x946F, //CJK UNIFIED IDEOGRAPH + 0xE880: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xE881: 0x9471, //CJK UNIFIED IDEOGRAPH + 0xE882: 0x9472, //CJK UNIFIED IDEOGRAPH + 0xE883: 0x9473, //CJK UNIFIED IDEOGRAPH + 0xE884: 0x9474, //CJK UNIFIED IDEOGRAPH + 0xE885: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xE886: 0x9476, //CJK UNIFIED IDEOGRAPH + 0xE887: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xE888: 0x9478, //CJK UNIFIED IDEOGRAPH + 0xE889: 0x9479, //CJK UNIFIED IDEOGRAPH + 0xE88A: 0x947A, //CJK UNIFIED IDEOGRAPH + 0xE88B: 0x947B, //CJK UNIFIED IDEOGRAPH + 0xE88C: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xE88D: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xE88E: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xE88F: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xE890: 0x9480, //CJK UNIFIED IDEOGRAPH + 0xE891: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xE892: 0x9482, //CJK UNIFIED IDEOGRAPH + 0xE893: 0x9483, //CJK UNIFIED IDEOGRAPH + 0xE894: 0x9484, //CJK UNIFIED IDEOGRAPH + 0xE895: 0x9491, //CJK UNIFIED IDEOGRAPH + 0xE896: 0x9496, //CJK UNIFIED IDEOGRAPH + 0xE897: 0x9498, //CJK UNIFIED IDEOGRAPH + 0xE898: 0x94C7, //CJK UNIFIED IDEOGRAPH + 0xE899: 0x94CF, //CJK UNIFIED IDEOGRAPH + 0xE89A: 0x94D3, //CJK UNIFIED IDEOGRAPH + 0xE89B: 0x94D4, //CJK UNIFIED IDEOGRAPH + 0xE89C: 0x94DA, //CJK UNIFIED IDEOGRAPH + 0xE89D: 0x94E6, //CJK UNIFIED IDEOGRAPH + 0xE89E: 0x94FB, //CJK UNIFIED IDEOGRAPH + 0xE89F: 0x951C, //CJK UNIFIED IDEOGRAPH + 0xE8A0: 0x9520, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x741A, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x7477, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x746D, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x748E, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x7480, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x7481, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x74A9, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x7490, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x74D2, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x74BA, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x97EA, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x97EB, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x97EC, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x674C, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x6748, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x6769, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x67A5, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x676A, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x6798, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x67A7, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x67A8, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x679E, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x67AD, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x677C, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x6809, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x680A, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x680C, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x67D9, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x67B5, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x6800, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x67C3, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x680E, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x67FD, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x6832, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x6833, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x6860, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x6861, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x6862, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x6864, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x6883, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x681D, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x6855, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x6866, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x6867, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x683E, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x684A, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x6849, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x6829, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x6874, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x6877, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x686B, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x68C2, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x68FC, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x691F, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x6920, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x9527, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x9533, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x953D, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x9543, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x9548, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x954B, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x9555, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x955A, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x9560, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x956E, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x9574, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x9575, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x9578, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x9579, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x957A, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x957B, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x957C, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x957D, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x957E, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x9581, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x9584, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x9585, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x9586, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x9587, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x9588, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x958A, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x958C, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x958D, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x958E, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x9590, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x9595, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x9596, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x9597, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x9599, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x959A, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x959B, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x959C, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x959D, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x959E, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x959F, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x95A0, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x95A1, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x95A2, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x95A6, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x95A7, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x95A9, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x95AA, //CJK UNIFIED IDEOGRAPH + 0xE980: 0x95AB, //CJK UNIFIED IDEOGRAPH + 0xE981: 0x95AC, //CJK UNIFIED IDEOGRAPH + 0xE982: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xE983: 0x95AE, //CJK UNIFIED IDEOGRAPH + 0xE984: 0x95AF, //CJK UNIFIED IDEOGRAPH + 0xE985: 0x95B0, //CJK UNIFIED IDEOGRAPH + 0xE986: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xE987: 0x95B2, //CJK UNIFIED IDEOGRAPH + 0xE988: 0x95B3, //CJK UNIFIED IDEOGRAPH + 0xE989: 0x95B4, //CJK UNIFIED IDEOGRAPH + 0xE98A: 0x95B5, //CJK UNIFIED IDEOGRAPH + 0xE98B: 0x95B6, //CJK UNIFIED IDEOGRAPH + 0xE98C: 0x95B7, //CJK UNIFIED IDEOGRAPH + 0xE98D: 0x95B8, //CJK UNIFIED IDEOGRAPH + 0xE98E: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xE98F: 0x95BA, //CJK UNIFIED IDEOGRAPH + 0xE990: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE991: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE992: 0x95BD, //CJK UNIFIED IDEOGRAPH + 0xE993: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xE994: 0x95BF, //CJK UNIFIED IDEOGRAPH + 0xE995: 0x95C0, //CJK UNIFIED IDEOGRAPH + 0xE996: 0x95C1, //CJK UNIFIED IDEOGRAPH + 0xE997: 0x95C2, //CJK UNIFIED IDEOGRAPH + 0xE998: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xE999: 0x95C4, //CJK UNIFIED IDEOGRAPH + 0xE99A: 0x95C5, //CJK UNIFIED IDEOGRAPH + 0xE99B: 0x95C6, //CJK UNIFIED IDEOGRAPH + 0xE99C: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xE99D: 0x95C8, //CJK UNIFIED IDEOGRAPH + 0xE99E: 0x95C9, //CJK UNIFIED IDEOGRAPH + 0xE99F: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xE9A0: 0x95CB, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x6924, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x68F0, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x690B, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x6901, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x6910, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x6971, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x6939, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x6942, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x695D, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x6984, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x6980, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x6934, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x6987, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x6988, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x6989, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x6966, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x69AB, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x69AD, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x69D4, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x69DF, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x69E0, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x698D, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x6A2F, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x6A18, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x6A65, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x6A3E, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x6A50, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x6A5B, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x6A79, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6A28, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x6A7C, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x6A91, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x6AA9, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x6AAB, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x6B81, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x6B82, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x6B87, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x6B92, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x6B93, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x6B9A, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x6B9B, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x6BA1, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x8F6B, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x8F6D, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x8F71, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x8F72, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x8F73, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x8F75, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x8F76, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x8F78, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x8F77, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x8F79, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x8F7A, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x8F7C, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x8F7E, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x8F81, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x8F82, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x8F84, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x8F87, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x8F8B, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x95CE, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x95CF, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x95D0, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x95D1, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x95D2, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x95D3, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x95D7, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x95D8, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x95D9, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x95DA, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x95DB, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x95DD, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x95DE, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x95DF, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x95E0, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x95E3, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x95E4, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x95E6, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x95E7, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x95EC, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x95FF, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x9607, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x9613, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x9618, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x961B, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x961E, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x9620, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x9623, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x9624, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x9625, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x9626, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x9627, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x9629, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x962B, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x962C, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x962D, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x9630, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x9637, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x9638, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x9639, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x963A, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x963E, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x9641, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x9643, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x964A, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x964E, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x9651, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x9652, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x9653, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x9656, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x9657, //CJK UNIFIED IDEOGRAPH + 0xEA80: 0x9658, //CJK UNIFIED IDEOGRAPH + 0xEA81: 0x9659, //CJK UNIFIED IDEOGRAPH + 0xEA82: 0x965A, //CJK UNIFIED IDEOGRAPH + 0xEA83: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xEA84: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xEA85: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xEA86: 0x9660, //CJK UNIFIED IDEOGRAPH + 0xEA87: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xEA88: 0x9665, //CJK UNIFIED IDEOGRAPH + 0xEA89: 0x9666, //CJK UNIFIED IDEOGRAPH + 0xEA8A: 0x966B, //CJK UNIFIED IDEOGRAPH + 0xEA8B: 0x966D, //CJK UNIFIED IDEOGRAPH + 0xEA8C: 0x966E, //CJK UNIFIED IDEOGRAPH + 0xEA8D: 0x966F, //CJK UNIFIED IDEOGRAPH + 0xEA8E: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xEA8F: 0x9671, //CJK UNIFIED IDEOGRAPH + 0xEA90: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xEA91: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xEA92: 0x9679, //CJK UNIFIED IDEOGRAPH + 0xEA93: 0x967A, //CJK UNIFIED IDEOGRAPH + 0xEA94: 0x967B, //CJK UNIFIED IDEOGRAPH + 0xEA95: 0x967C, //CJK UNIFIED IDEOGRAPH + 0xEA96: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xEA97: 0x967E, //CJK UNIFIED IDEOGRAPH + 0xEA98: 0x967F, //CJK UNIFIED IDEOGRAPH + 0xEA99: 0x9680, //CJK UNIFIED IDEOGRAPH + 0xEA9A: 0x9681, //CJK UNIFIED IDEOGRAPH + 0xEA9B: 0x9682, //CJK UNIFIED IDEOGRAPH + 0xEA9C: 0x9683, //CJK UNIFIED IDEOGRAPH + 0xEA9D: 0x9684, //CJK UNIFIED IDEOGRAPH + 0xEA9E: 0x9687, //CJK UNIFIED IDEOGRAPH + 0xEA9F: 0x9689, //CJK UNIFIED IDEOGRAPH + 0xEAA0: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x8F8D, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x8F8E, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x8F8F, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x8F98, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x8F9A, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x8ECE, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x620B, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x6217, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x621B, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x6222, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x6225, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x6224, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x622C, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x74EF, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x74F4, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x74FF, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x750F, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x6534, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x65EE, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x65EF, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x65F0, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x6619, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x6772, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x6603, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xEAC2: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x661D, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x6635, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x6654, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x6656, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x6661, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x668C, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x66A7, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x66DB, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x8D32, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x8D33, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x8D36, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x8D3B, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x8D3D, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x8D40, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x8D45, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x8D46, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x8D48, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x8D49, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x8D47, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0x8D4D, //CJK UNIFIED IDEOGRAPH + 0xEAE6: 0x8D55, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x8D59, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x89C7, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x89CA, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x89CB, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x89CC, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x89CE, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x89CF, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x89D0, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x89D1, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x726E, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x729F, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x7266, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0x726F, //CJK UNIFIED IDEOGRAPH + 0xEAF5: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x727F, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0x7284, //CJK UNIFIED IDEOGRAPH + 0xEAF8: 0x728B, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x728D, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x728F, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0x6308, //CJK UNIFIED IDEOGRAPH + 0xEAFD: 0x6332, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0x63B0, //CJK UNIFIED IDEOGRAPH + 0xEB40: 0x968C, //CJK UNIFIED IDEOGRAPH + 0xEB41: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xEB42: 0x9691, //CJK UNIFIED IDEOGRAPH + 0xEB43: 0x9692, //CJK UNIFIED IDEOGRAPH + 0xEB44: 0x9693, //CJK UNIFIED IDEOGRAPH + 0xEB45: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xEB46: 0x9696, //CJK UNIFIED IDEOGRAPH + 0xEB47: 0x969A, //CJK UNIFIED IDEOGRAPH + 0xEB48: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xEB49: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xEB4A: 0x969E, //CJK UNIFIED IDEOGRAPH + 0xEB4B: 0x969F, //CJK UNIFIED IDEOGRAPH + 0xEB4C: 0x96A0, //CJK UNIFIED IDEOGRAPH + 0xEB4D: 0x96A1, //CJK UNIFIED IDEOGRAPH + 0xEB4E: 0x96A2, //CJK UNIFIED IDEOGRAPH + 0xEB4F: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0xEB50: 0x96A4, //CJK UNIFIED IDEOGRAPH + 0xEB51: 0x96A5, //CJK UNIFIED IDEOGRAPH + 0xEB52: 0x96A6, //CJK UNIFIED IDEOGRAPH + 0xEB53: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xEB54: 0x96A9, //CJK UNIFIED IDEOGRAPH + 0xEB55: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xEB56: 0x96AB, //CJK UNIFIED IDEOGRAPH + 0xEB57: 0x96AC, //CJK UNIFIED IDEOGRAPH + 0xEB58: 0x96AD, //CJK UNIFIED IDEOGRAPH + 0xEB59: 0x96AE, //CJK UNIFIED IDEOGRAPH + 0xEB5A: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xEB5B: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xEB5C: 0x96B2, //CJK UNIFIED IDEOGRAPH + 0xEB5D: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xEB5E: 0x96B5, //CJK UNIFIED IDEOGRAPH + 0xEB5F: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0xEB60: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xEB61: 0x96BA, //CJK UNIFIED IDEOGRAPH + 0xEB62: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xEB63: 0x96BF, //CJK UNIFIED IDEOGRAPH + 0xEB64: 0x96C2, //CJK UNIFIED IDEOGRAPH + 0xEB65: 0x96C3, //CJK UNIFIED IDEOGRAPH + 0xEB66: 0x96C8, //CJK UNIFIED IDEOGRAPH + 0xEB67: 0x96CA, //CJK UNIFIED IDEOGRAPH + 0xEB68: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xEB69: 0x96D0, //CJK UNIFIED IDEOGRAPH + 0xEB6A: 0x96D1, //CJK UNIFIED IDEOGRAPH + 0xEB6B: 0x96D3, //CJK UNIFIED IDEOGRAPH + 0xEB6C: 0x96D4, //CJK UNIFIED IDEOGRAPH + 0xEB6D: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xEB6E: 0x96D7, //CJK UNIFIED IDEOGRAPH + 0xEB6F: 0x96D8, //CJK UNIFIED IDEOGRAPH + 0xEB70: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xEB71: 0x96DA, //CJK UNIFIED IDEOGRAPH + 0xEB72: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xEB73: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xEB74: 0x96DD, //CJK UNIFIED IDEOGRAPH + 0xEB75: 0x96DE, //CJK UNIFIED IDEOGRAPH + 0xEB76: 0x96DF, //CJK UNIFIED IDEOGRAPH + 0xEB77: 0x96E1, //CJK UNIFIED IDEOGRAPH + 0xEB78: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xEB79: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xEB7A: 0x96E4, //CJK UNIFIED IDEOGRAPH + 0xEB7B: 0x96E5, //CJK UNIFIED IDEOGRAPH + 0xEB7C: 0x96E6, //CJK UNIFIED IDEOGRAPH + 0xEB7D: 0x96E7, //CJK UNIFIED IDEOGRAPH + 0xEB7E: 0x96EB, //CJK UNIFIED IDEOGRAPH + 0xEB80: 0x96EC, //CJK UNIFIED IDEOGRAPH + 0xEB81: 0x96ED, //CJK UNIFIED IDEOGRAPH + 0xEB82: 0x96EE, //CJK UNIFIED IDEOGRAPH + 0xEB83: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xEB84: 0x96F1, //CJK UNIFIED IDEOGRAPH + 0xEB85: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xEB86: 0x96F4, //CJK UNIFIED IDEOGRAPH + 0xEB87: 0x96F5, //CJK UNIFIED IDEOGRAPH + 0xEB88: 0x96F8, //CJK UNIFIED IDEOGRAPH + 0xEB89: 0x96FA, //CJK UNIFIED IDEOGRAPH + 0xEB8A: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xEB8B: 0x96FC, //CJK UNIFIED IDEOGRAPH + 0xEB8C: 0x96FD, //CJK UNIFIED IDEOGRAPH + 0xEB8D: 0x96FF, //CJK UNIFIED IDEOGRAPH + 0xEB8E: 0x9702, //CJK UNIFIED IDEOGRAPH + 0xEB8F: 0x9703, //CJK UNIFIED IDEOGRAPH + 0xEB90: 0x9705, //CJK UNIFIED IDEOGRAPH + 0xEB91: 0x970A, //CJK UNIFIED IDEOGRAPH + 0xEB92: 0x970B, //CJK UNIFIED IDEOGRAPH + 0xEB93: 0x970C, //CJK UNIFIED IDEOGRAPH + 0xEB94: 0x9710, //CJK UNIFIED IDEOGRAPH + 0xEB95: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xEB96: 0x9712, //CJK UNIFIED IDEOGRAPH + 0xEB97: 0x9714, //CJK UNIFIED IDEOGRAPH + 0xEB98: 0x9715, //CJK UNIFIED IDEOGRAPH + 0xEB99: 0x9717, //CJK UNIFIED IDEOGRAPH + 0xEB9A: 0x9718, //CJK UNIFIED IDEOGRAPH + 0xEB9B: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xEB9C: 0x971A, //CJK UNIFIED IDEOGRAPH + 0xEB9D: 0x971B, //CJK UNIFIED IDEOGRAPH + 0xEB9E: 0x971D, //CJK UNIFIED IDEOGRAPH + 0xEB9F: 0x971F, //CJK UNIFIED IDEOGRAPH + 0xEBA0: 0x9720, //CJK UNIFIED IDEOGRAPH + 0xEBA1: 0x643F, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0x6BEA, //CJK UNIFIED IDEOGRAPH + 0xEBA5: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x6BFD, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0x6BF5, //CJK UNIFIED IDEOGRAPH + 0xEBA8: 0x6BF9, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0x6C05, //CJK UNIFIED IDEOGRAPH + 0xEBAA: 0x6C07, //CJK UNIFIED IDEOGRAPH + 0xEBAB: 0x6C06, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x6C0D, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x6C15, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x6C18, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x6C19, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x6C1A, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x6C21, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x6C29, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x6C2A, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x6C32, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x6535, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x6555, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x656B, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x724D, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xEBBB: 0x7256, //CJK UNIFIED IDEOGRAPH + 0xEBBC: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0x8662, //CJK UNIFIED IDEOGRAPH + 0xEBBE: 0x5216, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x809F, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x809C, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xEBC2: 0x80BC, //CJK UNIFIED IDEOGRAPH + 0xEBC3: 0x670A, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x80BD, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0x80AB, //CJK UNIFIED IDEOGRAPH + 0xEBC7: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xEBC8: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x80B7, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x80E7, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x80E8, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0x80E9, //CJK UNIFIED IDEOGRAPH + 0xEBCD: 0x80EA, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0x80C2, //CJK UNIFIED IDEOGRAPH + 0xEBD0: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xEBD1: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xEBD2: 0x80CD, //CJK UNIFIED IDEOGRAPH + 0xEBD3: 0x80D7, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x6710, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x80EB, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xEBD9: 0x80ED, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x810D, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x810E, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x80F2, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x8112, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x8136, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x811E, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x812C, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x8132, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x8148, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x814C, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x8159, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x815A, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x8160, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x8169, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x817C, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x817D, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x816D, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x8167, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x584D, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x5AB5, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x8191, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x81AA, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x81CC, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x81CA, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x81BB, //CJK UNIFIED IDEOGRAPH + 0xEC40: 0x9721, //CJK UNIFIED IDEOGRAPH + 0xEC41: 0x9722, //CJK UNIFIED IDEOGRAPH + 0xEC42: 0x9723, //CJK UNIFIED IDEOGRAPH + 0xEC43: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xEC44: 0x9725, //CJK UNIFIED IDEOGRAPH + 0xEC45: 0x9726, //CJK UNIFIED IDEOGRAPH + 0xEC46: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xEC47: 0x9728, //CJK UNIFIED IDEOGRAPH + 0xEC48: 0x9729, //CJK UNIFIED IDEOGRAPH + 0xEC49: 0x972B, //CJK UNIFIED IDEOGRAPH + 0xEC4A: 0x972C, //CJK UNIFIED IDEOGRAPH + 0xEC4B: 0x972E, //CJK UNIFIED IDEOGRAPH + 0xEC4C: 0x972F, //CJK UNIFIED IDEOGRAPH + 0xEC4D: 0x9731, //CJK UNIFIED IDEOGRAPH + 0xEC4E: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xEC4F: 0x9734, //CJK UNIFIED IDEOGRAPH + 0xEC50: 0x9735, //CJK UNIFIED IDEOGRAPH + 0xEC51: 0x9736, //CJK UNIFIED IDEOGRAPH + 0xEC52: 0x9737, //CJK UNIFIED IDEOGRAPH + 0xEC53: 0x973A, //CJK UNIFIED IDEOGRAPH + 0xEC54: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xEC55: 0x973C, //CJK UNIFIED IDEOGRAPH + 0xEC56: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xEC57: 0x973F, //CJK UNIFIED IDEOGRAPH + 0xEC58: 0x9740, //CJK UNIFIED IDEOGRAPH + 0xEC59: 0x9741, //CJK UNIFIED IDEOGRAPH + 0xEC5A: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xEC5B: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xEC5C: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xEC5D: 0x9745, //CJK UNIFIED IDEOGRAPH + 0xEC5E: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xEC5F: 0x9747, //CJK UNIFIED IDEOGRAPH + 0xEC60: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xEC61: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xEC62: 0x974A, //CJK UNIFIED IDEOGRAPH + 0xEC63: 0x974B, //CJK UNIFIED IDEOGRAPH + 0xEC64: 0x974C, //CJK UNIFIED IDEOGRAPH + 0xEC65: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xEC66: 0x974E, //CJK UNIFIED IDEOGRAPH + 0xEC67: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xEC68: 0x9750, //CJK UNIFIED IDEOGRAPH + 0xEC69: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xEC6A: 0x9754, //CJK UNIFIED IDEOGRAPH + 0xEC6B: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xEC6C: 0x9757, //CJK UNIFIED IDEOGRAPH + 0xEC6D: 0x9758, //CJK UNIFIED IDEOGRAPH + 0xEC6E: 0x975A, //CJK UNIFIED IDEOGRAPH + 0xEC6F: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xEC70: 0x975D, //CJK UNIFIED IDEOGRAPH + 0xEC71: 0x975F, //CJK UNIFIED IDEOGRAPH + 0xEC72: 0x9763, //CJK UNIFIED IDEOGRAPH + 0xEC73: 0x9764, //CJK UNIFIED IDEOGRAPH + 0xEC74: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xEC75: 0x9767, //CJK UNIFIED IDEOGRAPH + 0xEC76: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xEC77: 0x976A, //CJK UNIFIED IDEOGRAPH + 0xEC78: 0x976B, //CJK UNIFIED IDEOGRAPH + 0xEC79: 0x976C, //CJK UNIFIED IDEOGRAPH + 0xEC7A: 0x976D, //CJK UNIFIED IDEOGRAPH + 0xEC7B: 0x976E, //CJK UNIFIED IDEOGRAPH + 0xEC7C: 0x976F, //CJK UNIFIED IDEOGRAPH + 0xEC7D: 0x9770, //CJK UNIFIED IDEOGRAPH + 0xEC7E: 0x9771, //CJK UNIFIED IDEOGRAPH + 0xEC80: 0x9772, //CJK UNIFIED IDEOGRAPH + 0xEC81: 0x9775, //CJK UNIFIED IDEOGRAPH + 0xEC82: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xEC83: 0x9778, //CJK UNIFIED IDEOGRAPH + 0xEC84: 0x9779, //CJK UNIFIED IDEOGRAPH + 0xEC85: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xEC86: 0x977B, //CJK UNIFIED IDEOGRAPH + 0xEC87: 0x977D, //CJK UNIFIED IDEOGRAPH + 0xEC88: 0x977E, //CJK UNIFIED IDEOGRAPH + 0xEC89: 0x977F, //CJK UNIFIED IDEOGRAPH + 0xEC8A: 0x9780, //CJK UNIFIED IDEOGRAPH + 0xEC8B: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xEC8C: 0x9782, //CJK UNIFIED IDEOGRAPH + 0xEC8D: 0x9783, //CJK UNIFIED IDEOGRAPH + 0xEC8E: 0x9784, //CJK UNIFIED IDEOGRAPH + 0xEC8F: 0x9786, //CJK UNIFIED IDEOGRAPH + 0xEC90: 0x9787, //CJK UNIFIED IDEOGRAPH + 0xEC91: 0x9788, //CJK UNIFIED IDEOGRAPH + 0xEC92: 0x9789, //CJK UNIFIED IDEOGRAPH + 0xEC93: 0x978A, //CJK UNIFIED IDEOGRAPH + 0xEC94: 0x978C, //CJK UNIFIED IDEOGRAPH + 0xEC95: 0x978E, //CJK UNIFIED IDEOGRAPH + 0xEC96: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xEC97: 0x9790, //CJK UNIFIED IDEOGRAPH + 0xEC98: 0x9793, //CJK UNIFIED IDEOGRAPH + 0xEC99: 0x9795, //CJK UNIFIED IDEOGRAPH + 0xEC9A: 0x9796, //CJK UNIFIED IDEOGRAPH + 0xEC9B: 0x9797, //CJK UNIFIED IDEOGRAPH + 0xEC9C: 0x9799, //CJK UNIFIED IDEOGRAPH + 0xEC9D: 0x979A, //CJK UNIFIED IDEOGRAPH + 0xEC9E: 0x979B, //CJK UNIFIED IDEOGRAPH + 0xEC9F: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xECA0: 0x979D, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x81C1, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x81A6, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x6B24, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0xECA7: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xECA8: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x98D1, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0x98D2, //CJK UNIFIED IDEOGRAPH + 0xECAB: 0x98D3, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x98D5, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x98D9, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x98DA, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0xECB0: 0x5F40, //CJK UNIFIED IDEOGRAPH + 0xECB1: 0x6BC2, //CJK UNIFIED IDEOGRAPH + 0xECB2: 0x89F3, //CJK UNIFIED IDEOGRAPH + 0xECB3: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x9F51, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0x6593, //CJK UNIFIED IDEOGRAPH + 0xECB6: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0xECB9: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xECBB: 0x65CE, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x65D6, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x7080, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x709C, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0x7096, //CJK UNIFIED IDEOGRAPH + 0xECC1: 0x709D, //CJK UNIFIED IDEOGRAPH + 0xECC2: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x70C0, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xECC6: 0x70B1, //CJK UNIFIED IDEOGRAPH + 0xECC7: 0x70E8, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x70CA, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0x7110, //CJK UNIFIED IDEOGRAPH + 0xECCA: 0x7113, //CJK UNIFIED IDEOGRAPH + 0xECCB: 0x7116, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x712F, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x7131, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x7173, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x7168, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x7145, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x7172, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x714A, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x7178, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0x717A, //CJK UNIFIED IDEOGRAPH + 0xECD6: 0x7198, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x71B3, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x71B5, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x71A0, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xECDE: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xECDF: 0x721D, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0x706C, //CJK UNIFIED IDEOGRAPH + 0xECE2: 0x7118, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xECE5: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x623D, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0x6243, //CJK UNIFIED IDEOGRAPH + 0xECE8: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xECE9: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x793B, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x7946, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x7962, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x796F, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x7967, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xECF8: 0x7985, //CJK UNIFIED IDEOGRAPH + 0xECF9: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0x799A, //CJK UNIFIED IDEOGRAPH + 0xECFB: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x5FD1, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x5FD0, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x979E, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x979F, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x97A1, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x97A2, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x97A4, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x97A5, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x97A7, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x97A9, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x97AA, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x97AC, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x97AE, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x97B0, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x97B1, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x97B5, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x97B6, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x97B7, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x97B8, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x97B9, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x97BA, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x97BB, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x97BC, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x97BD, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x97BE, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x97BF, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x97C0, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x97C1, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x97C2, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x97C4, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x97C5, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x97C7, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x97C8, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x97C9, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x97CA, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x97CC, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x97CD, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x97CE, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x97CF, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x97D0, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x97D1, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x97D2, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x97D4, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x97D5, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x97D6, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x97D7, //CJK UNIFIED IDEOGRAPH + 0xED73: 0x97D8, //CJK UNIFIED IDEOGRAPH + 0xED74: 0x97D9, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x97DA, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x97DB, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x97DD, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x97DE, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x97DF, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x97E0, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x97E1, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x97E2, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0x97E3, //CJK UNIFIED IDEOGRAPH + 0xED80: 0x97E4, //CJK UNIFIED IDEOGRAPH + 0xED81: 0x97E5, //CJK UNIFIED IDEOGRAPH + 0xED82: 0x97E8, //CJK UNIFIED IDEOGRAPH + 0xED83: 0x97EE, //CJK UNIFIED IDEOGRAPH + 0xED84: 0x97EF, //CJK UNIFIED IDEOGRAPH + 0xED85: 0x97F0, //CJK UNIFIED IDEOGRAPH + 0xED86: 0x97F1, //CJK UNIFIED IDEOGRAPH + 0xED87: 0x97F2, //CJK UNIFIED IDEOGRAPH + 0xED88: 0x97F4, //CJK UNIFIED IDEOGRAPH + 0xED89: 0x97F7, //CJK UNIFIED IDEOGRAPH + 0xED8A: 0x97F8, //CJK UNIFIED IDEOGRAPH + 0xED8B: 0x97F9, //CJK UNIFIED IDEOGRAPH + 0xED8C: 0x97FA, //CJK UNIFIED IDEOGRAPH + 0xED8D: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xED8E: 0x97FC, //CJK UNIFIED IDEOGRAPH + 0xED8F: 0x97FD, //CJK UNIFIED IDEOGRAPH + 0xED90: 0x97FE, //CJK UNIFIED IDEOGRAPH + 0xED91: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xED92: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xED93: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xED94: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xED95: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xED96: 0x9804, //CJK UNIFIED IDEOGRAPH + 0xED97: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xED98: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xED99: 0x9807, //CJK UNIFIED IDEOGRAPH + 0xED9A: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xED9B: 0x9809, //CJK UNIFIED IDEOGRAPH + 0xED9C: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xED9D: 0x980B, //CJK UNIFIED IDEOGRAPH + 0xED9E: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xED9F: 0x980D, //CJK UNIFIED IDEOGRAPH + 0xEDA0: 0x980E, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x603C, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x605A, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x6067, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x60AB, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x619D, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x61D1, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x6206, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x8080, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x6CF6, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x77F6, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x77F8, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x7800, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7809, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x7817, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x7818, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x7811, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x782D, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x781C, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x781D, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x7839, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x783A, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x783B, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x781F, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x783C, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x7823, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7829, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x786D, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x7856, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x7857, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x7850, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x7847, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x784C, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x786A, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x789B, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x7893, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x789C, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x78A1, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x78B2, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x78B9, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x78A5, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x78D9, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x78C9, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x78F2, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x7905, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x7913, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x7924, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x791E, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x7934, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x9F9B, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x76F1, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x770D, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x76F9, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x771A, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x7722, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x7719, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x772D, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x7726, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x7735, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x7750, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x7751, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x7743, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xEE43: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x9814, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x9815, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x9816, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x9819, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x981A, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x981B, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x981C, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x981D, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x981E, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x981F, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x9820, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x9822, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x9823, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x9825, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x9826, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x9827, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0x9828, //CJK UNIFIED IDEOGRAPH + 0xEE5A: 0x9829, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x982A, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x982B, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x982C, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x982E, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x982F, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xEE62: 0x9831, //CJK UNIFIED IDEOGRAPH + 0xEE63: 0x9832, //CJK UNIFIED IDEOGRAPH + 0xEE64: 0x9833, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0x9834, //CJK UNIFIED IDEOGRAPH + 0xEE66: 0x9835, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x9836, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xEE6A: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x983A, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xEE6D: 0x983C, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x983D, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x983E, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x983F, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x9840, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x9841, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x9842, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x9843, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0x9844, //CJK UNIFIED IDEOGRAPH + 0xEE76: 0x9845, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x9847, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x9848, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x9849, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x984A, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x984B, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xEE80: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xEE81: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xEE82: 0x9850, //CJK UNIFIED IDEOGRAPH + 0xEE83: 0x9851, //CJK UNIFIED IDEOGRAPH + 0xEE84: 0x9852, //CJK UNIFIED IDEOGRAPH + 0xEE85: 0x9853, //CJK UNIFIED IDEOGRAPH + 0xEE86: 0x9854, //CJK UNIFIED IDEOGRAPH + 0xEE87: 0x9855, //CJK UNIFIED IDEOGRAPH + 0xEE88: 0x9856, //CJK UNIFIED IDEOGRAPH + 0xEE89: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xEE8A: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xEE8B: 0x9859, //CJK UNIFIED IDEOGRAPH + 0xEE8C: 0x985A, //CJK UNIFIED IDEOGRAPH + 0xEE8D: 0x985B, //CJK UNIFIED IDEOGRAPH + 0xEE8E: 0x985C, //CJK UNIFIED IDEOGRAPH + 0xEE8F: 0x985D, //CJK UNIFIED IDEOGRAPH + 0xEE90: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xEE91: 0x985F, //CJK UNIFIED IDEOGRAPH + 0xEE92: 0x9860, //CJK UNIFIED IDEOGRAPH + 0xEE93: 0x9861, //CJK UNIFIED IDEOGRAPH + 0xEE94: 0x9862, //CJK UNIFIED IDEOGRAPH + 0xEE95: 0x9863, //CJK UNIFIED IDEOGRAPH + 0xEE96: 0x9864, //CJK UNIFIED IDEOGRAPH + 0xEE97: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xEE98: 0x9866, //CJK UNIFIED IDEOGRAPH + 0xEE99: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xEE9A: 0x9868, //CJK UNIFIED IDEOGRAPH + 0xEE9B: 0x9869, //CJK UNIFIED IDEOGRAPH + 0xEE9C: 0x986A, //CJK UNIFIED IDEOGRAPH + 0xEE9D: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xEE9E: 0x986C, //CJK UNIFIED IDEOGRAPH + 0xEE9F: 0x986D, //CJK UNIFIED IDEOGRAPH + 0xEEA0: 0x986E, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x7762, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x778D, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x777D, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x7780, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x778C, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x779F, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x77B5, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x7540, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x754E, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x754B, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x7548, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x7572, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x7579, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x7583, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x7F61, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x7F74, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x7F71, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x7F81, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x7F7E, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x8832, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9485, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x9486, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x9487, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x948B, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x948A, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x948C, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x948D, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x948F, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x9490, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x9494, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x9497, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x9495, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x949A, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x949B, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x949C, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x94A3, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x94A4, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x94AB, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x94AA, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x94AD, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x94AC, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x94AF, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x94B0, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0x94B2, //CJK UNIFIED IDEOGRAPH + 0xEEDC: 0x94B4, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x94B6, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x94B7, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x94B8, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x94B9, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x94BA, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x94BC, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x94BD, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x94BF, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x94C4, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x94C8, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x94C9, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x94CA, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x94CB, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x94CC, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x94CD, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x94CE, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x94D0, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x94D1, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x94D2, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x94D5, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x94D6, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x94D7, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x94D9, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x94D8, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x94DB, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x94DE, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x94DF, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x94E0, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x94E2, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x94E4, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x94E5, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x94E7, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x94E8, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x94EA, //CJK UNIFIED IDEOGRAPH + 0xEF40: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xEF41: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xEF42: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xEF43: 0x9872, //CJK UNIFIED IDEOGRAPH + 0xEF44: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xEF45: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xEF46: 0x988B, //CJK UNIFIED IDEOGRAPH + 0xEF47: 0x988E, //CJK UNIFIED IDEOGRAPH + 0xEF48: 0x9892, //CJK UNIFIED IDEOGRAPH + 0xEF49: 0x9895, //CJK UNIFIED IDEOGRAPH + 0xEF4A: 0x9899, //CJK UNIFIED IDEOGRAPH + 0xEF4B: 0x98A3, //CJK UNIFIED IDEOGRAPH + 0xEF4C: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xEF4D: 0x98A9, //CJK UNIFIED IDEOGRAPH + 0xEF4E: 0x98AA, //CJK UNIFIED IDEOGRAPH + 0xEF4F: 0x98AB, //CJK UNIFIED IDEOGRAPH + 0xEF50: 0x98AC, //CJK UNIFIED IDEOGRAPH + 0xEF51: 0x98AD, //CJK UNIFIED IDEOGRAPH + 0xEF52: 0x98AE, //CJK UNIFIED IDEOGRAPH + 0xEF53: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xEF54: 0x98B0, //CJK UNIFIED IDEOGRAPH + 0xEF55: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xEF56: 0x98B2, //CJK UNIFIED IDEOGRAPH + 0xEF57: 0x98B3, //CJK UNIFIED IDEOGRAPH + 0xEF58: 0x98B4, //CJK UNIFIED IDEOGRAPH + 0xEF59: 0x98B5, //CJK UNIFIED IDEOGRAPH + 0xEF5A: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xEF5B: 0x98B7, //CJK UNIFIED IDEOGRAPH + 0xEF5C: 0x98B8, //CJK UNIFIED IDEOGRAPH + 0xEF5D: 0x98B9, //CJK UNIFIED IDEOGRAPH + 0xEF5E: 0x98BA, //CJK UNIFIED IDEOGRAPH + 0xEF5F: 0x98BB, //CJK UNIFIED IDEOGRAPH + 0xEF60: 0x98BC, //CJK UNIFIED IDEOGRAPH + 0xEF61: 0x98BD, //CJK UNIFIED IDEOGRAPH + 0xEF62: 0x98BE, //CJK UNIFIED IDEOGRAPH + 0xEF63: 0x98BF, //CJK UNIFIED IDEOGRAPH + 0xEF64: 0x98C0, //CJK UNIFIED IDEOGRAPH + 0xEF65: 0x98C1, //CJK UNIFIED IDEOGRAPH + 0xEF66: 0x98C2, //CJK UNIFIED IDEOGRAPH + 0xEF67: 0x98C3, //CJK UNIFIED IDEOGRAPH + 0xEF68: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xEF69: 0x98C5, //CJK UNIFIED IDEOGRAPH + 0xEF6A: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xEF6B: 0x98C7, //CJK UNIFIED IDEOGRAPH + 0xEF6C: 0x98C8, //CJK UNIFIED IDEOGRAPH + 0xEF6D: 0x98C9, //CJK UNIFIED IDEOGRAPH + 0xEF6E: 0x98CA, //CJK UNIFIED IDEOGRAPH + 0xEF6F: 0x98CB, //CJK UNIFIED IDEOGRAPH + 0xEF70: 0x98CC, //CJK UNIFIED IDEOGRAPH + 0xEF71: 0x98CD, //CJK UNIFIED IDEOGRAPH + 0xEF72: 0x98CF, //CJK UNIFIED IDEOGRAPH + 0xEF73: 0x98D0, //CJK UNIFIED IDEOGRAPH + 0xEF74: 0x98D4, //CJK UNIFIED IDEOGRAPH + 0xEF75: 0x98D6, //CJK UNIFIED IDEOGRAPH + 0xEF76: 0x98D7, //CJK UNIFIED IDEOGRAPH + 0xEF77: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xEF78: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xEF79: 0x98DD, //CJK UNIFIED IDEOGRAPH + 0xEF7A: 0x98E0, //CJK UNIFIED IDEOGRAPH + 0xEF7B: 0x98E1, //CJK UNIFIED IDEOGRAPH + 0xEF7C: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xEF7D: 0x98E3, //CJK UNIFIED IDEOGRAPH + 0xEF7E: 0x98E4, //CJK UNIFIED IDEOGRAPH + 0xEF80: 0x98E5, //CJK UNIFIED IDEOGRAPH + 0xEF81: 0x98E6, //CJK UNIFIED IDEOGRAPH + 0xEF82: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xEF83: 0x98EA, //CJK UNIFIED IDEOGRAPH + 0xEF84: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xEF85: 0x98EC, //CJK UNIFIED IDEOGRAPH + 0xEF86: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xEF87: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0xEF88: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xEF89: 0x98F0, //CJK UNIFIED IDEOGRAPH + 0xEF8A: 0x98F1, //CJK UNIFIED IDEOGRAPH + 0xEF8B: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0xEF8C: 0x98F3, //CJK UNIFIED IDEOGRAPH + 0xEF8D: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xEF8E: 0x98F5, //CJK UNIFIED IDEOGRAPH + 0xEF8F: 0x98F6, //CJK UNIFIED IDEOGRAPH + 0xEF90: 0x98F7, //CJK UNIFIED IDEOGRAPH + 0xEF91: 0x98F8, //CJK UNIFIED IDEOGRAPH + 0xEF92: 0x98F9, //CJK UNIFIED IDEOGRAPH + 0xEF93: 0x98FA, //CJK UNIFIED IDEOGRAPH + 0xEF94: 0x98FB, //CJK UNIFIED IDEOGRAPH + 0xEF95: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xEF96: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xEF97: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xEF98: 0x98FF, //CJK UNIFIED IDEOGRAPH + 0xEF99: 0x9900, //CJK UNIFIED IDEOGRAPH + 0xEF9A: 0x9901, //CJK UNIFIED IDEOGRAPH + 0xEF9B: 0x9902, //CJK UNIFIED IDEOGRAPH + 0xEF9C: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xEF9D: 0x9904, //CJK UNIFIED IDEOGRAPH + 0xEF9E: 0x9905, //CJK UNIFIED IDEOGRAPH + 0xEF9F: 0x9906, //CJK UNIFIED IDEOGRAPH + 0xEFA0: 0x9907, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x94E9, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x94EB, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x94EE, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x94EF, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x94F3, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x94F4, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x94F5, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x94F7, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x94F9, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x94FC, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x94FD, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x94FF, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x9503, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x9502, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x9506, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9507, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9509, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x950A, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x950D, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x950E, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x950F, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x9512, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x9513, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x9514, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x9515, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x9516, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x9518, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x951B, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x951D, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x951E, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x951F, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x9522, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x952A, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x952B, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x9529, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x952C, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x9531, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x9532, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x9534, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x9536, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x9537, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x9538, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x953C, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x953E, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x953F, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x9542, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x9535, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x9544, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x9545, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x9546, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x9549, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x954C, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x954E, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x954F, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x9552, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x9553, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x9554, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x9556, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x9557, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x9558, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x9559, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x955B, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x955E, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x955F, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x955D, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x9561, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x9562, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x9564, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x9565, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x9566, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x9567, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x9568, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x9569, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x956A, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x956B, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x956C, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x956F, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x9571, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x9572, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x9573, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x953A, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x77EC, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x79ED, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x79EB, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x7A06, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x5D47, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x7A03, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x7A02, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x7A1E, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xF040: 0x9908, //CJK UNIFIED IDEOGRAPH + 0xF041: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xF042: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xF043: 0x990B, //CJK UNIFIED IDEOGRAPH + 0xF044: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xF045: 0x990E, //CJK UNIFIED IDEOGRAPH + 0xF046: 0x990F, //CJK UNIFIED IDEOGRAPH + 0xF047: 0x9911, //CJK UNIFIED IDEOGRAPH + 0xF048: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xF049: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xF04A: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xF04B: 0x9915, //CJK UNIFIED IDEOGRAPH + 0xF04C: 0x9916, //CJK UNIFIED IDEOGRAPH + 0xF04D: 0x9917, //CJK UNIFIED IDEOGRAPH + 0xF04E: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xF04F: 0x9919, //CJK UNIFIED IDEOGRAPH + 0xF050: 0x991A, //CJK UNIFIED IDEOGRAPH + 0xF051: 0x991B, //CJK UNIFIED IDEOGRAPH + 0xF052: 0x991C, //CJK UNIFIED IDEOGRAPH + 0xF053: 0x991D, //CJK UNIFIED IDEOGRAPH + 0xF054: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xF055: 0x991F, //CJK UNIFIED IDEOGRAPH + 0xF056: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xF057: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xF058: 0x9922, //CJK UNIFIED IDEOGRAPH + 0xF059: 0x9923, //CJK UNIFIED IDEOGRAPH + 0xF05A: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xF05B: 0x9925, //CJK UNIFIED IDEOGRAPH + 0xF05C: 0x9926, //CJK UNIFIED IDEOGRAPH + 0xF05D: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xF05E: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xF05F: 0x9929, //CJK UNIFIED IDEOGRAPH + 0xF060: 0x992A, //CJK UNIFIED IDEOGRAPH + 0xF061: 0x992B, //CJK UNIFIED IDEOGRAPH + 0xF062: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xF063: 0x992D, //CJK UNIFIED IDEOGRAPH + 0xF064: 0x992F, //CJK UNIFIED IDEOGRAPH + 0xF065: 0x9930, //CJK UNIFIED IDEOGRAPH + 0xF066: 0x9931, //CJK UNIFIED IDEOGRAPH + 0xF067: 0x9932, //CJK UNIFIED IDEOGRAPH + 0xF068: 0x9933, //CJK UNIFIED IDEOGRAPH + 0xF069: 0x9934, //CJK UNIFIED IDEOGRAPH + 0xF06A: 0x9935, //CJK UNIFIED IDEOGRAPH + 0xF06B: 0x9936, //CJK UNIFIED IDEOGRAPH + 0xF06C: 0x9937, //CJK UNIFIED IDEOGRAPH + 0xF06D: 0x9938, //CJK UNIFIED IDEOGRAPH + 0xF06E: 0x9939, //CJK UNIFIED IDEOGRAPH + 0xF06F: 0x993A, //CJK UNIFIED IDEOGRAPH + 0xF070: 0x993B, //CJK UNIFIED IDEOGRAPH + 0xF071: 0x993C, //CJK UNIFIED IDEOGRAPH + 0xF072: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xF073: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xF074: 0x993F, //CJK UNIFIED IDEOGRAPH + 0xF075: 0x9940, //CJK UNIFIED IDEOGRAPH + 0xF076: 0x9941, //CJK UNIFIED IDEOGRAPH + 0xF077: 0x9942, //CJK UNIFIED IDEOGRAPH + 0xF078: 0x9943, //CJK UNIFIED IDEOGRAPH + 0xF079: 0x9944, //CJK UNIFIED IDEOGRAPH + 0xF07A: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xF07B: 0x9946, //CJK UNIFIED IDEOGRAPH + 0xF07C: 0x9947, //CJK UNIFIED IDEOGRAPH + 0xF07D: 0x9948, //CJK UNIFIED IDEOGRAPH + 0xF07E: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xF080: 0x994A, //CJK UNIFIED IDEOGRAPH + 0xF081: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xF082: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF083: 0x994D, //CJK UNIFIED IDEOGRAPH + 0xF084: 0x994E, //CJK UNIFIED IDEOGRAPH + 0xF085: 0x994F, //CJK UNIFIED IDEOGRAPH + 0xF086: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xF087: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xF088: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xF089: 0x9953, //CJK UNIFIED IDEOGRAPH + 0xF08A: 0x9956, //CJK UNIFIED IDEOGRAPH + 0xF08B: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xF08C: 0x9958, //CJK UNIFIED IDEOGRAPH + 0xF08D: 0x9959, //CJK UNIFIED IDEOGRAPH + 0xF08E: 0x995A, //CJK UNIFIED IDEOGRAPH + 0xF08F: 0x995B, //CJK UNIFIED IDEOGRAPH + 0xF090: 0x995C, //CJK UNIFIED IDEOGRAPH + 0xF091: 0x995D, //CJK UNIFIED IDEOGRAPH + 0xF092: 0x995E, //CJK UNIFIED IDEOGRAPH + 0xF093: 0x995F, //CJK UNIFIED IDEOGRAPH + 0xF094: 0x9960, //CJK UNIFIED IDEOGRAPH + 0xF095: 0x9961, //CJK UNIFIED IDEOGRAPH + 0xF096: 0x9962, //CJK UNIFIED IDEOGRAPH + 0xF097: 0x9964, //CJK UNIFIED IDEOGRAPH + 0xF098: 0x9966, //CJK UNIFIED IDEOGRAPH + 0xF099: 0x9973, //CJK UNIFIED IDEOGRAPH + 0xF09A: 0x9978, //CJK UNIFIED IDEOGRAPH + 0xF09B: 0x9979, //CJK UNIFIED IDEOGRAPH + 0xF09C: 0x997B, //CJK UNIFIED IDEOGRAPH + 0xF09D: 0x997E, //CJK UNIFIED IDEOGRAPH + 0xF09E: 0x9982, //CJK UNIFIED IDEOGRAPH + 0xF09F: 0x9983, //CJK UNIFIED IDEOGRAPH + 0xF0A0: 0x9989, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x7A39, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x7A51, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x76A4, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x74DE, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x9E20, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x9E22, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x9E28, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x9E29, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x9E2A, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x9E2B, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x9E2C, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x9E32, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x9E31, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x9E36, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x9E38, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x9E37, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x9E39, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x9E3A, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x9E3E, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x9E41, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x9E42, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x9E44, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x9E46, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x9E47, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x9E48, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x9E49, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x9E4B, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x9E4C, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x9E4E, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x9E51, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x9E55, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x9E57, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x9E5A, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x9E5B, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x9E5C, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x9E5E, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x9E63, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x9E66, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x9E67, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x9E68, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x9E69, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x9E6A, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x9E6B, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x9E6C, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x9E71, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x9E6D, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x9E73, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x7592, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x7596, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x75A0, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x75AC, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x75B4, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x75C4, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x75B0, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x75C3, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x75D6, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x75E8, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x75E6, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x75E4, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x75EB, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x75E7, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x7603, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x75F1, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x7610, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x7605, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x760C, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x7617, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x760A, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x7625, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x7618, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x7615, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xF140: 0x998C, //CJK UNIFIED IDEOGRAPH + 0xF141: 0x998E, //CJK UNIFIED IDEOGRAPH + 0xF142: 0x999A, //CJK UNIFIED IDEOGRAPH + 0xF143: 0x999B, //CJK UNIFIED IDEOGRAPH + 0xF144: 0x999C, //CJK UNIFIED IDEOGRAPH + 0xF145: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xF146: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xF147: 0x999F, //CJK UNIFIED IDEOGRAPH + 0xF148: 0x99A0, //CJK UNIFIED IDEOGRAPH + 0xF149: 0x99A1, //CJK UNIFIED IDEOGRAPH + 0xF14A: 0x99A2, //CJK UNIFIED IDEOGRAPH + 0xF14B: 0x99A3, //CJK UNIFIED IDEOGRAPH + 0xF14C: 0x99A4, //CJK UNIFIED IDEOGRAPH + 0xF14D: 0x99A6, //CJK UNIFIED IDEOGRAPH + 0xF14E: 0x99A7, //CJK UNIFIED IDEOGRAPH + 0xF14F: 0x99A9, //CJK UNIFIED IDEOGRAPH + 0xF150: 0x99AA, //CJK UNIFIED IDEOGRAPH + 0xF151: 0x99AB, //CJK UNIFIED IDEOGRAPH + 0xF152: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xF153: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xF154: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xF155: 0x99AF, //CJK UNIFIED IDEOGRAPH + 0xF156: 0x99B0, //CJK UNIFIED IDEOGRAPH + 0xF157: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xF158: 0x99B2, //CJK UNIFIED IDEOGRAPH + 0xF159: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xF15A: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xF15B: 0x99B5, //CJK UNIFIED IDEOGRAPH + 0xF15C: 0x99B6, //CJK UNIFIED IDEOGRAPH + 0xF15D: 0x99B7, //CJK UNIFIED IDEOGRAPH + 0xF15E: 0x99B8, //CJK UNIFIED IDEOGRAPH + 0xF15F: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xF160: 0x99BA, //CJK UNIFIED IDEOGRAPH + 0xF161: 0x99BB, //CJK UNIFIED IDEOGRAPH + 0xF162: 0x99BC, //CJK UNIFIED IDEOGRAPH + 0xF163: 0x99BD, //CJK UNIFIED IDEOGRAPH + 0xF164: 0x99BE, //CJK UNIFIED IDEOGRAPH + 0xF165: 0x99BF, //CJK UNIFIED IDEOGRAPH + 0xF166: 0x99C0, //CJK UNIFIED IDEOGRAPH + 0xF167: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xF168: 0x99C2, //CJK UNIFIED IDEOGRAPH + 0xF169: 0x99C3, //CJK UNIFIED IDEOGRAPH + 0xF16A: 0x99C4, //CJK UNIFIED IDEOGRAPH + 0xF16B: 0x99C5, //CJK UNIFIED IDEOGRAPH + 0xF16C: 0x99C6, //CJK UNIFIED IDEOGRAPH + 0xF16D: 0x99C7, //CJK UNIFIED IDEOGRAPH + 0xF16E: 0x99C8, //CJK UNIFIED IDEOGRAPH + 0xF16F: 0x99C9, //CJK UNIFIED IDEOGRAPH + 0xF170: 0x99CA, //CJK UNIFIED IDEOGRAPH + 0xF171: 0x99CB, //CJK UNIFIED IDEOGRAPH + 0xF172: 0x99CC, //CJK UNIFIED IDEOGRAPH + 0xF173: 0x99CD, //CJK UNIFIED IDEOGRAPH + 0xF174: 0x99CE, //CJK UNIFIED IDEOGRAPH + 0xF175: 0x99CF, //CJK UNIFIED IDEOGRAPH + 0xF176: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xF177: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xF178: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xF179: 0x99D3, //CJK UNIFIED IDEOGRAPH + 0xF17A: 0x99D4, //CJK UNIFIED IDEOGRAPH + 0xF17B: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xF17C: 0x99D6, //CJK UNIFIED IDEOGRAPH + 0xF17D: 0x99D7, //CJK UNIFIED IDEOGRAPH + 0xF17E: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xF180: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xF181: 0x99DA, //CJK UNIFIED IDEOGRAPH + 0xF182: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xF183: 0x99DC, //CJK UNIFIED IDEOGRAPH + 0xF184: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xF185: 0x99DE, //CJK UNIFIED IDEOGRAPH + 0xF186: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xF187: 0x99E0, //CJK UNIFIED IDEOGRAPH + 0xF188: 0x99E1, //CJK UNIFIED IDEOGRAPH + 0xF189: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xF18A: 0x99E3, //CJK UNIFIED IDEOGRAPH + 0xF18B: 0x99E4, //CJK UNIFIED IDEOGRAPH + 0xF18C: 0x99E5, //CJK UNIFIED IDEOGRAPH + 0xF18D: 0x99E6, //CJK UNIFIED IDEOGRAPH + 0xF18E: 0x99E7, //CJK UNIFIED IDEOGRAPH + 0xF18F: 0x99E8, //CJK UNIFIED IDEOGRAPH + 0xF190: 0x99E9, //CJK UNIFIED IDEOGRAPH + 0xF191: 0x99EA, //CJK UNIFIED IDEOGRAPH + 0xF192: 0x99EB, //CJK UNIFIED IDEOGRAPH + 0xF193: 0x99EC, //CJK UNIFIED IDEOGRAPH + 0xF194: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xF195: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xF196: 0x99EF, //CJK UNIFIED IDEOGRAPH + 0xF197: 0x99F0, //CJK UNIFIED IDEOGRAPH + 0xF198: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xF199: 0x99F2, //CJK UNIFIED IDEOGRAPH + 0xF19A: 0x99F3, //CJK UNIFIED IDEOGRAPH + 0xF19B: 0x99F4, //CJK UNIFIED IDEOGRAPH + 0xF19C: 0x99F5, //CJK UNIFIED IDEOGRAPH + 0xF19D: 0x99F6, //CJK UNIFIED IDEOGRAPH + 0xF19E: 0x99F7, //CJK UNIFIED IDEOGRAPH + 0xF19F: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xF1A0: 0x99F9, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x761B, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x763C, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x7640, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x762D, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x763F, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x7635, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x7643, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x763E, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x7633, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x764D, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x765E, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x7654, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x766B, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x766F, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x7A78, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x7A80, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x7A86, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x7AA6, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x7AA0, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x7AAC, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x7AA8, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x7AAD, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x7AB3, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x8864, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x8869, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x88C6, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x88BC, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x88C9, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x88E2, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x88CE, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x88E3, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x88E5, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x88F1, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x891A, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x88F0, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x8921, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x891B, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x8934, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x897B, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x76B2, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x8014, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x8016, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x8020, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x8022, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x8025, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x8026, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x8027, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x8029, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x8031, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x8035, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x804D, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x8069, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x8071, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x9878, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x9880, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x9883, //CJK UNIFIED IDEOGRAPH + 0xF240: 0x99FA, //CJK UNIFIED IDEOGRAPH + 0xF241: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xF242: 0x99FC, //CJK UNIFIED IDEOGRAPH + 0xF243: 0x99FD, //CJK UNIFIED IDEOGRAPH + 0xF244: 0x99FE, //CJK UNIFIED IDEOGRAPH + 0xF245: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xF246: 0x9A00, //CJK UNIFIED IDEOGRAPH + 0xF247: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xF248: 0x9A02, //CJK UNIFIED IDEOGRAPH + 0xF249: 0x9A03, //CJK UNIFIED IDEOGRAPH + 0xF24A: 0x9A04, //CJK UNIFIED IDEOGRAPH + 0xF24B: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xF24C: 0x9A06, //CJK UNIFIED IDEOGRAPH + 0xF24D: 0x9A07, //CJK UNIFIED IDEOGRAPH + 0xF24E: 0x9A08, //CJK UNIFIED IDEOGRAPH + 0xF24F: 0x9A09, //CJK UNIFIED IDEOGRAPH + 0xF250: 0x9A0A, //CJK UNIFIED IDEOGRAPH + 0xF251: 0x9A0B, //CJK UNIFIED IDEOGRAPH + 0xF252: 0x9A0C, //CJK UNIFIED IDEOGRAPH + 0xF253: 0x9A0D, //CJK UNIFIED IDEOGRAPH + 0xF254: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xF255: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xF256: 0x9A10, //CJK UNIFIED IDEOGRAPH + 0xF257: 0x9A11, //CJK UNIFIED IDEOGRAPH + 0xF258: 0x9A12, //CJK UNIFIED IDEOGRAPH + 0xF259: 0x9A13, //CJK UNIFIED IDEOGRAPH + 0xF25A: 0x9A14, //CJK UNIFIED IDEOGRAPH + 0xF25B: 0x9A15, //CJK UNIFIED IDEOGRAPH + 0xF25C: 0x9A16, //CJK UNIFIED IDEOGRAPH + 0xF25D: 0x9A17, //CJK UNIFIED IDEOGRAPH + 0xF25E: 0x9A18, //CJK UNIFIED IDEOGRAPH + 0xF25F: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xF260: 0x9A1A, //CJK UNIFIED IDEOGRAPH + 0xF261: 0x9A1B, //CJK UNIFIED IDEOGRAPH + 0xF262: 0x9A1C, //CJK UNIFIED IDEOGRAPH + 0xF263: 0x9A1D, //CJK UNIFIED IDEOGRAPH + 0xF264: 0x9A1E, //CJK UNIFIED IDEOGRAPH + 0xF265: 0x9A1F, //CJK UNIFIED IDEOGRAPH + 0xF266: 0x9A20, //CJK UNIFIED IDEOGRAPH + 0xF267: 0x9A21, //CJK UNIFIED IDEOGRAPH + 0xF268: 0x9A22, //CJK UNIFIED IDEOGRAPH + 0xF269: 0x9A23, //CJK UNIFIED IDEOGRAPH + 0xF26A: 0x9A24, //CJK UNIFIED IDEOGRAPH + 0xF26B: 0x9A25, //CJK UNIFIED IDEOGRAPH + 0xF26C: 0x9A26, //CJK UNIFIED IDEOGRAPH + 0xF26D: 0x9A27, //CJK UNIFIED IDEOGRAPH + 0xF26E: 0x9A28, //CJK UNIFIED IDEOGRAPH + 0xF26F: 0x9A29, //CJK UNIFIED IDEOGRAPH + 0xF270: 0x9A2A, //CJK UNIFIED IDEOGRAPH + 0xF271: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xF272: 0x9A2C, //CJK UNIFIED IDEOGRAPH + 0xF273: 0x9A2D, //CJK UNIFIED IDEOGRAPH + 0xF274: 0x9A2E, //CJK UNIFIED IDEOGRAPH + 0xF275: 0x9A2F, //CJK UNIFIED IDEOGRAPH + 0xF276: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xF277: 0x9A31, //CJK UNIFIED IDEOGRAPH + 0xF278: 0x9A32, //CJK UNIFIED IDEOGRAPH + 0xF279: 0x9A33, //CJK UNIFIED IDEOGRAPH + 0xF27A: 0x9A34, //CJK UNIFIED IDEOGRAPH + 0xF27B: 0x9A35, //CJK UNIFIED IDEOGRAPH + 0xF27C: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF27D: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xF27E: 0x9A38, //CJK UNIFIED IDEOGRAPH + 0xF280: 0x9A39, //CJK UNIFIED IDEOGRAPH + 0xF281: 0x9A3A, //CJK UNIFIED IDEOGRAPH + 0xF282: 0x9A3B, //CJK UNIFIED IDEOGRAPH + 0xF283: 0x9A3C, //CJK UNIFIED IDEOGRAPH + 0xF284: 0x9A3D, //CJK UNIFIED IDEOGRAPH + 0xF285: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xF286: 0x9A3F, //CJK UNIFIED IDEOGRAPH + 0xF287: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xF288: 0x9A41, //CJK UNIFIED IDEOGRAPH + 0xF289: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xF28A: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xF28B: 0x9A44, //CJK UNIFIED IDEOGRAPH + 0xF28C: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xF28D: 0x9A46, //CJK UNIFIED IDEOGRAPH + 0xF28E: 0x9A47, //CJK UNIFIED IDEOGRAPH + 0xF28F: 0x9A48, //CJK UNIFIED IDEOGRAPH + 0xF290: 0x9A49, //CJK UNIFIED IDEOGRAPH + 0xF291: 0x9A4A, //CJK UNIFIED IDEOGRAPH + 0xF292: 0x9A4B, //CJK UNIFIED IDEOGRAPH + 0xF293: 0x9A4C, //CJK UNIFIED IDEOGRAPH + 0xF294: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xF295: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xF296: 0x9A4F, //CJK UNIFIED IDEOGRAPH + 0xF297: 0x9A50, //CJK UNIFIED IDEOGRAPH + 0xF298: 0x9A51, //CJK UNIFIED IDEOGRAPH + 0xF299: 0x9A52, //CJK UNIFIED IDEOGRAPH + 0xF29A: 0x9A53, //CJK UNIFIED IDEOGRAPH + 0xF29B: 0x9A54, //CJK UNIFIED IDEOGRAPH + 0xF29C: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xF29D: 0x9A56, //CJK UNIFIED IDEOGRAPH + 0xF29E: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xF29F: 0x9A58, //CJK UNIFIED IDEOGRAPH + 0xF2A0: 0x9A59, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x9889, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x988C, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x988D, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x988F, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x9894, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x989A, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x989B, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x989E, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x989F, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x98A1, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x98A2, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x98A5, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x98A6, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x866C, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x866E, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x867F, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x867A, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x867C, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x867B, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x86A8, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x868D, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x86AC, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x869D, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x86A7, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xF2BE: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x86B5, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x86CE, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x86BA, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x86B1, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x86CF, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x86B4, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x86F1, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x86F2, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x86F3, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x86D0, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x8713, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x86F4, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x86D8, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x86D1, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x8707, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x8723, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x871E, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x872E, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x873E, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x8748, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x8731, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x8722, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x877D, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x877E, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x877B, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x8770, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x878B, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x877C, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x8764, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0x8765, //CJK UNIFIED IDEOGRAPH + 0xF2FB: 0x8793, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x87A8, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xF340: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xF341: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xF342: 0x9A5C, //CJK UNIFIED IDEOGRAPH + 0xF343: 0x9A5D, //CJK UNIFIED IDEOGRAPH + 0xF344: 0x9A5E, //CJK UNIFIED IDEOGRAPH + 0xF345: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xF346: 0x9A60, //CJK UNIFIED IDEOGRAPH + 0xF347: 0x9A61, //CJK UNIFIED IDEOGRAPH + 0xF348: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xF349: 0x9A63, //CJK UNIFIED IDEOGRAPH + 0xF34A: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xF34B: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xF34C: 0x9A66, //CJK UNIFIED IDEOGRAPH + 0xF34D: 0x9A67, //CJK UNIFIED IDEOGRAPH + 0xF34E: 0x9A68, //CJK UNIFIED IDEOGRAPH + 0xF34F: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xF350: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xF351: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xF352: 0x9A72, //CJK UNIFIED IDEOGRAPH + 0xF353: 0x9A83, //CJK UNIFIED IDEOGRAPH + 0xF354: 0x9A89, //CJK UNIFIED IDEOGRAPH + 0xF355: 0x9A8D, //CJK UNIFIED IDEOGRAPH + 0xF356: 0x9A8E, //CJK UNIFIED IDEOGRAPH + 0xF357: 0x9A94, //CJK UNIFIED IDEOGRAPH + 0xF358: 0x9A95, //CJK UNIFIED IDEOGRAPH + 0xF359: 0x9A99, //CJK UNIFIED IDEOGRAPH + 0xF35A: 0x9AA6, //CJK UNIFIED IDEOGRAPH + 0xF35B: 0x9AA9, //CJK UNIFIED IDEOGRAPH + 0xF35C: 0x9AAA, //CJK UNIFIED IDEOGRAPH + 0xF35D: 0x9AAB, //CJK UNIFIED IDEOGRAPH + 0xF35E: 0x9AAC, //CJK UNIFIED IDEOGRAPH + 0xF35F: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xF360: 0x9AAE, //CJK UNIFIED IDEOGRAPH + 0xF361: 0x9AAF, //CJK UNIFIED IDEOGRAPH + 0xF362: 0x9AB2, //CJK UNIFIED IDEOGRAPH + 0xF363: 0x9AB3, //CJK UNIFIED IDEOGRAPH + 0xF364: 0x9AB4, //CJK UNIFIED IDEOGRAPH + 0xF365: 0x9AB5, //CJK UNIFIED IDEOGRAPH + 0xF366: 0x9AB9, //CJK UNIFIED IDEOGRAPH + 0xF367: 0x9ABB, //CJK UNIFIED IDEOGRAPH + 0xF368: 0x9ABD, //CJK UNIFIED IDEOGRAPH + 0xF369: 0x9ABE, //CJK UNIFIED IDEOGRAPH + 0xF36A: 0x9ABF, //CJK UNIFIED IDEOGRAPH + 0xF36B: 0x9AC3, //CJK UNIFIED IDEOGRAPH + 0xF36C: 0x9AC4, //CJK UNIFIED IDEOGRAPH + 0xF36D: 0x9AC6, //CJK UNIFIED IDEOGRAPH + 0xF36E: 0x9AC7, //CJK UNIFIED IDEOGRAPH + 0xF36F: 0x9AC8, //CJK UNIFIED IDEOGRAPH + 0xF370: 0x9AC9, //CJK UNIFIED IDEOGRAPH + 0xF371: 0x9ACA, //CJK UNIFIED IDEOGRAPH + 0xF372: 0x9ACD, //CJK UNIFIED IDEOGRAPH + 0xF373: 0x9ACE, //CJK UNIFIED IDEOGRAPH + 0xF374: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xF375: 0x9AD0, //CJK UNIFIED IDEOGRAPH + 0xF376: 0x9AD2, //CJK UNIFIED IDEOGRAPH + 0xF377: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xF378: 0x9AD5, //CJK UNIFIED IDEOGRAPH + 0xF379: 0x9AD6, //CJK UNIFIED IDEOGRAPH + 0xF37A: 0x9AD7, //CJK UNIFIED IDEOGRAPH + 0xF37B: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xF37C: 0x9ADA, //CJK UNIFIED IDEOGRAPH + 0xF37D: 0x9ADB, //CJK UNIFIED IDEOGRAPH + 0xF37E: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xF380: 0x9ADD, //CJK UNIFIED IDEOGRAPH + 0xF381: 0x9ADE, //CJK UNIFIED IDEOGRAPH + 0xF382: 0x9AE0, //CJK UNIFIED IDEOGRAPH + 0xF383: 0x9AE2, //CJK UNIFIED IDEOGRAPH + 0xF384: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xF385: 0x9AE4, //CJK UNIFIED IDEOGRAPH + 0xF386: 0x9AE5, //CJK UNIFIED IDEOGRAPH + 0xF387: 0x9AE7, //CJK UNIFIED IDEOGRAPH + 0xF388: 0x9AE8, //CJK UNIFIED IDEOGRAPH + 0xF389: 0x9AE9, //CJK UNIFIED IDEOGRAPH + 0xF38A: 0x9AEA, //CJK UNIFIED IDEOGRAPH + 0xF38B: 0x9AEC, //CJK UNIFIED IDEOGRAPH + 0xF38C: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xF38D: 0x9AF0, //CJK UNIFIED IDEOGRAPH + 0xF38E: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xF38F: 0x9AF2, //CJK UNIFIED IDEOGRAPH + 0xF390: 0x9AF3, //CJK UNIFIED IDEOGRAPH + 0xF391: 0x9AF4, //CJK UNIFIED IDEOGRAPH + 0xF392: 0x9AF5, //CJK UNIFIED IDEOGRAPH + 0xF393: 0x9AF6, //CJK UNIFIED IDEOGRAPH + 0xF394: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xF395: 0x9AF8, //CJK UNIFIED IDEOGRAPH + 0xF396: 0x9AFA, //CJK UNIFIED IDEOGRAPH + 0xF397: 0x9AFC, //CJK UNIFIED IDEOGRAPH + 0xF398: 0x9AFD, //CJK UNIFIED IDEOGRAPH + 0xF399: 0x9AFE, //CJK UNIFIED IDEOGRAPH + 0xF39A: 0x9AFF, //CJK UNIFIED IDEOGRAPH + 0xF39B: 0x9B00, //CJK UNIFIED IDEOGRAPH + 0xF39C: 0x9B01, //CJK UNIFIED IDEOGRAPH + 0xF39D: 0x9B02, //CJK UNIFIED IDEOGRAPH + 0xF39E: 0x9B04, //CJK UNIFIED IDEOGRAPH + 0xF39F: 0x9B05, //CJK UNIFIED IDEOGRAPH + 0xF3A0: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x8788, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x8785, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x87AD, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x8797, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x8783, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x87E5, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x87AC, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x87B5, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x87D3, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x87D1, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0x87CA, //CJK UNIFIED IDEOGRAPH + 0xF3B2: 0x87DB, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x87EA, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x87EE, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x8813, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x880A, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x881B, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x883C, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x7F42, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x7F44, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x7AFD, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x7B03, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x7B15, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x7B2B, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x7B47, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x7B38, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x7B2A, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x7B2E, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x7B31, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x7B24, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x7B3E, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x7B58, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x7B5A, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x7B5D, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x7B7B, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x7B62, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x7B72, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x7B90, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x7BA6, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x7BA7, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x7BAC, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x7BA8, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x7B85, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x7BAA, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x7BA2, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x7BAB, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x7BD1, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x7BDA, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x7BEA, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x7C0C, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x7BFE, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x7BFC, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x7C0F, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x7C16, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x7C0B, //CJK UNIFIED IDEOGRAPH + 0xF440: 0x9B07, //CJK UNIFIED IDEOGRAPH + 0xF441: 0x9B09, //CJK UNIFIED IDEOGRAPH + 0xF442: 0x9B0A, //CJK UNIFIED IDEOGRAPH + 0xF443: 0x9B0B, //CJK UNIFIED IDEOGRAPH + 0xF444: 0x9B0C, //CJK UNIFIED IDEOGRAPH + 0xF445: 0x9B0D, //CJK UNIFIED IDEOGRAPH + 0xF446: 0x9B0E, //CJK UNIFIED IDEOGRAPH + 0xF447: 0x9B10, //CJK UNIFIED IDEOGRAPH + 0xF448: 0x9B11, //CJK UNIFIED IDEOGRAPH + 0xF449: 0x9B12, //CJK UNIFIED IDEOGRAPH + 0xF44A: 0x9B14, //CJK UNIFIED IDEOGRAPH + 0xF44B: 0x9B15, //CJK UNIFIED IDEOGRAPH + 0xF44C: 0x9B16, //CJK UNIFIED IDEOGRAPH + 0xF44D: 0x9B17, //CJK UNIFIED IDEOGRAPH + 0xF44E: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xF44F: 0x9B19, //CJK UNIFIED IDEOGRAPH + 0xF450: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xF451: 0x9B1B, //CJK UNIFIED IDEOGRAPH + 0xF452: 0x9B1C, //CJK UNIFIED IDEOGRAPH + 0xF453: 0x9B1D, //CJK UNIFIED IDEOGRAPH + 0xF454: 0x9B1E, //CJK UNIFIED IDEOGRAPH + 0xF455: 0x9B20, //CJK UNIFIED IDEOGRAPH + 0xF456: 0x9B21, //CJK UNIFIED IDEOGRAPH + 0xF457: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xF458: 0x9B24, //CJK UNIFIED IDEOGRAPH + 0xF459: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xF45A: 0x9B26, //CJK UNIFIED IDEOGRAPH + 0xF45B: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xF45C: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xF45D: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xF45E: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xF45F: 0x9B2B, //CJK UNIFIED IDEOGRAPH + 0xF460: 0x9B2C, //CJK UNIFIED IDEOGRAPH + 0xF461: 0x9B2D, //CJK UNIFIED IDEOGRAPH + 0xF462: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xF463: 0x9B30, //CJK UNIFIED IDEOGRAPH + 0xF464: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xF465: 0x9B33, //CJK UNIFIED IDEOGRAPH + 0xF466: 0x9B34, //CJK UNIFIED IDEOGRAPH + 0xF467: 0x9B35, //CJK UNIFIED IDEOGRAPH + 0xF468: 0x9B36, //CJK UNIFIED IDEOGRAPH + 0xF469: 0x9B37, //CJK UNIFIED IDEOGRAPH + 0xF46A: 0x9B38, //CJK UNIFIED IDEOGRAPH + 0xF46B: 0x9B39, //CJK UNIFIED IDEOGRAPH + 0xF46C: 0x9B3A, //CJK UNIFIED IDEOGRAPH + 0xF46D: 0x9B3D, //CJK UNIFIED IDEOGRAPH + 0xF46E: 0x9B3E, //CJK UNIFIED IDEOGRAPH + 0xF46F: 0x9B3F, //CJK UNIFIED IDEOGRAPH + 0xF470: 0x9B40, //CJK UNIFIED IDEOGRAPH + 0xF471: 0x9B46, //CJK UNIFIED IDEOGRAPH + 0xF472: 0x9B4A, //CJK UNIFIED IDEOGRAPH + 0xF473: 0x9B4B, //CJK UNIFIED IDEOGRAPH + 0xF474: 0x9B4C, //CJK UNIFIED IDEOGRAPH + 0xF475: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xF476: 0x9B50, //CJK UNIFIED IDEOGRAPH + 0xF477: 0x9B52, //CJK UNIFIED IDEOGRAPH + 0xF478: 0x9B53, //CJK UNIFIED IDEOGRAPH + 0xF479: 0x9B55, //CJK UNIFIED IDEOGRAPH + 0xF47A: 0x9B56, //CJK UNIFIED IDEOGRAPH + 0xF47B: 0x9B57, //CJK UNIFIED IDEOGRAPH + 0xF47C: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xF47D: 0x9B59, //CJK UNIFIED IDEOGRAPH + 0xF47E: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xF480: 0x9B5B, //CJK UNIFIED IDEOGRAPH + 0xF481: 0x9B5C, //CJK UNIFIED IDEOGRAPH + 0xF482: 0x9B5D, //CJK UNIFIED IDEOGRAPH + 0xF483: 0x9B5E, //CJK UNIFIED IDEOGRAPH + 0xF484: 0x9B5F, //CJK UNIFIED IDEOGRAPH + 0xF485: 0x9B60, //CJK UNIFIED IDEOGRAPH + 0xF486: 0x9B61, //CJK UNIFIED IDEOGRAPH + 0xF487: 0x9B62, //CJK UNIFIED IDEOGRAPH + 0xF488: 0x9B63, //CJK UNIFIED IDEOGRAPH + 0xF489: 0x9B64, //CJK UNIFIED IDEOGRAPH + 0xF48A: 0x9B65, //CJK UNIFIED IDEOGRAPH + 0xF48B: 0x9B66, //CJK UNIFIED IDEOGRAPH + 0xF48C: 0x9B67, //CJK UNIFIED IDEOGRAPH + 0xF48D: 0x9B68, //CJK UNIFIED IDEOGRAPH + 0xF48E: 0x9B69, //CJK UNIFIED IDEOGRAPH + 0xF48F: 0x9B6A, //CJK UNIFIED IDEOGRAPH + 0xF490: 0x9B6B, //CJK UNIFIED IDEOGRAPH + 0xF491: 0x9B6C, //CJK UNIFIED IDEOGRAPH + 0xF492: 0x9B6D, //CJK UNIFIED IDEOGRAPH + 0xF493: 0x9B6E, //CJK UNIFIED IDEOGRAPH + 0xF494: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xF495: 0x9B70, //CJK UNIFIED IDEOGRAPH + 0xF496: 0x9B71, //CJK UNIFIED IDEOGRAPH + 0xF497: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xF498: 0x9B73, //CJK UNIFIED IDEOGRAPH + 0xF499: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xF49A: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xF49B: 0x9B76, //CJK UNIFIED IDEOGRAPH + 0xF49C: 0x9B77, //CJK UNIFIED IDEOGRAPH + 0xF49D: 0x9B78, //CJK UNIFIED IDEOGRAPH + 0xF49E: 0x9B79, //CJK UNIFIED IDEOGRAPH + 0xF49F: 0x9B7A, //CJK UNIFIED IDEOGRAPH + 0xF4A0: 0x9B7B, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x7C26, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x7C41, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xF4A8: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x8204, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x81EC, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x8222, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x8223, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x822D, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x822F, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8228, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x823B, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x8234, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x823E, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x8244, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x8249, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x824B, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x824F, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8885, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x7F9F, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x7FA7, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x7FB0, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x7C7C, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x6549, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x7C91, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x7C9D, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x7C9C, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x7C9E, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x7CBC, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x7CC1, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x7CC7, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x7CCC, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x7CCD, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x7CC8, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x7CD7, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x7CE8, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x66A8, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x7FBF, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x7FE5, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x7FEE, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x7D77, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x7DA6, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xF4EF: 0x9EB8, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x8D84, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x8D94, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x8D91, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x8DB1, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x8C47, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x8C49, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x9150, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x914F, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x9164, //CJK UNIFIED IDEOGRAPH + 0xF540: 0x9B7C, //CJK UNIFIED IDEOGRAPH + 0xF541: 0x9B7D, //CJK UNIFIED IDEOGRAPH + 0xF542: 0x9B7E, //CJK UNIFIED IDEOGRAPH + 0xF543: 0x9B7F, //CJK UNIFIED IDEOGRAPH + 0xF544: 0x9B80, //CJK UNIFIED IDEOGRAPH + 0xF545: 0x9B81, //CJK UNIFIED IDEOGRAPH + 0xF546: 0x9B82, //CJK UNIFIED IDEOGRAPH + 0xF547: 0x9B83, //CJK UNIFIED IDEOGRAPH + 0xF548: 0x9B84, //CJK UNIFIED IDEOGRAPH + 0xF549: 0x9B85, //CJK UNIFIED IDEOGRAPH + 0xF54A: 0x9B86, //CJK UNIFIED IDEOGRAPH + 0xF54B: 0x9B87, //CJK UNIFIED IDEOGRAPH + 0xF54C: 0x9B88, //CJK UNIFIED IDEOGRAPH + 0xF54D: 0x9B89, //CJK UNIFIED IDEOGRAPH + 0xF54E: 0x9B8A, //CJK UNIFIED IDEOGRAPH + 0xF54F: 0x9B8B, //CJK UNIFIED IDEOGRAPH + 0xF550: 0x9B8C, //CJK UNIFIED IDEOGRAPH + 0xF551: 0x9B8D, //CJK UNIFIED IDEOGRAPH + 0xF552: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0xF553: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xF554: 0x9B90, //CJK UNIFIED IDEOGRAPH + 0xF555: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xF556: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0xF557: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xF558: 0x9B94, //CJK UNIFIED IDEOGRAPH + 0xF559: 0x9B95, //CJK UNIFIED IDEOGRAPH + 0xF55A: 0x9B96, //CJK UNIFIED IDEOGRAPH + 0xF55B: 0x9B97, //CJK UNIFIED IDEOGRAPH + 0xF55C: 0x9B98, //CJK UNIFIED IDEOGRAPH + 0xF55D: 0x9B99, //CJK UNIFIED IDEOGRAPH + 0xF55E: 0x9B9A, //CJK UNIFIED IDEOGRAPH + 0xF55F: 0x9B9B, //CJK UNIFIED IDEOGRAPH + 0xF560: 0x9B9C, //CJK UNIFIED IDEOGRAPH + 0xF561: 0x9B9D, //CJK UNIFIED IDEOGRAPH + 0xF562: 0x9B9E, //CJK UNIFIED IDEOGRAPH + 0xF563: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xF564: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xF565: 0x9BA1, //CJK UNIFIED IDEOGRAPH + 0xF566: 0x9BA2, //CJK UNIFIED IDEOGRAPH + 0xF567: 0x9BA3, //CJK UNIFIED IDEOGRAPH + 0xF568: 0x9BA4, //CJK UNIFIED IDEOGRAPH + 0xF569: 0x9BA5, //CJK UNIFIED IDEOGRAPH + 0xF56A: 0x9BA6, //CJK UNIFIED IDEOGRAPH + 0xF56B: 0x9BA7, //CJK UNIFIED IDEOGRAPH + 0xF56C: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xF56D: 0x9BA9, //CJK UNIFIED IDEOGRAPH + 0xF56E: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0xF56F: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xF570: 0x9BAC, //CJK UNIFIED IDEOGRAPH + 0xF571: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0xF572: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xF573: 0x9BAF, //CJK UNIFIED IDEOGRAPH + 0xF574: 0x9BB0, //CJK UNIFIED IDEOGRAPH + 0xF575: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xF576: 0x9BB2, //CJK UNIFIED IDEOGRAPH + 0xF577: 0x9BB3, //CJK UNIFIED IDEOGRAPH + 0xF578: 0x9BB4, //CJK UNIFIED IDEOGRAPH + 0xF579: 0x9BB5, //CJK UNIFIED IDEOGRAPH + 0xF57A: 0x9BB6, //CJK UNIFIED IDEOGRAPH + 0xF57B: 0x9BB7, //CJK UNIFIED IDEOGRAPH + 0xF57C: 0x9BB8, //CJK UNIFIED IDEOGRAPH + 0xF57D: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xF57E: 0x9BBA, //CJK UNIFIED IDEOGRAPH + 0xF580: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xF581: 0x9BBC, //CJK UNIFIED IDEOGRAPH + 0xF582: 0x9BBD, //CJK UNIFIED IDEOGRAPH + 0xF583: 0x9BBE, //CJK UNIFIED IDEOGRAPH + 0xF584: 0x9BBF, //CJK UNIFIED IDEOGRAPH + 0xF585: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xF586: 0x9BC1, //CJK UNIFIED IDEOGRAPH + 0xF587: 0x9BC2, //CJK UNIFIED IDEOGRAPH + 0xF588: 0x9BC3, //CJK UNIFIED IDEOGRAPH + 0xF589: 0x9BC4, //CJK UNIFIED IDEOGRAPH + 0xF58A: 0x9BC5, //CJK UNIFIED IDEOGRAPH + 0xF58B: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xF58C: 0x9BC7, //CJK UNIFIED IDEOGRAPH + 0xF58D: 0x9BC8, //CJK UNIFIED IDEOGRAPH + 0xF58E: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xF58F: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xF590: 0x9BCB, //CJK UNIFIED IDEOGRAPH + 0xF591: 0x9BCC, //CJK UNIFIED IDEOGRAPH + 0xF592: 0x9BCD, //CJK UNIFIED IDEOGRAPH + 0xF593: 0x9BCE, //CJK UNIFIED IDEOGRAPH + 0xF594: 0x9BCF, //CJK UNIFIED IDEOGRAPH + 0xF595: 0x9BD0, //CJK UNIFIED IDEOGRAPH + 0xF596: 0x9BD1, //CJK UNIFIED IDEOGRAPH + 0xF597: 0x9BD2, //CJK UNIFIED IDEOGRAPH + 0xF598: 0x9BD3, //CJK UNIFIED IDEOGRAPH + 0xF599: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xF59A: 0x9BD5, //CJK UNIFIED IDEOGRAPH + 0xF59B: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xF59C: 0x9BD7, //CJK UNIFIED IDEOGRAPH + 0xF59D: 0x9BD8, //CJK UNIFIED IDEOGRAPH + 0xF59E: 0x9BD9, //CJK UNIFIED IDEOGRAPH + 0xF59F: 0x9BDA, //CJK UNIFIED IDEOGRAPH + 0xF5A0: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x9161, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x9170, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x916F, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x917D, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x917E, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x9174, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x9179, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x918C, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x9185, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x9190, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x9191, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x91A3, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x91AD, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x9E7E, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x8DB8, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x8E05, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x8E69, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x8DB5, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x8DBF, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x8DBC, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x8DC4, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x8DD7, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x8DDE, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x8DCE, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x8DEC, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x8DF7, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x8DF8, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x8DF9, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x8DFB, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x8DE4, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x8DFD, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x8E14, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x8E2C, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x8E2E, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x8E23, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x8E2F, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x8E3A, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x8E40, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x8E39, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x8E3D, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x8E31, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x8E41, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x8E51, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x8E52, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x8E70, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x8E6F, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x8E8F, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x8E90, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x8E9C, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x8E9E, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x89D6, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x89DE, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xF640: 0x9BDC, //CJK UNIFIED IDEOGRAPH + 0xF641: 0x9BDD, //CJK UNIFIED IDEOGRAPH + 0xF642: 0x9BDE, //CJK UNIFIED IDEOGRAPH + 0xF643: 0x9BDF, //CJK UNIFIED IDEOGRAPH + 0xF644: 0x9BE0, //CJK UNIFIED IDEOGRAPH + 0xF645: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xF646: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xF647: 0x9BE3, //CJK UNIFIED IDEOGRAPH + 0xF648: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xF649: 0x9BE5, //CJK UNIFIED IDEOGRAPH + 0xF64A: 0x9BE6, //CJK UNIFIED IDEOGRAPH + 0xF64B: 0x9BE7, //CJK UNIFIED IDEOGRAPH + 0xF64C: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xF64D: 0x9BE9, //CJK UNIFIED IDEOGRAPH + 0xF64E: 0x9BEA, //CJK UNIFIED IDEOGRAPH + 0xF64F: 0x9BEB, //CJK UNIFIED IDEOGRAPH + 0xF650: 0x9BEC, //CJK UNIFIED IDEOGRAPH + 0xF651: 0x9BED, //CJK UNIFIED IDEOGRAPH + 0xF652: 0x9BEE, //CJK UNIFIED IDEOGRAPH + 0xF653: 0x9BEF, //CJK UNIFIED IDEOGRAPH + 0xF654: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xF655: 0x9BF1, //CJK UNIFIED IDEOGRAPH + 0xF656: 0x9BF2, //CJK UNIFIED IDEOGRAPH + 0xF657: 0x9BF3, //CJK UNIFIED IDEOGRAPH + 0xF658: 0x9BF4, //CJK UNIFIED IDEOGRAPH + 0xF659: 0x9BF5, //CJK UNIFIED IDEOGRAPH + 0xF65A: 0x9BF6, //CJK UNIFIED IDEOGRAPH + 0xF65B: 0x9BF7, //CJK UNIFIED IDEOGRAPH + 0xF65C: 0x9BF8, //CJK UNIFIED IDEOGRAPH + 0xF65D: 0x9BF9, //CJK UNIFIED IDEOGRAPH + 0xF65E: 0x9BFA, //CJK UNIFIED IDEOGRAPH + 0xF65F: 0x9BFB, //CJK UNIFIED IDEOGRAPH + 0xF660: 0x9BFC, //CJK UNIFIED IDEOGRAPH + 0xF661: 0x9BFD, //CJK UNIFIED IDEOGRAPH + 0xF662: 0x9BFE, //CJK UNIFIED IDEOGRAPH + 0xF663: 0x9BFF, //CJK UNIFIED IDEOGRAPH + 0xF664: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xF665: 0x9C01, //CJK UNIFIED IDEOGRAPH + 0xF666: 0x9C02, //CJK UNIFIED IDEOGRAPH + 0xF667: 0x9C03, //CJK UNIFIED IDEOGRAPH + 0xF668: 0x9C04, //CJK UNIFIED IDEOGRAPH + 0xF669: 0x9C05, //CJK UNIFIED IDEOGRAPH + 0xF66A: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xF66B: 0x9C07, //CJK UNIFIED IDEOGRAPH + 0xF66C: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xF66D: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xF66E: 0x9C0A, //CJK UNIFIED IDEOGRAPH + 0xF66F: 0x9C0B, //CJK UNIFIED IDEOGRAPH + 0xF670: 0x9C0C, //CJK UNIFIED IDEOGRAPH + 0xF671: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xF672: 0x9C0E, //CJK UNIFIED IDEOGRAPH + 0xF673: 0x9C0F, //CJK UNIFIED IDEOGRAPH + 0xF674: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0xF675: 0x9C11, //CJK UNIFIED IDEOGRAPH + 0xF676: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xF677: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xF678: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xF679: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xF67A: 0x9C16, //CJK UNIFIED IDEOGRAPH + 0xF67B: 0x9C17, //CJK UNIFIED IDEOGRAPH + 0xF67C: 0x9C18, //CJK UNIFIED IDEOGRAPH + 0xF67D: 0x9C19, //CJK UNIFIED IDEOGRAPH + 0xF67E: 0x9C1A, //CJK UNIFIED IDEOGRAPH + 0xF680: 0x9C1B, //CJK UNIFIED IDEOGRAPH + 0xF681: 0x9C1C, //CJK UNIFIED IDEOGRAPH + 0xF682: 0x9C1D, //CJK UNIFIED IDEOGRAPH + 0xF683: 0x9C1E, //CJK UNIFIED IDEOGRAPH + 0xF684: 0x9C1F, //CJK UNIFIED IDEOGRAPH + 0xF685: 0x9C20, //CJK UNIFIED IDEOGRAPH + 0xF686: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xF687: 0x9C22, //CJK UNIFIED IDEOGRAPH + 0xF688: 0x9C23, //CJK UNIFIED IDEOGRAPH + 0xF689: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xF68A: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xF68B: 0x9C26, //CJK UNIFIED IDEOGRAPH + 0xF68C: 0x9C27, //CJK UNIFIED IDEOGRAPH + 0xF68D: 0x9C28, //CJK UNIFIED IDEOGRAPH + 0xF68E: 0x9C29, //CJK UNIFIED IDEOGRAPH + 0xF68F: 0x9C2A, //CJK UNIFIED IDEOGRAPH + 0xF690: 0x9C2B, //CJK UNIFIED IDEOGRAPH + 0xF691: 0x9C2C, //CJK UNIFIED IDEOGRAPH + 0xF692: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0xF693: 0x9C2E, //CJK UNIFIED IDEOGRAPH + 0xF694: 0x9C2F, //CJK UNIFIED IDEOGRAPH + 0xF695: 0x9C30, //CJK UNIFIED IDEOGRAPH + 0xF696: 0x9C31, //CJK UNIFIED IDEOGRAPH + 0xF697: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xF698: 0x9C33, //CJK UNIFIED IDEOGRAPH + 0xF699: 0x9C34, //CJK UNIFIED IDEOGRAPH + 0xF69A: 0x9C35, //CJK UNIFIED IDEOGRAPH + 0xF69B: 0x9C36, //CJK UNIFIED IDEOGRAPH + 0xF69C: 0x9C37, //CJK UNIFIED IDEOGRAPH + 0xF69D: 0x9C38, //CJK UNIFIED IDEOGRAPH + 0xF69E: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0xF69F: 0x9C3A, //CJK UNIFIED IDEOGRAPH + 0xF6A0: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x89E5, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x89EB, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x89EF, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x8A3E, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x9753, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x96F3, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x9701, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x972D, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x9F80, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x9F83, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x9F85, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x9F86, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x9F87, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x9F88, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x9F89, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x9F8A, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x9F8C, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x9EFE, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x9F0B, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x9F0D, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x96BD, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x96D2, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x96E0, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x928E, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x92AE, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x92C8, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x933E, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x936A, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x93CA, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x938F, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x943E, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x946B, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x9C7F, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x9C82, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x9C85, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x9C86, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x9C87, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x9C88, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x7A23, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x9C8B, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x9C8E, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x9C90, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x9C91, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x9C92, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x9C94, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x9C95, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x9C9A, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x9C9B, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x9C9E, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x9C9F, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x9CA0, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x9CA1, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x9CA2, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x9CA3, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x9CA5, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x9CA6, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x9CA7, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x9CA8, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x9CA9, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x9CAB, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x9CAD, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x9CAE, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x9CB0, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x9CB1, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x9CB2, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x9CB3, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x9CB4, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x9CB5, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x9CB6, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0x9CB7, //CJK UNIFIED IDEOGRAPH + 0xF6F5: 0x9CBA, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0x9CBB, //CJK UNIFIED IDEOGRAPH + 0xF6F7: 0x9CBC, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x9CBD, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x9CC4, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x9CC5, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x9CC6, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x9CC7, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x9CCA, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x9CCB, //CJK UNIFIED IDEOGRAPH + 0xF740: 0x9C3C, //CJK UNIFIED IDEOGRAPH + 0xF741: 0x9C3D, //CJK UNIFIED IDEOGRAPH + 0xF742: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xF743: 0x9C3F, //CJK UNIFIED IDEOGRAPH + 0xF744: 0x9C40, //CJK UNIFIED IDEOGRAPH + 0xF745: 0x9C41, //CJK UNIFIED IDEOGRAPH + 0xF746: 0x9C42, //CJK UNIFIED IDEOGRAPH + 0xF747: 0x9C43, //CJK UNIFIED IDEOGRAPH + 0xF748: 0x9C44, //CJK UNIFIED IDEOGRAPH + 0xF749: 0x9C45, //CJK UNIFIED IDEOGRAPH + 0xF74A: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xF74B: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xF74C: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0xF74D: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xF74E: 0x9C4A, //CJK UNIFIED IDEOGRAPH + 0xF74F: 0x9C4B, //CJK UNIFIED IDEOGRAPH + 0xF750: 0x9C4C, //CJK UNIFIED IDEOGRAPH + 0xF751: 0x9C4D, //CJK UNIFIED IDEOGRAPH + 0xF752: 0x9C4E, //CJK UNIFIED IDEOGRAPH + 0xF753: 0x9C4F, //CJK UNIFIED IDEOGRAPH + 0xF754: 0x9C50, //CJK UNIFIED IDEOGRAPH + 0xF755: 0x9C51, //CJK UNIFIED IDEOGRAPH + 0xF756: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0xF757: 0x9C53, //CJK UNIFIED IDEOGRAPH + 0xF758: 0x9C54, //CJK UNIFIED IDEOGRAPH + 0xF759: 0x9C55, //CJK UNIFIED IDEOGRAPH + 0xF75A: 0x9C56, //CJK UNIFIED IDEOGRAPH + 0xF75B: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xF75C: 0x9C58, //CJK UNIFIED IDEOGRAPH + 0xF75D: 0x9C59, //CJK UNIFIED IDEOGRAPH + 0xF75E: 0x9C5A, //CJK UNIFIED IDEOGRAPH + 0xF75F: 0x9C5B, //CJK UNIFIED IDEOGRAPH + 0xF760: 0x9C5C, //CJK UNIFIED IDEOGRAPH + 0xF761: 0x9C5D, //CJK UNIFIED IDEOGRAPH + 0xF762: 0x9C5E, //CJK UNIFIED IDEOGRAPH + 0xF763: 0x9C5F, //CJK UNIFIED IDEOGRAPH + 0xF764: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xF765: 0x9C61, //CJK UNIFIED IDEOGRAPH + 0xF766: 0x9C62, //CJK UNIFIED IDEOGRAPH + 0xF767: 0x9C63, //CJK UNIFIED IDEOGRAPH + 0xF768: 0x9C64, //CJK UNIFIED IDEOGRAPH + 0xF769: 0x9C65, //CJK UNIFIED IDEOGRAPH + 0xF76A: 0x9C66, //CJK UNIFIED IDEOGRAPH + 0xF76B: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xF76C: 0x9C68, //CJK UNIFIED IDEOGRAPH + 0xF76D: 0x9C69, //CJK UNIFIED IDEOGRAPH + 0xF76E: 0x9C6A, //CJK UNIFIED IDEOGRAPH + 0xF76F: 0x9C6B, //CJK UNIFIED IDEOGRAPH + 0xF770: 0x9C6C, //CJK UNIFIED IDEOGRAPH + 0xF771: 0x9C6D, //CJK UNIFIED IDEOGRAPH + 0xF772: 0x9C6E, //CJK UNIFIED IDEOGRAPH + 0xF773: 0x9C6F, //CJK UNIFIED IDEOGRAPH + 0xF774: 0x9C70, //CJK UNIFIED IDEOGRAPH + 0xF775: 0x9C71, //CJK UNIFIED IDEOGRAPH + 0xF776: 0x9C72, //CJK UNIFIED IDEOGRAPH + 0xF777: 0x9C73, //CJK UNIFIED IDEOGRAPH + 0xF778: 0x9C74, //CJK UNIFIED IDEOGRAPH + 0xF779: 0x9C75, //CJK UNIFIED IDEOGRAPH + 0xF77A: 0x9C76, //CJK UNIFIED IDEOGRAPH + 0xF77B: 0x9C77, //CJK UNIFIED IDEOGRAPH + 0xF77C: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xF77D: 0x9C79, //CJK UNIFIED IDEOGRAPH + 0xF77E: 0x9C7A, //CJK UNIFIED IDEOGRAPH + 0xF780: 0x9C7B, //CJK UNIFIED IDEOGRAPH + 0xF781: 0x9C7D, //CJK UNIFIED IDEOGRAPH + 0xF782: 0x9C7E, //CJK UNIFIED IDEOGRAPH + 0xF783: 0x9C80, //CJK UNIFIED IDEOGRAPH + 0xF784: 0x9C83, //CJK UNIFIED IDEOGRAPH + 0xF785: 0x9C84, //CJK UNIFIED IDEOGRAPH + 0xF786: 0x9C89, //CJK UNIFIED IDEOGRAPH + 0xF787: 0x9C8A, //CJK UNIFIED IDEOGRAPH + 0xF788: 0x9C8C, //CJK UNIFIED IDEOGRAPH + 0xF789: 0x9C8F, //CJK UNIFIED IDEOGRAPH + 0xF78A: 0x9C93, //CJK UNIFIED IDEOGRAPH + 0xF78B: 0x9C96, //CJK UNIFIED IDEOGRAPH + 0xF78C: 0x9C97, //CJK UNIFIED IDEOGRAPH + 0xF78D: 0x9C98, //CJK UNIFIED IDEOGRAPH + 0xF78E: 0x9C99, //CJK UNIFIED IDEOGRAPH + 0xF78F: 0x9C9D, //CJK UNIFIED IDEOGRAPH + 0xF790: 0x9CAA, //CJK UNIFIED IDEOGRAPH + 0xF791: 0x9CAC, //CJK UNIFIED IDEOGRAPH + 0xF792: 0x9CAF, //CJK UNIFIED IDEOGRAPH + 0xF793: 0x9CB9, //CJK UNIFIED IDEOGRAPH + 0xF794: 0x9CBE, //CJK UNIFIED IDEOGRAPH + 0xF795: 0x9CBF, //CJK UNIFIED IDEOGRAPH + 0xF796: 0x9CC0, //CJK UNIFIED IDEOGRAPH + 0xF797: 0x9CC1, //CJK UNIFIED IDEOGRAPH + 0xF798: 0x9CC2, //CJK UNIFIED IDEOGRAPH + 0xF799: 0x9CC8, //CJK UNIFIED IDEOGRAPH + 0xF79A: 0x9CC9, //CJK UNIFIED IDEOGRAPH + 0xF79B: 0x9CD1, //CJK UNIFIED IDEOGRAPH + 0xF79C: 0x9CD2, //CJK UNIFIED IDEOGRAPH + 0xF79D: 0x9CDA, //CJK UNIFIED IDEOGRAPH + 0xF79E: 0x9CDB, //CJK UNIFIED IDEOGRAPH + 0xF79F: 0x9CE0, //CJK UNIFIED IDEOGRAPH + 0xF7A0: 0x9CE1, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9CCC, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x9CCD, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x9CCE, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x9CCF, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x9CD0, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x9CD3, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x9CD4, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x9CD5, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x9CD7, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x9CD8, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x9CD9, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x9CDC, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x9CDD, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x9CDF, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x9CE2, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x9791, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x9792, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x9794, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x97AF, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0x97B2, //CJK UNIFIED IDEOGRAPH + 0xF7B9: 0x97B4, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x9AB1, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x9AB7, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x9E58, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x9AB6, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x9ABA, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x9AC1, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x9AC5, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x9AC2, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x9ACB, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x9ACC, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xF7C9: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x9B47, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x9B49, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x9B48, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x98E8, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x990D, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xF7D4: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x9AE1, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x9AF9, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x9B08, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x9B0F, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x9B13, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x9EBD, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x9E82, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x9E87, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x9EDF, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x9EE2, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x9EE9, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x9EE7, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x9EEA, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x9F22, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x9F2F, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x9F39, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x9F37, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x9F3D, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x9F44, //CJK UNIFIED IDEOGRAPH + 0xF840: 0x9CE3, //CJK UNIFIED IDEOGRAPH + 0xF841: 0x9CE4, //CJK UNIFIED IDEOGRAPH + 0xF842: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xF843: 0x9CE6, //CJK UNIFIED IDEOGRAPH + 0xF844: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xF845: 0x9CE8, //CJK UNIFIED IDEOGRAPH + 0xF846: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xF847: 0x9CEA, //CJK UNIFIED IDEOGRAPH + 0xF848: 0x9CEB, //CJK UNIFIED IDEOGRAPH + 0xF849: 0x9CEC, //CJK UNIFIED IDEOGRAPH + 0xF84A: 0x9CED, //CJK UNIFIED IDEOGRAPH + 0xF84B: 0x9CEE, //CJK UNIFIED IDEOGRAPH + 0xF84C: 0x9CEF, //CJK UNIFIED IDEOGRAPH + 0xF84D: 0x9CF0, //CJK UNIFIED IDEOGRAPH + 0xF84E: 0x9CF1, //CJK UNIFIED IDEOGRAPH + 0xF84F: 0x9CF2, //CJK UNIFIED IDEOGRAPH + 0xF850: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xF851: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xF852: 0x9CF5, //CJK UNIFIED IDEOGRAPH + 0xF853: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xF854: 0x9CF7, //CJK UNIFIED IDEOGRAPH + 0xF855: 0x9CF8, //CJK UNIFIED IDEOGRAPH + 0xF856: 0x9CF9, //CJK UNIFIED IDEOGRAPH + 0xF857: 0x9CFA, //CJK UNIFIED IDEOGRAPH + 0xF858: 0x9CFB, //CJK UNIFIED IDEOGRAPH + 0xF859: 0x9CFC, //CJK UNIFIED IDEOGRAPH + 0xF85A: 0x9CFD, //CJK UNIFIED IDEOGRAPH + 0xF85B: 0x9CFE, //CJK UNIFIED IDEOGRAPH + 0xF85C: 0x9CFF, //CJK UNIFIED IDEOGRAPH + 0xF85D: 0x9D00, //CJK UNIFIED IDEOGRAPH + 0xF85E: 0x9D01, //CJK UNIFIED IDEOGRAPH + 0xF85F: 0x9D02, //CJK UNIFIED IDEOGRAPH + 0xF860: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xF861: 0x9D04, //CJK UNIFIED IDEOGRAPH + 0xF862: 0x9D05, //CJK UNIFIED IDEOGRAPH + 0xF863: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xF864: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0xF865: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xF866: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xF867: 0x9D0A, //CJK UNIFIED IDEOGRAPH + 0xF868: 0x9D0B, //CJK UNIFIED IDEOGRAPH + 0xF869: 0x9D0C, //CJK UNIFIED IDEOGRAPH + 0xF86A: 0x9D0D, //CJK UNIFIED IDEOGRAPH + 0xF86B: 0x9D0E, //CJK UNIFIED IDEOGRAPH + 0xF86C: 0x9D0F, //CJK UNIFIED IDEOGRAPH + 0xF86D: 0x9D10, //CJK UNIFIED IDEOGRAPH + 0xF86E: 0x9D11, //CJK UNIFIED IDEOGRAPH + 0xF86F: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xF870: 0x9D13, //CJK UNIFIED IDEOGRAPH + 0xF871: 0x9D14, //CJK UNIFIED IDEOGRAPH + 0xF872: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xF873: 0x9D16, //CJK UNIFIED IDEOGRAPH + 0xF874: 0x9D17, //CJK UNIFIED IDEOGRAPH + 0xF875: 0x9D18, //CJK UNIFIED IDEOGRAPH + 0xF876: 0x9D19, //CJK UNIFIED IDEOGRAPH + 0xF877: 0x9D1A, //CJK UNIFIED IDEOGRAPH + 0xF878: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xF879: 0x9D1C, //CJK UNIFIED IDEOGRAPH + 0xF87A: 0x9D1D, //CJK UNIFIED IDEOGRAPH + 0xF87B: 0x9D1E, //CJK UNIFIED IDEOGRAPH + 0xF87C: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xF87D: 0x9D20, //CJK UNIFIED IDEOGRAPH + 0xF87E: 0x9D21, //CJK UNIFIED IDEOGRAPH + 0xF880: 0x9D22, //CJK UNIFIED IDEOGRAPH + 0xF881: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xF882: 0x9D24, //CJK UNIFIED IDEOGRAPH + 0xF883: 0x9D25, //CJK UNIFIED IDEOGRAPH + 0xF884: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xF885: 0x9D27, //CJK UNIFIED IDEOGRAPH + 0xF886: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xF887: 0x9D29, //CJK UNIFIED IDEOGRAPH + 0xF888: 0x9D2A, //CJK UNIFIED IDEOGRAPH + 0xF889: 0x9D2B, //CJK UNIFIED IDEOGRAPH + 0xF88A: 0x9D2C, //CJK UNIFIED IDEOGRAPH + 0xF88B: 0x9D2D, //CJK UNIFIED IDEOGRAPH + 0xF88C: 0x9D2E, //CJK UNIFIED IDEOGRAPH + 0xF88D: 0x9D2F, //CJK UNIFIED IDEOGRAPH + 0xF88E: 0x9D30, //CJK UNIFIED IDEOGRAPH + 0xF88F: 0x9D31, //CJK UNIFIED IDEOGRAPH + 0xF890: 0x9D32, //CJK UNIFIED IDEOGRAPH + 0xF891: 0x9D33, //CJK UNIFIED IDEOGRAPH + 0xF892: 0x9D34, //CJK UNIFIED IDEOGRAPH + 0xF893: 0x9D35, //CJK UNIFIED IDEOGRAPH + 0xF894: 0x9D36, //CJK UNIFIED IDEOGRAPH + 0xF895: 0x9D37, //CJK UNIFIED IDEOGRAPH + 0xF896: 0x9D38, //CJK UNIFIED IDEOGRAPH + 0xF897: 0x9D39, //CJK UNIFIED IDEOGRAPH + 0xF898: 0x9D3A, //CJK UNIFIED IDEOGRAPH + 0xF899: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xF89A: 0x9D3C, //CJK UNIFIED IDEOGRAPH + 0xF89B: 0x9D3D, //CJK UNIFIED IDEOGRAPH + 0xF89C: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xF89D: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xF89E: 0x9D40, //CJK UNIFIED IDEOGRAPH + 0xF89F: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xF8A0: 0x9D42, //CJK UNIFIED IDEOGRAPH + 0xF940: 0x9D43, //CJK UNIFIED IDEOGRAPH + 0xF941: 0x9D44, //CJK UNIFIED IDEOGRAPH + 0xF942: 0x9D45, //CJK UNIFIED IDEOGRAPH + 0xF943: 0x9D46, //CJK UNIFIED IDEOGRAPH + 0xF944: 0x9D47, //CJK UNIFIED IDEOGRAPH + 0xF945: 0x9D48, //CJK UNIFIED IDEOGRAPH + 0xF946: 0x9D49, //CJK UNIFIED IDEOGRAPH + 0xF947: 0x9D4A, //CJK UNIFIED IDEOGRAPH + 0xF948: 0x9D4B, //CJK UNIFIED IDEOGRAPH + 0xF949: 0x9D4C, //CJK UNIFIED IDEOGRAPH + 0xF94A: 0x9D4D, //CJK UNIFIED IDEOGRAPH + 0xF94B: 0x9D4E, //CJK UNIFIED IDEOGRAPH + 0xF94C: 0x9D4F, //CJK UNIFIED IDEOGRAPH + 0xF94D: 0x9D50, //CJK UNIFIED IDEOGRAPH + 0xF94E: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xF94F: 0x9D52, //CJK UNIFIED IDEOGRAPH + 0xF950: 0x9D53, //CJK UNIFIED IDEOGRAPH + 0xF951: 0x9D54, //CJK UNIFIED IDEOGRAPH + 0xF952: 0x9D55, //CJK UNIFIED IDEOGRAPH + 0xF953: 0x9D56, //CJK UNIFIED IDEOGRAPH + 0xF954: 0x9D57, //CJK UNIFIED IDEOGRAPH + 0xF955: 0x9D58, //CJK UNIFIED IDEOGRAPH + 0xF956: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xF957: 0x9D5A, //CJK UNIFIED IDEOGRAPH + 0xF958: 0x9D5B, //CJK UNIFIED IDEOGRAPH + 0xF959: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0xF95A: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xF95B: 0x9D5E, //CJK UNIFIED IDEOGRAPH + 0xF95C: 0x9D5F, //CJK UNIFIED IDEOGRAPH + 0xF95D: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xF95E: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xF95F: 0x9D62, //CJK UNIFIED IDEOGRAPH + 0xF960: 0x9D63, //CJK UNIFIED IDEOGRAPH + 0xF961: 0x9D64, //CJK UNIFIED IDEOGRAPH + 0xF962: 0x9D65, //CJK UNIFIED IDEOGRAPH + 0xF963: 0x9D66, //CJK UNIFIED IDEOGRAPH + 0xF964: 0x9D67, //CJK UNIFIED IDEOGRAPH + 0xF965: 0x9D68, //CJK UNIFIED IDEOGRAPH + 0xF966: 0x9D69, //CJK UNIFIED IDEOGRAPH + 0xF967: 0x9D6A, //CJK UNIFIED IDEOGRAPH + 0xF968: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xF969: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xF96A: 0x9D6D, //CJK UNIFIED IDEOGRAPH + 0xF96B: 0x9D6E, //CJK UNIFIED IDEOGRAPH + 0xF96C: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xF96D: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xF96E: 0x9D71, //CJK UNIFIED IDEOGRAPH + 0xF96F: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xF970: 0x9D73, //CJK UNIFIED IDEOGRAPH + 0xF971: 0x9D74, //CJK UNIFIED IDEOGRAPH + 0xF972: 0x9D75, //CJK UNIFIED IDEOGRAPH + 0xF973: 0x9D76, //CJK UNIFIED IDEOGRAPH + 0xF974: 0x9D77, //CJK UNIFIED IDEOGRAPH + 0xF975: 0x9D78, //CJK UNIFIED IDEOGRAPH + 0xF976: 0x9D79, //CJK UNIFIED IDEOGRAPH + 0xF977: 0x9D7A, //CJK UNIFIED IDEOGRAPH + 0xF978: 0x9D7B, //CJK UNIFIED IDEOGRAPH + 0xF979: 0x9D7C, //CJK UNIFIED IDEOGRAPH + 0xF97A: 0x9D7D, //CJK UNIFIED IDEOGRAPH + 0xF97B: 0x9D7E, //CJK UNIFIED IDEOGRAPH + 0xF97C: 0x9D7F, //CJK UNIFIED IDEOGRAPH + 0xF97D: 0x9D80, //CJK UNIFIED IDEOGRAPH + 0xF97E: 0x9D81, //CJK UNIFIED IDEOGRAPH + 0xF980: 0x9D82, //CJK UNIFIED IDEOGRAPH + 0xF981: 0x9D83, //CJK UNIFIED IDEOGRAPH + 0xF982: 0x9D84, //CJK UNIFIED IDEOGRAPH + 0xF983: 0x9D85, //CJK UNIFIED IDEOGRAPH + 0xF984: 0x9D86, //CJK UNIFIED IDEOGRAPH + 0xF985: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xF986: 0x9D88, //CJK UNIFIED IDEOGRAPH + 0xF987: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xF988: 0x9D8A, //CJK UNIFIED IDEOGRAPH + 0xF989: 0x9D8B, //CJK UNIFIED IDEOGRAPH + 0xF98A: 0x9D8C, //CJK UNIFIED IDEOGRAPH + 0xF98B: 0x9D8D, //CJK UNIFIED IDEOGRAPH + 0xF98C: 0x9D8E, //CJK UNIFIED IDEOGRAPH + 0xF98D: 0x9D8F, //CJK UNIFIED IDEOGRAPH + 0xF98E: 0x9D90, //CJK UNIFIED IDEOGRAPH + 0xF98F: 0x9D91, //CJK UNIFIED IDEOGRAPH + 0xF990: 0x9D92, //CJK UNIFIED IDEOGRAPH + 0xF991: 0x9D93, //CJK UNIFIED IDEOGRAPH + 0xF992: 0x9D94, //CJK UNIFIED IDEOGRAPH + 0xF993: 0x9D95, //CJK UNIFIED IDEOGRAPH + 0xF994: 0x9D96, //CJK UNIFIED IDEOGRAPH + 0xF995: 0x9D97, //CJK UNIFIED IDEOGRAPH + 0xF996: 0x9D98, //CJK UNIFIED IDEOGRAPH + 0xF997: 0x9D99, //CJK UNIFIED IDEOGRAPH + 0xF998: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xF999: 0x9D9B, //CJK UNIFIED IDEOGRAPH + 0xF99A: 0x9D9C, //CJK UNIFIED IDEOGRAPH + 0xF99B: 0x9D9D, //CJK UNIFIED IDEOGRAPH + 0xF99C: 0x9D9E, //CJK UNIFIED IDEOGRAPH + 0xF99D: 0x9D9F, //CJK UNIFIED IDEOGRAPH + 0xF99E: 0x9DA0, //CJK UNIFIED IDEOGRAPH + 0xF99F: 0x9DA1, //CJK UNIFIED IDEOGRAPH + 0xF9A0: 0x9DA2, //CJK UNIFIED IDEOGRAPH + 0xFA40: 0x9DA3, //CJK UNIFIED IDEOGRAPH + 0xFA41: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xFA42: 0x9DA5, //CJK UNIFIED IDEOGRAPH + 0xFA43: 0x9DA6, //CJK UNIFIED IDEOGRAPH + 0xFA44: 0x9DA7, //CJK UNIFIED IDEOGRAPH + 0xFA45: 0x9DA8, //CJK UNIFIED IDEOGRAPH + 0xFA46: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xFA47: 0x9DAA, //CJK UNIFIED IDEOGRAPH + 0xFA48: 0x9DAB, //CJK UNIFIED IDEOGRAPH + 0xFA49: 0x9DAC, //CJK UNIFIED IDEOGRAPH + 0xFA4A: 0x9DAD, //CJK UNIFIED IDEOGRAPH + 0xFA4B: 0x9DAE, //CJK UNIFIED IDEOGRAPH + 0xFA4C: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xFA4D: 0x9DB0, //CJK UNIFIED IDEOGRAPH + 0xFA4E: 0x9DB1, //CJK UNIFIED IDEOGRAPH + 0xFA4F: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xFA50: 0x9DB3, //CJK UNIFIED IDEOGRAPH + 0xFA51: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xFA52: 0x9DB5, //CJK UNIFIED IDEOGRAPH + 0xFA53: 0x9DB6, //CJK UNIFIED IDEOGRAPH + 0xFA54: 0x9DB7, //CJK UNIFIED IDEOGRAPH + 0xFA55: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xFA56: 0x9DB9, //CJK UNIFIED IDEOGRAPH + 0xFA57: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xFA58: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xFA59: 0x9DBC, //CJK UNIFIED IDEOGRAPH + 0xFA5A: 0x9DBD, //CJK UNIFIED IDEOGRAPH + 0xFA5B: 0x9DBE, //CJK UNIFIED IDEOGRAPH + 0xFA5C: 0x9DBF, //CJK UNIFIED IDEOGRAPH + 0xFA5D: 0x9DC0, //CJK UNIFIED IDEOGRAPH + 0xFA5E: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xFA5F: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xFA60: 0x9DC3, //CJK UNIFIED IDEOGRAPH + 0xFA61: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xFA62: 0x9DC5, //CJK UNIFIED IDEOGRAPH + 0xFA63: 0x9DC6, //CJK UNIFIED IDEOGRAPH + 0xFA64: 0x9DC7, //CJK UNIFIED IDEOGRAPH + 0xFA65: 0x9DC8, //CJK UNIFIED IDEOGRAPH + 0xFA66: 0x9DC9, //CJK UNIFIED IDEOGRAPH + 0xFA67: 0x9DCA, //CJK UNIFIED IDEOGRAPH + 0xFA68: 0x9DCB, //CJK UNIFIED IDEOGRAPH + 0xFA69: 0x9DCC, //CJK UNIFIED IDEOGRAPH + 0xFA6A: 0x9DCD, //CJK UNIFIED IDEOGRAPH + 0xFA6B: 0x9DCE, //CJK UNIFIED IDEOGRAPH + 0xFA6C: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xFA6D: 0x9DD0, //CJK UNIFIED IDEOGRAPH + 0xFA6E: 0x9DD1, //CJK UNIFIED IDEOGRAPH + 0xFA6F: 0x9DD2, //CJK UNIFIED IDEOGRAPH + 0xFA70: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xFA71: 0x9DD4, //CJK UNIFIED IDEOGRAPH + 0xFA72: 0x9DD5, //CJK UNIFIED IDEOGRAPH + 0xFA73: 0x9DD6, //CJK UNIFIED IDEOGRAPH + 0xFA74: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xFA75: 0x9DD8, //CJK UNIFIED IDEOGRAPH + 0xFA76: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xFA77: 0x9DDA, //CJK UNIFIED IDEOGRAPH + 0xFA78: 0x9DDB, //CJK UNIFIED IDEOGRAPH + 0xFA79: 0x9DDC, //CJK UNIFIED IDEOGRAPH + 0xFA7A: 0x9DDD, //CJK UNIFIED IDEOGRAPH + 0xFA7B: 0x9DDE, //CJK UNIFIED IDEOGRAPH + 0xFA7C: 0x9DDF, //CJK UNIFIED IDEOGRAPH + 0xFA7D: 0x9DE0, //CJK UNIFIED IDEOGRAPH + 0xFA7E: 0x9DE1, //CJK UNIFIED IDEOGRAPH + 0xFA80: 0x9DE2, //CJK UNIFIED IDEOGRAPH + 0xFA81: 0x9DE3, //CJK UNIFIED IDEOGRAPH + 0xFA82: 0x9DE4, //CJK UNIFIED IDEOGRAPH + 0xFA83: 0x9DE5, //CJK UNIFIED IDEOGRAPH + 0xFA84: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xFA85: 0x9DE7, //CJK UNIFIED IDEOGRAPH + 0xFA86: 0x9DE8, //CJK UNIFIED IDEOGRAPH + 0xFA87: 0x9DE9, //CJK UNIFIED IDEOGRAPH + 0xFA88: 0x9DEA, //CJK UNIFIED IDEOGRAPH + 0xFA89: 0x9DEB, //CJK UNIFIED IDEOGRAPH + 0xFA8A: 0x9DEC, //CJK UNIFIED IDEOGRAPH + 0xFA8B: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xFA8C: 0x9DEE, //CJK UNIFIED IDEOGRAPH + 0xFA8D: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xFA8E: 0x9DF0, //CJK UNIFIED IDEOGRAPH + 0xFA8F: 0x9DF1, //CJK UNIFIED IDEOGRAPH + 0xFA90: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xFA91: 0x9DF3, //CJK UNIFIED IDEOGRAPH + 0xFA92: 0x9DF4, //CJK UNIFIED IDEOGRAPH + 0xFA93: 0x9DF5, //CJK UNIFIED IDEOGRAPH + 0xFA94: 0x9DF6, //CJK UNIFIED IDEOGRAPH + 0xFA95: 0x9DF7, //CJK UNIFIED IDEOGRAPH + 0xFA96: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xFA97: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xFA98: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xFA99: 0x9DFB, //CJK UNIFIED IDEOGRAPH + 0xFA9A: 0x9DFC, //CJK UNIFIED IDEOGRAPH + 0xFA9B: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xFA9C: 0x9DFE, //CJK UNIFIED IDEOGRAPH + 0xFA9D: 0x9DFF, //CJK UNIFIED IDEOGRAPH + 0xFA9E: 0x9E00, //CJK UNIFIED IDEOGRAPH + 0xFA9F: 0x9E01, //CJK UNIFIED IDEOGRAPH + 0xFAA0: 0x9E02, //CJK UNIFIED IDEOGRAPH + 0xFB40: 0x9E03, //CJK UNIFIED IDEOGRAPH + 0xFB41: 0x9E04, //CJK UNIFIED IDEOGRAPH + 0xFB42: 0x9E05, //CJK UNIFIED IDEOGRAPH + 0xFB43: 0x9E06, //CJK UNIFIED IDEOGRAPH + 0xFB44: 0x9E07, //CJK UNIFIED IDEOGRAPH + 0xFB45: 0x9E08, //CJK UNIFIED IDEOGRAPH + 0xFB46: 0x9E09, //CJK UNIFIED IDEOGRAPH + 0xFB47: 0x9E0A, //CJK UNIFIED IDEOGRAPH + 0xFB48: 0x9E0B, //CJK UNIFIED IDEOGRAPH + 0xFB49: 0x9E0C, //CJK UNIFIED IDEOGRAPH + 0xFB4A: 0x9E0D, //CJK UNIFIED IDEOGRAPH + 0xFB4B: 0x9E0E, //CJK UNIFIED IDEOGRAPH + 0xFB4C: 0x9E0F, //CJK UNIFIED IDEOGRAPH + 0xFB4D: 0x9E10, //CJK UNIFIED IDEOGRAPH + 0xFB4E: 0x9E11, //CJK UNIFIED IDEOGRAPH + 0xFB4F: 0x9E12, //CJK UNIFIED IDEOGRAPH + 0xFB50: 0x9E13, //CJK UNIFIED IDEOGRAPH + 0xFB51: 0x9E14, //CJK UNIFIED IDEOGRAPH + 0xFB52: 0x9E15, //CJK UNIFIED IDEOGRAPH + 0xFB53: 0x9E16, //CJK UNIFIED IDEOGRAPH + 0xFB54: 0x9E17, //CJK UNIFIED IDEOGRAPH + 0xFB55: 0x9E18, //CJK UNIFIED IDEOGRAPH + 0xFB56: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xFB57: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xFB58: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xFB59: 0x9E1C, //CJK UNIFIED IDEOGRAPH + 0xFB5A: 0x9E1D, //CJK UNIFIED IDEOGRAPH + 0xFB5B: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xFB5C: 0x9E24, //CJK UNIFIED IDEOGRAPH + 0xFB5D: 0x9E27, //CJK UNIFIED IDEOGRAPH + 0xFB5E: 0x9E2E, //CJK UNIFIED IDEOGRAPH + 0xFB5F: 0x9E30, //CJK UNIFIED IDEOGRAPH + 0xFB60: 0x9E34, //CJK UNIFIED IDEOGRAPH + 0xFB61: 0x9E3B, //CJK UNIFIED IDEOGRAPH + 0xFB62: 0x9E3C, //CJK UNIFIED IDEOGRAPH + 0xFB63: 0x9E40, //CJK UNIFIED IDEOGRAPH + 0xFB64: 0x9E4D, //CJK UNIFIED IDEOGRAPH + 0xFB65: 0x9E50, //CJK UNIFIED IDEOGRAPH + 0xFB66: 0x9E52, //CJK UNIFIED IDEOGRAPH + 0xFB67: 0x9E53, //CJK UNIFIED IDEOGRAPH + 0xFB68: 0x9E54, //CJK UNIFIED IDEOGRAPH + 0xFB69: 0x9E56, //CJK UNIFIED IDEOGRAPH + 0xFB6A: 0x9E59, //CJK UNIFIED IDEOGRAPH + 0xFB6B: 0x9E5D, //CJK UNIFIED IDEOGRAPH + 0xFB6C: 0x9E5F, //CJK UNIFIED IDEOGRAPH + 0xFB6D: 0x9E60, //CJK UNIFIED IDEOGRAPH + 0xFB6E: 0x9E61, //CJK UNIFIED IDEOGRAPH + 0xFB6F: 0x9E62, //CJK UNIFIED IDEOGRAPH + 0xFB70: 0x9E65, //CJK UNIFIED IDEOGRAPH + 0xFB71: 0x9E6E, //CJK UNIFIED IDEOGRAPH + 0xFB72: 0x9E6F, //CJK UNIFIED IDEOGRAPH + 0xFB73: 0x9E72, //CJK UNIFIED IDEOGRAPH + 0xFB74: 0x9E74, //CJK UNIFIED IDEOGRAPH + 0xFB75: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xFB76: 0x9E76, //CJK UNIFIED IDEOGRAPH + 0xFB77: 0x9E77, //CJK UNIFIED IDEOGRAPH + 0xFB78: 0x9E78, //CJK UNIFIED IDEOGRAPH + 0xFB79: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xFB7A: 0x9E7A, //CJK UNIFIED IDEOGRAPH + 0xFB7B: 0x9E7B, //CJK UNIFIED IDEOGRAPH + 0xFB7C: 0x9E7C, //CJK UNIFIED IDEOGRAPH + 0xFB7D: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xFB7E: 0x9E80, //CJK UNIFIED IDEOGRAPH + 0xFB80: 0x9E81, //CJK UNIFIED IDEOGRAPH + 0xFB81: 0x9E83, //CJK UNIFIED IDEOGRAPH + 0xFB82: 0x9E84, //CJK UNIFIED IDEOGRAPH + 0xFB83: 0x9E85, //CJK UNIFIED IDEOGRAPH + 0xFB84: 0x9E86, //CJK UNIFIED IDEOGRAPH + 0xFB85: 0x9E89, //CJK UNIFIED IDEOGRAPH + 0xFB86: 0x9E8A, //CJK UNIFIED IDEOGRAPH + 0xFB87: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xFB88: 0x9E8D, //CJK UNIFIED IDEOGRAPH + 0xFB89: 0x9E8E, //CJK UNIFIED IDEOGRAPH + 0xFB8A: 0x9E8F, //CJK UNIFIED IDEOGRAPH + 0xFB8B: 0x9E90, //CJK UNIFIED IDEOGRAPH + 0xFB8C: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xFB8D: 0x9E94, //CJK UNIFIED IDEOGRAPH + 0xFB8E: 0x9E95, //CJK UNIFIED IDEOGRAPH + 0xFB8F: 0x9E96, //CJK UNIFIED IDEOGRAPH + 0xFB90: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xFB91: 0x9E98, //CJK UNIFIED IDEOGRAPH + 0xFB92: 0x9E99, //CJK UNIFIED IDEOGRAPH + 0xFB93: 0x9E9A, //CJK UNIFIED IDEOGRAPH + 0xFB94: 0x9E9B, //CJK UNIFIED IDEOGRAPH + 0xFB95: 0x9E9C, //CJK UNIFIED IDEOGRAPH + 0xFB96: 0x9E9E, //CJK UNIFIED IDEOGRAPH + 0xFB97: 0x9EA0, //CJK UNIFIED IDEOGRAPH + 0xFB98: 0x9EA1, //CJK UNIFIED IDEOGRAPH + 0xFB99: 0x9EA2, //CJK UNIFIED IDEOGRAPH + 0xFB9A: 0x9EA3, //CJK UNIFIED IDEOGRAPH + 0xFB9B: 0x9EA4, //CJK UNIFIED IDEOGRAPH + 0xFB9C: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xFB9D: 0x9EA7, //CJK UNIFIED IDEOGRAPH + 0xFB9E: 0x9EA8, //CJK UNIFIED IDEOGRAPH + 0xFB9F: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xFBA0: 0x9EAA, //CJK UNIFIED IDEOGRAPH + 0xFC40: 0x9EAB, //CJK UNIFIED IDEOGRAPH + 0xFC41: 0x9EAC, //CJK UNIFIED IDEOGRAPH + 0xFC42: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xFC43: 0x9EAE, //CJK UNIFIED IDEOGRAPH + 0xFC44: 0x9EAF, //CJK UNIFIED IDEOGRAPH + 0xFC45: 0x9EB0, //CJK UNIFIED IDEOGRAPH + 0xFC46: 0x9EB1, //CJK UNIFIED IDEOGRAPH + 0xFC47: 0x9EB2, //CJK UNIFIED IDEOGRAPH + 0xFC48: 0x9EB3, //CJK UNIFIED IDEOGRAPH + 0xFC49: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xFC4A: 0x9EB6, //CJK UNIFIED IDEOGRAPH + 0xFC4B: 0x9EB7, //CJK UNIFIED IDEOGRAPH + 0xFC4C: 0x9EB9, //CJK UNIFIED IDEOGRAPH + 0xFC4D: 0x9EBA, //CJK UNIFIED IDEOGRAPH + 0xFC4E: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0xFC4F: 0x9EBF, //CJK UNIFIED IDEOGRAPH + 0xFC50: 0x9EC0, //CJK UNIFIED IDEOGRAPH + 0xFC51: 0x9EC1, //CJK UNIFIED IDEOGRAPH + 0xFC52: 0x9EC2, //CJK UNIFIED IDEOGRAPH + 0xFC53: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xFC54: 0x9EC5, //CJK UNIFIED IDEOGRAPH + 0xFC55: 0x9EC6, //CJK UNIFIED IDEOGRAPH + 0xFC56: 0x9EC7, //CJK UNIFIED IDEOGRAPH + 0xFC57: 0x9EC8, //CJK UNIFIED IDEOGRAPH + 0xFC58: 0x9ECA, //CJK UNIFIED IDEOGRAPH + 0xFC59: 0x9ECB, //CJK UNIFIED IDEOGRAPH + 0xFC5A: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xFC5B: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xFC5C: 0x9ED2, //CJK UNIFIED IDEOGRAPH + 0xFC5D: 0x9ED3, //CJK UNIFIED IDEOGRAPH + 0xFC5E: 0x9ED5, //CJK UNIFIED IDEOGRAPH + 0xFC5F: 0x9ED6, //CJK UNIFIED IDEOGRAPH + 0xFC60: 0x9ED7, //CJK UNIFIED IDEOGRAPH + 0xFC61: 0x9ED9, //CJK UNIFIED IDEOGRAPH + 0xFC62: 0x9EDA, //CJK UNIFIED IDEOGRAPH + 0xFC63: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xFC64: 0x9EE1, //CJK UNIFIED IDEOGRAPH + 0xFC65: 0x9EE3, //CJK UNIFIED IDEOGRAPH + 0xFC66: 0x9EE4, //CJK UNIFIED IDEOGRAPH + 0xFC67: 0x9EE6, //CJK UNIFIED IDEOGRAPH + 0xFC68: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xFC69: 0x9EEB, //CJK UNIFIED IDEOGRAPH + 0xFC6A: 0x9EEC, //CJK UNIFIED IDEOGRAPH + 0xFC6B: 0x9EED, //CJK UNIFIED IDEOGRAPH + 0xFC6C: 0x9EEE, //CJK UNIFIED IDEOGRAPH + 0xFC6D: 0x9EF0, //CJK UNIFIED IDEOGRAPH + 0xFC6E: 0x9EF1, //CJK UNIFIED IDEOGRAPH + 0xFC6F: 0x9EF2, //CJK UNIFIED IDEOGRAPH + 0xFC70: 0x9EF3, //CJK UNIFIED IDEOGRAPH + 0xFC71: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xFC72: 0x9EF5, //CJK UNIFIED IDEOGRAPH + 0xFC73: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xFC74: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xFC75: 0x9EF8, //CJK UNIFIED IDEOGRAPH + 0xFC76: 0x9EFA, //CJK UNIFIED IDEOGRAPH + 0xFC77: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xFC78: 0x9EFF, //CJK UNIFIED IDEOGRAPH + 0xFC79: 0x9F00, //CJK UNIFIED IDEOGRAPH + 0xFC7A: 0x9F01, //CJK UNIFIED IDEOGRAPH + 0xFC7B: 0x9F02, //CJK UNIFIED IDEOGRAPH + 0xFC7C: 0x9F03, //CJK UNIFIED IDEOGRAPH + 0xFC7D: 0x9F04, //CJK UNIFIED IDEOGRAPH + 0xFC7E: 0x9F05, //CJK UNIFIED IDEOGRAPH + 0xFC80: 0x9F06, //CJK UNIFIED IDEOGRAPH + 0xFC81: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xFC82: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xFC83: 0x9F09, //CJK UNIFIED IDEOGRAPH + 0xFC84: 0x9F0A, //CJK UNIFIED IDEOGRAPH + 0xFC85: 0x9F0C, //CJK UNIFIED IDEOGRAPH + 0xFC86: 0x9F0F, //CJK UNIFIED IDEOGRAPH + 0xFC87: 0x9F11, //CJK UNIFIED IDEOGRAPH + 0xFC88: 0x9F12, //CJK UNIFIED IDEOGRAPH + 0xFC89: 0x9F14, //CJK UNIFIED IDEOGRAPH + 0xFC8A: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xFC8B: 0x9F16, //CJK UNIFIED IDEOGRAPH + 0xFC8C: 0x9F18, //CJK UNIFIED IDEOGRAPH + 0xFC8D: 0x9F1A, //CJK UNIFIED IDEOGRAPH + 0xFC8E: 0x9F1B, //CJK UNIFIED IDEOGRAPH + 0xFC8F: 0x9F1C, //CJK UNIFIED IDEOGRAPH + 0xFC90: 0x9F1D, //CJK UNIFIED IDEOGRAPH + 0xFC91: 0x9F1E, //CJK UNIFIED IDEOGRAPH + 0xFC92: 0x9F1F, //CJK UNIFIED IDEOGRAPH + 0xFC93: 0x9F21, //CJK UNIFIED IDEOGRAPH + 0xFC94: 0x9F23, //CJK UNIFIED IDEOGRAPH + 0xFC95: 0x9F24, //CJK UNIFIED IDEOGRAPH + 0xFC96: 0x9F25, //CJK UNIFIED IDEOGRAPH + 0xFC97: 0x9F26, //CJK UNIFIED IDEOGRAPH + 0xFC98: 0x9F27, //CJK UNIFIED IDEOGRAPH + 0xFC99: 0x9F28, //CJK UNIFIED IDEOGRAPH + 0xFC9A: 0x9F29, //CJK UNIFIED IDEOGRAPH + 0xFC9B: 0x9F2A, //CJK UNIFIED IDEOGRAPH + 0xFC9C: 0x9F2B, //CJK UNIFIED IDEOGRAPH + 0xFC9D: 0x9F2D, //CJK UNIFIED IDEOGRAPH + 0xFC9E: 0x9F2E, //CJK UNIFIED IDEOGRAPH + 0xFC9F: 0x9F30, //CJK UNIFIED IDEOGRAPH + 0xFCA0: 0x9F31, //CJK UNIFIED IDEOGRAPH + 0xFD40: 0x9F32, //CJK UNIFIED IDEOGRAPH + 0xFD41: 0x9F33, //CJK UNIFIED IDEOGRAPH + 0xFD42: 0x9F34, //CJK UNIFIED IDEOGRAPH + 0xFD43: 0x9F35, //CJK UNIFIED IDEOGRAPH + 0xFD44: 0x9F36, //CJK UNIFIED IDEOGRAPH + 0xFD45: 0x9F38, //CJK UNIFIED IDEOGRAPH + 0xFD46: 0x9F3A, //CJK UNIFIED IDEOGRAPH + 0xFD47: 0x9F3C, //CJK UNIFIED IDEOGRAPH + 0xFD48: 0x9F3F, //CJK UNIFIED IDEOGRAPH + 0xFD49: 0x9F40, //CJK UNIFIED IDEOGRAPH + 0xFD4A: 0x9F41, //CJK UNIFIED IDEOGRAPH + 0xFD4B: 0x9F42, //CJK UNIFIED IDEOGRAPH + 0xFD4C: 0x9F43, //CJK UNIFIED IDEOGRAPH + 0xFD4D: 0x9F45, //CJK UNIFIED IDEOGRAPH + 0xFD4E: 0x9F46, //CJK UNIFIED IDEOGRAPH + 0xFD4F: 0x9F47, //CJK UNIFIED IDEOGRAPH + 0xFD50: 0x9F48, //CJK UNIFIED IDEOGRAPH + 0xFD51: 0x9F49, //CJK UNIFIED IDEOGRAPH + 0xFD52: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xFD53: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xFD54: 0x9F4C, //CJK UNIFIED IDEOGRAPH + 0xFD55: 0x9F4D, //CJK UNIFIED IDEOGRAPH + 0xFD56: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xFD57: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xFD58: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xFD59: 0x9F53, //CJK UNIFIED IDEOGRAPH + 0xFD5A: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xFD5B: 0x9F55, //CJK UNIFIED IDEOGRAPH + 0xFD5C: 0x9F56, //CJK UNIFIED IDEOGRAPH + 0xFD5D: 0x9F57, //CJK UNIFIED IDEOGRAPH + 0xFD5E: 0x9F58, //CJK UNIFIED IDEOGRAPH + 0xFD5F: 0x9F59, //CJK UNIFIED IDEOGRAPH + 0xFD60: 0x9F5A, //CJK UNIFIED IDEOGRAPH + 0xFD61: 0x9F5B, //CJK UNIFIED IDEOGRAPH + 0xFD62: 0x9F5C, //CJK UNIFIED IDEOGRAPH + 0xFD63: 0x9F5D, //CJK UNIFIED IDEOGRAPH + 0xFD64: 0x9F5E, //CJK UNIFIED IDEOGRAPH + 0xFD65: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xFD66: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xFD67: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xFD68: 0x9F62, //CJK UNIFIED IDEOGRAPH + 0xFD69: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xFD6A: 0x9F64, //CJK UNIFIED IDEOGRAPH + 0xFD6B: 0x9F65, //CJK UNIFIED IDEOGRAPH + 0xFD6C: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xFD6D: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xFD6E: 0x9F68, //CJK UNIFIED IDEOGRAPH + 0xFD6F: 0x9F69, //CJK UNIFIED IDEOGRAPH + 0xFD70: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xFD71: 0x9F6B, //CJK UNIFIED IDEOGRAPH + 0xFD72: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xFD73: 0x9F6D, //CJK UNIFIED IDEOGRAPH + 0xFD74: 0x9F6E, //CJK UNIFIED IDEOGRAPH + 0xFD75: 0x9F6F, //CJK UNIFIED IDEOGRAPH + 0xFD76: 0x9F70, //CJK UNIFIED IDEOGRAPH + 0xFD77: 0x9F71, //CJK UNIFIED IDEOGRAPH + 0xFD78: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xFD79: 0x9F73, //CJK UNIFIED IDEOGRAPH + 0xFD7A: 0x9F74, //CJK UNIFIED IDEOGRAPH + 0xFD7B: 0x9F75, //CJK UNIFIED IDEOGRAPH + 0xFD7C: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xFD7D: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xFD7E: 0x9F78, //CJK UNIFIED IDEOGRAPH + 0xFD80: 0x9F79, //CJK UNIFIED IDEOGRAPH + 0xFD81: 0x9F7A, //CJK UNIFIED IDEOGRAPH + 0xFD82: 0x9F7B, //CJK UNIFIED IDEOGRAPH + 0xFD83: 0x9F7C, //CJK UNIFIED IDEOGRAPH + 0xFD84: 0x9F7D, //CJK UNIFIED IDEOGRAPH + 0xFD85: 0x9F7E, //CJK UNIFIED IDEOGRAPH + 0xFD86: 0x9F81, //CJK UNIFIED IDEOGRAPH + 0xFD87: 0x9F82, //CJK UNIFIED IDEOGRAPH + 0xFD88: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xFD89: 0x9F8E, //CJK UNIFIED IDEOGRAPH + 0xFD8A: 0x9F8F, //CJK UNIFIED IDEOGRAPH + 0xFD8B: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xFD8C: 0x9F91, //CJK UNIFIED IDEOGRAPH + 0xFD8D: 0x9F92, //CJK UNIFIED IDEOGRAPH + 0xFD8E: 0x9F93, //CJK UNIFIED IDEOGRAPH + 0xFD8F: 0x9F94, //CJK UNIFIED IDEOGRAPH + 0xFD90: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xFD91: 0x9F96, //CJK UNIFIED IDEOGRAPH + 0xFD92: 0x9F97, //CJK UNIFIED IDEOGRAPH + 0xFD93: 0x9F98, //CJK UNIFIED IDEOGRAPH + 0xFD94: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xFD95: 0x9F9D, //CJK UNIFIED IDEOGRAPH + 0xFD96: 0x9F9E, //CJK UNIFIED IDEOGRAPH + 0xFD97: 0x9FA1, //CJK UNIFIED IDEOGRAPH + 0xFD98: 0x9FA2, //CJK UNIFIED IDEOGRAPH + 0xFD99: 0x9FA3, //CJK UNIFIED IDEOGRAPH + 0xFD9A: 0x9FA4, //CJK UNIFIED IDEOGRAPH + 0xFD9B: 0x9FA5, //CJK UNIFIED IDEOGRAPH + 0xFD9C: 0xF92C, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9D: 0xF979, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9E: 0xF995, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9F: 0xF9E7, //CJK COMPATIBILITY IDEOGRAPH + 0xFDA0: 0xF9F1, //CJK COMPATIBILITY IDEOGRAPH + 0xFE40: 0xFA0C, //CJK COMPATIBILITY IDEOGRAPH + 0xFE41: 0xFA0D, //CJK COMPATIBILITY IDEOGRAPH + 0xFE42: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xFE43: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xFE44: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xFE45: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xFE46: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xFE47: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xFE48: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xFE49: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4A: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4B: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4C: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4D: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4E: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4F: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go new file mode 100644 index 0000000..52c708d --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go @@ -0,0 +1,17312 @@ +package cp + +var cp949 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8141: 0xAC02, //HANGUL SYLLABLE KIYEOK A SSANGKIYEOK + 0x8142: 0xAC03, //HANGUL SYLLABLE KIYEOK A KIYEOKSIOS + 0x8143: 0xAC05, //HANGUL SYLLABLE KIYEOK A NIEUNCIEUC + 0x8144: 0xAC06, //HANGUL SYLLABLE KIYEOK A NIEUNHIEUH + 0x8145: 0xAC0B, //HANGUL SYLLABLE KIYEOK A RIEULPIEUP + 0x8146: 0xAC0C, //HANGUL SYLLABLE KIYEOK A RIEULSIOS + 0x8147: 0xAC0D, //HANGUL SYLLABLE KIYEOK A RIEULTHIEUTH + 0x8148: 0xAC0E, //HANGUL SYLLABLE KIYEOK A RIEULPHIEUPH + 0x8149: 0xAC0F, //HANGUL SYLLABLE KIYEOK A RIEULHIEUH + 0x814A: 0xAC18, //HANGUL SYLLABLE KIYEOK A KHIEUKH + 0x814B: 0xAC1E, //HANGUL SYLLABLE KIYEOK AE SSANGKIYEOK + 0x814C: 0xAC1F, //HANGUL SYLLABLE KIYEOK AE KIYEOKSIOS + 0x814D: 0xAC21, //HANGUL SYLLABLE KIYEOK AE NIEUNCIEUC + 0x814E: 0xAC22, //HANGUL SYLLABLE KIYEOK AE NIEUNHIEUH + 0x814F: 0xAC23, //HANGUL SYLLABLE KIYEOK AE TIKEUT + 0x8150: 0xAC25, //HANGUL SYLLABLE KIYEOK AE RIEULKIYEOK + 0x8151: 0xAC26, //HANGUL SYLLABLE KIYEOK AE RIEULMIEUM + 0x8152: 0xAC27, //HANGUL SYLLABLE KIYEOK AE RIEULPIEUP + 0x8153: 0xAC28, //HANGUL SYLLABLE KIYEOK AE RIEULSIOS + 0x8154: 0xAC29, //HANGUL SYLLABLE KIYEOK AE RIEULTHIEUTH + 0x8155: 0xAC2A, //HANGUL SYLLABLE KIYEOK AE RIEULPHIEUPH + 0x8156: 0xAC2B, //HANGUL SYLLABLE KIYEOK AE RIEULHIEUH + 0x8157: 0xAC2E, //HANGUL SYLLABLE KIYEOK AE PIEUPSIOS + 0x8158: 0xAC32, //HANGUL SYLLABLE KIYEOK AE CIEUC + 0x8159: 0xAC33, //HANGUL SYLLABLE KIYEOK AE CHIEUCH + 0x815A: 0xAC34, //HANGUL SYLLABLE KIYEOK AE KHIEUKH + 0x8161: 0xAC35, //HANGUL SYLLABLE KIYEOK AE THIEUTH + 0x8162: 0xAC36, //HANGUL SYLLABLE KIYEOK AE PHIEUPH + 0x8163: 0xAC37, //HANGUL SYLLABLE KIYEOK AE HIEUH + 0x8164: 0xAC3A, //HANGUL SYLLABLE KIYEOK YA SSANGKIYEOK + 0x8165: 0xAC3B, //HANGUL SYLLABLE KIYEOK YA KIYEOKSIOS + 0x8166: 0xAC3D, //HANGUL SYLLABLE KIYEOK YA NIEUNCIEUC + 0x8167: 0xAC3E, //HANGUL SYLLABLE KIYEOK YA NIEUNHIEUH + 0x8168: 0xAC3F, //HANGUL SYLLABLE KIYEOK YA TIKEUT + 0x8169: 0xAC41, //HANGUL SYLLABLE KIYEOK YA RIEULKIYEOK + 0x816A: 0xAC42, //HANGUL SYLLABLE KIYEOK YA RIEULMIEUM + 0x816B: 0xAC43, //HANGUL SYLLABLE KIYEOK YA RIEULPIEUP + 0x816C: 0xAC44, //HANGUL SYLLABLE KIYEOK YA RIEULSIOS + 0x816D: 0xAC45, //HANGUL SYLLABLE KIYEOK YA RIEULTHIEUTH + 0x816E: 0xAC46, //HANGUL SYLLABLE KIYEOK YA RIEULPHIEUPH + 0x816F: 0xAC47, //HANGUL SYLLABLE KIYEOK YA RIEULHIEUH + 0x8170: 0xAC48, //HANGUL SYLLABLE KIYEOK YA MIEUM + 0x8171: 0xAC49, //HANGUL SYLLABLE KIYEOK YA PIEUP + 0x8172: 0xAC4A, //HANGUL SYLLABLE KIYEOK YA PIEUPSIOS + 0x8173: 0xAC4C, //HANGUL SYLLABLE KIYEOK YA SSANGSIOS + 0x8174: 0xAC4E, //HANGUL SYLLABLE KIYEOK YA CIEUC + 0x8175: 0xAC4F, //HANGUL SYLLABLE KIYEOK YA CHIEUCH + 0x8176: 0xAC50, //HANGUL SYLLABLE KIYEOK YA KHIEUKH + 0x8177: 0xAC51, //HANGUL SYLLABLE KIYEOK YA THIEUTH + 0x8178: 0xAC52, //HANGUL SYLLABLE KIYEOK YA PHIEUPH + 0x8179: 0xAC53, //HANGUL SYLLABLE KIYEOK YA HIEUH + 0x817A: 0xAC55, //HANGUL SYLLABLE KIYEOK YAE KIYEOK + 0x8181: 0xAC56, //HANGUL SYLLABLE KIYEOK YAE SSANGKIYEOK + 0x8182: 0xAC57, //HANGUL SYLLABLE KIYEOK YAE KIYEOKSIOS + 0x8183: 0xAC59, //HANGUL SYLLABLE KIYEOK YAE NIEUNCIEUC + 0x8184: 0xAC5A, //HANGUL SYLLABLE KIYEOK YAE NIEUNHIEUH + 0x8185: 0xAC5B, //HANGUL SYLLABLE KIYEOK YAE TIKEUT + 0x8186: 0xAC5D, //HANGUL SYLLABLE KIYEOK YAE RIEULKIYEOK + 0x8187: 0xAC5E, //HANGUL SYLLABLE KIYEOK YAE RIEULMIEUM + 0x8188: 0xAC5F, //HANGUL SYLLABLE KIYEOK YAE RIEULPIEUP + 0x8189: 0xAC60, //HANGUL SYLLABLE KIYEOK YAE RIEULSIOS + 0x818A: 0xAC61, //HANGUL SYLLABLE KIYEOK YAE RIEULTHIEUTH + 0x818B: 0xAC62, //HANGUL SYLLABLE KIYEOK YAE RIEULPHIEUPH + 0x818C: 0xAC63, //HANGUL SYLLABLE KIYEOK YAE RIEULHIEUH + 0x818D: 0xAC64, //HANGUL SYLLABLE KIYEOK YAE MIEUM + 0x818E: 0xAC65, //HANGUL SYLLABLE KIYEOK YAE PIEUP + 0x818F: 0xAC66, //HANGUL SYLLABLE KIYEOK YAE PIEUPSIOS + 0x8190: 0xAC67, //HANGUL SYLLABLE KIYEOK YAE SIOS + 0x8191: 0xAC68, //HANGUL SYLLABLE KIYEOK YAE SSANGSIOS + 0x8192: 0xAC69, //HANGUL SYLLABLE KIYEOK YAE IEUNG + 0x8193: 0xAC6A, //HANGUL SYLLABLE KIYEOK YAE CIEUC + 0x8194: 0xAC6B, //HANGUL SYLLABLE KIYEOK YAE CHIEUCH + 0x8195: 0xAC6C, //HANGUL SYLLABLE KIYEOK YAE KHIEUKH + 0x8196: 0xAC6D, //HANGUL SYLLABLE KIYEOK YAE THIEUTH + 0x8197: 0xAC6E, //HANGUL SYLLABLE KIYEOK YAE PHIEUPH + 0x8198: 0xAC6F, //HANGUL SYLLABLE KIYEOK YAE HIEUH + 0x8199: 0xAC72, //HANGUL SYLLABLE KIYEOK EO SSANGKIYEOK + 0x819A: 0xAC73, //HANGUL SYLLABLE KIYEOK EO KIYEOKSIOS + 0x819B: 0xAC75, //HANGUL SYLLABLE KIYEOK EO NIEUNCIEUC + 0x819C: 0xAC76, //HANGUL SYLLABLE KIYEOK EO NIEUNHIEUH + 0x819D: 0xAC79, //HANGUL SYLLABLE KIYEOK EO RIEULKIYEOK + 0x819E: 0xAC7B, //HANGUL SYLLABLE KIYEOK EO RIEULPIEUP + 0x819F: 0xAC7C, //HANGUL SYLLABLE KIYEOK EO RIEULSIOS + 0x81A0: 0xAC7D, //HANGUL SYLLABLE KIYEOK EO RIEULTHIEUTH + 0x81A1: 0xAC7E, //HANGUL SYLLABLE KIYEOK EO RIEULPHIEUPH + 0x81A2: 0xAC7F, //HANGUL SYLLABLE KIYEOK EO RIEULHIEUH + 0x81A3: 0xAC82, //HANGUL SYLLABLE KIYEOK EO PIEUPSIOS + 0x81A4: 0xAC87, //HANGUL SYLLABLE KIYEOK EO CHIEUCH + 0x81A5: 0xAC88, //HANGUL SYLLABLE KIYEOK EO KHIEUKH + 0x81A6: 0xAC8D, //HANGUL SYLLABLE KIYEOK E KIYEOK + 0x81A7: 0xAC8E, //HANGUL SYLLABLE KIYEOK E SSANGKIYEOK + 0x81A8: 0xAC8F, //HANGUL SYLLABLE KIYEOK E KIYEOKSIOS + 0x81A9: 0xAC91, //HANGUL SYLLABLE KIYEOK E NIEUNCIEUC + 0x81AA: 0xAC92, //HANGUL SYLLABLE KIYEOK E NIEUNHIEUH + 0x81AB: 0xAC93, //HANGUL SYLLABLE KIYEOK E TIKEUT + 0x81AC: 0xAC95, //HANGUL SYLLABLE KIYEOK E RIEULKIYEOK + 0x81AD: 0xAC96, //HANGUL SYLLABLE KIYEOK E RIEULMIEUM + 0x81AE: 0xAC97, //HANGUL SYLLABLE KIYEOK E RIEULPIEUP + 0x81AF: 0xAC98, //HANGUL SYLLABLE KIYEOK E RIEULSIOS + 0x81B0: 0xAC99, //HANGUL SYLLABLE KIYEOK E RIEULTHIEUTH + 0x81B1: 0xAC9A, //HANGUL SYLLABLE KIYEOK E RIEULPHIEUPH + 0x81B2: 0xAC9B, //HANGUL SYLLABLE KIYEOK E RIEULHIEUH + 0x81B3: 0xAC9E, //HANGUL SYLLABLE KIYEOK E PIEUPSIOS + 0x81B4: 0xACA2, //HANGUL SYLLABLE KIYEOK E CIEUC + 0x81B5: 0xACA3, //HANGUL SYLLABLE KIYEOK E CHIEUCH + 0x81B6: 0xACA4, //HANGUL SYLLABLE KIYEOK E KHIEUKH + 0x81B7: 0xACA5, //HANGUL SYLLABLE KIYEOK E THIEUTH + 0x81B8: 0xACA6, //HANGUL SYLLABLE KIYEOK E PHIEUPH + 0x81B9: 0xACA7, //HANGUL SYLLABLE KIYEOK E HIEUH + 0x81BA: 0xACAB, //HANGUL SYLLABLE KIYEOK YEO KIYEOKSIOS + 0x81BB: 0xACAD, //HANGUL SYLLABLE KIYEOK YEO NIEUNCIEUC + 0x81BC: 0xACAE, //HANGUL SYLLABLE KIYEOK YEO NIEUNHIEUH + 0x81BD: 0xACB1, //HANGUL SYLLABLE KIYEOK YEO RIEULKIYEOK + 0x81BE: 0xACB2, //HANGUL SYLLABLE KIYEOK YEO RIEULMIEUM + 0x81BF: 0xACB3, //HANGUL SYLLABLE KIYEOK YEO RIEULPIEUP + 0x81C0: 0xACB4, //HANGUL SYLLABLE KIYEOK YEO RIEULSIOS + 0x81C1: 0xACB5, //HANGUL SYLLABLE KIYEOK YEO RIEULTHIEUTH + 0x81C2: 0xACB6, //HANGUL SYLLABLE KIYEOK YEO RIEULPHIEUPH + 0x81C3: 0xACB7, //HANGUL SYLLABLE KIYEOK YEO RIEULHIEUH + 0x81C4: 0xACBA, //HANGUL SYLLABLE KIYEOK YEO PIEUPSIOS + 0x81C5: 0xACBE, //HANGUL SYLLABLE KIYEOK YEO CIEUC + 0x81C6: 0xACBF, //HANGUL SYLLABLE KIYEOK YEO CHIEUCH + 0x81C7: 0xACC0, //HANGUL SYLLABLE KIYEOK YEO KHIEUKH + 0x81C8: 0xACC2, //HANGUL SYLLABLE KIYEOK YEO PHIEUPH + 0x81C9: 0xACC3, //HANGUL SYLLABLE KIYEOK YEO HIEUH + 0x81CA: 0xACC5, //HANGUL SYLLABLE KIYEOK YE KIYEOK + 0x81CB: 0xACC6, //HANGUL SYLLABLE KIYEOK YE SSANGKIYEOK + 0x81CC: 0xACC7, //HANGUL SYLLABLE KIYEOK YE KIYEOKSIOS + 0x81CD: 0xACC9, //HANGUL SYLLABLE KIYEOK YE NIEUNCIEUC + 0x81CE: 0xACCA, //HANGUL SYLLABLE KIYEOK YE NIEUNHIEUH + 0x81CF: 0xACCB, //HANGUL SYLLABLE KIYEOK YE TIKEUT + 0x81D0: 0xACCD, //HANGUL SYLLABLE KIYEOK YE RIEULKIYEOK + 0x81D1: 0xACCE, //HANGUL SYLLABLE KIYEOK YE RIEULMIEUM + 0x81D2: 0xACCF, //HANGUL SYLLABLE KIYEOK YE RIEULPIEUP + 0x81D3: 0xACD0, //HANGUL SYLLABLE KIYEOK YE RIEULSIOS + 0x81D4: 0xACD1, //HANGUL SYLLABLE KIYEOK YE RIEULTHIEUTH + 0x81D5: 0xACD2, //HANGUL SYLLABLE KIYEOK YE RIEULPHIEUPH + 0x81D6: 0xACD3, //HANGUL SYLLABLE KIYEOK YE RIEULHIEUH + 0x81D7: 0xACD4, //HANGUL SYLLABLE KIYEOK YE MIEUM + 0x81D8: 0xACD6, //HANGUL SYLLABLE KIYEOK YE PIEUPSIOS + 0x81D9: 0xACD8, //HANGUL SYLLABLE KIYEOK YE SSANGSIOS + 0x81DA: 0xACD9, //HANGUL SYLLABLE KIYEOK YE IEUNG + 0x81DB: 0xACDA, //HANGUL SYLLABLE KIYEOK YE CIEUC + 0x81DC: 0xACDB, //HANGUL SYLLABLE KIYEOK YE CHIEUCH + 0x81DD: 0xACDC, //HANGUL SYLLABLE KIYEOK YE KHIEUKH + 0x81DE: 0xACDD, //HANGUL SYLLABLE KIYEOK YE THIEUTH + 0x81DF: 0xACDE, //HANGUL SYLLABLE KIYEOK YE PHIEUPH + 0x81E0: 0xACDF, //HANGUL SYLLABLE KIYEOK YE HIEUH + 0x81E1: 0xACE2, //HANGUL SYLLABLE KIYEOK O SSANGKIYEOK + 0x81E2: 0xACE3, //HANGUL SYLLABLE KIYEOK O KIYEOKSIOS + 0x81E3: 0xACE5, //HANGUL SYLLABLE KIYEOK O NIEUNCIEUC + 0x81E4: 0xACE6, //HANGUL SYLLABLE KIYEOK O NIEUNHIEUH + 0x81E5: 0xACE9, //HANGUL SYLLABLE KIYEOK O RIEULKIYEOK + 0x81E6: 0xACEB, //HANGUL SYLLABLE KIYEOK O RIEULPIEUP + 0x81E7: 0xACED, //HANGUL SYLLABLE KIYEOK O RIEULTHIEUTH + 0x81E8: 0xACEE, //HANGUL SYLLABLE KIYEOK O RIEULPHIEUPH + 0x81E9: 0xACF2, //HANGUL SYLLABLE KIYEOK O PIEUPSIOS + 0x81EA: 0xACF4, //HANGUL SYLLABLE KIYEOK O SSANGSIOS + 0x81EB: 0xACF7, //HANGUL SYLLABLE KIYEOK O CHIEUCH + 0x81EC: 0xACF8, //HANGUL SYLLABLE KIYEOK O KHIEUKH + 0x81ED: 0xACF9, //HANGUL SYLLABLE KIYEOK O THIEUTH + 0x81EE: 0xACFA, //HANGUL SYLLABLE KIYEOK O PHIEUPH + 0x81EF: 0xACFB, //HANGUL SYLLABLE KIYEOK O HIEUH + 0x81F0: 0xACFE, //HANGUL SYLLABLE KIYEOK WA SSANGKIYEOK + 0x81F1: 0xACFF, //HANGUL SYLLABLE KIYEOK WA KIYEOKSIOS + 0x81F2: 0xAD01, //HANGUL SYLLABLE KIYEOK WA NIEUNCIEUC + 0x81F3: 0xAD02, //HANGUL SYLLABLE KIYEOK WA NIEUNHIEUH + 0x81F4: 0xAD03, //HANGUL SYLLABLE KIYEOK WA TIKEUT + 0x81F5: 0xAD05, //HANGUL SYLLABLE KIYEOK WA RIEULKIYEOK + 0x81F6: 0xAD07, //HANGUL SYLLABLE KIYEOK WA RIEULPIEUP + 0x81F7: 0xAD08, //HANGUL SYLLABLE KIYEOK WA RIEULSIOS + 0x81F8: 0xAD09, //HANGUL SYLLABLE KIYEOK WA RIEULTHIEUTH + 0x81F9: 0xAD0A, //HANGUL SYLLABLE KIYEOK WA RIEULPHIEUPH + 0x81FA: 0xAD0B, //HANGUL SYLLABLE KIYEOK WA RIEULHIEUH + 0x81FB: 0xAD0E, //HANGUL SYLLABLE KIYEOK WA PIEUPSIOS + 0x81FC: 0xAD10, //HANGUL SYLLABLE KIYEOK WA SSANGSIOS + 0x81FD: 0xAD12, //HANGUL SYLLABLE KIYEOK WA CIEUC + 0x81FE: 0xAD13, //HANGUL SYLLABLE KIYEOK WA CHIEUCH + 0x8241: 0xAD14, //HANGUL SYLLABLE KIYEOK WA KHIEUKH + 0x8242: 0xAD15, //HANGUL SYLLABLE KIYEOK WA THIEUTH + 0x8243: 0xAD16, //HANGUL SYLLABLE KIYEOK WA PHIEUPH + 0x8244: 0xAD17, //HANGUL SYLLABLE KIYEOK WA HIEUH + 0x8245: 0xAD19, //HANGUL SYLLABLE KIYEOK WAE KIYEOK + 0x8246: 0xAD1A, //HANGUL SYLLABLE KIYEOK WAE SSANGKIYEOK + 0x8247: 0xAD1B, //HANGUL SYLLABLE KIYEOK WAE KIYEOKSIOS + 0x8248: 0xAD1D, //HANGUL SYLLABLE KIYEOK WAE NIEUNCIEUC + 0x8249: 0xAD1E, //HANGUL SYLLABLE KIYEOK WAE NIEUNHIEUH + 0x824A: 0xAD1F, //HANGUL SYLLABLE KIYEOK WAE TIKEUT + 0x824B: 0xAD21, //HANGUL SYLLABLE KIYEOK WAE RIEULKIYEOK + 0x824C: 0xAD22, //HANGUL SYLLABLE KIYEOK WAE RIEULMIEUM + 0x824D: 0xAD23, //HANGUL SYLLABLE KIYEOK WAE RIEULPIEUP + 0x824E: 0xAD24, //HANGUL SYLLABLE KIYEOK WAE RIEULSIOS + 0x824F: 0xAD25, //HANGUL SYLLABLE KIYEOK WAE RIEULTHIEUTH + 0x8250: 0xAD26, //HANGUL SYLLABLE KIYEOK WAE RIEULPHIEUPH + 0x8251: 0xAD27, //HANGUL SYLLABLE KIYEOK WAE RIEULHIEUH + 0x8252: 0xAD28, //HANGUL SYLLABLE KIYEOK WAE MIEUM + 0x8253: 0xAD2A, //HANGUL SYLLABLE KIYEOK WAE PIEUPSIOS + 0x8254: 0xAD2B, //HANGUL SYLLABLE KIYEOK WAE SIOS + 0x8255: 0xAD2E, //HANGUL SYLLABLE KIYEOK WAE CIEUC + 0x8256: 0xAD2F, //HANGUL SYLLABLE KIYEOK WAE CHIEUCH + 0x8257: 0xAD30, //HANGUL SYLLABLE KIYEOK WAE KHIEUKH + 0x8258: 0xAD31, //HANGUL SYLLABLE KIYEOK WAE THIEUTH + 0x8259: 0xAD32, //HANGUL SYLLABLE KIYEOK WAE PHIEUPH + 0x825A: 0xAD33, //HANGUL SYLLABLE KIYEOK WAE HIEUH + 0x8261: 0xAD36, //HANGUL SYLLABLE KIYEOK OE SSANGKIYEOK + 0x8262: 0xAD37, //HANGUL SYLLABLE KIYEOK OE KIYEOKSIOS + 0x8263: 0xAD39, //HANGUL SYLLABLE KIYEOK OE NIEUNCIEUC + 0x8264: 0xAD3A, //HANGUL SYLLABLE KIYEOK OE NIEUNHIEUH + 0x8265: 0xAD3B, //HANGUL SYLLABLE KIYEOK OE TIKEUT + 0x8266: 0xAD3D, //HANGUL SYLLABLE KIYEOK OE RIEULKIYEOK + 0x8267: 0xAD3E, //HANGUL SYLLABLE KIYEOK OE RIEULMIEUM + 0x8268: 0xAD3F, //HANGUL SYLLABLE KIYEOK OE RIEULPIEUP + 0x8269: 0xAD40, //HANGUL SYLLABLE KIYEOK OE RIEULSIOS + 0x826A: 0xAD41, //HANGUL SYLLABLE KIYEOK OE RIEULTHIEUTH + 0x826B: 0xAD42, //HANGUL SYLLABLE KIYEOK OE RIEULPHIEUPH + 0x826C: 0xAD43, //HANGUL SYLLABLE KIYEOK OE RIEULHIEUH + 0x826D: 0xAD46, //HANGUL SYLLABLE KIYEOK OE PIEUPSIOS + 0x826E: 0xAD48, //HANGUL SYLLABLE KIYEOK OE SSANGSIOS + 0x826F: 0xAD4A, //HANGUL SYLLABLE KIYEOK OE CIEUC + 0x8270: 0xAD4B, //HANGUL SYLLABLE KIYEOK OE CHIEUCH + 0x8271: 0xAD4C, //HANGUL SYLLABLE KIYEOK OE KHIEUKH + 0x8272: 0xAD4D, //HANGUL SYLLABLE KIYEOK OE THIEUTH + 0x8273: 0xAD4E, //HANGUL SYLLABLE KIYEOK OE PHIEUPH + 0x8274: 0xAD4F, //HANGUL SYLLABLE KIYEOK OE HIEUH + 0x8275: 0xAD51, //HANGUL SYLLABLE KIYEOK YO KIYEOK + 0x8276: 0xAD52, //HANGUL SYLLABLE KIYEOK YO SSANGKIYEOK + 0x8277: 0xAD53, //HANGUL SYLLABLE KIYEOK YO KIYEOKSIOS + 0x8278: 0xAD55, //HANGUL SYLLABLE KIYEOK YO NIEUNCIEUC + 0x8279: 0xAD56, //HANGUL SYLLABLE KIYEOK YO NIEUNHIEUH + 0x827A: 0xAD57, //HANGUL SYLLABLE KIYEOK YO TIKEUT + 0x8281: 0xAD59, //HANGUL SYLLABLE KIYEOK YO RIEULKIYEOK + 0x8282: 0xAD5A, //HANGUL SYLLABLE KIYEOK YO RIEULMIEUM + 0x8283: 0xAD5B, //HANGUL SYLLABLE KIYEOK YO RIEULPIEUP + 0x8284: 0xAD5C, //HANGUL SYLLABLE KIYEOK YO RIEULSIOS + 0x8285: 0xAD5D, //HANGUL SYLLABLE KIYEOK YO RIEULTHIEUTH + 0x8286: 0xAD5E, //HANGUL SYLLABLE KIYEOK YO RIEULPHIEUPH + 0x8287: 0xAD5F, //HANGUL SYLLABLE KIYEOK YO RIEULHIEUH + 0x8288: 0xAD60, //HANGUL SYLLABLE KIYEOK YO MIEUM + 0x8289: 0xAD62, //HANGUL SYLLABLE KIYEOK YO PIEUPSIOS + 0x828A: 0xAD64, //HANGUL SYLLABLE KIYEOK YO SSANGSIOS + 0x828B: 0xAD65, //HANGUL SYLLABLE KIYEOK YO IEUNG + 0x828C: 0xAD66, //HANGUL SYLLABLE KIYEOK YO CIEUC + 0x828D: 0xAD67, //HANGUL SYLLABLE KIYEOK YO CHIEUCH + 0x828E: 0xAD68, //HANGUL SYLLABLE KIYEOK YO KHIEUKH + 0x828F: 0xAD69, //HANGUL SYLLABLE KIYEOK YO THIEUTH + 0x8290: 0xAD6A, //HANGUL SYLLABLE KIYEOK YO PHIEUPH + 0x8291: 0xAD6B, //HANGUL SYLLABLE KIYEOK YO HIEUH + 0x8292: 0xAD6E, //HANGUL SYLLABLE KIYEOK U SSANGKIYEOK + 0x8293: 0xAD6F, //HANGUL SYLLABLE KIYEOK U KIYEOKSIOS + 0x8294: 0xAD71, //HANGUL SYLLABLE KIYEOK U NIEUNCIEUC + 0x8295: 0xAD72, //HANGUL SYLLABLE KIYEOK U NIEUNHIEUH + 0x8296: 0xAD77, //HANGUL SYLLABLE KIYEOK U RIEULPIEUP + 0x8297: 0xAD78, //HANGUL SYLLABLE KIYEOK U RIEULSIOS + 0x8298: 0xAD79, //HANGUL SYLLABLE KIYEOK U RIEULTHIEUTH + 0x8299: 0xAD7A, //HANGUL SYLLABLE KIYEOK U RIEULPHIEUPH + 0x829A: 0xAD7E, //HANGUL SYLLABLE KIYEOK U PIEUPSIOS + 0x829B: 0xAD80, //HANGUL SYLLABLE KIYEOK U SSANGSIOS + 0x829C: 0xAD83, //HANGUL SYLLABLE KIYEOK U CHIEUCH + 0x829D: 0xAD84, //HANGUL SYLLABLE KIYEOK U KHIEUKH + 0x829E: 0xAD85, //HANGUL SYLLABLE KIYEOK U THIEUTH + 0x829F: 0xAD86, //HANGUL SYLLABLE KIYEOK U PHIEUPH + 0x82A0: 0xAD87, //HANGUL SYLLABLE KIYEOK U HIEUH + 0x82A1: 0xAD8A, //HANGUL SYLLABLE KIYEOK WEO SSANGKIYEOK + 0x82A2: 0xAD8B, //HANGUL SYLLABLE KIYEOK WEO KIYEOKSIOS + 0x82A3: 0xAD8D, //HANGUL SYLLABLE KIYEOK WEO NIEUNCIEUC + 0x82A4: 0xAD8E, //HANGUL SYLLABLE KIYEOK WEO NIEUNHIEUH + 0x82A5: 0xAD8F, //HANGUL SYLLABLE KIYEOK WEO TIKEUT + 0x82A6: 0xAD91, //HANGUL SYLLABLE KIYEOK WEO RIEULKIYEOK + 0x82A7: 0xAD92, //HANGUL SYLLABLE KIYEOK WEO RIEULMIEUM + 0x82A8: 0xAD93, //HANGUL SYLLABLE KIYEOK WEO RIEULPIEUP + 0x82A9: 0xAD94, //HANGUL SYLLABLE KIYEOK WEO RIEULSIOS + 0x82AA: 0xAD95, //HANGUL SYLLABLE KIYEOK WEO RIEULTHIEUTH + 0x82AB: 0xAD96, //HANGUL SYLLABLE KIYEOK WEO RIEULPHIEUPH + 0x82AC: 0xAD97, //HANGUL SYLLABLE KIYEOK WEO RIEULHIEUH + 0x82AD: 0xAD98, //HANGUL SYLLABLE KIYEOK WEO MIEUM + 0x82AE: 0xAD99, //HANGUL SYLLABLE KIYEOK WEO PIEUP + 0x82AF: 0xAD9A, //HANGUL SYLLABLE KIYEOK WEO PIEUPSIOS + 0x82B0: 0xAD9B, //HANGUL SYLLABLE KIYEOK WEO SIOS + 0x82B1: 0xAD9E, //HANGUL SYLLABLE KIYEOK WEO CIEUC + 0x82B2: 0xAD9F, //HANGUL SYLLABLE KIYEOK WEO CHIEUCH + 0x82B3: 0xADA0, //HANGUL SYLLABLE KIYEOK WEO KHIEUKH + 0x82B4: 0xADA1, //HANGUL SYLLABLE KIYEOK WEO THIEUTH + 0x82B5: 0xADA2, //HANGUL SYLLABLE KIYEOK WEO PHIEUPH + 0x82B6: 0xADA3, //HANGUL SYLLABLE KIYEOK WEO HIEUH + 0x82B7: 0xADA5, //HANGUL SYLLABLE KIYEOK WE KIYEOK + 0x82B8: 0xADA6, //HANGUL SYLLABLE KIYEOK WE SSANGKIYEOK + 0x82B9: 0xADA7, //HANGUL SYLLABLE KIYEOK WE KIYEOKSIOS + 0x82BA: 0xADA8, //HANGUL SYLLABLE KIYEOK WE NIEUN + 0x82BB: 0xADA9, //HANGUL SYLLABLE KIYEOK WE NIEUNCIEUC + 0x82BC: 0xADAA, //HANGUL SYLLABLE KIYEOK WE NIEUNHIEUH + 0x82BD: 0xADAB, //HANGUL SYLLABLE KIYEOK WE TIKEUT + 0x82BE: 0xADAC, //HANGUL SYLLABLE KIYEOK WE RIEUL + 0x82BF: 0xADAD, //HANGUL SYLLABLE KIYEOK WE RIEULKIYEOK + 0x82C0: 0xADAE, //HANGUL SYLLABLE KIYEOK WE RIEULMIEUM + 0x82C1: 0xADAF, //HANGUL SYLLABLE KIYEOK WE RIEULPIEUP + 0x82C2: 0xADB0, //HANGUL SYLLABLE KIYEOK WE RIEULSIOS + 0x82C3: 0xADB1, //HANGUL SYLLABLE KIYEOK WE RIEULTHIEUTH + 0x82C4: 0xADB2, //HANGUL SYLLABLE KIYEOK WE RIEULPHIEUPH + 0x82C5: 0xADB3, //HANGUL SYLLABLE KIYEOK WE RIEULHIEUH + 0x82C6: 0xADB4, //HANGUL SYLLABLE KIYEOK WE MIEUM + 0x82C7: 0xADB5, //HANGUL SYLLABLE KIYEOK WE PIEUP + 0x82C8: 0xADB6, //HANGUL SYLLABLE KIYEOK WE PIEUPSIOS + 0x82C9: 0xADB8, //HANGUL SYLLABLE KIYEOK WE SSANGSIOS + 0x82CA: 0xADB9, //HANGUL SYLLABLE KIYEOK WE IEUNG + 0x82CB: 0xADBA, //HANGUL SYLLABLE KIYEOK WE CIEUC + 0x82CC: 0xADBB, //HANGUL SYLLABLE KIYEOK WE CHIEUCH + 0x82CD: 0xADBC, //HANGUL SYLLABLE KIYEOK WE KHIEUKH + 0x82CE: 0xADBD, //HANGUL SYLLABLE KIYEOK WE THIEUTH + 0x82CF: 0xADBE, //HANGUL SYLLABLE KIYEOK WE PHIEUPH + 0x82D0: 0xADBF, //HANGUL SYLLABLE KIYEOK WE HIEUH + 0x82D1: 0xADC2, //HANGUL SYLLABLE KIYEOK WI SSANGKIYEOK + 0x82D2: 0xADC3, //HANGUL SYLLABLE KIYEOK WI KIYEOKSIOS + 0x82D3: 0xADC5, //HANGUL SYLLABLE KIYEOK WI NIEUNCIEUC + 0x82D4: 0xADC6, //HANGUL SYLLABLE KIYEOK WI NIEUNHIEUH + 0x82D5: 0xADC7, //HANGUL SYLLABLE KIYEOK WI TIKEUT + 0x82D6: 0xADC9, //HANGUL SYLLABLE KIYEOK WI RIEULKIYEOK + 0x82D7: 0xADCA, //HANGUL SYLLABLE KIYEOK WI RIEULMIEUM + 0x82D8: 0xADCB, //HANGUL SYLLABLE KIYEOK WI RIEULPIEUP + 0x82D9: 0xADCC, //HANGUL SYLLABLE KIYEOK WI RIEULSIOS + 0x82DA: 0xADCD, //HANGUL SYLLABLE KIYEOK WI RIEULTHIEUTH + 0x82DB: 0xADCE, //HANGUL SYLLABLE KIYEOK WI RIEULPHIEUPH + 0x82DC: 0xADCF, //HANGUL SYLLABLE KIYEOK WI RIEULHIEUH + 0x82DD: 0xADD2, //HANGUL SYLLABLE KIYEOK WI PIEUPSIOS + 0x82DE: 0xADD4, //HANGUL SYLLABLE KIYEOK WI SSANGSIOS + 0x82DF: 0xADD5, //HANGUL SYLLABLE KIYEOK WI IEUNG + 0x82E0: 0xADD6, //HANGUL SYLLABLE KIYEOK WI CIEUC + 0x82E1: 0xADD7, //HANGUL SYLLABLE KIYEOK WI CHIEUCH + 0x82E2: 0xADD8, //HANGUL SYLLABLE KIYEOK WI KHIEUKH + 0x82E3: 0xADD9, //HANGUL SYLLABLE KIYEOK WI THIEUTH + 0x82E4: 0xADDA, //HANGUL SYLLABLE KIYEOK WI PHIEUPH + 0x82E5: 0xADDB, //HANGUL SYLLABLE KIYEOK WI HIEUH + 0x82E6: 0xADDD, //HANGUL SYLLABLE KIYEOK YU KIYEOK + 0x82E7: 0xADDE, //HANGUL SYLLABLE KIYEOK YU SSANGKIYEOK + 0x82E8: 0xADDF, //HANGUL SYLLABLE KIYEOK YU KIYEOKSIOS + 0x82E9: 0xADE1, //HANGUL SYLLABLE KIYEOK YU NIEUNCIEUC + 0x82EA: 0xADE2, //HANGUL SYLLABLE KIYEOK YU NIEUNHIEUH + 0x82EB: 0xADE3, //HANGUL SYLLABLE KIYEOK YU TIKEUT + 0x82EC: 0xADE5, //HANGUL SYLLABLE KIYEOK YU RIEULKIYEOK + 0x82ED: 0xADE6, //HANGUL SYLLABLE KIYEOK YU RIEULMIEUM + 0x82EE: 0xADE7, //HANGUL SYLLABLE KIYEOK YU RIEULPIEUP + 0x82EF: 0xADE8, //HANGUL SYLLABLE KIYEOK YU RIEULSIOS + 0x82F0: 0xADE9, //HANGUL SYLLABLE KIYEOK YU RIEULTHIEUTH + 0x82F1: 0xADEA, //HANGUL SYLLABLE KIYEOK YU RIEULPHIEUPH + 0x82F2: 0xADEB, //HANGUL SYLLABLE KIYEOK YU RIEULHIEUH + 0x82F3: 0xADEC, //HANGUL SYLLABLE KIYEOK YU MIEUM + 0x82F4: 0xADED, //HANGUL SYLLABLE KIYEOK YU PIEUP + 0x82F5: 0xADEE, //HANGUL SYLLABLE KIYEOK YU PIEUPSIOS + 0x82F6: 0xADEF, //HANGUL SYLLABLE KIYEOK YU SIOS + 0x82F7: 0xADF0, //HANGUL SYLLABLE KIYEOK YU SSANGSIOS + 0x82F8: 0xADF1, //HANGUL SYLLABLE KIYEOK YU IEUNG + 0x82F9: 0xADF2, //HANGUL SYLLABLE KIYEOK YU CIEUC + 0x82FA: 0xADF3, //HANGUL SYLLABLE KIYEOK YU CHIEUCH + 0x82FB: 0xADF4, //HANGUL SYLLABLE KIYEOK YU KHIEUKH + 0x82FC: 0xADF5, //HANGUL SYLLABLE KIYEOK YU THIEUTH + 0x82FD: 0xADF6, //HANGUL SYLLABLE KIYEOK YU PHIEUPH + 0x82FE: 0xADF7, //HANGUL SYLLABLE KIYEOK YU HIEUH + 0x8341: 0xADFA, //HANGUL SYLLABLE KIYEOK EU SSANGKIYEOK + 0x8342: 0xADFB, //HANGUL SYLLABLE KIYEOK EU KIYEOKSIOS + 0x8343: 0xADFD, //HANGUL SYLLABLE KIYEOK EU NIEUNCIEUC + 0x8344: 0xADFE, //HANGUL SYLLABLE KIYEOK EU NIEUNHIEUH + 0x8345: 0xAE02, //HANGUL SYLLABLE KIYEOK EU RIEULMIEUM + 0x8346: 0xAE03, //HANGUL SYLLABLE KIYEOK EU RIEULPIEUP + 0x8347: 0xAE04, //HANGUL SYLLABLE KIYEOK EU RIEULSIOS + 0x8348: 0xAE05, //HANGUL SYLLABLE KIYEOK EU RIEULTHIEUTH + 0x8349: 0xAE06, //HANGUL SYLLABLE KIYEOK EU RIEULPHIEUPH + 0x834A: 0xAE07, //HANGUL SYLLABLE KIYEOK EU RIEULHIEUH + 0x834B: 0xAE0A, //HANGUL SYLLABLE KIYEOK EU PIEUPSIOS + 0x834C: 0xAE0C, //HANGUL SYLLABLE KIYEOK EU SSANGSIOS + 0x834D: 0xAE0E, //HANGUL SYLLABLE KIYEOK EU CIEUC + 0x834E: 0xAE0F, //HANGUL SYLLABLE KIYEOK EU CHIEUCH + 0x834F: 0xAE10, //HANGUL SYLLABLE KIYEOK EU KHIEUKH + 0x8350: 0xAE11, //HANGUL SYLLABLE KIYEOK EU THIEUTH + 0x8351: 0xAE12, //HANGUL SYLLABLE KIYEOK EU PHIEUPH + 0x8352: 0xAE13, //HANGUL SYLLABLE KIYEOK EU HIEUH + 0x8353: 0xAE15, //HANGUL SYLLABLE KIYEOK YI KIYEOK + 0x8354: 0xAE16, //HANGUL SYLLABLE KIYEOK YI SSANGKIYEOK + 0x8355: 0xAE17, //HANGUL SYLLABLE KIYEOK YI KIYEOKSIOS + 0x8356: 0xAE18, //HANGUL SYLLABLE KIYEOK YI NIEUN + 0x8357: 0xAE19, //HANGUL SYLLABLE KIYEOK YI NIEUNCIEUC + 0x8358: 0xAE1A, //HANGUL SYLLABLE KIYEOK YI NIEUNHIEUH + 0x8359: 0xAE1B, //HANGUL SYLLABLE KIYEOK YI TIKEUT + 0x835A: 0xAE1C, //HANGUL SYLLABLE KIYEOK YI RIEUL + 0x8361: 0xAE1D, //HANGUL SYLLABLE KIYEOK YI RIEULKIYEOK + 0x8362: 0xAE1E, //HANGUL SYLLABLE KIYEOK YI RIEULMIEUM + 0x8363: 0xAE1F, //HANGUL SYLLABLE KIYEOK YI RIEULPIEUP + 0x8364: 0xAE20, //HANGUL SYLLABLE KIYEOK YI RIEULSIOS + 0x8365: 0xAE21, //HANGUL SYLLABLE KIYEOK YI RIEULTHIEUTH + 0x8366: 0xAE22, //HANGUL SYLLABLE KIYEOK YI RIEULPHIEUPH + 0x8367: 0xAE23, //HANGUL SYLLABLE KIYEOK YI RIEULHIEUH + 0x8368: 0xAE24, //HANGUL SYLLABLE KIYEOK YI MIEUM + 0x8369: 0xAE25, //HANGUL SYLLABLE KIYEOK YI PIEUP + 0x836A: 0xAE26, //HANGUL SYLLABLE KIYEOK YI PIEUPSIOS + 0x836B: 0xAE27, //HANGUL SYLLABLE KIYEOK YI SIOS + 0x836C: 0xAE28, //HANGUL SYLLABLE KIYEOK YI SSANGSIOS + 0x836D: 0xAE29, //HANGUL SYLLABLE KIYEOK YI IEUNG + 0x836E: 0xAE2A, //HANGUL SYLLABLE KIYEOK YI CIEUC + 0x836F: 0xAE2B, //HANGUL SYLLABLE KIYEOK YI CHIEUCH + 0x8370: 0xAE2C, //HANGUL SYLLABLE KIYEOK YI KHIEUKH + 0x8371: 0xAE2D, //HANGUL SYLLABLE KIYEOK YI THIEUTH + 0x8372: 0xAE2E, //HANGUL SYLLABLE KIYEOK YI PHIEUPH + 0x8373: 0xAE2F, //HANGUL SYLLABLE KIYEOK YI HIEUH + 0x8374: 0xAE32, //HANGUL SYLLABLE KIYEOK I SSANGKIYEOK + 0x8375: 0xAE33, //HANGUL SYLLABLE KIYEOK I KIYEOKSIOS + 0x8376: 0xAE35, //HANGUL SYLLABLE KIYEOK I NIEUNCIEUC + 0x8377: 0xAE36, //HANGUL SYLLABLE KIYEOK I NIEUNHIEUH + 0x8378: 0xAE39, //HANGUL SYLLABLE KIYEOK I RIEULKIYEOK + 0x8379: 0xAE3B, //HANGUL SYLLABLE KIYEOK I RIEULPIEUP + 0x837A: 0xAE3C, //HANGUL SYLLABLE KIYEOK I RIEULSIOS + 0x8381: 0xAE3D, //HANGUL SYLLABLE KIYEOK I RIEULTHIEUTH + 0x8382: 0xAE3E, //HANGUL SYLLABLE KIYEOK I RIEULPHIEUPH + 0x8383: 0xAE3F, //HANGUL SYLLABLE KIYEOK I RIEULHIEUH + 0x8384: 0xAE42, //HANGUL SYLLABLE KIYEOK I PIEUPSIOS + 0x8385: 0xAE44, //HANGUL SYLLABLE KIYEOK I SSANGSIOS + 0x8386: 0xAE47, //HANGUL SYLLABLE KIYEOK I CHIEUCH + 0x8387: 0xAE48, //HANGUL SYLLABLE KIYEOK I KHIEUKH + 0x8388: 0xAE49, //HANGUL SYLLABLE KIYEOK I THIEUTH + 0x8389: 0xAE4B, //HANGUL SYLLABLE KIYEOK I HIEUH + 0x838A: 0xAE4F, //HANGUL SYLLABLE SSANGKIYEOK A KIYEOKSIOS + 0x838B: 0xAE51, //HANGUL SYLLABLE SSANGKIYEOK A NIEUNCIEUC + 0x838C: 0xAE52, //HANGUL SYLLABLE SSANGKIYEOK A NIEUNHIEUH + 0x838D: 0xAE53, //HANGUL SYLLABLE SSANGKIYEOK A TIKEUT + 0x838E: 0xAE55, //HANGUL SYLLABLE SSANGKIYEOK A RIEULKIYEOK + 0x838F: 0xAE57, //HANGUL SYLLABLE SSANGKIYEOK A RIEULPIEUP + 0x8390: 0xAE58, //HANGUL SYLLABLE SSANGKIYEOK A RIEULSIOS + 0x8391: 0xAE59, //HANGUL SYLLABLE SSANGKIYEOK A RIEULTHIEUTH + 0x8392: 0xAE5A, //HANGUL SYLLABLE SSANGKIYEOK A RIEULPHIEUPH + 0x8393: 0xAE5B, //HANGUL SYLLABLE SSANGKIYEOK A RIEULHIEUH + 0x8394: 0xAE5E, //HANGUL SYLLABLE SSANGKIYEOK A PIEUPSIOS + 0x8395: 0xAE62, //HANGUL SYLLABLE SSANGKIYEOK A CIEUC + 0x8396: 0xAE63, //HANGUL SYLLABLE SSANGKIYEOK A CHIEUCH + 0x8397: 0xAE64, //HANGUL SYLLABLE SSANGKIYEOK A KHIEUKH + 0x8398: 0xAE66, //HANGUL SYLLABLE SSANGKIYEOK A PHIEUPH + 0x8399: 0xAE67, //HANGUL SYLLABLE SSANGKIYEOK A HIEUH + 0x839A: 0xAE6A, //HANGUL SYLLABLE SSANGKIYEOK AE SSANGKIYEOK + 0x839B: 0xAE6B, //HANGUL SYLLABLE SSANGKIYEOK AE KIYEOKSIOS + 0x839C: 0xAE6D, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUNCIEUC + 0x839D: 0xAE6E, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUNHIEUH + 0x839E: 0xAE6F, //HANGUL SYLLABLE SSANGKIYEOK AE TIKEUT + 0x839F: 0xAE71, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULKIYEOK + 0x83A0: 0xAE72, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULMIEUM + 0x83A1: 0xAE73, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULPIEUP + 0x83A2: 0xAE74, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULSIOS + 0x83A3: 0xAE75, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULTHIEUTH + 0x83A4: 0xAE76, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULPHIEUPH + 0x83A5: 0xAE77, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULHIEUH + 0x83A6: 0xAE7A, //HANGUL SYLLABLE SSANGKIYEOK AE PIEUPSIOS + 0x83A7: 0xAE7E, //HANGUL SYLLABLE SSANGKIYEOK AE CIEUC + 0x83A8: 0xAE7F, //HANGUL SYLLABLE SSANGKIYEOK AE CHIEUCH + 0x83A9: 0xAE80, //HANGUL SYLLABLE SSANGKIYEOK AE KHIEUKH + 0x83AA: 0xAE81, //HANGUL SYLLABLE SSANGKIYEOK AE THIEUTH + 0x83AB: 0xAE82, //HANGUL SYLLABLE SSANGKIYEOK AE PHIEUPH + 0x83AC: 0xAE83, //HANGUL SYLLABLE SSANGKIYEOK AE HIEUH + 0x83AD: 0xAE86, //HANGUL SYLLABLE SSANGKIYEOK YA SSANGKIYEOK + 0x83AE: 0xAE87, //HANGUL SYLLABLE SSANGKIYEOK YA KIYEOKSIOS + 0x83AF: 0xAE88, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUN + 0x83B0: 0xAE89, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUNCIEUC + 0x83B1: 0xAE8A, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUNHIEUH + 0x83B2: 0xAE8B, //HANGUL SYLLABLE SSANGKIYEOK YA TIKEUT + 0x83B3: 0xAE8D, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULKIYEOK + 0x83B4: 0xAE8E, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULMIEUM + 0x83B5: 0xAE8F, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULPIEUP + 0x83B6: 0xAE90, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULSIOS + 0x83B7: 0xAE91, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULTHIEUTH + 0x83B8: 0xAE92, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULPHIEUPH + 0x83B9: 0xAE93, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULHIEUH + 0x83BA: 0xAE94, //HANGUL SYLLABLE SSANGKIYEOK YA MIEUM + 0x83BB: 0xAE95, //HANGUL SYLLABLE SSANGKIYEOK YA PIEUP + 0x83BC: 0xAE96, //HANGUL SYLLABLE SSANGKIYEOK YA PIEUPSIOS + 0x83BD: 0xAE97, //HANGUL SYLLABLE SSANGKIYEOK YA SIOS + 0x83BE: 0xAE98, //HANGUL SYLLABLE SSANGKIYEOK YA SSANGSIOS + 0x83BF: 0xAE99, //HANGUL SYLLABLE SSANGKIYEOK YA IEUNG + 0x83C0: 0xAE9A, //HANGUL SYLLABLE SSANGKIYEOK YA CIEUC + 0x83C1: 0xAE9B, //HANGUL SYLLABLE SSANGKIYEOK YA CHIEUCH + 0x83C2: 0xAE9C, //HANGUL SYLLABLE SSANGKIYEOK YA KHIEUKH + 0x83C3: 0xAE9D, //HANGUL SYLLABLE SSANGKIYEOK YA THIEUTH + 0x83C4: 0xAE9E, //HANGUL SYLLABLE SSANGKIYEOK YA PHIEUPH + 0x83C5: 0xAE9F, //HANGUL SYLLABLE SSANGKIYEOK YA HIEUH + 0x83C6: 0xAEA0, //HANGUL SYLLABLE SSANGKIYEOK YAE + 0x83C7: 0xAEA1, //HANGUL SYLLABLE SSANGKIYEOK YAE KIYEOK + 0x83C8: 0xAEA2, //HANGUL SYLLABLE SSANGKIYEOK YAE SSANGKIYEOK + 0x83C9: 0xAEA3, //HANGUL SYLLABLE SSANGKIYEOK YAE KIYEOKSIOS + 0x83CA: 0xAEA4, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUN + 0x83CB: 0xAEA5, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUNCIEUC + 0x83CC: 0xAEA6, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUNHIEUH + 0x83CD: 0xAEA7, //HANGUL SYLLABLE SSANGKIYEOK YAE TIKEUT + 0x83CE: 0xAEA8, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEUL + 0x83CF: 0xAEA9, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULKIYEOK + 0x83D0: 0xAEAA, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULMIEUM + 0x83D1: 0xAEAB, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULPIEUP + 0x83D2: 0xAEAC, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULSIOS + 0x83D3: 0xAEAD, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULTHIEUTH + 0x83D4: 0xAEAE, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULPHIEUPH + 0x83D5: 0xAEAF, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULHIEUH + 0x83D6: 0xAEB0, //HANGUL SYLLABLE SSANGKIYEOK YAE MIEUM + 0x83D7: 0xAEB1, //HANGUL SYLLABLE SSANGKIYEOK YAE PIEUP + 0x83D8: 0xAEB2, //HANGUL SYLLABLE SSANGKIYEOK YAE PIEUPSIOS + 0x83D9: 0xAEB3, //HANGUL SYLLABLE SSANGKIYEOK YAE SIOS + 0x83DA: 0xAEB4, //HANGUL SYLLABLE SSANGKIYEOK YAE SSANGSIOS + 0x83DB: 0xAEB5, //HANGUL SYLLABLE SSANGKIYEOK YAE IEUNG + 0x83DC: 0xAEB6, //HANGUL SYLLABLE SSANGKIYEOK YAE CIEUC + 0x83DD: 0xAEB7, //HANGUL SYLLABLE SSANGKIYEOK YAE CHIEUCH + 0x83DE: 0xAEB8, //HANGUL SYLLABLE SSANGKIYEOK YAE KHIEUKH + 0x83DF: 0xAEB9, //HANGUL SYLLABLE SSANGKIYEOK YAE THIEUTH + 0x83E0: 0xAEBA, //HANGUL SYLLABLE SSANGKIYEOK YAE PHIEUPH + 0x83E1: 0xAEBB, //HANGUL SYLLABLE SSANGKIYEOK YAE HIEUH + 0x83E2: 0xAEBF, //HANGUL SYLLABLE SSANGKIYEOK EO KIYEOKSIOS + 0x83E3: 0xAEC1, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUNCIEUC + 0x83E4: 0xAEC2, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUNHIEUH + 0x83E5: 0xAEC3, //HANGUL SYLLABLE SSANGKIYEOK EO TIKEUT + 0x83E6: 0xAEC5, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULKIYEOK + 0x83E7: 0xAEC6, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULMIEUM + 0x83E8: 0xAEC7, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULPIEUP + 0x83E9: 0xAEC8, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULSIOS + 0x83EA: 0xAEC9, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULTHIEUTH + 0x83EB: 0xAECA, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULPHIEUPH + 0x83EC: 0xAECB, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULHIEUH + 0x83ED: 0xAECE, //HANGUL SYLLABLE SSANGKIYEOK EO PIEUPSIOS + 0x83EE: 0xAED2, //HANGUL SYLLABLE SSANGKIYEOK EO CIEUC + 0x83EF: 0xAED3, //HANGUL SYLLABLE SSANGKIYEOK EO CHIEUCH + 0x83F0: 0xAED4, //HANGUL SYLLABLE SSANGKIYEOK EO KHIEUKH + 0x83F1: 0xAED5, //HANGUL SYLLABLE SSANGKIYEOK EO THIEUTH + 0x83F2: 0xAED6, //HANGUL SYLLABLE SSANGKIYEOK EO PHIEUPH + 0x83F3: 0xAED7, //HANGUL SYLLABLE SSANGKIYEOK EO HIEUH + 0x83F4: 0xAEDA, //HANGUL SYLLABLE SSANGKIYEOK E SSANGKIYEOK + 0x83F5: 0xAEDB, //HANGUL SYLLABLE SSANGKIYEOK E KIYEOKSIOS + 0x83F6: 0xAEDD, //HANGUL SYLLABLE SSANGKIYEOK E NIEUNCIEUC + 0x83F7: 0xAEDE, //HANGUL SYLLABLE SSANGKIYEOK E NIEUNHIEUH + 0x83F8: 0xAEDF, //HANGUL SYLLABLE SSANGKIYEOK E TIKEUT + 0x83F9: 0xAEE0, //HANGUL SYLLABLE SSANGKIYEOK E RIEUL + 0x83FA: 0xAEE1, //HANGUL SYLLABLE SSANGKIYEOK E RIEULKIYEOK + 0x83FB: 0xAEE2, //HANGUL SYLLABLE SSANGKIYEOK E RIEULMIEUM + 0x83FC: 0xAEE3, //HANGUL SYLLABLE SSANGKIYEOK E RIEULPIEUP + 0x83FD: 0xAEE4, //HANGUL SYLLABLE SSANGKIYEOK E RIEULSIOS + 0x83FE: 0xAEE5, //HANGUL SYLLABLE SSANGKIYEOK E RIEULTHIEUTH + 0x8441: 0xAEE6, //HANGUL SYLLABLE SSANGKIYEOK E RIEULPHIEUPH + 0x8442: 0xAEE7, //HANGUL SYLLABLE SSANGKIYEOK E RIEULHIEUH + 0x8443: 0xAEE9, //HANGUL SYLLABLE SSANGKIYEOK E PIEUP + 0x8444: 0xAEEA, //HANGUL SYLLABLE SSANGKIYEOK E PIEUPSIOS + 0x8445: 0xAEEC, //HANGUL SYLLABLE SSANGKIYEOK E SSANGSIOS + 0x8446: 0xAEEE, //HANGUL SYLLABLE SSANGKIYEOK E CIEUC + 0x8447: 0xAEEF, //HANGUL SYLLABLE SSANGKIYEOK E CHIEUCH + 0x8448: 0xAEF0, //HANGUL SYLLABLE SSANGKIYEOK E KHIEUKH + 0x8449: 0xAEF1, //HANGUL SYLLABLE SSANGKIYEOK E THIEUTH + 0x844A: 0xAEF2, //HANGUL SYLLABLE SSANGKIYEOK E PHIEUPH + 0x844B: 0xAEF3, //HANGUL SYLLABLE SSANGKIYEOK E HIEUH + 0x844C: 0xAEF5, //HANGUL SYLLABLE SSANGKIYEOK YEO KIYEOK + 0x844D: 0xAEF6, //HANGUL SYLLABLE SSANGKIYEOK YEO SSANGKIYEOK + 0x844E: 0xAEF7, //HANGUL SYLLABLE SSANGKIYEOK YEO KIYEOKSIOS + 0x844F: 0xAEF9, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUNCIEUC + 0x8450: 0xAEFA, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUNHIEUH + 0x8451: 0xAEFB, //HANGUL SYLLABLE SSANGKIYEOK YEO TIKEUT + 0x8452: 0xAEFD, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULKIYEOK + 0x8453: 0xAEFE, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULMIEUM + 0x8454: 0xAEFF, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULPIEUP + 0x8455: 0xAF00, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULSIOS + 0x8456: 0xAF01, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULTHIEUTH + 0x8457: 0xAF02, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULPHIEUPH + 0x8458: 0xAF03, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULHIEUH + 0x8459: 0xAF04, //HANGUL SYLLABLE SSANGKIYEOK YEO MIEUM + 0x845A: 0xAF05, //HANGUL SYLLABLE SSANGKIYEOK YEO PIEUP + 0x8461: 0xAF06, //HANGUL SYLLABLE SSANGKIYEOK YEO PIEUPSIOS + 0x8462: 0xAF09, //HANGUL SYLLABLE SSANGKIYEOK YEO IEUNG + 0x8463: 0xAF0A, //HANGUL SYLLABLE SSANGKIYEOK YEO CIEUC + 0x8464: 0xAF0B, //HANGUL SYLLABLE SSANGKIYEOK YEO CHIEUCH + 0x8465: 0xAF0C, //HANGUL SYLLABLE SSANGKIYEOK YEO KHIEUKH + 0x8466: 0xAF0E, //HANGUL SYLLABLE SSANGKIYEOK YEO PHIEUPH + 0x8467: 0xAF0F, //HANGUL SYLLABLE SSANGKIYEOK YEO HIEUH + 0x8468: 0xAF11, //HANGUL SYLLABLE SSANGKIYEOK YE KIYEOK + 0x8469: 0xAF12, //HANGUL SYLLABLE SSANGKIYEOK YE SSANGKIYEOK + 0x846A: 0xAF13, //HANGUL SYLLABLE SSANGKIYEOK YE KIYEOKSIOS + 0x846B: 0xAF14, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUN + 0x846C: 0xAF15, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUNCIEUC + 0x846D: 0xAF16, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUNHIEUH + 0x846E: 0xAF17, //HANGUL SYLLABLE SSANGKIYEOK YE TIKEUT + 0x846F: 0xAF18, //HANGUL SYLLABLE SSANGKIYEOK YE RIEUL + 0x8470: 0xAF19, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULKIYEOK + 0x8471: 0xAF1A, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULMIEUM + 0x8472: 0xAF1B, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULPIEUP + 0x8473: 0xAF1C, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULSIOS + 0x8474: 0xAF1D, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULTHIEUTH + 0x8475: 0xAF1E, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULPHIEUPH + 0x8476: 0xAF1F, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULHIEUH + 0x8477: 0xAF20, //HANGUL SYLLABLE SSANGKIYEOK YE MIEUM + 0x8478: 0xAF21, //HANGUL SYLLABLE SSANGKIYEOK YE PIEUP + 0x8479: 0xAF22, //HANGUL SYLLABLE SSANGKIYEOK YE PIEUPSIOS + 0x847A: 0xAF23, //HANGUL SYLLABLE SSANGKIYEOK YE SIOS + 0x8481: 0xAF24, //HANGUL SYLLABLE SSANGKIYEOK YE SSANGSIOS + 0x8482: 0xAF25, //HANGUL SYLLABLE SSANGKIYEOK YE IEUNG + 0x8483: 0xAF26, //HANGUL SYLLABLE SSANGKIYEOK YE CIEUC + 0x8484: 0xAF27, //HANGUL SYLLABLE SSANGKIYEOK YE CHIEUCH + 0x8485: 0xAF28, //HANGUL SYLLABLE SSANGKIYEOK YE KHIEUKH + 0x8486: 0xAF29, //HANGUL SYLLABLE SSANGKIYEOK YE THIEUTH + 0x8487: 0xAF2A, //HANGUL SYLLABLE SSANGKIYEOK YE PHIEUPH + 0x8488: 0xAF2B, //HANGUL SYLLABLE SSANGKIYEOK YE HIEUH + 0x8489: 0xAF2E, //HANGUL SYLLABLE SSANGKIYEOK O SSANGKIYEOK + 0x848A: 0xAF2F, //HANGUL SYLLABLE SSANGKIYEOK O KIYEOKSIOS + 0x848B: 0xAF31, //HANGUL SYLLABLE SSANGKIYEOK O NIEUNCIEUC + 0x848C: 0xAF33, //HANGUL SYLLABLE SSANGKIYEOK O TIKEUT + 0x848D: 0xAF35, //HANGUL SYLLABLE SSANGKIYEOK O RIEULKIYEOK + 0x848E: 0xAF36, //HANGUL SYLLABLE SSANGKIYEOK O RIEULMIEUM + 0x848F: 0xAF37, //HANGUL SYLLABLE SSANGKIYEOK O RIEULPIEUP + 0x8490: 0xAF38, //HANGUL SYLLABLE SSANGKIYEOK O RIEULSIOS + 0x8491: 0xAF39, //HANGUL SYLLABLE SSANGKIYEOK O RIEULTHIEUTH + 0x8492: 0xAF3A, //HANGUL SYLLABLE SSANGKIYEOK O RIEULPHIEUPH + 0x8493: 0xAF3B, //HANGUL SYLLABLE SSANGKIYEOK O RIEULHIEUH + 0x8494: 0xAF3E, //HANGUL SYLLABLE SSANGKIYEOK O PIEUPSIOS + 0x8495: 0xAF40, //HANGUL SYLLABLE SSANGKIYEOK O SSANGSIOS + 0x8496: 0xAF44, //HANGUL SYLLABLE SSANGKIYEOK O KHIEUKH + 0x8497: 0xAF45, //HANGUL SYLLABLE SSANGKIYEOK O THIEUTH + 0x8498: 0xAF46, //HANGUL SYLLABLE SSANGKIYEOK O PHIEUPH + 0x8499: 0xAF47, //HANGUL SYLLABLE SSANGKIYEOK O HIEUH + 0x849A: 0xAF4A, //HANGUL SYLLABLE SSANGKIYEOK WA SSANGKIYEOK + 0x849B: 0xAF4B, //HANGUL SYLLABLE SSANGKIYEOK WA KIYEOKSIOS + 0x849C: 0xAF4C, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUN + 0x849D: 0xAF4D, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUNCIEUC + 0x849E: 0xAF4E, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUNHIEUH + 0x849F: 0xAF4F, //HANGUL SYLLABLE SSANGKIYEOK WA TIKEUT + 0x84A0: 0xAF51, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULKIYEOK + 0x84A1: 0xAF52, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULMIEUM + 0x84A2: 0xAF53, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULPIEUP + 0x84A3: 0xAF54, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULSIOS + 0x84A4: 0xAF55, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULTHIEUTH + 0x84A5: 0xAF56, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULPHIEUPH + 0x84A6: 0xAF57, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULHIEUH + 0x84A7: 0xAF58, //HANGUL SYLLABLE SSANGKIYEOK WA MIEUM + 0x84A8: 0xAF59, //HANGUL SYLLABLE SSANGKIYEOK WA PIEUP + 0x84A9: 0xAF5A, //HANGUL SYLLABLE SSANGKIYEOK WA PIEUPSIOS + 0x84AA: 0xAF5B, //HANGUL SYLLABLE SSANGKIYEOK WA SIOS + 0x84AB: 0xAF5E, //HANGUL SYLLABLE SSANGKIYEOK WA CIEUC + 0x84AC: 0xAF5F, //HANGUL SYLLABLE SSANGKIYEOK WA CHIEUCH + 0x84AD: 0xAF60, //HANGUL SYLLABLE SSANGKIYEOK WA KHIEUKH + 0x84AE: 0xAF61, //HANGUL SYLLABLE SSANGKIYEOK WA THIEUTH + 0x84AF: 0xAF62, //HANGUL SYLLABLE SSANGKIYEOK WA PHIEUPH + 0x84B0: 0xAF63, //HANGUL SYLLABLE SSANGKIYEOK WA HIEUH + 0x84B1: 0xAF66, //HANGUL SYLLABLE SSANGKIYEOK WAE SSANGKIYEOK + 0x84B2: 0xAF67, //HANGUL SYLLABLE SSANGKIYEOK WAE KIYEOKSIOS + 0x84B3: 0xAF68, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUN + 0x84B4: 0xAF69, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUNCIEUC + 0x84B5: 0xAF6A, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUNHIEUH + 0x84B6: 0xAF6B, //HANGUL SYLLABLE SSANGKIYEOK WAE TIKEUT + 0x84B7: 0xAF6C, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEUL + 0x84B8: 0xAF6D, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULKIYEOK + 0x84B9: 0xAF6E, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULMIEUM + 0x84BA: 0xAF6F, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULPIEUP + 0x84BB: 0xAF70, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULSIOS + 0x84BC: 0xAF71, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULTHIEUTH + 0x84BD: 0xAF72, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULPHIEUPH + 0x84BE: 0xAF73, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULHIEUH + 0x84BF: 0xAF74, //HANGUL SYLLABLE SSANGKIYEOK WAE MIEUM + 0x84C0: 0xAF75, //HANGUL SYLLABLE SSANGKIYEOK WAE PIEUP + 0x84C1: 0xAF76, //HANGUL SYLLABLE SSANGKIYEOK WAE PIEUPSIOS + 0x84C2: 0xAF77, //HANGUL SYLLABLE SSANGKIYEOK WAE SIOS + 0x84C3: 0xAF78, //HANGUL SYLLABLE SSANGKIYEOK WAE SSANGSIOS + 0x84C4: 0xAF7A, //HANGUL SYLLABLE SSANGKIYEOK WAE CIEUC + 0x84C5: 0xAF7B, //HANGUL SYLLABLE SSANGKIYEOK WAE CHIEUCH + 0x84C6: 0xAF7C, //HANGUL SYLLABLE SSANGKIYEOK WAE KHIEUKH + 0x84C7: 0xAF7D, //HANGUL SYLLABLE SSANGKIYEOK WAE THIEUTH + 0x84C8: 0xAF7E, //HANGUL SYLLABLE SSANGKIYEOK WAE PHIEUPH + 0x84C9: 0xAF7F, //HANGUL SYLLABLE SSANGKIYEOK WAE HIEUH + 0x84CA: 0xAF81, //HANGUL SYLLABLE SSANGKIYEOK OE KIYEOK + 0x84CB: 0xAF82, //HANGUL SYLLABLE SSANGKIYEOK OE SSANGKIYEOK + 0x84CC: 0xAF83, //HANGUL SYLLABLE SSANGKIYEOK OE KIYEOKSIOS + 0x84CD: 0xAF85, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUNCIEUC + 0x84CE: 0xAF86, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUNHIEUH + 0x84CF: 0xAF87, //HANGUL SYLLABLE SSANGKIYEOK OE TIKEUT + 0x84D0: 0xAF89, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULKIYEOK + 0x84D1: 0xAF8A, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULMIEUM + 0x84D2: 0xAF8B, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULPIEUP + 0x84D3: 0xAF8C, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULSIOS + 0x84D4: 0xAF8D, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULTHIEUTH + 0x84D5: 0xAF8E, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULPHIEUPH + 0x84D6: 0xAF8F, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULHIEUH + 0x84D7: 0xAF92, //HANGUL SYLLABLE SSANGKIYEOK OE PIEUPSIOS + 0x84D8: 0xAF93, //HANGUL SYLLABLE SSANGKIYEOK OE SIOS + 0x84D9: 0xAF94, //HANGUL SYLLABLE SSANGKIYEOK OE SSANGSIOS + 0x84DA: 0xAF96, //HANGUL SYLLABLE SSANGKIYEOK OE CIEUC + 0x84DB: 0xAF97, //HANGUL SYLLABLE SSANGKIYEOK OE CHIEUCH + 0x84DC: 0xAF98, //HANGUL SYLLABLE SSANGKIYEOK OE KHIEUKH + 0x84DD: 0xAF99, //HANGUL SYLLABLE SSANGKIYEOK OE THIEUTH + 0x84DE: 0xAF9A, //HANGUL SYLLABLE SSANGKIYEOK OE PHIEUPH + 0x84DF: 0xAF9B, //HANGUL SYLLABLE SSANGKIYEOK OE HIEUH + 0x84E0: 0xAF9D, //HANGUL SYLLABLE SSANGKIYEOK YO KIYEOK + 0x84E1: 0xAF9E, //HANGUL SYLLABLE SSANGKIYEOK YO SSANGKIYEOK + 0x84E2: 0xAF9F, //HANGUL SYLLABLE SSANGKIYEOK YO KIYEOKSIOS + 0x84E3: 0xAFA0, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUN + 0x84E4: 0xAFA1, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUNCIEUC + 0x84E5: 0xAFA2, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUNHIEUH + 0x84E6: 0xAFA3, //HANGUL SYLLABLE SSANGKIYEOK YO TIKEUT + 0x84E7: 0xAFA4, //HANGUL SYLLABLE SSANGKIYEOK YO RIEUL + 0x84E8: 0xAFA5, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULKIYEOK + 0x84E9: 0xAFA6, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULMIEUM + 0x84EA: 0xAFA7, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULPIEUP + 0x84EB: 0xAFA8, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULSIOS + 0x84EC: 0xAFA9, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULTHIEUTH + 0x84ED: 0xAFAA, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULPHIEUPH + 0x84EE: 0xAFAB, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULHIEUH + 0x84EF: 0xAFAC, //HANGUL SYLLABLE SSANGKIYEOK YO MIEUM + 0x84F0: 0xAFAD, //HANGUL SYLLABLE SSANGKIYEOK YO PIEUP + 0x84F1: 0xAFAE, //HANGUL SYLLABLE SSANGKIYEOK YO PIEUPSIOS + 0x84F2: 0xAFAF, //HANGUL SYLLABLE SSANGKIYEOK YO SIOS + 0x84F3: 0xAFB0, //HANGUL SYLLABLE SSANGKIYEOK YO SSANGSIOS + 0x84F4: 0xAFB1, //HANGUL SYLLABLE SSANGKIYEOK YO IEUNG + 0x84F5: 0xAFB2, //HANGUL SYLLABLE SSANGKIYEOK YO CIEUC + 0x84F6: 0xAFB3, //HANGUL SYLLABLE SSANGKIYEOK YO CHIEUCH + 0x84F7: 0xAFB4, //HANGUL SYLLABLE SSANGKIYEOK YO KHIEUKH + 0x84F8: 0xAFB5, //HANGUL SYLLABLE SSANGKIYEOK YO THIEUTH + 0x84F9: 0xAFB6, //HANGUL SYLLABLE SSANGKIYEOK YO PHIEUPH + 0x84FA: 0xAFB7, //HANGUL SYLLABLE SSANGKIYEOK YO HIEUH + 0x84FB: 0xAFBA, //HANGUL SYLLABLE SSANGKIYEOK U SSANGKIYEOK + 0x84FC: 0xAFBB, //HANGUL SYLLABLE SSANGKIYEOK U KIYEOKSIOS + 0x84FD: 0xAFBD, //HANGUL SYLLABLE SSANGKIYEOK U NIEUNCIEUC + 0x84FE: 0xAFBE, //HANGUL SYLLABLE SSANGKIYEOK U NIEUNHIEUH + 0x8541: 0xAFBF, //HANGUL SYLLABLE SSANGKIYEOK U TIKEUT + 0x8542: 0xAFC1, //HANGUL SYLLABLE SSANGKIYEOK U RIEULKIYEOK + 0x8543: 0xAFC2, //HANGUL SYLLABLE SSANGKIYEOK U RIEULMIEUM + 0x8544: 0xAFC3, //HANGUL SYLLABLE SSANGKIYEOK U RIEULPIEUP + 0x8545: 0xAFC4, //HANGUL SYLLABLE SSANGKIYEOK U RIEULSIOS + 0x8546: 0xAFC5, //HANGUL SYLLABLE SSANGKIYEOK U RIEULTHIEUTH + 0x8547: 0xAFC6, //HANGUL SYLLABLE SSANGKIYEOK U RIEULPHIEUPH + 0x8548: 0xAFCA, //HANGUL SYLLABLE SSANGKIYEOK U PIEUPSIOS + 0x8549: 0xAFCC, //HANGUL SYLLABLE SSANGKIYEOK U SSANGSIOS + 0x854A: 0xAFCF, //HANGUL SYLLABLE SSANGKIYEOK U CHIEUCH + 0x854B: 0xAFD0, //HANGUL SYLLABLE SSANGKIYEOK U KHIEUKH + 0x854C: 0xAFD1, //HANGUL SYLLABLE SSANGKIYEOK U THIEUTH + 0x854D: 0xAFD2, //HANGUL SYLLABLE SSANGKIYEOK U PHIEUPH + 0x854E: 0xAFD3, //HANGUL SYLLABLE SSANGKIYEOK U HIEUH + 0x854F: 0xAFD5, //HANGUL SYLLABLE SSANGKIYEOK WEO KIYEOK + 0x8550: 0xAFD6, //HANGUL SYLLABLE SSANGKIYEOK WEO SSANGKIYEOK + 0x8551: 0xAFD7, //HANGUL SYLLABLE SSANGKIYEOK WEO KIYEOKSIOS + 0x8552: 0xAFD8, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUN + 0x8553: 0xAFD9, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUNCIEUC + 0x8554: 0xAFDA, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUNHIEUH + 0x8555: 0xAFDB, //HANGUL SYLLABLE SSANGKIYEOK WEO TIKEUT + 0x8556: 0xAFDD, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULKIYEOK + 0x8557: 0xAFDE, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULMIEUM + 0x8558: 0xAFDF, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULPIEUP + 0x8559: 0xAFE0, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULSIOS + 0x855A: 0xAFE1, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULTHIEUTH + 0x8561: 0xAFE2, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULPHIEUPH + 0x8562: 0xAFE3, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULHIEUH + 0x8563: 0xAFE4, //HANGUL SYLLABLE SSANGKIYEOK WEO MIEUM + 0x8564: 0xAFE5, //HANGUL SYLLABLE SSANGKIYEOK WEO PIEUP + 0x8565: 0xAFE6, //HANGUL SYLLABLE SSANGKIYEOK WEO PIEUPSIOS + 0x8566: 0xAFE7, //HANGUL SYLLABLE SSANGKIYEOK WEO SIOS + 0x8567: 0xAFEA, //HANGUL SYLLABLE SSANGKIYEOK WEO CIEUC + 0x8568: 0xAFEB, //HANGUL SYLLABLE SSANGKIYEOK WEO CHIEUCH + 0x8569: 0xAFEC, //HANGUL SYLLABLE SSANGKIYEOK WEO KHIEUKH + 0x856A: 0xAFED, //HANGUL SYLLABLE SSANGKIYEOK WEO THIEUTH + 0x856B: 0xAFEE, //HANGUL SYLLABLE SSANGKIYEOK WEO PHIEUPH + 0x856C: 0xAFEF, //HANGUL SYLLABLE SSANGKIYEOK WEO HIEUH + 0x856D: 0xAFF2, //HANGUL SYLLABLE SSANGKIYEOK WE SSANGKIYEOK + 0x856E: 0xAFF3, //HANGUL SYLLABLE SSANGKIYEOK WE KIYEOKSIOS + 0x856F: 0xAFF5, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUNCIEUC + 0x8570: 0xAFF6, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUNHIEUH + 0x8571: 0xAFF7, //HANGUL SYLLABLE SSANGKIYEOK WE TIKEUT + 0x8572: 0xAFF9, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULKIYEOK + 0x8573: 0xAFFA, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULMIEUM + 0x8574: 0xAFFB, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULPIEUP + 0x8575: 0xAFFC, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULSIOS + 0x8576: 0xAFFD, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULTHIEUTH + 0x8577: 0xAFFE, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULPHIEUPH + 0x8578: 0xAFFF, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULHIEUH + 0x8579: 0xB002, //HANGUL SYLLABLE SSANGKIYEOK WE PIEUPSIOS + 0x857A: 0xB003, //HANGUL SYLLABLE SSANGKIYEOK WE SIOS + 0x8581: 0xB005, //HANGUL SYLLABLE SSANGKIYEOK WE IEUNG + 0x8582: 0xB006, //HANGUL SYLLABLE SSANGKIYEOK WE CIEUC + 0x8583: 0xB007, //HANGUL SYLLABLE SSANGKIYEOK WE CHIEUCH + 0x8584: 0xB008, //HANGUL SYLLABLE SSANGKIYEOK WE KHIEUKH + 0x8585: 0xB009, //HANGUL SYLLABLE SSANGKIYEOK WE THIEUTH + 0x8586: 0xB00A, //HANGUL SYLLABLE SSANGKIYEOK WE PHIEUPH + 0x8587: 0xB00B, //HANGUL SYLLABLE SSANGKIYEOK WE HIEUH + 0x8588: 0xB00D, //HANGUL SYLLABLE SSANGKIYEOK WI KIYEOK + 0x8589: 0xB00E, //HANGUL SYLLABLE SSANGKIYEOK WI SSANGKIYEOK + 0x858A: 0xB00F, //HANGUL SYLLABLE SSANGKIYEOK WI KIYEOKSIOS + 0x858B: 0xB011, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUNCIEUC + 0x858C: 0xB012, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUNHIEUH + 0x858D: 0xB013, //HANGUL SYLLABLE SSANGKIYEOK WI TIKEUT + 0x858E: 0xB015, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULKIYEOK + 0x858F: 0xB016, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULMIEUM + 0x8590: 0xB017, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULPIEUP + 0x8591: 0xB018, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULSIOS + 0x8592: 0xB019, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULTHIEUTH + 0x8593: 0xB01A, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULPHIEUPH + 0x8594: 0xB01B, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULHIEUH + 0x8595: 0xB01E, //HANGUL SYLLABLE SSANGKIYEOK WI PIEUPSIOS + 0x8596: 0xB01F, //HANGUL SYLLABLE SSANGKIYEOK WI SIOS + 0x8597: 0xB020, //HANGUL SYLLABLE SSANGKIYEOK WI SSANGSIOS + 0x8598: 0xB021, //HANGUL SYLLABLE SSANGKIYEOK WI IEUNG + 0x8599: 0xB022, //HANGUL SYLLABLE SSANGKIYEOK WI CIEUC + 0x859A: 0xB023, //HANGUL SYLLABLE SSANGKIYEOK WI CHIEUCH + 0x859B: 0xB024, //HANGUL SYLLABLE SSANGKIYEOK WI KHIEUKH + 0x859C: 0xB025, //HANGUL SYLLABLE SSANGKIYEOK WI THIEUTH + 0x859D: 0xB026, //HANGUL SYLLABLE SSANGKIYEOK WI PHIEUPH + 0x859E: 0xB027, //HANGUL SYLLABLE SSANGKIYEOK WI HIEUH + 0x859F: 0xB029, //HANGUL SYLLABLE SSANGKIYEOK YU KIYEOK + 0x85A0: 0xB02A, //HANGUL SYLLABLE SSANGKIYEOK YU SSANGKIYEOK + 0x85A1: 0xB02B, //HANGUL SYLLABLE SSANGKIYEOK YU KIYEOKSIOS + 0x85A2: 0xB02C, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUN + 0x85A3: 0xB02D, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUNCIEUC + 0x85A4: 0xB02E, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUNHIEUH + 0x85A5: 0xB02F, //HANGUL SYLLABLE SSANGKIYEOK YU TIKEUT + 0x85A6: 0xB030, //HANGUL SYLLABLE SSANGKIYEOK YU RIEUL + 0x85A7: 0xB031, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULKIYEOK + 0x85A8: 0xB032, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULMIEUM + 0x85A9: 0xB033, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULPIEUP + 0x85AA: 0xB034, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULSIOS + 0x85AB: 0xB035, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULTHIEUTH + 0x85AC: 0xB036, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULPHIEUPH + 0x85AD: 0xB037, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULHIEUH + 0x85AE: 0xB038, //HANGUL SYLLABLE SSANGKIYEOK YU MIEUM + 0x85AF: 0xB039, //HANGUL SYLLABLE SSANGKIYEOK YU PIEUP + 0x85B0: 0xB03A, //HANGUL SYLLABLE SSANGKIYEOK YU PIEUPSIOS + 0x85B1: 0xB03B, //HANGUL SYLLABLE SSANGKIYEOK YU SIOS + 0x85B2: 0xB03C, //HANGUL SYLLABLE SSANGKIYEOK YU SSANGSIOS + 0x85B3: 0xB03D, //HANGUL SYLLABLE SSANGKIYEOK YU IEUNG + 0x85B4: 0xB03E, //HANGUL SYLLABLE SSANGKIYEOK YU CIEUC + 0x85B5: 0xB03F, //HANGUL SYLLABLE SSANGKIYEOK YU CHIEUCH + 0x85B6: 0xB040, //HANGUL SYLLABLE SSANGKIYEOK YU KHIEUKH + 0x85B7: 0xB041, //HANGUL SYLLABLE SSANGKIYEOK YU THIEUTH + 0x85B8: 0xB042, //HANGUL SYLLABLE SSANGKIYEOK YU PHIEUPH + 0x85B9: 0xB043, //HANGUL SYLLABLE SSANGKIYEOK YU HIEUH + 0x85BA: 0xB046, //HANGUL SYLLABLE SSANGKIYEOK EU SSANGKIYEOK + 0x85BB: 0xB047, //HANGUL SYLLABLE SSANGKIYEOK EU KIYEOKSIOS + 0x85BC: 0xB049, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUNCIEUC + 0x85BD: 0xB04B, //HANGUL SYLLABLE SSANGKIYEOK EU TIKEUT + 0x85BE: 0xB04D, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULKIYEOK + 0x85BF: 0xB04F, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULPIEUP + 0x85C0: 0xB050, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULSIOS + 0x85C1: 0xB051, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULTHIEUTH + 0x85C2: 0xB052, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULPHIEUPH + 0x85C3: 0xB056, //HANGUL SYLLABLE SSANGKIYEOK EU PIEUPSIOS + 0x85C4: 0xB058, //HANGUL SYLLABLE SSANGKIYEOK EU SSANGSIOS + 0x85C5: 0xB05A, //HANGUL SYLLABLE SSANGKIYEOK EU CIEUC + 0x85C6: 0xB05B, //HANGUL SYLLABLE SSANGKIYEOK EU CHIEUCH + 0x85C7: 0xB05C, //HANGUL SYLLABLE SSANGKIYEOK EU KHIEUKH + 0x85C8: 0xB05E, //HANGUL SYLLABLE SSANGKIYEOK EU PHIEUPH + 0x85C9: 0xB05F, //HANGUL SYLLABLE SSANGKIYEOK EU HIEUH + 0x85CA: 0xB060, //HANGUL SYLLABLE SSANGKIYEOK YI + 0x85CB: 0xB061, //HANGUL SYLLABLE SSANGKIYEOK YI KIYEOK + 0x85CC: 0xB062, //HANGUL SYLLABLE SSANGKIYEOK YI SSANGKIYEOK + 0x85CD: 0xB063, //HANGUL SYLLABLE SSANGKIYEOK YI KIYEOKSIOS + 0x85CE: 0xB064, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUN + 0x85CF: 0xB065, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUNCIEUC + 0x85D0: 0xB066, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUNHIEUH + 0x85D1: 0xB067, //HANGUL SYLLABLE SSANGKIYEOK YI TIKEUT + 0x85D2: 0xB068, //HANGUL SYLLABLE SSANGKIYEOK YI RIEUL + 0x85D3: 0xB069, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULKIYEOK + 0x85D4: 0xB06A, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULMIEUM + 0x85D5: 0xB06B, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULPIEUP + 0x85D6: 0xB06C, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULSIOS + 0x85D7: 0xB06D, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULTHIEUTH + 0x85D8: 0xB06E, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULPHIEUPH + 0x85D9: 0xB06F, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULHIEUH + 0x85DA: 0xB070, //HANGUL SYLLABLE SSANGKIYEOK YI MIEUM + 0x85DB: 0xB071, //HANGUL SYLLABLE SSANGKIYEOK YI PIEUP + 0x85DC: 0xB072, //HANGUL SYLLABLE SSANGKIYEOK YI PIEUPSIOS + 0x85DD: 0xB073, //HANGUL SYLLABLE SSANGKIYEOK YI SIOS + 0x85DE: 0xB074, //HANGUL SYLLABLE SSANGKIYEOK YI SSANGSIOS + 0x85DF: 0xB075, //HANGUL SYLLABLE SSANGKIYEOK YI IEUNG + 0x85E0: 0xB076, //HANGUL SYLLABLE SSANGKIYEOK YI CIEUC + 0x85E1: 0xB077, //HANGUL SYLLABLE SSANGKIYEOK YI CHIEUCH + 0x85E2: 0xB078, //HANGUL SYLLABLE SSANGKIYEOK YI KHIEUKH + 0x85E3: 0xB079, //HANGUL SYLLABLE SSANGKIYEOK YI THIEUTH + 0x85E4: 0xB07A, //HANGUL SYLLABLE SSANGKIYEOK YI PHIEUPH + 0x85E5: 0xB07B, //HANGUL SYLLABLE SSANGKIYEOK YI HIEUH + 0x85E6: 0xB07E, //HANGUL SYLLABLE SSANGKIYEOK I SSANGKIYEOK + 0x85E7: 0xB07F, //HANGUL SYLLABLE SSANGKIYEOK I KIYEOKSIOS + 0x85E8: 0xB081, //HANGUL SYLLABLE SSANGKIYEOK I NIEUNCIEUC + 0x85E9: 0xB082, //HANGUL SYLLABLE SSANGKIYEOK I NIEUNHIEUH + 0x85EA: 0xB083, //HANGUL SYLLABLE SSANGKIYEOK I TIKEUT + 0x85EB: 0xB085, //HANGUL SYLLABLE SSANGKIYEOK I RIEULKIYEOK + 0x85EC: 0xB086, //HANGUL SYLLABLE SSANGKIYEOK I RIEULMIEUM + 0x85ED: 0xB087, //HANGUL SYLLABLE SSANGKIYEOK I RIEULPIEUP + 0x85EE: 0xB088, //HANGUL SYLLABLE SSANGKIYEOK I RIEULSIOS + 0x85EF: 0xB089, //HANGUL SYLLABLE SSANGKIYEOK I RIEULTHIEUTH + 0x85F0: 0xB08A, //HANGUL SYLLABLE SSANGKIYEOK I RIEULPHIEUPH + 0x85F1: 0xB08B, //HANGUL SYLLABLE SSANGKIYEOK I RIEULHIEUH + 0x85F2: 0xB08E, //HANGUL SYLLABLE SSANGKIYEOK I PIEUPSIOS + 0x85F3: 0xB090, //HANGUL SYLLABLE SSANGKIYEOK I SSANGSIOS + 0x85F4: 0xB092, //HANGUL SYLLABLE SSANGKIYEOK I CIEUC + 0x85F5: 0xB093, //HANGUL SYLLABLE SSANGKIYEOK I CHIEUCH + 0x85F6: 0xB094, //HANGUL SYLLABLE SSANGKIYEOK I KHIEUKH + 0x85F7: 0xB095, //HANGUL SYLLABLE SSANGKIYEOK I THIEUTH + 0x85F8: 0xB096, //HANGUL SYLLABLE SSANGKIYEOK I PHIEUPH + 0x85F9: 0xB097, //HANGUL SYLLABLE SSANGKIYEOK I HIEUH + 0x85FA: 0xB09B, //HANGUL SYLLABLE NIEUN A KIYEOKSIOS + 0x85FB: 0xB09D, //HANGUL SYLLABLE NIEUN A NIEUNCIEUC + 0x85FC: 0xB09E, //HANGUL SYLLABLE NIEUN A NIEUNHIEUH + 0x85FD: 0xB0A3, //HANGUL SYLLABLE NIEUN A RIEULPIEUP + 0x85FE: 0xB0A4, //HANGUL SYLLABLE NIEUN A RIEULSIOS + 0x8641: 0xB0A5, //HANGUL SYLLABLE NIEUN A RIEULTHIEUTH + 0x8642: 0xB0A6, //HANGUL SYLLABLE NIEUN A RIEULPHIEUPH + 0x8643: 0xB0A7, //HANGUL SYLLABLE NIEUN A RIEULHIEUH + 0x8644: 0xB0AA, //HANGUL SYLLABLE NIEUN A PIEUPSIOS + 0x8645: 0xB0B0, //HANGUL SYLLABLE NIEUN A KHIEUKH + 0x8646: 0xB0B2, //HANGUL SYLLABLE NIEUN A PHIEUPH + 0x8647: 0xB0B6, //HANGUL SYLLABLE NIEUN AE SSANGKIYEOK + 0x8648: 0xB0B7, //HANGUL SYLLABLE NIEUN AE KIYEOKSIOS + 0x8649: 0xB0B9, //HANGUL SYLLABLE NIEUN AE NIEUNCIEUC + 0x864A: 0xB0BA, //HANGUL SYLLABLE NIEUN AE NIEUNHIEUH + 0x864B: 0xB0BB, //HANGUL SYLLABLE NIEUN AE TIKEUT + 0x864C: 0xB0BD, //HANGUL SYLLABLE NIEUN AE RIEULKIYEOK + 0x864D: 0xB0BE, //HANGUL SYLLABLE NIEUN AE RIEULMIEUM + 0x864E: 0xB0BF, //HANGUL SYLLABLE NIEUN AE RIEULPIEUP + 0x864F: 0xB0C0, //HANGUL SYLLABLE NIEUN AE RIEULSIOS + 0x8650: 0xB0C1, //HANGUL SYLLABLE NIEUN AE RIEULTHIEUTH + 0x8651: 0xB0C2, //HANGUL SYLLABLE NIEUN AE RIEULPHIEUPH + 0x8652: 0xB0C3, //HANGUL SYLLABLE NIEUN AE RIEULHIEUH + 0x8653: 0xB0C6, //HANGUL SYLLABLE NIEUN AE PIEUPSIOS + 0x8654: 0xB0CA, //HANGUL SYLLABLE NIEUN AE CIEUC + 0x8655: 0xB0CB, //HANGUL SYLLABLE NIEUN AE CHIEUCH + 0x8656: 0xB0CC, //HANGUL SYLLABLE NIEUN AE KHIEUKH + 0x8657: 0xB0CD, //HANGUL SYLLABLE NIEUN AE THIEUTH + 0x8658: 0xB0CE, //HANGUL SYLLABLE NIEUN AE PHIEUPH + 0x8659: 0xB0CF, //HANGUL SYLLABLE NIEUN AE HIEUH + 0x865A: 0xB0D2, //HANGUL SYLLABLE NIEUN YA SSANGKIYEOK + 0x8661: 0xB0D3, //HANGUL SYLLABLE NIEUN YA KIYEOKSIOS + 0x8662: 0xB0D5, //HANGUL SYLLABLE NIEUN YA NIEUNCIEUC + 0x8663: 0xB0D6, //HANGUL SYLLABLE NIEUN YA NIEUNHIEUH + 0x8664: 0xB0D7, //HANGUL SYLLABLE NIEUN YA TIKEUT + 0x8665: 0xB0D9, //HANGUL SYLLABLE NIEUN YA RIEULKIYEOK + 0x8666: 0xB0DA, //HANGUL SYLLABLE NIEUN YA RIEULMIEUM + 0x8667: 0xB0DB, //HANGUL SYLLABLE NIEUN YA RIEULPIEUP + 0x8668: 0xB0DC, //HANGUL SYLLABLE NIEUN YA RIEULSIOS + 0x8669: 0xB0DD, //HANGUL SYLLABLE NIEUN YA RIEULTHIEUTH + 0x866A: 0xB0DE, //HANGUL SYLLABLE NIEUN YA RIEULPHIEUPH + 0x866B: 0xB0DF, //HANGUL SYLLABLE NIEUN YA RIEULHIEUH + 0x866C: 0xB0E1, //HANGUL SYLLABLE NIEUN YA PIEUP + 0x866D: 0xB0E2, //HANGUL SYLLABLE NIEUN YA PIEUPSIOS + 0x866E: 0xB0E3, //HANGUL SYLLABLE NIEUN YA SIOS + 0x866F: 0xB0E4, //HANGUL SYLLABLE NIEUN YA SSANGSIOS + 0x8670: 0xB0E6, //HANGUL SYLLABLE NIEUN YA CIEUC + 0x8671: 0xB0E7, //HANGUL SYLLABLE NIEUN YA CHIEUCH + 0x8672: 0xB0E8, //HANGUL SYLLABLE NIEUN YA KHIEUKH + 0x8673: 0xB0E9, //HANGUL SYLLABLE NIEUN YA THIEUTH + 0x8674: 0xB0EA, //HANGUL SYLLABLE NIEUN YA PHIEUPH + 0x8675: 0xB0EB, //HANGUL SYLLABLE NIEUN YA HIEUH + 0x8676: 0xB0EC, //HANGUL SYLLABLE NIEUN YAE + 0x8677: 0xB0ED, //HANGUL SYLLABLE NIEUN YAE KIYEOK + 0x8678: 0xB0EE, //HANGUL SYLLABLE NIEUN YAE SSANGKIYEOK + 0x8679: 0xB0EF, //HANGUL SYLLABLE NIEUN YAE KIYEOKSIOS + 0x867A: 0xB0F0, //HANGUL SYLLABLE NIEUN YAE NIEUN + 0x8681: 0xB0F1, //HANGUL SYLLABLE NIEUN YAE NIEUNCIEUC + 0x8682: 0xB0F2, //HANGUL SYLLABLE NIEUN YAE NIEUNHIEUH + 0x8683: 0xB0F3, //HANGUL SYLLABLE NIEUN YAE TIKEUT + 0x8684: 0xB0F4, //HANGUL SYLLABLE NIEUN YAE RIEUL + 0x8685: 0xB0F5, //HANGUL SYLLABLE NIEUN YAE RIEULKIYEOK + 0x8686: 0xB0F6, //HANGUL SYLLABLE NIEUN YAE RIEULMIEUM + 0x8687: 0xB0F7, //HANGUL SYLLABLE NIEUN YAE RIEULPIEUP + 0x8688: 0xB0F8, //HANGUL SYLLABLE NIEUN YAE RIEULSIOS + 0x8689: 0xB0F9, //HANGUL SYLLABLE NIEUN YAE RIEULTHIEUTH + 0x868A: 0xB0FA, //HANGUL SYLLABLE NIEUN YAE RIEULPHIEUPH + 0x868B: 0xB0FB, //HANGUL SYLLABLE NIEUN YAE RIEULHIEUH + 0x868C: 0xB0FC, //HANGUL SYLLABLE NIEUN YAE MIEUM + 0x868D: 0xB0FD, //HANGUL SYLLABLE NIEUN YAE PIEUP + 0x868E: 0xB0FE, //HANGUL SYLLABLE NIEUN YAE PIEUPSIOS + 0x868F: 0xB0FF, //HANGUL SYLLABLE NIEUN YAE SIOS + 0x8690: 0xB100, //HANGUL SYLLABLE NIEUN YAE SSANGSIOS + 0x8691: 0xB101, //HANGUL SYLLABLE NIEUN YAE IEUNG + 0x8692: 0xB102, //HANGUL SYLLABLE NIEUN YAE CIEUC + 0x8693: 0xB103, //HANGUL SYLLABLE NIEUN YAE CHIEUCH + 0x8694: 0xB104, //HANGUL SYLLABLE NIEUN YAE KHIEUKH + 0x8695: 0xB105, //HANGUL SYLLABLE NIEUN YAE THIEUTH + 0x8696: 0xB106, //HANGUL SYLLABLE NIEUN YAE PHIEUPH + 0x8697: 0xB107, //HANGUL SYLLABLE NIEUN YAE HIEUH + 0x8698: 0xB10A, //HANGUL SYLLABLE NIEUN EO SSANGKIYEOK + 0x8699: 0xB10D, //HANGUL SYLLABLE NIEUN EO NIEUNCIEUC + 0x869A: 0xB10E, //HANGUL SYLLABLE NIEUN EO NIEUNHIEUH + 0x869B: 0xB10F, //HANGUL SYLLABLE NIEUN EO TIKEUT + 0x869C: 0xB111, //HANGUL SYLLABLE NIEUN EO RIEULKIYEOK + 0x869D: 0xB114, //HANGUL SYLLABLE NIEUN EO RIEULSIOS + 0x869E: 0xB115, //HANGUL SYLLABLE NIEUN EO RIEULTHIEUTH + 0x869F: 0xB116, //HANGUL SYLLABLE NIEUN EO RIEULPHIEUPH + 0x86A0: 0xB117, //HANGUL SYLLABLE NIEUN EO RIEULHIEUH + 0x86A1: 0xB11A, //HANGUL SYLLABLE NIEUN EO PIEUPSIOS + 0x86A2: 0xB11E, //HANGUL SYLLABLE NIEUN EO CIEUC + 0x86A3: 0xB11F, //HANGUL SYLLABLE NIEUN EO CHIEUCH + 0x86A4: 0xB120, //HANGUL SYLLABLE NIEUN EO KHIEUKH + 0x86A5: 0xB121, //HANGUL SYLLABLE NIEUN EO THIEUTH + 0x86A6: 0xB122, //HANGUL SYLLABLE NIEUN EO PHIEUPH + 0x86A7: 0xB126, //HANGUL SYLLABLE NIEUN E SSANGKIYEOK + 0x86A8: 0xB127, //HANGUL SYLLABLE NIEUN E KIYEOKSIOS + 0x86A9: 0xB129, //HANGUL SYLLABLE NIEUN E NIEUNCIEUC + 0x86AA: 0xB12A, //HANGUL SYLLABLE NIEUN E NIEUNHIEUH + 0x86AB: 0xB12B, //HANGUL SYLLABLE NIEUN E TIKEUT + 0x86AC: 0xB12D, //HANGUL SYLLABLE NIEUN E RIEULKIYEOK + 0x86AD: 0xB12E, //HANGUL SYLLABLE NIEUN E RIEULMIEUM + 0x86AE: 0xB12F, //HANGUL SYLLABLE NIEUN E RIEULPIEUP + 0x86AF: 0xB130, //HANGUL SYLLABLE NIEUN E RIEULSIOS + 0x86B0: 0xB131, //HANGUL SYLLABLE NIEUN E RIEULTHIEUTH + 0x86B1: 0xB132, //HANGUL SYLLABLE NIEUN E RIEULPHIEUPH + 0x86B2: 0xB133, //HANGUL SYLLABLE NIEUN E RIEULHIEUH + 0x86B3: 0xB136, //HANGUL SYLLABLE NIEUN E PIEUPSIOS + 0x86B4: 0xB13A, //HANGUL SYLLABLE NIEUN E CIEUC + 0x86B5: 0xB13B, //HANGUL SYLLABLE NIEUN E CHIEUCH + 0x86B6: 0xB13C, //HANGUL SYLLABLE NIEUN E KHIEUKH + 0x86B7: 0xB13D, //HANGUL SYLLABLE NIEUN E THIEUTH + 0x86B8: 0xB13E, //HANGUL SYLLABLE NIEUN E PHIEUPH + 0x86B9: 0xB13F, //HANGUL SYLLABLE NIEUN E HIEUH + 0x86BA: 0xB142, //HANGUL SYLLABLE NIEUN YEO SSANGKIYEOK + 0x86BB: 0xB143, //HANGUL SYLLABLE NIEUN YEO KIYEOKSIOS + 0x86BC: 0xB145, //HANGUL SYLLABLE NIEUN YEO NIEUNCIEUC + 0x86BD: 0xB146, //HANGUL SYLLABLE NIEUN YEO NIEUNHIEUH + 0x86BE: 0xB147, //HANGUL SYLLABLE NIEUN YEO TIKEUT + 0x86BF: 0xB149, //HANGUL SYLLABLE NIEUN YEO RIEULKIYEOK + 0x86C0: 0xB14A, //HANGUL SYLLABLE NIEUN YEO RIEULMIEUM + 0x86C1: 0xB14B, //HANGUL SYLLABLE NIEUN YEO RIEULPIEUP + 0x86C2: 0xB14C, //HANGUL SYLLABLE NIEUN YEO RIEULSIOS + 0x86C3: 0xB14D, //HANGUL SYLLABLE NIEUN YEO RIEULTHIEUTH + 0x86C4: 0xB14E, //HANGUL SYLLABLE NIEUN YEO RIEULPHIEUPH + 0x86C5: 0xB14F, //HANGUL SYLLABLE NIEUN YEO RIEULHIEUH + 0x86C6: 0xB152, //HANGUL SYLLABLE NIEUN YEO PIEUPSIOS + 0x86C7: 0xB153, //HANGUL SYLLABLE NIEUN YEO SIOS + 0x86C8: 0xB156, //HANGUL SYLLABLE NIEUN YEO CIEUC + 0x86C9: 0xB157, //HANGUL SYLLABLE NIEUN YEO CHIEUCH + 0x86CA: 0xB159, //HANGUL SYLLABLE NIEUN YEO THIEUTH + 0x86CB: 0xB15A, //HANGUL SYLLABLE NIEUN YEO PHIEUPH + 0x86CC: 0xB15B, //HANGUL SYLLABLE NIEUN YEO HIEUH + 0x86CD: 0xB15D, //HANGUL SYLLABLE NIEUN YE KIYEOK + 0x86CE: 0xB15E, //HANGUL SYLLABLE NIEUN YE SSANGKIYEOK + 0x86CF: 0xB15F, //HANGUL SYLLABLE NIEUN YE KIYEOKSIOS + 0x86D0: 0xB161, //HANGUL SYLLABLE NIEUN YE NIEUNCIEUC + 0x86D1: 0xB162, //HANGUL SYLLABLE NIEUN YE NIEUNHIEUH + 0x86D2: 0xB163, //HANGUL SYLLABLE NIEUN YE TIKEUT + 0x86D3: 0xB164, //HANGUL SYLLABLE NIEUN YE RIEUL + 0x86D4: 0xB165, //HANGUL SYLLABLE NIEUN YE RIEULKIYEOK + 0x86D5: 0xB166, //HANGUL SYLLABLE NIEUN YE RIEULMIEUM + 0x86D6: 0xB167, //HANGUL SYLLABLE NIEUN YE RIEULPIEUP + 0x86D7: 0xB168, //HANGUL SYLLABLE NIEUN YE RIEULSIOS + 0x86D8: 0xB169, //HANGUL SYLLABLE NIEUN YE RIEULTHIEUTH + 0x86D9: 0xB16A, //HANGUL SYLLABLE NIEUN YE RIEULPHIEUPH + 0x86DA: 0xB16B, //HANGUL SYLLABLE NIEUN YE RIEULHIEUH + 0x86DB: 0xB16C, //HANGUL SYLLABLE NIEUN YE MIEUM + 0x86DC: 0xB16D, //HANGUL SYLLABLE NIEUN YE PIEUP + 0x86DD: 0xB16E, //HANGUL SYLLABLE NIEUN YE PIEUPSIOS + 0x86DE: 0xB16F, //HANGUL SYLLABLE NIEUN YE SIOS + 0x86DF: 0xB170, //HANGUL SYLLABLE NIEUN YE SSANGSIOS + 0x86E0: 0xB171, //HANGUL SYLLABLE NIEUN YE IEUNG + 0x86E1: 0xB172, //HANGUL SYLLABLE NIEUN YE CIEUC + 0x86E2: 0xB173, //HANGUL SYLLABLE NIEUN YE CHIEUCH + 0x86E3: 0xB174, //HANGUL SYLLABLE NIEUN YE KHIEUKH + 0x86E4: 0xB175, //HANGUL SYLLABLE NIEUN YE THIEUTH + 0x86E5: 0xB176, //HANGUL SYLLABLE NIEUN YE PHIEUPH + 0x86E6: 0xB177, //HANGUL SYLLABLE NIEUN YE HIEUH + 0x86E7: 0xB17A, //HANGUL SYLLABLE NIEUN O SSANGKIYEOK + 0x86E8: 0xB17B, //HANGUL SYLLABLE NIEUN O KIYEOKSIOS + 0x86E9: 0xB17D, //HANGUL SYLLABLE NIEUN O NIEUNCIEUC + 0x86EA: 0xB17E, //HANGUL SYLLABLE NIEUN O NIEUNHIEUH + 0x86EB: 0xB17F, //HANGUL SYLLABLE NIEUN O TIKEUT + 0x86EC: 0xB181, //HANGUL SYLLABLE NIEUN O RIEULKIYEOK + 0x86ED: 0xB183, //HANGUL SYLLABLE NIEUN O RIEULPIEUP + 0x86EE: 0xB184, //HANGUL SYLLABLE NIEUN O RIEULSIOS + 0x86EF: 0xB185, //HANGUL SYLLABLE NIEUN O RIEULTHIEUTH + 0x86F0: 0xB186, //HANGUL SYLLABLE NIEUN O RIEULPHIEUPH + 0x86F1: 0xB187, //HANGUL SYLLABLE NIEUN O RIEULHIEUH + 0x86F2: 0xB18A, //HANGUL SYLLABLE NIEUN O PIEUPSIOS + 0x86F3: 0xB18C, //HANGUL SYLLABLE NIEUN O SSANGSIOS + 0x86F4: 0xB18E, //HANGUL SYLLABLE NIEUN O CIEUC + 0x86F5: 0xB18F, //HANGUL SYLLABLE NIEUN O CHIEUCH + 0x86F6: 0xB190, //HANGUL SYLLABLE NIEUN O KHIEUKH + 0x86F7: 0xB191, //HANGUL SYLLABLE NIEUN O THIEUTH + 0x86F8: 0xB195, //HANGUL SYLLABLE NIEUN WA KIYEOK + 0x86F9: 0xB196, //HANGUL SYLLABLE NIEUN WA SSANGKIYEOK + 0x86FA: 0xB197, //HANGUL SYLLABLE NIEUN WA KIYEOKSIOS + 0x86FB: 0xB199, //HANGUL SYLLABLE NIEUN WA NIEUNCIEUC + 0x86FC: 0xB19A, //HANGUL SYLLABLE NIEUN WA NIEUNHIEUH + 0x86FD: 0xB19B, //HANGUL SYLLABLE NIEUN WA TIKEUT + 0x86FE: 0xB19D, //HANGUL SYLLABLE NIEUN WA RIEULKIYEOK + 0x8741: 0xB19E, //HANGUL SYLLABLE NIEUN WA RIEULMIEUM + 0x8742: 0xB19F, //HANGUL SYLLABLE NIEUN WA RIEULPIEUP + 0x8743: 0xB1A0, //HANGUL SYLLABLE NIEUN WA RIEULSIOS + 0x8744: 0xB1A1, //HANGUL SYLLABLE NIEUN WA RIEULTHIEUTH + 0x8745: 0xB1A2, //HANGUL SYLLABLE NIEUN WA RIEULPHIEUPH + 0x8746: 0xB1A3, //HANGUL SYLLABLE NIEUN WA RIEULHIEUH + 0x8747: 0xB1A4, //HANGUL SYLLABLE NIEUN WA MIEUM + 0x8748: 0xB1A5, //HANGUL SYLLABLE NIEUN WA PIEUP + 0x8749: 0xB1A6, //HANGUL SYLLABLE NIEUN WA PIEUPSIOS + 0x874A: 0xB1A7, //HANGUL SYLLABLE NIEUN WA SIOS + 0x874B: 0xB1A9, //HANGUL SYLLABLE NIEUN WA IEUNG + 0x874C: 0xB1AA, //HANGUL SYLLABLE NIEUN WA CIEUC + 0x874D: 0xB1AB, //HANGUL SYLLABLE NIEUN WA CHIEUCH + 0x874E: 0xB1AC, //HANGUL SYLLABLE NIEUN WA KHIEUKH + 0x874F: 0xB1AD, //HANGUL SYLLABLE NIEUN WA THIEUTH + 0x8750: 0xB1AE, //HANGUL SYLLABLE NIEUN WA PHIEUPH + 0x8751: 0xB1AF, //HANGUL SYLLABLE NIEUN WA HIEUH + 0x8752: 0xB1B0, //HANGUL SYLLABLE NIEUN WAE + 0x8753: 0xB1B1, //HANGUL SYLLABLE NIEUN WAE KIYEOK + 0x8754: 0xB1B2, //HANGUL SYLLABLE NIEUN WAE SSANGKIYEOK + 0x8755: 0xB1B3, //HANGUL SYLLABLE NIEUN WAE KIYEOKSIOS + 0x8756: 0xB1B4, //HANGUL SYLLABLE NIEUN WAE NIEUN + 0x8757: 0xB1B5, //HANGUL SYLLABLE NIEUN WAE NIEUNCIEUC + 0x8758: 0xB1B6, //HANGUL SYLLABLE NIEUN WAE NIEUNHIEUH + 0x8759: 0xB1B7, //HANGUL SYLLABLE NIEUN WAE TIKEUT + 0x875A: 0xB1B8, //HANGUL SYLLABLE NIEUN WAE RIEUL + 0x8761: 0xB1B9, //HANGUL SYLLABLE NIEUN WAE RIEULKIYEOK + 0x8762: 0xB1BA, //HANGUL SYLLABLE NIEUN WAE RIEULMIEUM + 0x8763: 0xB1BB, //HANGUL SYLLABLE NIEUN WAE RIEULPIEUP + 0x8764: 0xB1BC, //HANGUL SYLLABLE NIEUN WAE RIEULSIOS + 0x8765: 0xB1BD, //HANGUL SYLLABLE NIEUN WAE RIEULTHIEUTH + 0x8766: 0xB1BE, //HANGUL SYLLABLE NIEUN WAE RIEULPHIEUPH + 0x8767: 0xB1BF, //HANGUL SYLLABLE NIEUN WAE RIEULHIEUH + 0x8768: 0xB1C0, //HANGUL SYLLABLE NIEUN WAE MIEUM + 0x8769: 0xB1C1, //HANGUL SYLLABLE NIEUN WAE PIEUP + 0x876A: 0xB1C2, //HANGUL SYLLABLE NIEUN WAE PIEUPSIOS + 0x876B: 0xB1C3, //HANGUL SYLLABLE NIEUN WAE SIOS + 0x876C: 0xB1C4, //HANGUL SYLLABLE NIEUN WAE SSANGSIOS + 0x876D: 0xB1C5, //HANGUL SYLLABLE NIEUN WAE IEUNG + 0x876E: 0xB1C6, //HANGUL SYLLABLE NIEUN WAE CIEUC + 0x876F: 0xB1C7, //HANGUL SYLLABLE NIEUN WAE CHIEUCH + 0x8770: 0xB1C8, //HANGUL SYLLABLE NIEUN WAE KHIEUKH + 0x8771: 0xB1C9, //HANGUL SYLLABLE NIEUN WAE THIEUTH + 0x8772: 0xB1CA, //HANGUL SYLLABLE NIEUN WAE PHIEUPH + 0x8773: 0xB1CB, //HANGUL SYLLABLE NIEUN WAE HIEUH + 0x8774: 0xB1CD, //HANGUL SYLLABLE NIEUN OE KIYEOK + 0x8775: 0xB1CE, //HANGUL SYLLABLE NIEUN OE SSANGKIYEOK + 0x8776: 0xB1CF, //HANGUL SYLLABLE NIEUN OE KIYEOKSIOS + 0x8777: 0xB1D1, //HANGUL SYLLABLE NIEUN OE NIEUNCIEUC + 0x8778: 0xB1D2, //HANGUL SYLLABLE NIEUN OE NIEUNHIEUH + 0x8779: 0xB1D3, //HANGUL SYLLABLE NIEUN OE TIKEUT + 0x877A: 0xB1D5, //HANGUL SYLLABLE NIEUN OE RIEULKIYEOK + 0x8781: 0xB1D6, //HANGUL SYLLABLE NIEUN OE RIEULMIEUM + 0x8782: 0xB1D7, //HANGUL SYLLABLE NIEUN OE RIEULPIEUP + 0x8783: 0xB1D8, //HANGUL SYLLABLE NIEUN OE RIEULSIOS + 0x8784: 0xB1D9, //HANGUL SYLLABLE NIEUN OE RIEULTHIEUTH + 0x8785: 0xB1DA, //HANGUL SYLLABLE NIEUN OE RIEULPHIEUPH + 0x8786: 0xB1DB, //HANGUL SYLLABLE NIEUN OE RIEULHIEUH + 0x8787: 0xB1DE, //HANGUL SYLLABLE NIEUN OE PIEUPSIOS + 0x8788: 0xB1E0, //HANGUL SYLLABLE NIEUN OE SSANGSIOS + 0x8789: 0xB1E1, //HANGUL SYLLABLE NIEUN OE IEUNG + 0x878A: 0xB1E2, //HANGUL SYLLABLE NIEUN OE CIEUC + 0x878B: 0xB1E3, //HANGUL SYLLABLE NIEUN OE CHIEUCH + 0x878C: 0xB1E4, //HANGUL SYLLABLE NIEUN OE KHIEUKH + 0x878D: 0xB1E5, //HANGUL SYLLABLE NIEUN OE THIEUTH + 0x878E: 0xB1E6, //HANGUL SYLLABLE NIEUN OE PHIEUPH + 0x878F: 0xB1E7, //HANGUL SYLLABLE NIEUN OE HIEUH + 0x8790: 0xB1EA, //HANGUL SYLLABLE NIEUN YO SSANGKIYEOK + 0x8791: 0xB1EB, //HANGUL SYLLABLE NIEUN YO KIYEOKSIOS + 0x8792: 0xB1ED, //HANGUL SYLLABLE NIEUN YO NIEUNCIEUC + 0x8793: 0xB1EE, //HANGUL SYLLABLE NIEUN YO NIEUNHIEUH + 0x8794: 0xB1EF, //HANGUL SYLLABLE NIEUN YO TIKEUT + 0x8795: 0xB1F1, //HANGUL SYLLABLE NIEUN YO RIEULKIYEOK + 0x8796: 0xB1F2, //HANGUL SYLLABLE NIEUN YO RIEULMIEUM + 0x8797: 0xB1F3, //HANGUL SYLLABLE NIEUN YO RIEULPIEUP + 0x8798: 0xB1F4, //HANGUL SYLLABLE NIEUN YO RIEULSIOS + 0x8799: 0xB1F5, //HANGUL SYLLABLE NIEUN YO RIEULTHIEUTH + 0x879A: 0xB1F6, //HANGUL SYLLABLE NIEUN YO RIEULPHIEUPH + 0x879B: 0xB1F7, //HANGUL SYLLABLE NIEUN YO RIEULHIEUH + 0x879C: 0xB1F8, //HANGUL SYLLABLE NIEUN YO MIEUM + 0x879D: 0xB1FA, //HANGUL SYLLABLE NIEUN YO PIEUPSIOS + 0x879E: 0xB1FC, //HANGUL SYLLABLE NIEUN YO SSANGSIOS + 0x879F: 0xB1FE, //HANGUL SYLLABLE NIEUN YO CIEUC + 0x87A0: 0xB1FF, //HANGUL SYLLABLE NIEUN YO CHIEUCH + 0x87A1: 0xB200, //HANGUL SYLLABLE NIEUN YO KHIEUKH + 0x87A2: 0xB201, //HANGUL SYLLABLE NIEUN YO THIEUTH + 0x87A3: 0xB202, //HANGUL SYLLABLE NIEUN YO PHIEUPH + 0x87A4: 0xB203, //HANGUL SYLLABLE NIEUN YO HIEUH + 0x87A5: 0xB206, //HANGUL SYLLABLE NIEUN U SSANGKIYEOK + 0x87A6: 0xB207, //HANGUL SYLLABLE NIEUN U KIYEOKSIOS + 0x87A7: 0xB209, //HANGUL SYLLABLE NIEUN U NIEUNCIEUC + 0x87A8: 0xB20A, //HANGUL SYLLABLE NIEUN U NIEUNHIEUH + 0x87A9: 0xB20D, //HANGUL SYLLABLE NIEUN U RIEULKIYEOK + 0x87AA: 0xB20E, //HANGUL SYLLABLE NIEUN U RIEULMIEUM + 0x87AB: 0xB20F, //HANGUL SYLLABLE NIEUN U RIEULPIEUP + 0x87AC: 0xB210, //HANGUL SYLLABLE NIEUN U RIEULSIOS + 0x87AD: 0xB211, //HANGUL SYLLABLE NIEUN U RIEULTHIEUTH + 0x87AE: 0xB212, //HANGUL SYLLABLE NIEUN U RIEULPHIEUPH + 0x87AF: 0xB213, //HANGUL SYLLABLE NIEUN U RIEULHIEUH + 0x87B0: 0xB216, //HANGUL SYLLABLE NIEUN U PIEUPSIOS + 0x87B1: 0xB218, //HANGUL SYLLABLE NIEUN U SSANGSIOS + 0x87B2: 0xB21A, //HANGUL SYLLABLE NIEUN U CIEUC + 0x87B3: 0xB21B, //HANGUL SYLLABLE NIEUN U CHIEUCH + 0x87B4: 0xB21C, //HANGUL SYLLABLE NIEUN U KHIEUKH + 0x87B5: 0xB21D, //HANGUL SYLLABLE NIEUN U THIEUTH + 0x87B6: 0xB21E, //HANGUL SYLLABLE NIEUN U PHIEUPH + 0x87B7: 0xB21F, //HANGUL SYLLABLE NIEUN U HIEUH + 0x87B8: 0xB221, //HANGUL SYLLABLE NIEUN WEO KIYEOK + 0x87B9: 0xB222, //HANGUL SYLLABLE NIEUN WEO SSANGKIYEOK + 0x87BA: 0xB223, //HANGUL SYLLABLE NIEUN WEO KIYEOKSIOS + 0x87BB: 0xB224, //HANGUL SYLLABLE NIEUN WEO NIEUN + 0x87BC: 0xB225, //HANGUL SYLLABLE NIEUN WEO NIEUNCIEUC + 0x87BD: 0xB226, //HANGUL SYLLABLE NIEUN WEO NIEUNHIEUH + 0x87BE: 0xB227, //HANGUL SYLLABLE NIEUN WEO TIKEUT + 0x87BF: 0xB228, //HANGUL SYLLABLE NIEUN WEO RIEUL + 0x87C0: 0xB229, //HANGUL SYLLABLE NIEUN WEO RIEULKIYEOK + 0x87C1: 0xB22A, //HANGUL SYLLABLE NIEUN WEO RIEULMIEUM + 0x87C2: 0xB22B, //HANGUL SYLLABLE NIEUN WEO RIEULPIEUP + 0x87C3: 0xB22C, //HANGUL SYLLABLE NIEUN WEO RIEULSIOS + 0x87C4: 0xB22D, //HANGUL SYLLABLE NIEUN WEO RIEULTHIEUTH + 0x87C5: 0xB22E, //HANGUL SYLLABLE NIEUN WEO RIEULPHIEUPH + 0x87C6: 0xB22F, //HANGUL SYLLABLE NIEUN WEO RIEULHIEUH + 0x87C7: 0xB230, //HANGUL SYLLABLE NIEUN WEO MIEUM + 0x87C8: 0xB231, //HANGUL SYLLABLE NIEUN WEO PIEUP + 0x87C9: 0xB232, //HANGUL SYLLABLE NIEUN WEO PIEUPSIOS + 0x87CA: 0xB233, //HANGUL SYLLABLE NIEUN WEO SIOS + 0x87CB: 0xB235, //HANGUL SYLLABLE NIEUN WEO IEUNG + 0x87CC: 0xB236, //HANGUL SYLLABLE NIEUN WEO CIEUC + 0x87CD: 0xB237, //HANGUL SYLLABLE NIEUN WEO CHIEUCH + 0x87CE: 0xB238, //HANGUL SYLLABLE NIEUN WEO KHIEUKH + 0x87CF: 0xB239, //HANGUL SYLLABLE NIEUN WEO THIEUTH + 0x87D0: 0xB23A, //HANGUL SYLLABLE NIEUN WEO PHIEUPH + 0x87D1: 0xB23B, //HANGUL SYLLABLE NIEUN WEO HIEUH + 0x87D2: 0xB23D, //HANGUL SYLLABLE NIEUN WE KIYEOK + 0x87D3: 0xB23E, //HANGUL SYLLABLE NIEUN WE SSANGKIYEOK + 0x87D4: 0xB23F, //HANGUL SYLLABLE NIEUN WE KIYEOKSIOS + 0x87D5: 0xB240, //HANGUL SYLLABLE NIEUN WE NIEUN + 0x87D6: 0xB241, //HANGUL SYLLABLE NIEUN WE NIEUNCIEUC + 0x87D7: 0xB242, //HANGUL SYLLABLE NIEUN WE NIEUNHIEUH + 0x87D8: 0xB243, //HANGUL SYLLABLE NIEUN WE TIKEUT + 0x87D9: 0xB244, //HANGUL SYLLABLE NIEUN WE RIEUL + 0x87DA: 0xB245, //HANGUL SYLLABLE NIEUN WE RIEULKIYEOK + 0x87DB: 0xB246, //HANGUL SYLLABLE NIEUN WE RIEULMIEUM + 0x87DC: 0xB247, //HANGUL SYLLABLE NIEUN WE RIEULPIEUP + 0x87DD: 0xB248, //HANGUL SYLLABLE NIEUN WE RIEULSIOS + 0x87DE: 0xB249, //HANGUL SYLLABLE NIEUN WE RIEULTHIEUTH + 0x87DF: 0xB24A, //HANGUL SYLLABLE NIEUN WE RIEULPHIEUPH + 0x87E0: 0xB24B, //HANGUL SYLLABLE NIEUN WE RIEULHIEUH + 0x87E1: 0xB24C, //HANGUL SYLLABLE NIEUN WE MIEUM + 0x87E2: 0xB24D, //HANGUL SYLLABLE NIEUN WE PIEUP + 0x87E3: 0xB24E, //HANGUL SYLLABLE NIEUN WE PIEUPSIOS + 0x87E4: 0xB24F, //HANGUL SYLLABLE NIEUN WE SIOS + 0x87E5: 0xB250, //HANGUL SYLLABLE NIEUN WE SSANGSIOS + 0x87E6: 0xB251, //HANGUL SYLLABLE NIEUN WE IEUNG + 0x87E7: 0xB252, //HANGUL SYLLABLE NIEUN WE CIEUC + 0x87E8: 0xB253, //HANGUL SYLLABLE NIEUN WE CHIEUCH + 0x87E9: 0xB254, //HANGUL SYLLABLE NIEUN WE KHIEUKH + 0x87EA: 0xB255, //HANGUL SYLLABLE NIEUN WE THIEUTH + 0x87EB: 0xB256, //HANGUL SYLLABLE NIEUN WE PHIEUPH + 0x87EC: 0xB257, //HANGUL SYLLABLE NIEUN WE HIEUH + 0x87ED: 0xB259, //HANGUL SYLLABLE NIEUN WI KIYEOK + 0x87EE: 0xB25A, //HANGUL SYLLABLE NIEUN WI SSANGKIYEOK + 0x87EF: 0xB25B, //HANGUL SYLLABLE NIEUN WI KIYEOKSIOS + 0x87F0: 0xB25D, //HANGUL SYLLABLE NIEUN WI NIEUNCIEUC + 0x87F1: 0xB25E, //HANGUL SYLLABLE NIEUN WI NIEUNHIEUH + 0x87F2: 0xB25F, //HANGUL SYLLABLE NIEUN WI TIKEUT + 0x87F3: 0xB261, //HANGUL SYLLABLE NIEUN WI RIEULKIYEOK + 0x87F4: 0xB262, //HANGUL SYLLABLE NIEUN WI RIEULMIEUM + 0x87F5: 0xB263, //HANGUL SYLLABLE NIEUN WI RIEULPIEUP + 0x87F6: 0xB264, //HANGUL SYLLABLE NIEUN WI RIEULSIOS + 0x87F7: 0xB265, //HANGUL SYLLABLE NIEUN WI RIEULTHIEUTH + 0x87F8: 0xB266, //HANGUL SYLLABLE NIEUN WI RIEULPHIEUPH + 0x87F9: 0xB267, //HANGUL SYLLABLE NIEUN WI RIEULHIEUH + 0x87FA: 0xB26A, //HANGUL SYLLABLE NIEUN WI PIEUPSIOS + 0x87FB: 0xB26B, //HANGUL SYLLABLE NIEUN WI SIOS + 0x87FC: 0xB26C, //HANGUL SYLLABLE NIEUN WI SSANGSIOS + 0x87FD: 0xB26D, //HANGUL SYLLABLE NIEUN WI IEUNG + 0x87FE: 0xB26E, //HANGUL SYLLABLE NIEUN WI CIEUC + 0x8841: 0xB26F, //HANGUL SYLLABLE NIEUN WI CHIEUCH + 0x8842: 0xB270, //HANGUL SYLLABLE NIEUN WI KHIEUKH + 0x8843: 0xB271, //HANGUL SYLLABLE NIEUN WI THIEUTH + 0x8844: 0xB272, //HANGUL SYLLABLE NIEUN WI PHIEUPH + 0x8845: 0xB273, //HANGUL SYLLABLE NIEUN WI HIEUH + 0x8846: 0xB276, //HANGUL SYLLABLE NIEUN YU SSANGKIYEOK + 0x8847: 0xB277, //HANGUL SYLLABLE NIEUN YU KIYEOKSIOS + 0x8848: 0xB278, //HANGUL SYLLABLE NIEUN YU NIEUN + 0x8849: 0xB279, //HANGUL SYLLABLE NIEUN YU NIEUNCIEUC + 0x884A: 0xB27A, //HANGUL SYLLABLE NIEUN YU NIEUNHIEUH + 0x884B: 0xB27B, //HANGUL SYLLABLE NIEUN YU TIKEUT + 0x884C: 0xB27D, //HANGUL SYLLABLE NIEUN YU RIEULKIYEOK + 0x884D: 0xB27E, //HANGUL SYLLABLE NIEUN YU RIEULMIEUM + 0x884E: 0xB27F, //HANGUL SYLLABLE NIEUN YU RIEULPIEUP + 0x884F: 0xB280, //HANGUL SYLLABLE NIEUN YU RIEULSIOS + 0x8850: 0xB281, //HANGUL SYLLABLE NIEUN YU RIEULTHIEUTH + 0x8851: 0xB282, //HANGUL SYLLABLE NIEUN YU RIEULPHIEUPH + 0x8852: 0xB283, //HANGUL SYLLABLE NIEUN YU RIEULHIEUH + 0x8853: 0xB286, //HANGUL SYLLABLE NIEUN YU PIEUPSIOS + 0x8854: 0xB287, //HANGUL SYLLABLE NIEUN YU SIOS + 0x8855: 0xB288, //HANGUL SYLLABLE NIEUN YU SSANGSIOS + 0x8856: 0xB28A, //HANGUL SYLLABLE NIEUN YU CIEUC + 0x8857: 0xB28B, //HANGUL SYLLABLE NIEUN YU CHIEUCH + 0x8858: 0xB28C, //HANGUL SYLLABLE NIEUN YU KHIEUKH + 0x8859: 0xB28D, //HANGUL SYLLABLE NIEUN YU THIEUTH + 0x885A: 0xB28E, //HANGUL SYLLABLE NIEUN YU PHIEUPH + 0x8861: 0xB28F, //HANGUL SYLLABLE NIEUN YU HIEUH + 0x8862: 0xB292, //HANGUL SYLLABLE NIEUN EU SSANGKIYEOK + 0x8863: 0xB293, //HANGUL SYLLABLE NIEUN EU KIYEOKSIOS + 0x8864: 0xB295, //HANGUL SYLLABLE NIEUN EU NIEUNCIEUC + 0x8865: 0xB296, //HANGUL SYLLABLE NIEUN EU NIEUNHIEUH + 0x8866: 0xB297, //HANGUL SYLLABLE NIEUN EU TIKEUT + 0x8867: 0xB29B, //HANGUL SYLLABLE NIEUN EU RIEULPIEUP + 0x8868: 0xB29C, //HANGUL SYLLABLE NIEUN EU RIEULSIOS + 0x8869: 0xB29D, //HANGUL SYLLABLE NIEUN EU RIEULTHIEUTH + 0x886A: 0xB29E, //HANGUL SYLLABLE NIEUN EU RIEULPHIEUPH + 0x886B: 0xB29F, //HANGUL SYLLABLE NIEUN EU RIEULHIEUH + 0x886C: 0xB2A2, //HANGUL SYLLABLE NIEUN EU PIEUPSIOS + 0x886D: 0xB2A4, //HANGUL SYLLABLE NIEUN EU SSANGSIOS + 0x886E: 0xB2A7, //HANGUL SYLLABLE NIEUN EU CHIEUCH + 0x886F: 0xB2A8, //HANGUL SYLLABLE NIEUN EU KHIEUKH + 0x8870: 0xB2A9, //HANGUL SYLLABLE NIEUN EU THIEUTH + 0x8871: 0xB2AB, //HANGUL SYLLABLE NIEUN EU HIEUH + 0x8872: 0xB2AD, //HANGUL SYLLABLE NIEUN YI KIYEOK + 0x8873: 0xB2AE, //HANGUL SYLLABLE NIEUN YI SSANGKIYEOK + 0x8874: 0xB2AF, //HANGUL SYLLABLE NIEUN YI KIYEOKSIOS + 0x8875: 0xB2B1, //HANGUL SYLLABLE NIEUN YI NIEUNCIEUC + 0x8876: 0xB2B2, //HANGUL SYLLABLE NIEUN YI NIEUNHIEUH + 0x8877: 0xB2B3, //HANGUL SYLLABLE NIEUN YI TIKEUT + 0x8878: 0xB2B5, //HANGUL SYLLABLE NIEUN YI RIEULKIYEOK + 0x8879: 0xB2B6, //HANGUL SYLLABLE NIEUN YI RIEULMIEUM + 0x887A: 0xB2B7, //HANGUL SYLLABLE NIEUN YI RIEULPIEUP + 0x8881: 0xB2B8, //HANGUL SYLLABLE NIEUN YI RIEULSIOS + 0x8882: 0xB2B9, //HANGUL SYLLABLE NIEUN YI RIEULTHIEUTH + 0x8883: 0xB2BA, //HANGUL SYLLABLE NIEUN YI RIEULPHIEUPH + 0x8884: 0xB2BB, //HANGUL SYLLABLE NIEUN YI RIEULHIEUH + 0x8885: 0xB2BC, //HANGUL SYLLABLE NIEUN YI MIEUM + 0x8886: 0xB2BD, //HANGUL SYLLABLE NIEUN YI PIEUP + 0x8887: 0xB2BE, //HANGUL SYLLABLE NIEUN YI PIEUPSIOS + 0x8888: 0xB2BF, //HANGUL SYLLABLE NIEUN YI SIOS + 0x8889: 0xB2C0, //HANGUL SYLLABLE NIEUN YI SSANGSIOS + 0x888A: 0xB2C1, //HANGUL SYLLABLE NIEUN YI IEUNG + 0x888B: 0xB2C2, //HANGUL SYLLABLE NIEUN YI CIEUC + 0x888C: 0xB2C3, //HANGUL SYLLABLE NIEUN YI CHIEUCH + 0x888D: 0xB2C4, //HANGUL SYLLABLE NIEUN YI KHIEUKH + 0x888E: 0xB2C5, //HANGUL SYLLABLE NIEUN YI THIEUTH + 0x888F: 0xB2C6, //HANGUL SYLLABLE NIEUN YI PHIEUPH + 0x8890: 0xB2C7, //HANGUL SYLLABLE NIEUN YI HIEUH + 0x8891: 0xB2CA, //HANGUL SYLLABLE NIEUN I SSANGKIYEOK + 0x8892: 0xB2CB, //HANGUL SYLLABLE NIEUN I KIYEOKSIOS + 0x8893: 0xB2CD, //HANGUL SYLLABLE NIEUN I NIEUNCIEUC + 0x8894: 0xB2CE, //HANGUL SYLLABLE NIEUN I NIEUNHIEUH + 0x8895: 0xB2CF, //HANGUL SYLLABLE NIEUN I TIKEUT + 0x8896: 0xB2D1, //HANGUL SYLLABLE NIEUN I RIEULKIYEOK + 0x8897: 0xB2D3, //HANGUL SYLLABLE NIEUN I RIEULPIEUP + 0x8898: 0xB2D4, //HANGUL SYLLABLE NIEUN I RIEULSIOS + 0x8899: 0xB2D5, //HANGUL SYLLABLE NIEUN I RIEULTHIEUTH + 0x889A: 0xB2D6, //HANGUL SYLLABLE NIEUN I RIEULPHIEUPH + 0x889B: 0xB2D7, //HANGUL SYLLABLE NIEUN I RIEULHIEUH + 0x889C: 0xB2DA, //HANGUL SYLLABLE NIEUN I PIEUPSIOS + 0x889D: 0xB2DC, //HANGUL SYLLABLE NIEUN I SSANGSIOS + 0x889E: 0xB2DE, //HANGUL SYLLABLE NIEUN I CIEUC + 0x889F: 0xB2DF, //HANGUL SYLLABLE NIEUN I CHIEUCH + 0x88A0: 0xB2E0, //HANGUL SYLLABLE NIEUN I KHIEUKH + 0x88A1: 0xB2E1, //HANGUL SYLLABLE NIEUN I THIEUTH + 0x88A2: 0xB2E3, //HANGUL SYLLABLE NIEUN I HIEUH + 0x88A3: 0xB2E7, //HANGUL SYLLABLE TIKEUT A KIYEOKSIOS + 0x88A4: 0xB2E9, //HANGUL SYLLABLE TIKEUT A NIEUNCIEUC + 0x88A5: 0xB2EA, //HANGUL SYLLABLE TIKEUT A NIEUNHIEUH + 0x88A6: 0xB2F0, //HANGUL SYLLABLE TIKEUT A RIEULSIOS + 0x88A7: 0xB2F1, //HANGUL SYLLABLE TIKEUT A RIEULTHIEUTH + 0x88A8: 0xB2F2, //HANGUL SYLLABLE TIKEUT A RIEULPHIEUPH + 0x88A9: 0xB2F6, //HANGUL SYLLABLE TIKEUT A PIEUPSIOS + 0x88AA: 0xB2FC, //HANGUL SYLLABLE TIKEUT A KHIEUKH + 0x88AB: 0xB2FD, //HANGUL SYLLABLE TIKEUT A THIEUTH + 0x88AC: 0xB2FE, //HANGUL SYLLABLE TIKEUT A PHIEUPH + 0x88AD: 0xB302, //HANGUL SYLLABLE TIKEUT AE SSANGKIYEOK + 0x88AE: 0xB303, //HANGUL SYLLABLE TIKEUT AE KIYEOKSIOS + 0x88AF: 0xB305, //HANGUL SYLLABLE TIKEUT AE NIEUNCIEUC + 0x88B0: 0xB306, //HANGUL SYLLABLE TIKEUT AE NIEUNHIEUH + 0x88B1: 0xB307, //HANGUL SYLLABLE TIKEUT AE TIKEUT + 0x88B2: 0xB309, //HANGUL SYLLABLE TIKEUT AE RIEULKIYEOK + 0x88B3: 0xB30A, //HANGUL SYLLABLE TIKEUT AE RIEULMIEUM + 0x88B4: 0xB30B, //HANGUL SYLLABLE TIKEUT AE RIEULPIEUP + 0x88B5: 0xB30C, //HANGUL SYLLABLE TIKEUT AE RIEULSIOS + 0x88B6: 0xB30D, //HANGUL SYLLABLE TIKEUT AE RIEULTHIEUTH + 0x88B7: 0xB30E, //HANGUL SYLLABLE TIKEUT AE RIEULPHIEUPH + 0x88B8: 0xB30F, //HANGUL SYLLABLE TIKEUT AE RIEULHIEUH + 0x88B9: 0xB312, //HANGUL SYLLABLE TIKEUT AE PIEUPSIOS + 0x88BA: 0xB316, //HANGUL SYLLABLE TIKEUT AE CIEUC + 0x88BB: 0xB317, //HANGUL SYLLABLE TIKEUT AE CHIEUCH + 0x88BC: 0xB318, //HANGUL SYLLABLE TIKEUT AE KHIEUKH + 0x88BD: 0xB319, //HANGUL SYLLABLE TIKEUT AE THIEUTH + 0x88BE: 0xB31A, //HANGUL SYLLABLE TIKEUT AE PHIEUPH + 0x88BF: 0xB31B, //HANGUL SYLLABLE TIKEUT AE HIEUH + 0x88C0: 0xB31D, //HANGUL SYLLABLE TIKEUT YA KIYEOK + 0x88C1: 0xB31E, //HANGUL SYLLABLE TIKEUT YA SSANGKIYEOK + 0x88C2: 0xB31F, //HANGUL SYLLABLE TIKEUT YA KIYEOKSIOS + 0x88C3: 0xB320, //HANGUL SYLLABLE TIKEUT YA NIEUN + 0x88C4: 0xB321, //HANGUL SYLLABLE TIKEUT YA NIEUNCIEUC + 0x88C5: 0xB322, //HANGUL SYLLABLE TIKEUT YA NIEUNHIEUH + 0x88C6: 0xB323, //HANGUL SYLLABLE TIKEUT YA TIKEUT + 0x88C7: 0xB324, //HANGUL SYLLABLE TIKEUT YA RIEUL + 0x88C8: 0xB325, //HANGUL SYLLABLE TIKEUT YA RIEULKIYEOK + 0x88C9: 0xB326, //HANGUL SYLLABLE TIKEUT YA RIEULMIEUM + 0x88CA: 0xB327, //HANGUL SYLLABLE TIKEUT YA RIEULPIEUP + 0x88CB: 0xB328, //HANGUL SYLLABLE TIKEUT YA RIEULSIOS + 0x88CC: 0xB329, //HANGUL SYLLABLE TIKEUT YA RIEULTHIEUTH + 0x88CD: 0xB32A, //HANGUL SYLLABLE TIKEUT YA RIEULPHIEUPH + 0x88CE: 0xB32B, //HANGUL SYLLABLE TIKEUT YA RIEULHIEUH + 0x88CF: 0xB32C, //HANGUL SYLLABLE TIKEUT YA MIEUM + 0x88D0: 0xB32D, //HANGUL SYLLABLE TIKEUT YA PIEUP + 0x88D1: 0xB32E, //HANGUL SYLLABLE TIKEUT YA PIEUPSIOS + 0x88D2: 0xB32F, //HANGUL SYLLABLE TIKEUT YA SIOS + 0x88D3: 0xB330, //HANGUL SYLLABLE TIKEUT YA SSANGSIOS + 0x88D4: 0xB331, //HANGUL SYLLABLE TIKEUT YA IEUNG + 0x88D5: 0xB332, //HANGUL SYLLABLE TIKEUT YA CIEUC + 0x88D6: 0xB333, //HANGUL SYLLABLE TIKEUT YA CHIEUCH + 0x88D7: 0xB334, //HANGUL SYLLABLE TIKEUT YA KHIEUKH + 0x88D8: 0xB335, //HANGUL SYLLABLE TIKEUT YA THIEUTH + 0x88D9: 0xB336, //HANGUL SYLLABLE TIKEUT YA PHIEUPH + 0x88DA: 0xB337, //HANGUL SYLLABLE TIKEUT YA HIEUH + 0x88DB: 0xB338, //HANGUL SYLLABLE TIKEUT YAE + 0x88DC: 0xB339, //HANGUL SYLLABLE TIKEUT YAE KIYEOK + 0x88DD: 0xB33A, //HANGUL SYLLABLE TIKEUT YAE SSANGKIYEOK + 0x88DE: 0xB33B, //HANGUL SYLLABLE TIKEUT YAE KIYEOKSIOS + 0x88DF: 0xB33C, //HANGUL SYLLABLE TIKEUT YAE NIEUN + 0x88E0: 0xB33D, //HANGUL SYLLABLE TIKEUT YAE NIEUNCIEUC + 0x88E1: 0xB33E, //HANGUL SYLLABLE TIKEUT YAE NIEUNHIEUH + 0x88E2: 0xB33F, //HANGUL SYLLABLE TIKEUT YAE TIKEUT + 0x88E3: 0xB340, //HANGUL SYLLABLE TIKEUT YAE RIEUL + 0x88E4: 0xB341, //HANGUL SYLLABLE TIKEUT YAE RIEULKIYEOK + 0x88E5: 0xB342, //HANGUL SYLLABLE TIKEUT YAE RIEULMIEUM + 0x88E6: 0xB343, //HANGUL SYLLABLE TIKEUT YAE RIEULPIEUP + 0x88E7: 0xB344, //HANGUL SYLLABLE TIKEUT YAE RIEULSIOS + 0x88E8: 0xB345, //HANGUL SYLLABLE TIKEUT YAE RIEULTHIEUTH + 0x88E9: 0xB346, //HANGUL SYLLABLE TIKEUT YAE RIEULPHIEUPH + 0x88EA: 0xB347, //HANGUL SYLLABLE TIKEUT YAE RIEULHIEUH + 0x88EB: 0xB348, //HANGUL SYLLABLE TIKEUT YAE MIEUM + 0x88EC: 0xB349, //HANGUL SYLLABLE TIKEUT YAE PIEUP + 0x88ED: 0xB34A, //HANGUL SYLLABLE TIKEUT YAE PIEUPSIOS + 0x88EE: 0xB34B, //HANGUL SYLLABLE TIKEUT YAE SIOS + 0x88EF: 0xB34C, //HANGUL SYLLABLE TIKEUT YAE SSANGSIOS + 0x88F0: 0xB34D, //HANGUL SYLLABLE TIKEUT YAE IEUNG + 0x88F1: 0xB34E, //HANGUL SYLLABLE TIKEUT YAE CIEUC + 0x88F2: 0xB34F, //HANGUL SYLLABLE TIKEUT YAE CHIEUCH + 0x88F3: 0xB350, //HANGUL SYLLABLE TIKEUT YAE KHIEUKH + 0x88F4: 0xB351, //HANGUL SYLLABLE TIKEUT YAE THIEUTH + 0x88F5: 0xB352, //HANGUL SYLLABLE TIKEUT YAE PHIEUPH + 0x88F6: 0xB353, //HANGUL SYLLABLE TIKEUT YAE HIEUH + 0x88F7: 0xB357, //HANGUL SYLLABLE TIKEUT EO KIYEOKSIOS + 0x88F8: 0xB359, //HANGUL SYLLABLE TIKEUT EO NIEUNCIEUC + 0x88F9: 0xB35A, //HANGUL SYLLABLE TIKEUT EO NIEUNHIEUH + 0x88FA: 0xB35D, //HANGUL SYLLABLE TIKEUT EO RIEULKIYEOK + 0x88FB: 0xB360, //HANGUL SYLLABLE TIKEUT EO RIEULSIOS + 0x88FC: 0xB361, //HANGUL SYLLABLE TIKEUT EO RIEULTHIEUTH + 0x88FD: 0xB362, //HANGUL SYLLABLE TIKEUT EO RIEULPHIEUPH + 0x88FE: 0xB363, //HANGUL SYLLABLE TIKEUT EO RIEULHIEUH + 0x8941: 0xB366, //HANGUL SYLLABLE TIKEUT EO PIEUPSIOS + 0x8942: 0xB368, //HANGUL SYLLABLE TIKEUT EO SSANGSIOS + 0x8943: 0xB36A, //HANGUL SYLLABLE TIKEUT EO CIEUC + 0x8944: 0xB36C, //HANGUL SYLLABLE TIKEUT EO KHIEUKH + 0x8945: 0xB36D, //HANGUL SYLLABLE TIKEUT EO THIEUTH + 0x8946: 0xB36F, //HANGUL SYLLABLE TIKEUT EO HIEUH + 0x8947: 0xB372, //HANGUL SYLLABLE TIKEUT E SSANGKIYEOK + 0x8948: 0xB373, //HANGUL SYLLABLE TIKEUT E KIYEOKSIOS + 0x8949: 0xB375, //HANGUL SYLLABLE TIKEUT E NIEUNCIEUC + 0x894A: 0xB376, //HANGUL SYLLABLE TIKEUT E NIEUNHIEUH + 0x894B: 0xB377, //HANGUL SYLLABLE TIKEUT E TIKEUT + 0x894C: 0xB379, //HANGUL SYLLABLE TIKEUT E RIEULKIYEOK + 0x894D: 0xB37A, //HANGUL SYLLABLE TIKEUT E RIEULMIEUM + 0x894E: 0xB37B, //HANGUL SYLLABLE TIKEUT E RIEULPIEUP + 0x894F: 0xB37C, //HANGUL SYLLABLE TIKEUT E RIEULSIOS + 0x8950: 0xB37D, //HANGUL SYLLABLE TIKEUT E RIEULTHIEUTH + 0x8951: 0xB37E, //HANGUL SYLLABLE TIKEUT E RIEULPHIEUPH + 0x8952: 0xB37F, //HANGUL SYLLABLE TIKEUT E RIEULHIEUH + 0x8953: 0xB382, //HANGUL SYLLABLE TIKEUT E PIEUPSIOS + 0x8954: 0xB386, //HANGUL SYLLABLE TIKEUT E CIEUC + 0x8955: 0xB387, //HANGUL SYLLABLE TIKEUT E CHIEUCH + 0x8956: 0xB388, //HANGUL SYLLABLE TIKEUT E KHIEUKH + 0x8957: 0xB389, //HANGUL SYLLABLE TIKEUT E THIEUTH + 0x8958: 0xB38A, //HANGUL SYLLABLE TIKEUT E PHIEUPH + 0x8959: 0xB38B, //HANGUL SYLLABLE TIKEUT E HIEUH + 0x895A: 0xB38D, //HANGUL SYLLABLE TIKEUT YEO KIYEOK + 0x8961: 0xB38E, //HANGUL SYLLABLE TIKEUT YEO SSANGKIYEOK + 0x8962: 0xB38F, //HANGUL SYLLABLE TIKEUT YEO KIYEOKSIOS + 0x8963: 0xB391, //HANGUL SYLLABLE TIKEUT YEO NIEUNCIEUC + 0x8964: 0xB392, //HANGUL SYLLABLE TIKEUT YEO NIEUNHIEUH + 0x8965: 0xB393, //HANGUL SYLLABLE TIKEUT YEO TIKEUT + 0x8966: 0xB395, //HANGUL SYLLABLE TIKEUT YEO RIEULKIYEOK + 0x8967: 0xB396, //HANGUL SYLLABLE TIKEUT YEO RIEULMIEUM + 0x8968: 0xB397, //HANGUL SYLLABLE TIKEUT YEO RIEULPIEUP + 0x8969: 0xB398, //HANGUL SYLLABLE TIKEUT YEO RIEULSIOS + 0x896A: 0xB399, //HANGUL SYLLABLE TIKEUT YEO RIEULTHIEUTH + 0x896B: 0xB39A, //HANGUL SYLLABLE TIKEUT YEO RIEULPHIEUPH + 0x896C: 0xB39B, //HANGUL SYLLABLE TIKEUT YEO RIEULHIEUH + 0x896D: 0xB39C, //HANGUL SYLLABLE TIKEUT YEO MIEUM + 0x896E: 0xB39D, //HANGUL SYLLABLE TIKEUT YEO PIEUP + 0x896F: 0xB39E, //HANGUL SYLLABLE TIKEUT YEO PIEUPSIOS + 0x8970: 0xB39F, //HANGUL SYLLABLE TIKEUT YEO SIOS + 0x8971: 0xB3A2, //HANGUL SYLLABLE TIKEUT YEO CIEUC + 0x8972: 0xB3A3, //HANGUL SYLLABLE TIKEUT YEO CHIEUCH + 0x8973: 0xB3A4, //HANGUL SYLLABLE TIKEUT YEO KHIEUKH + 0x8974: 0xB3A5, //HANGUL SYLLABLE TIKEUT YEO THIEUTH + 0x8975: 0xB3A6, //HANGUL SYLLABLE TIKEUT YEO PHIEUPH + 0x8976: 0xB3A7, //HANGUL SYLLABLE TIKEUT YEO HIEUH + 0x8977: 0xB3A9, //HANGUL SYLLABLE TIKEUT YE KIYEOK + 0x8978: 0xB3AA, //HANGUL SYLLABLE TIKEUT YE SSANGKIYEOK + 0x8979: 0xB3AB, //HANGUL SYLLABLE TIKEUT YE KIYEOKSIOS + 0x897A: 0xB3AD, //HANGUL SYLLABLE TIKEUT YE NIEUNCIEUC + 0x8981: 0xB3AE, //HANGUL SYLLABLE TIKEUT YE NIEUNHIEUH + 0x8982: 0xB3AF, //HANGUL SYLLABLE TIKEUT YE TIKEUT + 0x8983: 0xB3B0, //HANGUL SYLLABLE TIKEUT YE RIEUL + 0x8984: 0xB3B1, //HANGUL SYLLABLE TIKEUT YE RIEULKIYEOK + 0x8985: 0xB3B2, //HANGUL SYLLABLE TIKEUT YE RIEULMIEUM + 0x8986: 0xB3B3, //HANGUL SYLLABLE TIKEUT YE RIEULPIEUP + 0x8987: 0xB3B4, //HANGUL SYLLABLE TIKEUT YE RIEULSIOS + 0x8988: 0xB3B5, //HANGUL SYLLABLE TIKEUT YE RIEULTHIEUTH + 0x8989: 0xB3B6, //HANGUL SYLLABLE TIKEUT YE RIEULPHIEUPH + 0x898A: 0xB3B7, //HANGUL SYLLABLE TIKEUT YE RIEULHIEUH + 0x898B: 0xB3B8, //HANGUL SYLLABLE TIKEUT YE MIEUM + 0x898C: 0xB3B9, //HANGUL SYLLABLE TIKEUT YE PIEUP + 0x898D: 0xB3BA, //HANGUL SYLLABLE TIKEUT YE PIEUPSIOS + 0x898E: 0xB3BB, //HANGUL SYLLABLE TIKEUT YE SIOS + 0x898F: 0xB3BC, //HANGUL SYLLABLE TIKEUT YE SSANGSIOS + 0x8990: 0xB3BD, //HANGUL SYLLABLE TIKEUT YE IEUNG + 0x8991: 0xB3BE, //HANGUL SYLLABLE TIKEUT YE CIEUC + 0x8992: 0xB3BF, //HANGUL SYLLABLE TIKEUT YE CHIEUCH + 0x8993: 0xB3C0, //HANGUL SYLLABLE TIKEUT YE KHIEUKH + 0x8994: 0xB3C1, //HANGUL SYLLABLE TIKEUT YE THIEUTH + 0x8995: 0xB3C2, //HANGUL SYLLABLE TIKEUT YE PHIEUPH + 0x8996: 0xB3C3, //HANGUL SYLLABLE TIKEUT YE HIEUH + 0x8997: 0xB3C6, //HANGUL SYLLABLE TIKEUT O SSANGKIYEOK + 0x8998: 0xB3C7, //HANGUL SYLLABLE TIKEUT O KIYEOKSIOS + 0x8999: 0xB3C9, //HANGUL SYLLABLE TIKEUT O NIEUNCIEUC + 0x899A: 0xB3CA, //HANGUL SYLLABLE TIKEUT O NIEUNHIEUH + 0x899B: 0xB3CD, //HANGUL SYLLABLE TIKEUT O RIEULKIYEOK + 0x899C: 0xB3CF, //HANGUL SYLLABLE TIKEUT O RIEULPIEUP + 0x899D: 0xB3D1, //HANGUL SYLLABLE TIKEUT O RIEULTHIEUTH + 0x899E: 0xB3D2, //HANGUL SYLLABLE TIKEUT O RIEULPHIEUPH + 0x899F: 0xB3D3, //HANGUL SYLLABLE TIKEUT O RIEULHIEUH + 0x89A0: 0xB3D6, //HANGUL SYLLABLE TIKEUT O PIEUPSIOS + 0x89A1: 0xB3D8, //HANGUL SYLLABLE TIKEUT O SSANGSIOS + 0x89A2: 0xB3DA, //HANGUL SYLLABLE TIKEUT O CIEUC + 0x89A3: 0xB3DC, //HANGUL SYLLABLE TIKEUT O KHIEUKH + 0x89A4: 0xB3DE, //HANGUL SYLLABLE TIKEUT O PHIEUPH + 0x89A5: 0xB3DF, //HANGUL SYLLABLE TIKEUT O HIEUH + 0x89A6: 0xB3E1, //HANGUL SYLLABLE TIKEUT WA KIYEOK + 0x89A7: 0xB3E2, //HANGUL SYLLABLE TIKEUT WA SSANGKIYEOK + 0x89A8: 0xB3E3, //HANGUL SYLLABLE TIKEUT WA KIYEOKSIOS + 0x89A9: 0xB3E5, //HANGUL SYLLABLE TIKEUT WA NIEUNCIEUC + 0x89AA: 0xB3E6, //HANGUL SYLLABLE TIKEUT WA NIEUNHIEUH + 0x89AB: 0xB3E7, //HANGUL SYLLABLE TIKEUT WA TIKEUT + 0x89AC: 0xB3E9, //HANGUL SYLLABLE TIKEUT WA RIEULKIYEOK + 0x89AD: 0xB3EA, //HANGUL SYLLABLE TIKEUT WA RIEULMIEUM + 0x89AE: 0xB3EB, //HANGUL SYLLABLE TIKEUT WA RIEULPIEUP + 0x89AF: 0xB3EC, //HANGUL SYLLABLE TIKEUT WA RIEULSIOS + 0x89B0: 0xB3ED, //HANGUL SYLLABLE TIKEUT WA RIEULTHIEUTH + 0x89B1: 0xB3EE, //HANGUL SYLLABLE TIKEUT WA RIEULPHIEUPH + 0x89B2: 0xB3EF, //HANGUL SYLLABLE TIKEUT WA RIEULHIEUH + 0x89B3: 0xB3F0, //HANGUL SYLLABLE TIKEUT WA MIEUM + 0x89B4: 0xB3F1, //HANGUL SYLLABLE TIKEUT WA PIEUP + 0x89B5: 0xB3F2, //HANGUL SYLLABLE TIKEUT WA PIEUPSIOS + 0x89B6: 0xB3F3, //HANGUL SYLLABLE TIKEUT WA SIOS + 0x89B7: 0xB3F4, //HANGUL SYLLABLE TIKEUT WA SSANGSIOS + 0x89B8: 0xB3F5, //HANGUL SYLLABLE TIKEUT WA IEUNG + 0x89B9: 0xB3F6, //HANGUL SYLLABLE TIKEUT WA CIEUC + 0x89BA: 0xB3F7, //HANGUL SYLLABLE TIKEUT WA CHIEUCH + 0x89BB: 0xB3F8, //HANGUL SYLLABLE TIKEUT WA KHIEUKH + 0x89BC: 0xB3F9, //HANGUL SYLLABLE TIKEUT WA THIEUTH + 0x89BD: 0xB3FA, //HANGUL SYLLABLE TIKEUT WA PHIEUPH + 0x89BE: 0xB3FB, //HANGUL SYLLABLE TIKEUT WA HIEUH + 0x89BF: 0xB3FD, //HANGUL SYLLABLE TIKEUT WAE KIYEOK + 0x89C0: 0xB3FE, //HANGUL SYLLABLE TIKEUT WAE SSANGKIYEOK + 0x89C1: 0xB3FF, //HANGUL SYLLABLE TIKEUT WAE KIYEOKSIOS + 0x89C2: 0xB400, //HANGUL SYLLABLE TIKEUT WAE NIEUN + 0x89C3: 0xB401, //HANGUL SYLLABLE TIKEUT WAE NIEUNCIEUC + 0x89C4: 0xB402, //HANGUL SYLLABLE TIKEUT WAE NIEUNHIEUH + 0x89C5: 0xB403, //HANGUL SYLLABLE TIKEUT WAE TIKEUT + 0x89C6: 0xB404, //HANGUL SYLLABLE TIKEUT WAE RIEUL + 0x89C7: 0xB405, //HANGUL SYLLABLE TIKEUT WAE RIEULKIYEOK + 0x89C8: 0xB406, //HANGUL SYLLABLE TIKEUT WAE RIEULMIEUM + 0x89C9: 0xB407, //HANGUL SYLLABLE TIKEUT WAE RIEULPIEUP + 0x89CA: 0xB408, //HANGUL SYLLABLE TIKEUT WAE RIEULSIOS + 0x89CB: 0xB409, //HANGUL SYLLABLE TIKEUT WAE RIEULTHIEUTH + 0x89CC: 0xB40A, //HANGUL SYLLABLE TIKEUT WAE RIEULPHIEUPH + 0x89CD: 0xB40B, //HANGUL SYLLABLE TIKEUT WAE RIEULHIEUH + 0x89CE: 0xB40C, //HANGUL SYLLABLE TIKEUT WAE MIEUM + 0x89CF: 0xB40D, //HANGUL SYLLABLE TIKEUT WAE PIEUP + 0x89D0: 0xB40E, //HANGUL SYLLABLE TIKEUT WAE PIEUPSIOS + 0x89D1: 0xB40F, //HANGUL SYLLABLE TIKEUT WAE SIOS + 0x89D2: 0xB411, //HANGUL SYLLABLE TIKEUT WAE IEUNG + 0x89D3: 0xB412, //HANGUL SYLLABLE TIKEUT WAE CIEUC + 0x89D4: 0xB413, //HANGUL SYLLABLE TIKEUT WAE CHIEUCH + 0x89D5: 0xB414, //HANGUL SYLLABLE TIKEUT WAE KHIEUKH + 0x89D6: 0xB415, //HANGUL SYLLABLE TIKEUT WAE THIEUTH + 0x89D7: 0xB416, //HANGUL SYLLABLE TIKEUT WAE PHIEUPH + 0x89D8: 0xB417, //HANGUL SYLLABLE TIKEUT WAE HIEUH + 0x89D9: 0xB419, //HANGUL SYLLABLE TIKEUT OE KIYEOK + 0x89DA: 0xB41A, //HANGUL SYLLABLE TIKEUT OE SSANGKIYEOK + 0x89DB: 0xB41B, //HANGUL SYLLABLE TIKEUT OE KIYEOKSIOS + 0x89DC: 0xB41D, //HANGUL SYLLABLE TIKEUT OE NIEUNCIEUC + 0x89DD: 0xB41E, //HANGUL SYLLABLE TIKEUT OE NIEUNHIEUH + 0x89DE: 0xB41F, //HANGUL SYLLABLE TIKEUT OE TIKEUT + 0x89DF: 0xB421, //HANGUL SYLLABLE TIKEUT OE RIEULKIYEOK + 0x89E0: 0xB422, //HANGUL SYLLABLE TIKEUT OE RIEULMIEUM + 0x89E1: 0xB423, //HANGUL SYLLABLE TIKEUT OE RIEULPIEUP + 0x89E2: 0xB424, //HANGUL SYLLABLE TIKEUT OE RIEULSIOS + 0x89E3: 0xB425, //HANGUL SYLLABLE TIKEUT OE RIEULTHIEUTH + 0x89E4: 0xB426, //HANGUL SYLLABLE TIKEUT OE RIEULPHIEUPH + 0x89E5: 0xB427, //HANGUL SYLLABLE TIKEUT OE RIEULHIEUH + 0x89E6: 0xB42A, //HANGUL SYLLABLE TIKEUT OE PIEUPSIOS + 0x89E7: 0xB42C, //HANGUL SYLLABLE TIKEUT OE SSANGSIOS + 0x89E8: 0xB42D, //HANGUL SYLLABLE TIKEUT OE IEUNG + 0x89E9: 0xB42E, //HANGUL SYLLABLE TIKEUT OE CIEUC + 0x89EA: 0xB42F, //HANGUL SYLLABLE TIKEUT OE CHIEUCH + 0x89EB: 0xB430, //HANGUL SYLLABLE TIKEUT OE KHIEUKH + 0x89EC: 0xB431, //HANGUL SYLLABLE TIKEUT OE THIEUTH + 0x89ED: 0xB432, //HANGUL SYLLABLE TIKEUT OE PHIEUPH + 0x89EE: 0xB433, //HANGUL SYLLABLE TIKEUT OE HIEUH + 0x89EF: 0xB435, //HANGUL SYLLABLE TIKEUT YO KIYEOK + 0x89F0: 0xB436, //HANGUL SYLLABLE TIKEUT YO SSANGKIYEOK + 0x89F1: 0xB437, //HANGUL SYLLABLE TIKEUT YO KIYEOKSIOS + 0x89F2: 0xB438, //HANGUL SYLLABLE TIKEUT YO NIEUN + 0x89F3: 0xB439, //HANGUL SYLLABLE TIKEUT YO NIEUNCIEUC + 0x89F4: 0xB43A, //HANGUL SYLLABLE TIKEUT YO NIEUNHIEUH + 0x89F5: 0xB43B, //HANGUL SYLLABLE TIKEUT YO TIKEUT + 0x89F6: 0xB43C, //HANGUL SYLLABLE TIKEUT YO RIEUL + 0x89F7: 0xB43D, //HANGUL SYLLABLE TIKEUT YO RIEULKIYEOK + 0x89F8: 0xB43E, //HANGUL SYLLABLE TIKEUT YO RIEULMIEUM + 0x89F9: 0xB43F, //HANGUL SYLLABLE TIKEUT YO RIEULPIEUP + 0x89FA: 0xB440, //HANGUL SYLLABLE TIKEUT YO RIEULSIOS + 0x89FB: 0xB441, //HANGUL SYLLABLE TIKEUT YO RIEULTHIEUTH + 0x89FC: 0xB442, //HANGUL SYLLABLE TIKEUT YO RIEULPHIEUPH + 0x89FD: 0xB443, //HANGUL SYLLABLE TIKEUT YO RIEULHIEUH + 0x89FE: 0xB444, //HANGUL SYLLABLE TIKEUT YO MIEUM + 0x8A41: 0xB445, //HANGUL SYLLABLE TIKEUT YO PIEUP + 0x8A42: 0xB446, //HANGUL SYLLABLE TIKEUT YO PIEUPSIOS + 0x8A43: 0xB447, //HANGUL SYLLABLE TIKEUT YO SIOS + 0x8A44: 0xB448, //HANGUL SYLLABLE TIKEUT YO SSANGSIOS + 0x8A45: 0xB449, //HANGUL SYLLABLE TIKEUT YO IEUNG + 0x8A46: 0xB44A, //HANGUL SYLLABLE TIKEUT YO CIEUC + 0x8A47: 0xB44B, //HANGUL SYLLABLE TIKEUT YO CHIEUCH + 0x8A48: 0xB44C, //HANGUL SYLLABLE TIKEUT YO KHIEUKH + 0x8A49: 0xB44D, //HANGUL SYLLABLE TIKEUT YO THIEUTH + 0x8A4A: 0xB44E, //HANGUL SYLLABLE TIKEUT YO PHIEUPH + 0x8A4B: 0xB44F, //HANGUL SYLLABLE TIKEUT YO HIEUH + 0x8A4C: 0xB452, //HANGUL SYLLABLE TIKEUT U SSANGKIYEOK + 0x8A4D: 0xB453, //HANGUL SYLLABLE TIKEUT U KIYEOKSIOS + 0x8A4E: 0xB455, //HANGUL SYLLABLE TIKEUT U NIEUNCIEUC + 0x8A4F: 0xB456, //HANGUL SYLLABLE TIKEUT U NIEUNHIEUH + 0x8A50: 0xB457, //HANGUL SYLLABLE TIKEUT U TIKEUT + 0x8A51: 0xB459, //HANGUL SYLLABLE TIKEUT U RIEULKIYEOK + 0x8A52: 0xB45A, //HANGUL SYLLABLE TIKEUT U RIEULMIEUM + 0x8A53: 0xB45B, //HANGUL SYLLABLE TIKEUT U RIEULPIEUP + 0x8A54: 0xB45C, //HANGUL SYLLABLE TIKEUT U RIEULSIOS + 0x8A55: 0xB45D, //HANGUL SYLLABLE TIKEUT U RIEULTHIEUTH + 0x8A56: 0xB45E, //HANGUL SYLLABLE TIKEUT U RIEULPHIEUPH + 0x8A57: 0xB45F, //HANGUL SYLLABLE TIKEUT U RIEULHIEUH + 0x8A58: 0xB462, //HANGUL SYLLABLE TIKEUT U PIEUPSIOS + 0x8A59: 0xB464, //HANGUL SYLLABLE TIKEUT U SSANGSIOS + 0x8A5A: 0xB466, //HANGUL SYLLABLE TIKEUT U CIEUC + 0x8A61: 0xB467, //HANGUL SYLLABLE TIKEUT U CHIEUCH + 0x8A62: 0xB468, //HANGUL SYLLABLE TIKEUT U KHIEUKH + 0x8A63: 0xB469, //HANGUL SYLLABLE TIKEUT U THIEUTH + 0x8A64: 0xB46A, //HANGUL SYLLABLE TIKEUT U PHIEUPH + 0x8A65: 0xB46B, //HANGUL SYLLABLE TIKEUT U HIEUH + 0x8A66: 0xB46D, //HANGUL SYLLABLE TIKEUT WEO KIYEOK + 0x8A67: 0xB46E, //HANGUL SYLLABLE TIKEUT WEO SSANGKIYEOK + 0x8A68: 0xB46F, //HANGUL SYLLABLE TIKEUT WEO KIYEOKSIOS + 0x8A69: 0xB470, //HANGUL SYLLABLE TIKEUT WEO NIEUN + 0x8A6A: 0xB471, //HANGUL SYLLABLE TIKEUT WEO NIEUNCIEUC + 0x8A6B: 0xB472, //HANGUL SYLLABLE TIKEUT WEO NIEUNHIEUH + 0x8A6C: 0xB473, //HANGUL SYLLABLE TIKEUT WEO TIKEUT + 0x8A6D: 0xB474, //HANGUL SYLLABLE TIKEUT WEO RIEUL + 0x8A6E: 0xB475, //HANGUL SYLLABLE TIKEUT WEO RIEULKIYEOK + 0x8A6F: 0xB476, //HANGUL SYLLABLE TIKEUT WEO RIEULMIEUM + 0x8A70: 0xB477, //HANGUL SYLLABLE TIKEUT WEO RIEULPIEUP + 0x8A71: 0xB478, //HANGUL SYLLABLE TIKEUT WEO RIEULSIOS + 0x8A72: 0xB479, //HANGUL SYLLABLE TIKEUT WEO RIEULTHIEUTH + 0x8A73: 0xB47A, //HANGUL SYLLABLE TIKEUT WEO RIEULPHIEUPH + 0x8A74: 0xB47B, //HANGUL SYLLABLE TIKEUT WEO RIEULHIEUH + 0x8A75: 0xB47C, //HANGUL SYLLABLE TIKEUT WEO MIEUM + 0x8A76: 0xB47D, //HANGUL SYLLABLE TIKEUT WEO PIEUP + 0x8A77: 0xB47E, //HANGUL SYLLABLE TIKEUT WEO PIEUPSIOS + 0x8A78: 0xB47F, //HANGUL SYLLABLE TIKEUT WEO SIOS + 0x8A79: 0xB481, //HANGUL SYLLABLE TIKEUT WEO IEUNG + 0x8A7A: 0xB482, //HANGUL SYLLABLE TIKEUT WEO CIEUC + 0x8A81: 0xB483, //HANGUL SYLLABLE TIKEUT WEO CHIEUCH + 0x8A82: 0xB484, //HANGUL SYLLABLE TIKEUT WEO KHIEUKH + 0x8A83: 0xB485, //HANGUL SYLLABLE TIKEUT WEO THIEUTH + 0x8A84: 0xB486, //HANGUL SYLLABLE TIKEUT WEO PHIEUPH + 0x8A85: 0xB487, //HANGUL SYLLABLE TIKEUT WEO HIEUH + 0x8A86: 0xB489, //HANGUL SYLLABLE TIKEUT WE KIYEOK + 0x8A87: 0xB48A, //HANGUL SYLLABLE TIKEUT WE SSANGKIYEOK + 0x8A88: 0xB48B, //HANGUL SYLLABLE TIKEUT WE KIYEOKSIOS + 0x8A89: 0xB48C, //HANGUL SYLLABLE TIKEUT WE NIEUN + 0x8A8A: 0xB48D, //HANGUL SYLLABLE TIKEUT WE NIEUNCIEUC + 0x8A8B: 0xB48E, //HANGUL SYLLABLE TIKEUT WE NIEUNHIEUH + 0x8A8C: 0xB48F, //HANGUL SYLLABLE TIKEUT WE TIKEUT + 0x8A8D: 0xB490, //HANGUL SYLLABLE TIKEUT WE RIEUL + 0x8A8E: 0xB491, //HANGUL SYLLABLE TIKEUT WE RIEULKIYEOK + 0x8A8F: 0xB492, //HANGUL SYLLABLE TIKEUT WE RIEULMIEUM + 0x8A90: 0xB493, //HANGUL SYLLABLE TIKEUT WE RIEULPIEUP + 0x8A91: 0xB494, //HANGUL SYLLABLE TIKEUT WE RIEULSIOS + 0x8A92: 0xB495, //HANGUL SYLLABLE TIKEUT WE RIEULTHIEUTH + 0x8A93: 0xB496, //HANGUL SYLLABLE TIKEUT WE RIEULPHIEUPH + 0x8A94: 0xB497, //HANGUL SYLLABLE TIKEUT WE RIEULHIEUH + 0x8A95: 0xB498, //HANGUL SYLLABLE TIKEUT WE MIEUM + 0x8A96: 0xB499, //HANGUL SYLLABLE TIKEUT WE PIEUP + 0x8A97: 0xB49A, //HANGUL SYLLABLE TIKEUT WE PIEUPSIOS + 0x8A98: 0xB49B, //HANGUL SYLLABLE TIKEUT WE SIOS + 0x8A99: 0xB49C, //HANGUL SYLLABLE TIKEUT WE SSANGSIOS + 0x8A9A: 0xB49E, //HANGUL SYLLABLE TIKEUT WE CIEUC + 0x8A9B: 0xB49F, //HANGUL SYLLABLE TIKEUT WE CHIEUCH + 0x8A9C: 0xB4A0, //HANGUL SYLLABLE TIKEUT WE KHIEUKH + 0x8A9D: 0xB4A1, //HANGUL SYLLABLE TIKEUT WE THIEUTH + 0x8A9E: 0xB4A2, //HANGUL SYLLABLE TIKEUT WE PHIEUPH + 0x8A9F: 0xB4A3, //HANGUL SYLLABLE TIKEUT WE HIEUH + 0x8AA0: 0xB4A5, //HANGUL SYLLABLE TIKEUT WI KIYEOK + 0x8AA1: 0xB4A6, //HANGUL SYLLABLE TIKEUT WI SSANGKIYEOK + 0x8AA2: 0xB4A7, //HANGUL SYLLABLE TIKEUT WI KIYEOKSIOS + 0x8AA3: 0xB4A9, //HANGUL SYLLABLE TIKEUT WI NIEUNCIEUC + 0x8AA4: 0xB4AA, //HANGUL SYLLABLE TIKEUT WI NIEUNHIEUH + 0x8AA5: 0xB4AB, //HANGUL SYLLABLE TIKEUT WI TIKEUT + 0x8AA6: 0xB4AD, //HANGUL SYLLABLE TIKEUT WI RIEULKIYEOK + 0x8AA7: 0xB4AE, //HANGUL SYLLABLE TIKEUT WI RIEULMIEUM + 0x8AA8: 0xB4AF, //HANGUL SYLLABLE TIKEUT WI RIEULPIEUP + 0x8AA9: 0xB4B0, //HANGUL SYLLABLE TIKEUT WI RIEULSIOS + 0x8AAA: 0xB4B1, //HANGUL SYLLABLE TIKEUT WI RIEULTHIEUTH + 0x8AAB: 0xB4B2, //HANGUL SYLLABLE TIKEUT WI RIEULPHIEUPH + 0x8AAC: 0xB4B3, //HANGUL SYLLABLE TIKEUT WI RIEULHIEUH + 0x8AAD: 0xB4B4, //HANGUL SYLLABLE TIKEUT WI MIEUM + 0x8AAE: 0xB4B6, //HANGUL SYLLABLE TIKEUT WI PIEUPSIOS + 0x8AAF: 0xB4B8, //HANGUL SYLLABLE TIKEUT WI SSANGSIOS + 0x8AB0: 0xB4BA, //HANGUL SYLLABLE TIKEUT WI CIEUC + 0x8AB1: 0xB4BB, //HANGUL SYLLABLE TIKEUT WI CHIEUCH + 0x8AB2: 0xB4BC, //HANGUL SYLLABLE TIKEUT WI KHIEUKH + 0x8AB3: 0xB4BD, //HANGUL SYLLABLE TIKEUT WI THIEUTH + 0x8AB4: 0xB4BE, //HANGUL SYLLABLE TIKEUT WI PHIEUPH + 0x8AB5: 0xB4BF, //HANGUL SYLLABLE TIKEUT WI HIEUH + 0x8AB6: 0xB4C1, //HANGUL SYLLABLE TIKEUT YU KIYEOK + 0x8AB7: 0xB4C2, //HANGUL SYLLABLE TIKEUT YU SSANGKIYEOK + 0x8AB8: 0xB4C3, //HANGUL SYLLABLE TIKEUT YU KIYEOKSIOS + 0x8AB9: 0xB4C5, //HANGUL SYLLABLE TIKEUT YU NIEUNCIEUC + 0x8ABA: 0xB4C6, //HANGUL SYLLABLE TIKEUT YU NIEUNHIEUH + 0x8ABB: 0xB4C7, //HANGUL SYLLABLE TIKEUT YU TIKEUT + 0x8ABC: 0xB4C9, //HANGUL SYLLABLE TIKEUT YU RIEULKIYEOK + 0x8ABD: 0xB4CA, //HANGUL SYLLABLE TIKEUT YU RIEULMIEUM + 0x8ABE: 0xB4CB, //HANGUL SYLLABLE TIKEUT YU RIEULPIEUP + 0x8ABF: 0xB4CC, //HANGUL SYLLABLE TIKEUT YU RIEULSIOS + 0x8AC0: 0xB4CD, //HANGUL SYLLABLE TIKEUT YU RIEULTHIEUTH + 0x8AC1: 0xB4CE, //HANGUL SYLLABLE TIKEUT YU RIEULPHIEUPH + 0x8AC2: 0xB4CF, //HANGUL SYLLABLE TIKEUT YU RIEULHIEUH + 0x8AC3: 0xB4D1, //HANGUL SYLLABLE TIKEUT YU PIEUP + 0x8AC4: 0xB4D2, //HANGUL SYLLABLE TIKEUT YU PIEUPSIOS + 0x8AC5: 0xB4D3, //HANGUL SYLLABLE TIKEUT YU SIOS + 0x8AC6: 0xB4D4, //HANGUL SYLLABLE TIKEUT YU SSANGSIOS + 0x8AC7: 0xB4D6, //HANGUL SYLLABLE TIKEUT YU CIEUC + 0x8AC8: 0xB4D7, //HANGUL SYLLABLE TIKEUT YU CHIEUCH + 0x8AC9: 0xB4D8, //HANGUL SYLLABLE TIKEUT YU KHIEUKH + 0x8ACA: 0xB4D9, //HANGUL SYLLABLE TIKEUT YU THIEUTH + 0x8ACB: 0xB4DA, //HANGUL SYLLABLE TIKEUT YU PHIEUPH + 0x8ACC: 0xB4DB, //HANGUL SYLLABLE TIKEUT YU HIEUH + 0x8ACD: 0xB4DE, //HANGUL SYLLABLE TIKEUT EU SSANGKIYEOK + 0x8ACE: 0xB4DF, //HANGUL SYLLABLE TIKEUT EU KIYEOKSIOS + 0x8ACF: 0xB4E1, //HANGUL SYLLABLE TIKEUT EU NIEUNCIEUC + 0x8AD0: 0xB4E2, //HANGUL SYLLABLE TIKEUT EU NIEUNHIEUH + 0x8AD1: 0xB4E5, //HANGUL SYLLABLE TIKEUT EU RIEULKIYEOK + 0x8AD2: 0xB4E7, //HANGUL SYLLABLE TIKEUT EU RIEULPIEUP + 0x8AD3: 0xB4E8, //HANGUL SYLLABLE TIKEUT EU RIEULSIOS + 0x8AD4: 0xB4E9, //HANGUL SYLLABLE TIKEUT EU RIEULTHIEUTH + 0x8AD5: 0xB4EA, //HANGUL SYLLABLE TIKEUT EU RIEULPHIEUPH + 0x8AD6: 0xB4EB, //HANGUL SYLLABLE TIKEUT EU RIEULHIEUH + 0x8AD7: 0xB4EE, //HANGUL SYLLABLE TIKEUT EU PIEUPSIOS + 0x8AD8: 0xB4F0, //HANGUL SYLLABLE TIKEUT EU SSANGSIOS + 0x8AD9: 0xB4F2, //HANGUL SYLLABLE TIKEUT EU CIEUC + 0x8ADA: 0xB4F3, //HANGUL SYLLABLE TIKEUT EU CHIEUCH + 0x8ADB: 0xB4F4, //HANGUL SYLLABLE TIKEUT EU KHIEUKH + 0x8ADC: 0xB4F5, //HANGUL SYLLABLE TIKEUT EU THIEUTH + 0x8ADD: 0xB4F6, //HANGUL SYLLABLE TIKEUT EU PHIEUPH + 0x8ADE: 0xB4F7, //HANGUL SYLLABLE TIKEUT EU HIEUH + 0x8ADF: 0xB4F9, //HANGUL SYLLABLE TIKEUT YI KIYEOK + 0x8AE0: 0xB4FA, //HANGUL SYLLABLE TIKEUT YI SSANGKIYEOK + 0x8AE1: 0xB4FB, //HANGUL SYLLABLE TIKEUT YI KIYEOKSIOS + 0x8AE2: 0xB4FC, //HANGUL SYLLABLE TIKEUT YI NIEUN + 0x8AE3: 0xB4FD, //HANGUL SYLLABLE TIKEUT YI NIEUNCIEUC + 0x8AE4: 0xB4FE, //HANGUL SYLLABLE TIKEUT YI NIEUNHIEUH + 0x8AE5: 0xB4FF, //HANGUL SYLLABLE TIKEUT YI TIKEUT + 0x8AE6: 0xB500, //HANGUL SYLLABLE TIKEUT YI RIEUL + 0x8AE7: 0xB501, //HANGUL SYLLABLE TIKEUT YI RIEULKIYEOK + 0x8AE8: 0xB502, //HANGUL SYLLABLE TIKEUT YI RIEULMIEUM + 0x8AE9: 0xB503, //HANGUL SYLLABLE TIKEUT YI RIEULPIEUP + 0x8AEA: 0xB504, //HANGUL SYLLABLE TIKEUT YI RIEULSIOS + 0x8AEB: 0xB505, //HANGUL SYLLABLE TIKEUT YI RIEULTHIEUTH + 0x8AEC: 0xB506, //HANGUL SYLLABLE TIKEUT YI RIEULPHIEUPH + 0x8AED: 0xB507, //HANGUL SYLLABLE TIKEUT YI RIEULHIEUH + 0x8AEE: 0xB508, //HANGUL SYLLABLE TIKEUT YI MIEUM + 0x8AEF: 0xB509, //HANGUL SYLLABLE TIKEUT YI PIEUP + 0x8AF0: 0xB50A, //HANGUL SYLLABLE TIKEUT YI PIEUPSIOS + 0x8AF1: 0xB50B, //HANGUL SYLLABLE TIKEUT YI SIOS + 0x8AF2: 0xB50C, //HANGUL SYLLABLE TIKEUT YI SSANGSIOS + 0x8AF3: 0xB50D, //HANGUL SYLLABLE TIKEUT YI IEUNG + 0x8AF4: 0xB50E, //HANGUL SYLLABLE TIKEUT YI CIEUC + 0x8AF5: 0xB50F, //HANGUL SYLLABLE TIKEUT YI CHIEUCH + 0x8AF6: 0xB510, //HANGUL SYLLABLE TIKEUT YI KHIEUKH + 0x8AF7: 0xB511, //HANGUL SYLLABLE TIKEUT YI THIEUTH + 0x8AF8: 0xB512, //HANGUL SYLLABLE TIKEUT YI PHIEUPH + 0x8AF9: 0xB513, //HANGUL SYLLABLE TIKEUT YI HIEUH + 0x8AFA: 0xB516, //HANGUL SYLLABLE TIKEUT I SSANGKIYEOK + 0x8AFB: 0xB517, //HANGUL SYLLABLE TIKEUT I KIYEOKSIOS + 0x8AFC: 0xB519, //HANGUL SYLLABLE TIKEUT I NIEUNCIEUC + 0x8AFD: 0xB51A, //HANGUL SYLLABLE TIKEUT I NIEUNHIEUH + 0x8AFE: 0xB51D, //HANGUL SYLLABLE TIKEUT I RIEULKIYEOK + 0x8B41: 0xB51E, //HANGUL SYLLABLE TIKEUT I RIEULMIEUM + 0x8B42: 0xB51F, //HANGUL SYLLABLE TIKEUT I RIEULPIEUP + 0x8B43: 0xB520, //HANGUL SYLLABLE TIKEUT I RIEULSIOS + 0x8B44: 0xB521, //HANGUL SYLLABLE TIKEUT I RIEULTHIEUTH + 0x8B45: 0xB522, //HANGUL SYLLABLE TIKEUT I RIEULPHIEUPH + 0x8B46: 0xB523, //HANGUL SYLLABLE TIKEUT I RIEULHIEUH + 0x8B47: 0xB526, //HANGUL SYLLABLE TIKEUT I PIEUPSIOS + 0x8B48: 0xB52B, //HANGUL SYLLABLE TIKEUT I CHIEUCH + 0x8B49: 0xB52C, //HANGUL SYLLABLE TIKEUT I KHIEUKH + 0x8B4A: 0xB52D, //HANGUL SYLLABLE TIKEUT I THIEUTH + 0x8B4B: 0xB52E, //HANGUL SYLLABLE TIKEUT I PHIEUPH + 0x8B4C: 0xB52F, //HANGUL SYLLABLE TIKEUT I HIEUH + 0x8B4D: 0xB532, //HANGUL SYLLABLE SSANGTIKEUT A SSANGKIYEOK + 0x8B4E: 0xB533, //HANGUL SYLLABLE SSANGTIKEUT A KIYEOKSIOS + 0x8B4F: 0xB535, //HANGUL SYLLABLE SSANGTIKEUT A NIEUNCIEUC + 0x8B50: 0xB536, //HANGUL SYLLABLE SSANGTIKEUT A NIEUNHIEUH + 0x8B51: 0xB537, //HANGUL SYLLABLE SSANGTIKEUT A TIKEUT + 0x8B52: 0xB539, //HANGUL SYLLABLE SSANGTIKEUT A RIEULKIYEOK + 0x8B53: 0xB53A, //HANGUL SYLLABLE SSANGTIKEUT A RIEULMIEUM + 0x8B54: 0xB53B, //HANGUL SYLLABLE SSANGTIKEUT A RIEULPIEUP + 0x8B55: 0xB53C, //HANGUL SYLLABLE SSANGTIKEUT A RIEULSIOS + 0x8B56: 0xB53D, //HANGUL SYLLABLE SSANGTIKEUT A RIEULTHIEUTH + 0x8B57: 0xB53E, //HANGUL SYLLABLE SSANGTIKEUT A RIEULPHIEUPH + 0x8B58: 0xB53F, //HANGUL SYLLABLE SSANGTIKEUT A RIEULHIEUH + 0x8B59: 0xB542, //HANGUL SYLLABLE SSANGTIKEUT A PIEUPSIOS + 0x8B5A: 0xB546, //HANGUL SYLLABLE SSANGTIKEUT A CIEUC + 0x8B61: 0xB547, //HANGUL SYLLABLE SSANGTIKEUT A CHIEUCH + 0x8B62: 0xB548, //HANGUL SYLLABLE SSANGTIKEUT A KHIEUKH + 0x8B63: 0xB549, //HANGUL SYLLABLE SSANGTIKEUT A THIEUTH + 0x8B64: 0xB54A, //HANGUL SYLLABLE SSANGTIKEUT A PHIEUPH + 0x8B65: 0xB54E, //HANGUL SYLLABLE SSANGTIKEUT AE SSANGKIYEOK + 0x8B66: 0xB54F, //HANGUL SYLLABLE SSANGTIKEUT AE KIYEOKSIOS + 0x8B67: 0xB551, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUNCIEUC + 0x8B68: 0xB552, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUNHIEUH + 0x8B69: 0xB553, //HANGUL SYLLABLE SSANGTIKEUT AE TIKEUT + 0x8B6A: 0xB555, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULKIYEOK + 0x8B6B: 0xB556, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULMIEUM + 0x8B6C: 0xB557, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULPIEUP + 0x8B6D: 0xB558, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULSIOS + 0x8B6E: 0xB559, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULTHIEUTH + 0x8B6F: 0xB55A, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULPHIEUPH + 0x8B70: 0xB55B, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULHIEUH + 0x8B71: 0xB55E, //HANGUL SYLLABLE SSANGTIKEUT AE PIEUPSIOS + 0x8B72: 0xB562, //HANGUL SYLLABLE SSANGTIKEUT AE CIEUC + 0x8B73: 0xB563, //HANGUL SYLLABLE SSANGTIKEUT AE CHIEUCH + 0x8B74: 0xB564, //HANGUL SYLLABLE SSANGTIKEUT AE KHIEUKH + 0x8B75: 0xB565, //HANGUL SYLLABLE SSANGTIKEUT AE THIEUTH + 0x8B76: 0xB566, //HANGUL SYLLABLE SSANGTIKEUT AE PHIEUPH + 0x8B77: 0xB567, //HANGUL SYLLABLE SSANGTIKEUT AE HIEUH + 0x8B78: 0xB568, //HANGUL SYLLABLE SSANGTIKEUT YA + 0x8B79: 0xB569, //HANGUL SYLLABLE SSANGTIKEUT YA KIYEOK + 0x8B7A: 0xB56A, //HANGUL SYLLABLE SSANGTIKEUT YA SSANGKIYEOK + 0x8B81: 0xB56B, //HANGUL SYLLABLE SSANGTIKEUT YA KIYEOKSIOS + 0x8B82: 0xB56C, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUN + 0x8B83: 0xB56D, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUNCIEUC + 0x8B84: 0xB56E, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUNHIEUH + 0x8B85: 0xB56F, //HANGUL SYLLABLE SSANGTIKEUT YA TIKEUT + 0x8B86: 0xB570, //HANGUL SYLLABLE SSANGTIKEUT YA RIEUL + 0x8B87: 0xB571, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULKIYEOK + 0x8B88: 0xB572, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULMIEUM + 0x8B89: 0xB573, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULPIEUP + 0x8B8A: 0xB574, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULSIOS + 0x8B8B: 0xB575, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULTHIEUTH + 0x8B8C: 0xB576, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULPHIEUPH + 0x8B8D: 0xB577, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULHIEUH + 0x8B8E: 0xB578, //HANGUL SYLLABLE SSANGTIKEUT YA MIEUM + 0x8B8F: 0xB579, //HANGUL SYLLABLE SSANGTIKEUT YA PIEUP + 0x8B90: 0xB57A, //HANGUL SYLLABLE SSANGTIKEUT YA PIEUPSIOS + 0x8B91: 0xB57B, //HANGUL SYLLABLE SSANGTIKEUT YA SIOS + 0x8B92: 0xB57C, //HANGUL SYLLABLE SSANGTIKEUT YA SSANGSIOS + 0x8B93: 0xB57D, //HANGUL SYLLABLE SSANGTIKEUT YA IEUNG + 0x8B94: 0xB57E, //HANGUL SYLLABLE SSANGTIKEUT YA CIEUC + 0x8B95: 0xB57F, //HANGUL SYLLABLE SSANGTIKEUT YA CHIEUCH + 0x8B96: 0xB580, //HANGUL SYLLABLE SSANGTIKEUT YA KHIEUKH + 0x8B97: 0xB581, //HANGUL SYLLABLE SSANGTIKEUT YA THIEUTH + 0x8B98: 0xB582, //HANGUL SYLLABLE SSANGTIKEUT YA PHIEUPH + 0x8B99: 0xB583, //HANGUL SYLLABLE SSANGTIKEUT YA HIEUH + 0x8B9A: 0xB584, //HANGUL SYLLABLE SSANGTIKEUT YAE + 0x8B9B: 0xB585, //HANGUL SYLLABLE SSANGTIKEUT YAE KIYEOK + 0x8B9C: 0xB586, //HANGUL SYLLABLE SSANGTIKEUT YAE SSANGKIYEOK + 0x8B9D: 0xB587, //HANGUL SYLLABLE SSANGTIKEUT YAE KIYEOKSIOS + 0x8B9E: 0xB588, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUN + 0x8B9F: 0xB589, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUNCIEUC + 0x8BA0: 0xB58A, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUNHIEUH + 0x8BA1: 0xB58B, //HANGUL SYLLABLE SSANGTIKEUT YAE TIKEUT + 0x8BA2: 0xB58C, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEUL + 0x8BA3: 0xB58D, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULKIYEOK + 0x8BA4: 0xB58E, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULMIEUM + 0x8BA5: 0xB58F, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULPIEUP + 0x8BA6: 0xB590, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULSIOS + 0x8BA7: 0xB591, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULTHIEUTH + 0x8BA8: 0xB592, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULPHIEUPH + 0x8BA9: 0xB593, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULHIEUH + 0x8BAA: 0xB594, //HANGUL SYLLABLE SSANGTIKEUT YAE MIEUM + 0x8BAB: 0xB595, //HANGUL SYLLABLE SSANGTIKEUT YAE PIEUP + 0x8BAC: 0xB596, //HANGUL SYLLABLE SSANGTIKEUT YAE PIEUPSIOS + 0x8BAD: 0xB597, //HANGUL SYLLABLE SSANGTIKEUT YAE SIOS + 0x8BAE: 0xB598, //HANGUL SYLLABLE SSANGTIKEUT YAE SSANGSIOS + 0x8BAF: 0xB599, //HANGUL SYLLABLE SSANGTIKEUT YAE IEUNG + 0x8BB0: 0xB59A, //HANGUL SYLLABLE SSANGTIKEUT YAE CIEUC + 0x8BB1: 0xB59B, //HANGUL SYLLABLE SSANGTIKEUT YAE CHIEUCH + 0x8BB2: 0xB59C, //HANGUL SYLLABLE SSANGTIKEUT YAE KHIEUKH + 0x8BB3: 0xB59D, //HANGUL SYLLABLE SSANGTIKEUT YAE THIEUTH + 0x8BB4: 0xB59E, //HANGUL SYLLABLE SSANGTIKEUT YAE PHIEUPH + 0x8BB5: 0xB59F, //HANGUL SYLLABLE SSANGTIKEUT YAE HIEUH + 0x8BB6: 0xB5A2, //HANGUL SYLLABLE SSANGTIKEUT EO SSANGKIYEOK + 0x8BB7: 0xB5A3, //HANGUL SYLLABLE SSANGTIKEUT EO KIYEOKSIOS + 0x8BB8: 0xB5A5, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUNCIEUC + 0x8BB9: 0xB5A6, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUNHIEUH + 0x8BBA: 0xB5A7, //HANGUL SYLLABLE SSANGTIKEUT EO TIKEUT + 0x8BBB: 0xB5A9, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULKIYEOK + 0x8BBC: 0xB5AC, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULSIOS + 0x8BBD: 0xB5AD, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULTHIEUTH + 0x8BBE: 0xB5AE, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULPHIEUPH + 0x8BBF: 0xB5AF, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULHIEUH + 0x8BC0: 0xB5B2, //HANGUL SYLLABLE SSANGTIKEUT EO PIEUPSIOS + 0x8BC1: 0xB5B6, //HANGUL SYLLABLE SSANGTIKEUT EO CIEUC + 0x8BC2: 0xB5B7, //HANGUL SYLLABLE SSANGTIKEUT EO CHIEUCH + 0x8BC3: 0xB5B8, //HANGUL SYLLABLE SSANGTIKEUT EO KHIEUKH + 0x8BC4: 0xB5B9, //HANGUL SYLLABLE SSANGTIKEUT EO THIEUTH + 0x8BC5: 0xB5BA, //HANGUL SYLLABLE SSANGTIKEUT EO PHIEUPH + 0x8BC6: 0xB5BE, //HANGUL SYLLABLE SSANGTIKEUT E SSANGKIYEOK + 0x8BC7: 0xB5BF, //HANGUL SYLLABLE SSANGTIKEUT E KIYEOKSIOS + 0x8BC8: 0xB5C1, //HANGUL SYLLABLE SSANGTIKEUT E NIEUNCIEUC + 0x8BC9: 0xB5C2, //HANGUL SYLLABLE SSANGTIKEUT E NIEUNHIEUH + 0x8BCA: 0xB5C3, //HANGUL SYLLABLE SSANGTIKEUT E TIKEUT + 0x8BCB: 0xB5C5, //HANGUL SYLLABLE SSANGTIKEUT E RIEULKIYEOK + 0x8BCC: 0xB5C6, //HANGUL SYLLABLE SSANGTIKEUT E RIEULMIEUM + 0x8BCD: 0xB5C7, //HANGUL SYLLABLE SSANGTIKEUT E RIEULPIEUP + 0x8BCE: 0xB5C8, //HANGUL SYLLABLE SSANGTIKEUT E RIEULSIOS + 0x8BCF: 0xB5C9, //HANGUL SYLLABLE SSANGTIKEUT E RIEULTHIEUTH + 0x8BD0: 0xB5CA, //HANGUL SYLLABLE SSANGTIKEUT E RIEULPHIEUPH + 0x8BD1: 0xB5CB, //HANGUL SYLLABLE SSANGTIKEUT E RIEULHIEUH + 0x8BD2: 0xB5CE, //HANGUL SYLLABLE SSANGTIKEUT E PIEUPSIOS + 0x8BD3: 0xB5D2, //HANGUL SYLLABLE SSANGTIKEUT E CIEUC + 0x8BD4: 0xB5D3, //HANGUL SYLLABLE SSANGTIKEUT E CHIEUCH + 0x8BD5: 0xB5D4, //HANGUL SYLLABLE SSANGTIKEUT E KHIEUKH + 0x8BD6: 0xB5D5, //HANGUL SYLLABLE SSANGTIKEUT E THIEUTH + 0x8BD7: 0xB5D6, //HANGUL SYLLABLE SSANGTIKEUT E PHIEUPH + 0x8BD8: 0xB5D7, //HANGUL SYLLABLE SSANGTIKEUT E HIEUH + 0x8BD9: 0xB5D9, //HANGUL SYLLABLE SSANGTIKEUT YEO KIYEOK + 0x8BDA: 0xB5DA, //HANGUL SYLLABLE SSANGTIKEUT YEO SSANGKIYEOK + 0x8BDB: 0xB5DB, //HANGUL SYLLABLE SSANGTIKEUT YEO KIYEOKSIOS + 0x8BDC: 0xB5DC, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUN + 0x8BDD: 0xB5DD, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUNCIEUC + 0x8BDE: 0xB5DE, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUNHIEUH + 0x8BDF: 0xB5DF, //HANGUL SYLLABLE SSANGTIKEUT YEO TIKEUT + 0x8BE0: 0xB5E0, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEUL + 0x8BE1: 0xB5E1, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULKIYEOK + 0x8BE2: 0xB5E2, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULMIEUM + 0x8BE3: 0xB5E3, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULPIEUP + 0x8BE4: 0xB5E4, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULSIOS + 0x8BE5: 0xB5E5, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULTHIEUTH + 0x8BE6: 0xB5E6, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULPHIEUPH + 0x8BE7: 0xB5E7, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULHIEUH + 0x8BE8: 0xB5E8, //HANGUL SYLLABLE SSANGTIKEUT YEO MIEUM + 0x8BE9: 0xB5E9, //HANGUL SYLLABLE SSANGTIKEUT YEO PIEUP + 0x8BEA: 0xB5EA, //HANGUL SYLLABLE SSANGTIKEUT YEO PIEUPSIOS + 0x8BEB: 0xB5EB, //HANGUL SYLLABLE SSANGTIKEUT YEO SIOS + 0x8BEC: 0xB5ED, //HANGUL SYLLABLE SSANGTIKEUT YEO IEUNG + 0x8BED: 0xB5EE, //HANGUL SYLLABLE SSANGTIKEUT YEO CIEUC + 0x8BEE: 0xB5EF, //HANGUL SYLLABLE SSANGTIKEUT YEO CHIEUCH + 0x8BEF: 0xB5F0, //HANGUL SYLLABLE SSANGTIKEUT YEO KHIEUKH + 0x8BF0: 0xB5F1, //HANGUL SYLLABLE SSANGTIKEUT YEO THIEUTH + 0x8BF1: 0xB5F2, //HANGUL SYLLABLE SSANGTIKEUT YEO PHIEUPH + 0x8BF2: 0xB5F3, //HANGUL SYLLABLE SSANGTIKEUT YEO HIEUH + 0x8BF3: 0xB5F4, //HANGUL SYLLABLE SSANGTIKEUT YE + 0x8BF4: 0xB5F5, //HANGUL SYLLABLE SSANGTIKEUT YE KIYEOK + 0x8BF5: 0xB5F6, //HANGUL SYLLABLE SSANGTIKEUT YE SSANGKIYEOK + 0x8BF6: 0xB5F7, //HANGUL SYLLABLE SSANGTIKEUT YE KIYEOKSIOS + 0x8BF7: 0xB5F8, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUN + 0x8BF8: 0xB5F9, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUNCIEUC + 0x8BF9: 0xB5FA, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUNHIEUH + 0x8BFA: 0xB5FB, //HANGUL SYLLABLE SSANGTIKEUT YE TIKEUT + 0x8BFB: 0xB5FC, //HANGUL SYLLABLE SSANGTIKEUT YE RIEUL + 0x8BFC: 0xB5FD, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULKIYEOK + 0x8BFD: 0xB5FE, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULMIEUM + 0x8BFE: 0xB5FF, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULPIEUP + 0x8C41: 0xB600, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULSIOS + 0x8C42: 0xB601, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULTHIEUTH + 0x8C43: 0xB602, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULPHIEUPH + 0x8C44: 0xB603, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULHIEUH + 0x8C45: 0xB604, //HANGUL SYLLABLE SSANGTIKEUT YE MIEUM + 0x8C46: 0xB605, //HANGUL SYLLABLE SSANGTIKEUT YE PIEUP + 0x8C47: 0xB606, //HANGUL SYLLABLE SSANGTIKEUT YE PIEUPSIOS + 0x8C48: 0xB607, //HANGUL SYLLABLE SSANGTIKEUT YE SIOS + 0x8C49: 0xB608, //HANGUL SYLLABLE SSANGTIKEUT YE SSANGSIOS + 0x8C4A: 0xB609, //HANGUL SYLLABLE SSANGTIKEUT YE IEUNG + 0x8C4B: 0xB60A, //HANGUL SYLLABLE SSANGTIKEUT YE CIEUC + 0x8C4C: 0xB60B, //HANGUL SYLLABLE SSANGTIKEUT YE CHIEUCH + 0x8C4D: 0xB60C, //HANGUL SYLLABLE SSANGTIKEUT YE KHIEUKH + 0x8C4E: 0xB60D, //HANGUL SYLLABLE SSANGTIKEUT YE THIEUTH + 0x8C4F: 0xB60E, //HANGUL SYLLABLE SSANGTIKEUT YE PHIEUPH + 0x8C50: 0xB60F, //HANGUL SYLLABLE SSANGTIKEUT YE HIEUH + 0x8C51: 0xB612, //HANGUL SYLLABLE SSANGTIKEUT O SSANGKIYEOK + 0x8C52: 0xB613, //HANGUL SYLLABLE SSANGTIKEUT O KIYEOKSIOS + 0x8C53: 0xB615, //HANGUL SYLLABLE SSANGTIKEUT O NIEUNCIEUC + 0x8C54: 0xB616, //HANGUL SYLLABLE SSANGTIKEUT O NIEUNHIEUH + 0x8C55: 0xB617, //HANGUL SYLLABLE SSANGTIKEUT O TIKEUT + 0x8C56: 0xB619, //HANGUL SYLLABLE SSANGTIKEUT O RIEULKIYEOK + 0x8C57: 0xB61A, //HANGUL SYLLABLE SSANGTIKEUT O RIEULMIEUM + 0x8C58: 0xB61B, //HANGUL SYLLABLE SSANGTIKEUT O RIEULPIEUP + 0x8C59: 0xB61C, //HANGUL SYLLABLE SSANGTIKEUT O RIEULSIOS + 0x8C5A: 0xB61D, //HANGUL SYLLABLE SSANGTIKEUT O RIEULTHIEUTH + 0x8C61: 0xB61E, //HANGUL SYLLABLE SSANGTIKEUT O RIEULPHIEUPH + 0x8C62: 0xB61F, //HANGUL SYLLABLE SSANGTIKEUT O RIEULHIEUH + 0x8C63: 0xB620, //HANGUL SYLLABLE SSANGTIKEUT O MIEUM + 0x8C64: 0xB621, //HANGUL SYLLABLE SSANGTIKEUT O PIEUP + 0x8C65: 0xB622, //HANGUL SYLLABLE SSANGTIKEUT O PIEUPSIOS + 0x8C66: 0xB623, //HANGUL SYLLABLE SSANGTIKEUT O SIOS + 0x8C67: 0xB624, //HANGUL SYLLABLE SSANGTIKEUT O SSANGSIOS + 0x8C68: 0xB626, //HANGUL SYLLABLE SSANGTIKEUT O CIEUC + 0x8C69: 0xB627, //HANGUL SYLLABLE SSANGTIKEUT O CHIEUCH + 0x8C6A: 0xB628, //HANGUL SYLLABLE SSANGTIKEUT O KHIEUKH + 0x8C6B: 0xB629, //HANGUL SYLLABLE SSANGTIKEUT O THIEUTH + 0x8C6C: 0xB62A, //HANGUL SYLLABLE SSANGTIKEUT O PHIEUPH + 0x8C6D: 0xB62B, //HANGUL SYLLABLE SSANGTIKEUT O HIEUH + 0x8C6E: 0xB62D, //HANGUL SYLLABLE SSANGTIKEUT WA KIYEOK + 0x8C6F: 0xB62E, //HANGUL SYLLABLE SSANGTIKEUT WA SSANGKIYEOK + 0x8C70: 0xB62F, //HANGUL SYLLABLE SSANGTIKEUT WA KIYEOKSIOS + 0x8C71: 0xB630, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUN + 0x8C72: 0xB631, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUNCIEUC + 0x8C73: 0xB632, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUNHIEUH + 0x8C74: 0xB633, //HANGUL SYLLABLE SSANGTIKEUT WA TIKEUT + 0x8C75: 0xB635, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULKIYEOK + 0x8C76: 0xB636, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULMIEUM + 0x8C77: 0xB637, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULPIEUP + 0x8C78: 0xB638, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULSIOS + 0x8C79: 0xB639, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULTHIEUTH + 0x8C7A: 0xB63A, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULPHIEUPH + 0x8C81: 0xB63B, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULHIEUH + 0x8C82: 0xB63C, //HANGUL SYLLABLE SSANGTIKEUT WA MIEUM + 0x8C83: 0xB63D, //HANGUL SYLLABLE SSANGTIKEUT WA PIEUP + 0x8C84: 0xB63E, //HANGUL SYLLABLE SSANGTIKEUT WA PIEUPSIOS + 0x8C85: 0xB63F, //HANGUL SYLLABLE SSANGTIKEUT WA SIOS + 0x8C86: 0xB640, //HANGUL SYLLABLE SSANGTIKEUT WA SSANGSIOS + 0x8C87: 0xB641, //HANGUL SYLLABLE SSANGTIKEUT WA IEUNG + 0x8C88: 0xB642, //HANGUL SYLLABLE SSANGTIKEUT WA CIEUC + 0x8C89: 0xB643, //HANGUL SYLLABLE SSANGTIKEUT WA CHIEUCH + 0x8C8A: 0xB644, //HANGUL SYLLABLE SSANGTIKEUT WA KHIEUKH + 0x8C8B: 0xB645, //HANGUL SYLLABLE SSANGTIKEUT WA THIEUTH + 0x8C8C: 0xB646, //HANGUL SYLLABLE SSANGTIKEUT WA PHIEUPH + 0x8C8D: 0xB647, //HANGUL SYLLABLE SSANGTIKEUT WA HIEUH + 0x8C8E: 0xB649, //HANGUL SYLLABLE SSANGTIKEUT WAE KIYEOK + 0x8C8F: 0xB64A, //HANGUL SYLLABLE SSANGTIKEUT WAE SSANGKIYEOK + 0x8C90: 0xB64B, //HANGUL SYLLABLE SSANGTIKEUT WAE KIYEOKSIOS + 0x8C91: 0xB64C, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUN + 0x8C92: 0xB64D, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUNCIEUC + 0x8C93: 0xB64E, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUNHIEUH + 0x8C94: 0xB64F, //HANGUL SYLLABLE SSANGTIKEUT WAE TIKEUT + 0x8C95: 0xB650, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEUL + 0x8C96: 0xB651, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULKIYEOK + 0x8C97: 0xB652, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULMIEUM + 0x8C98: 0xB653, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULPIEUP + 0x8C99: 0xB654, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULSIOS + 0x8C9A: 0xB655, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULTHIEUTH + 0x8C9B: 0xB656, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULPHIEUPH + 0x8C9C: 0xB657, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULHIEUH + 0x8C9D: 0xB658, //HANGUL SYLLABLE SSANGTIKEUT WAE MIEUM + 0x8C9E: 0xB659, //HANGUL SYLLABLE SSANGTIKEUT WAE PIEUP + 0x8C9F: 0xB65A, //HANGUL SYLLABLE SSANGTIKEUT WAE PIEUPSIOS + 0x8CA0: 0xB65B, //HANGUL SYLLABLE SSANGTIKEUT WAE SIOS + 0x8CA1: 0xB65C, //HANGUL SYLLABLE SSANGTIKEUT WAE SSANGSIOS + 0x8CA2: 0xB65D, //HANGUL SYLLABLE SSANGTIKEUT WAE IEUNG + 0x8CA3: 0xB65E, //HANGUL SYLLABLE SSANGTIKEUT WAE CIEUC + 0x8CA4: 0xB65F, //HANGUL SYLLABLE SSANGTIKEUT WAE CHIEUCH + 0x8CA5: 0xB660, //HANGUL SYLLABLE SSANGTIKEUT WAE KHIEUKH + 0x8CA6: 0xB661, //HANGUL SYLLABLE SSANGTIKEUT WAE THIEUTH + 0x8CA7: 0xB662, //HANGUL SYLLABLE SSANGTIKEUT WAE PHIEUPH + 0x8CA8: 0xB663, //HANGUL SYLLABLE SSANGTIKEUT WAE HIEUH + 0x8CA9: 0xB665, //HANGUL SYLLABLE SSANGTIKEUT OE KIYEOK + 0x8CAA: 0xB666, //HANGUL SYLLABLE SSANGTIKEUT OE SSANGKIYEOK + 0x8CAB: 0xB667, //HANGUL SYLLABLE SSANGTIKEUT OE KIYEOKSIOS + 0x8CAC: 0xB669, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUNCIEUC + 0x8CAD: 0xB66A, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUNHIEUH + 0x8CAE: 0xB66B, //HANGUL SYLLABLE SSANGTIKEUT OE TIKEUT + 0x8CAF: 0xB66C, //HANGUL SYLLABLE SSANGTIKEUT OE RIEUL + 0x8CB0: 0xB66D, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULKIYEOK + 0x8CB1: 0xB66E, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULMIEUM + 0x8CB2: 0xB66F, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULPIEUP + 0x8CB3: 0xB670, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULSIOS + 0x8CB4: 0xB671, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULTHIEUTH + 0x8CB5: 0xB672, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULPHIEUPH + 0x8CB6: 0xB673, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULHIEUH + 0x8CB7: 0xB674, //HANGUL SYLLABLE SSANGTIKEUT OE MIEUM + 0x8CB8: 0xB675, //HANGUL SYLLABLE SSANGTIKEUT OE PIEUP + 0x8CB9: 0xB676, //HANGUL SYLLABLE SSANGTIKEUT OE PIEUPSIOS + 0x8CBA: 0xB677, //HANGUL SYLLABLE SSANGTIKEUT OE SIOS + 0x8CBB: 0xB678, //HANGUL SYLLABLE SSANGTIKEUT OE SSANGSIOS + 0x8CBC: 0xB679, //HANGUL SYLLABLE SSANGTIKEUT OE IEUNG + 0x8CBD: 0xB67A, //HANGUL SYLLABLE SSANGTIKEUT OE CIEUC + 0x8CBE: 0xB67B, //HANGUL SYLLABLE SSANGTIKEUT OE CHIEUCH + 0x8CBF: 0xB67C, //HANGUL SYLLABLE SSANGTIKEUT OE KHIEUKH + 0x8CC0: 0xB67D, //HANGUL SYLLABLE SSANGTIKEUT OE THIEUTH + 0x8CC1: 0xB67E, //HANGUL SYLLABLE SSANGTIKEUT OE PHIEUPH + 0x8CC2: 0xB67F, //HANGUL SYLLABLE SSANGTIKEUT OE HIEUH + 0x8CC3: 0xB680, //HANGUL SYLLABLE SSANGTIKEUT YO + 0x8CC4: 0xB681, //HANGUL SYLLABLE SSANGTIKEUT YO KIYEOK + 0x8CC5: 0xB682, //HANGUL SYLLABLE SSANGTIKEUT YO SSANGKIYEOK + 0x8CC6: 0xB683, //HANGUL SYLLABLE SSANGTIKEUT YO KIYEOKSIOS + 0x8CC7: 0xB684, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUN + 0x8CC8: 0xB685, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUNCIEUC + 0x8CC9: 0xB686, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUNHIEUH + 0x8CCA: 0xB687, //HANGUL SYLLABLE SSANGTIKEUT YO TIKEUT + 0x8CCB: 0xB688, //HANGUL SYLLABLE SSANGTIKEUT YO RIEUL + 0x8CCC: 0xB689, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULKIYEOK + 0x8CCD: 0xB68A, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULMIEUM + 0x8CCE: 0xB68B, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULPIEUP + 0x8CCF: 0xB68C, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULSIOS + 0x8CD0: 0xB68D, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULTHIEUTH + 0x8CD1: 0xB68E, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULPHIEUPH + 0x8CD2: 0xB68F, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULHIEUH + 0x8CD3: 0xB690, //HANGUL SYLLABLE SSANGTIKEUT YO MIEUM + 0x8CD4: 0xB691, //HANGUL SYLLABLE SSANGTIKEUT YO PIEUP + 0x8CD5: 0xB692, //HANGUL SYLLABLE SSANGTIKEUT YO PIEUPSIOS + 0x8CD6: 0xB693, //HANGUL SYLLABLE SSANGTIKEUT YO SIOS + 0x8CD7: 0xB694, //HANGUL SYLLABLE SSANGTIKEUT YO SSANGSIOS + 0x8CD8: 0xB695, //HANGUL SYLLABLE SSANGTIKEUT YO IEUNG + 0x8CD9: 0xB696, //HANGUL SYLLABLE SSANGTIKEUT YO CIEUC + 0x8CDA: 0xB697, //HANGUL SYLLABLE SSANGTIKEUT YO CHIEUCH + 0x8CDB: 0xB698, //HANGUL SYLLABLE SSANGTIKEUT YO KHIEUKH + 0x8CDC: 0xB699, //HANGUL SYLLABLE SSANGTIKEUT YO THIEUTH + 0x8CDD: 0xB69A, //HANGUL SYLLABLE SSANGTIKEUT YO PHIEUPH + 0x8CDE: 0xB69B, //HANGUL SYLLABLE SSANGTIKEUT YO HIEUH + 0x8CDF: 0xB69E, //HANGUL SYLLABLE SSANGTIKEUT U SSANGKIYEOK + 0x8CE0: 0xB69F, //HANGUL SYLLABLE SSANGTIKEUT U KIYEOKSIOS + 0x8CE1: 0xB6A1, //HANGUL SYLLABLE SSANGTIKEUT U NIEUNCIEUC + 0x8CE2: 0xB6A2, //HANGUL SYLLABLE SSANGTIKEUT U NIEUNHIEUH + 0x8CE3: 0xB6A3, //HANGUL SYLLABLE SSANGTIKEUT U TIKEUT + 0x8CE4: 0xB6A5, //HANGUL SYLLABLE SSANGTIKEUT U RIEULKIYEOK + 0x8CE5: 0xB6A6, //HANGUL SYLLABLE SSANGTIKEUT U RIEULMIEUM + 0x8CE6: 0xB6A7, //HANGUL SYLLABLE SSANGTIKEUT U RIEULPIEUP + 0x8CE7: 0xB6A8, //HANGUL SYLLABLE SSANGTIKEUT U RIEULSIOS + 0x8CE8: 0xB6A9, //HANGUL SYLLABLE SSANGTIKEUT U RIEULTHIEUTH + 0x8CE9: 0xB6AA, //HANGUL SYLLABLE SSANGTIKEUT U RIEULPHIEUPH + 0x8CEA: 0xB6AD, //HANGUL SYLLABLE SSANGTIKEUT U PIEUP + 0x8CEB: 0xB6AE, //HANGUL SYLLABLE SSANGTIKEUT U PIEUPSIOS + 0x8CEC: 0xB6AF, //HANGUL SYLLABLE SSANGTIKEUT U SIOS + 0x8CED: 0xB6B0, //HANGUL SYLLABLE SSANGTIKEUT U SSANGSIOS + 0x8CEE: 0xB6B2, //HANGUL SYLLABLE SSANGTIKEUT U CIEUC + 0x8CEF: 0xB6B3, //HANGUL SYLLABLE SSANGTIKEUT U CHIEUCH + 0x8CF0: 0xB6B4, //HANGUL SYLLABLE SSANGTIKEUT U KHIEUKH + 0x8CF1: 0xB6B5, //HANGUL SYLLABLE SSANGTIKEUT U THIEUTH + 0x8CF2: 0xB6B6, //HANGUL SYLLABLE SSANGTIKEUT U PHIEUPH + 0x8CF3: 0xB6B7, //HANGUL SYLLABLE SSANGTIKEUT U HIEUH + 0x8CF4: 0xB6B8, //HANGUL SYLLABLE SSANGTIKEUT WEO + 0x8CF5: 0xB6B9, //HANGUL SYLLABLE SSANGTIKEUT WEO KIYEOK + 0x8CF6: 0xB6BA, //HANGUL SYLLABLE SSANGTIKEUT WEO SSANGKIYEOK + 0x8CF7: 0xB6BB, //HANGUL SYLLABLE SSANGTIKEUT WEO KIYEOKSIOS + 0x8CF8: 0xB6BC, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUN + 0x8CF9: 0xB6BD, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUNCIEUC + 0x8CFA: 0xB6BE, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUNHIEUH + 0x8CFB: 0xB6BF, //HANGUL SYLLABLE SSANGTIKEUT WEO TIKEUT + 0x8CFC: 0xB6C0, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEUL + 0x8CFD: 0xB6C1, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULKIYEOK + 0x8CFE: 0xB6C2, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULMIEUM + 0x8D41: 0xB6C3, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULPIEUP + 0x8D42: 0xB6C4, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULSIOS + 0x8D43: 0xB6C5, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULTHIEUTH + 0x8D44: 0xB6C6, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULPHIEUPH + 0x8D45: 0xB6C7, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULHIEUH + 0x8D46: 0xB6C8, //HANGUL SYLLABLE SSANGTIKEUT WEO MIEUM + 0x8D47: 0xB6C9, //HANGUL SYLLABLE SSANGTIKEUT WEO PIEUP + 0x8D48: 0xB6CA, //HANGUL SYLLABLE SSANGTIKEUT WEO PIEUPSIOS + 0x8D49: 0xB6CB, //HANGUL SYLLABLE SSANGTIKEUT WEO SIOS + 0x8D4A: 0xB6CC, //HANGUL SYLLABLE SSANGTIKEUT WEO SSANGSIOS + 0x8D4B: 0xB6CD, //HANGUL SYLLABLE SSANGTIKEUT WEO IEUNG + 0x8D4C: 0xB6CE, //HANGUL SYLLABLE SSANGTIKEUT WEO CIEUC + 0x8D4D: 0xB6CF, //HANGUL SYLLABLE SSANGTIKEUT WEO CHIEUCH + 0x8D4E: 0xB6D0, //HANGUL SYLLABLE SSANGTIKEUT WEO KHIEUKH + 0x8D4F: 0xB6D1, //HANGUL SYLLABLE SSANGTIKEUT WEO THIEUTH + 0x8D50: 0xB6D2, //HANGUL SYLLABLE SSANGTIKEUT WEO PHIEUPH + 0x8D51: 0xB6D3, //HANGUL SYLLABLE SSANGTIKEUT WEO HIEUH + 0x8D52: 0xB6D5, //HANGUL SYLLABLE SSANGTIKEUT WE KIYEOK + 0x8D53: 0xB6D6, //HANGUL SYLLABLE SSANGTIKEUT WE SSANGKIYEOK + 0x8D54: 0xB6D7, //HANGUL SYLLABLE SSANGTIKEUT WE KIYEOKSIOS + 0x8D55: 0xB6D8, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUN + 0x8D56: 0xB6D9, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUNCIEUC + 0x8D57: 0xB6DA, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUNHIEUH + 0x8D58: 0xB6DB, //HANGUL SYLLABLE SSANGTIKEUT WE TIKEUT + 0x8D59: 0xB6DC, //HANGUL SYLLABLE SSANGTIKEUT WE RIEUL + 0x8D5A: 0xB6DD, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULKIYEOK + 0x8D61: 0xB6DE, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULMIEUM + 0x8D62: 0xB6DF, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULPIEUP + 0x8D63: 0xB6E0, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULSIOS + 0x8D64: 0xB6E1, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULTHIEUTH + 0x8D65: 0xB6E2, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULPHIEUPH + 0x8D66: 0xB6E3, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULHIEUH + 0x8D67: 0xB6E4, //HANGUL SYLLABLE SSANGTIKEUT WE MIEUM + 0x8D68: 0xB6E5, //HANGUL SYLLABLE SSANGTIKEUT WE PIEUP + 0x8D69: 0xB6E6, //HANGUL SYLLABLE SSANGTIKEUT WE PIEUPSIOS + 0x8D6A: 0xB6E7, //HANGUL SYLLABLE SSANGTIKEUT WE SIOS + 0x8D6B: 0xB6E8, //HANGUL SYLLABLE SSANGTIKEUT WE SSANGSIOS + 0x8D6C: 0xB6E9, //HANGUL SYLLABLE SSANGTIKEUT WE IEUNG + 0x8D6D: 0xB6EA, //HANGUL SYLLABLE SSANGTIKEUT WE CIEUC + 0x8D6E: 0xB6EB, //HANGUL SYLLABLE SSANGTIKEUT WE CHIEUCH + 0x8D6F: 0xB6EC, //HANGUL SYLLABLE SSANGTIKEUT WE KHIEUKH + 0x8D70: 0xB6ED, //HANGUL SYLLABLE SSANGTIKEUT WE THIEUTH + 0x8D71: 0xB6EE, //HANGUL SYLLABLE SSANGTIKEUT WE PHIEUPH + 0x8D72: 0xB6EF, //HANGUL SYLLABLE SSANGTIKEUT WE HIEUH + 0x8D73: 0xB6F1, //HANGUL SYLLABLE SSANGTIKEUT WI KIYEOK + 0x8D74: 0xB6F2, //HANGUL SYLLABLE SSANGTIKEUT WI SSANGKIYEOK + 0x8D75: 0xB6F3, //HANGUL SYLLABLE SSANGTIKEUT WI KIYEOKSIOS + 0x8D76: 0xB6F5, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUNCIEUC + 0x8D77: 0xB6F6, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUNHIEUH + 0x8D78: 0xB6F7, //HANGUL SYLLABLE SSANGTIKEUT WI TIKEUT + 0x8D79: 0xB6F9, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULKIYEOK + 0x8D7A: 0xB6FA, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULMIEUM + 0x8D81: 0xB6FB, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULPIEUP + 0x8D82: 0xB6FC, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULSIOS + 0x8D83: 0xB6FD, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULTHIEUTH + 0x8D84: 0xB6FE, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULPHIEUPH + 0x8D85: 0xB6FF, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULHIEUH + 0x8D86: 0xB702, //HANGUL SYLLABLE SSANGTIKEUT WI PIEUPSIOS + 0x8D87: 0xB703, //HANGUL SYLLABLE SSANGTIKEUT WI SIOS + 0x8D88: 0xB704, //HANGUL SYLLABLE SSANGTIKEUT WI SSANGSIOS + 0x8D89: 0xB706, //HANGUL SYLLABLE SSANGTIKEUT WI CIEUC + 0x8D8A: 0xB707, //HANGUL SYLLABLE SSANGTIKEUT WI CHIEUCH + 0x8D8B: 0xB708, //HANGUL SYLLABLE SSANGTIKEUT WI KHIEUKH + 0x8D8C: 0xB709, //HANGUL SYLLABLE SSANGTIKEUT WI THIEUTH + 0x8D8D: 0xB70A, //HANGUL SYLLABLE SSANGTIKEUT WI PHIEUPH + 0x8D8E: 0xB70B, //HANGUL SYLLABLE SSANGTIKEUT WI HIEUH + 0x8D8F: 0xB70C, //HANGUL SYLLABLE SSANGTIKEUT YU + 0x8D90: 0xB70D, //HANGUL SYLLABLE SSANGTIKEUT YU KIYEOK + 0x8D91: 0xB70E, //HANGUL SYLLABLE SSANGTIKEUT YU SSANGKIYEOK + 0x8D92: 0xB70F, //HANGUL SYLLABLE SSANGTIKEUT YU KIYEOKSIOS + 0x8D93: 0xB710, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUN + 0x8D94: 0xB711, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUNCIEUC + 0x8D95: 0xB712, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUNHIEUH + 0x8D96: 0xB713, //HANGUL SYLLABLE SSANGTIKEUT YU TIKEUT + 0x8D97: 0xB714, //HANGUL SYLLABLE SSANGTIKEUT YU RIEUL + 0x8D98: 0xB715, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULKIYEOK + 0x8D99: 0xB716, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULMIEUM + 0x8D9A: 0xB717, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULPIEUP + 0x8D9B: 0xB718, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULSIOS + 0x8D9C: 0xB719, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULTHIEUTH + 0x8D9D: 0xB71A, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULPHIEUPH + 0x8D9E: 0xB71B, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULHIEUH + 0x8D9F: 0xB71C, //HANGUL SYLLABLE SSANGTIKEUT YU MIEUM + 0x8DA0: 0xB71D, //HANGUL SYLLABLE SSANGTIKEUT YU PIEUP + 0x8DA1: 0xB71E, //HANGUL SYLLABLE SSANGTIKEUT YU PIEUPSIOS + 0x8DA2: 0xB71F, //HANGUL SYLLABLE SSANGTIKEUT YU SIOS + 0x8DA3: 0xB720, //HANGUL SYLLABLE SSANGTIKEUT YU SSANGSIOS + 0x8DA4: 0xB721, //HANGUL SYLLABLE SSANGTIKEUT YU IEUNG + 0x8DA5: 0xB722, //HANGUL SYLLABLE SSANGTIKEUT YU CIEUC + 0x8DA6: 0xB723, //HANGUL SYLLABLE SSANGTIKEUT YU CHIEUCH + 0x8DA7: 0xB724, //HANGUL SYLLABLE SSANGTIKEUT YU KHIEUKH + 0x8DA8: 0xB725, //HANGUL SYLLABLE SSANGTIKEUT YU THIEUTH + 0x8DA9: 0xB726, //HANGUL SYLLABLE SSANGTIKEUT YU PHIEUPH + 0x8DAA: 0xB727, //HANGUL SYLLABLE SSANGTIKEUT YU HIEUH + 0x8DAB: 0xB72A, //HANGUL SYLLABLE SSANGTIKEUT EU SSANGKIYEOK + 0x8DAC: 0xB72B, //HANGUL SYLLABLE SSANGTIKEUT EU KIYEOKSIOS + 0x8DAD: 0xB72D, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUNCIEUC + 0x8DAE: 0xB72E, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUNHIEUH + 0x8DAF: 0xB731, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULKIYEOK + 0x8DB0: 0xB732, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULMIEUM + 0x8DB1: 0xB733, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULPIEUP + 0x8DB2: 0xB734, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULSIOS + 0x8DB3: 0xB735, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULTHIEUTH + 0x8DB4: 0xB736, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULPHIEUPH + 0x8DB5: 0xB737, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULHIEUH + 0x8DB6: 0xB73A, //HANGUL SYLLABLE SSANGTIKEUT EU PIEUPSIOS + 0x8DB7: 0xB73C, //HANGUL SYLLABLE SSANGTIKEUT EU SSANGSIOS + 0x8DB8: 0xB73D, //HANGUL SYLLABLE SSANGTIKEUT EU IEUNG + 0x8DB9: 0xB73E, //HANGUL SYLLABLE SSANGTIKEUT EU CIEUC + 0x8DBA: 0xB73F, //HANGUL SYLLABLE SSANGTIKEUT EU CHIEUCH + 0x8DBB: 0xB740, //HANGUL SYLLABLE SSANGTIKEUT EU KHIEUKH + 0x8DBC: 0xB741, //HANGUL SYLLABLE SSANGTIKEUT EU THIEUTH + 0x8DBD: 0xB742, //HANGUL SYLLABLE SSANGTIKEUT EU PHIEUPH + 0x8DBE: 0xB743, //HANGUL SYLLABLE SSANGTIKEUT EU HIEUH + 0x8DBF: 0xB745, //HANGUL SYLLABLE SSANGTIKEUT YI KIYEOK + 0x8DC0: 0xB746, //HANGUL SYLLABLE SSANGTIKEUT YI SSANGKIYEOK + 0x8DC1: 0xB747, //HANGUL SYLLABLE SSANGTIKEUT YI KIYEOKSIOS + 0x8DC2: 0xB749, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUNCIEUC + 0x8DC3: 0xB74A, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUNHIEUH + 0x8DC4: 0xB74B, //HANGUL SYLLABLE SSANGTIKEUT YI TIKEUT + 0x8DC5: 0xB74D, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULKIYEOK + 0x8DC6: 0xB74E, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULMIEUM + 0x8DC7: 0xB74F, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULPIEUP + 0x8DC8: 0xB750, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULSIOS + 0x8DC9: 0xB751, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULTHIEUTH + 0x8DCA: 0xB752, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULPHIEUPH + 0x8DCB: 0xB753, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULHIEUH + 0x8DCC: 0xB756, //HANGUL SYLLABLE SSANGTIKEUT YI PIEUPSIOS + 0x8DCD: 0xB757, //HANGUL SYLLABLE SSANGTIKEUT YI SIOS + 0x8DCE: 0xB758, //HANGUL SYLLABLE SSANGTIKEUT YI SSANGSIOS + 0x8DCF: 0xB759, //HANGUL SYLLABLE SSANGTIKEUT YI IEUNG + 0x8DD0: 0xB75A, //HANGUL SYLLABLE SSANGTIKEUT YI CIEUC + 0x8DD1: 0xB75B, //HANGUL SYLLABLE SSANGTIKEUT YI CHIEUCH + 0x8DD2: 0xB75C, //HANGUL SYLLABLE SSANGTIKEUT YI KHIEUKH + 0x8DD3: 0xB75D, //HANGUL SYLLABLE SSANGTIKEUT YI THIEUTH + 0x8DD4: 0xB75E, //HANGUL SYLLABLE SSANGTIKEUT YI PHIEUPH + 0x8DD5: 0xB75F, //HANGUL SYLLABLE SSANGTIKEUT YI HIEUH + 0x8DD6: 0xB761, //HANGUL SYLLABLE SSANGTIKEUT I KIYEOK + 0x8DD7: 0xB762, //HANGUL SYLLABLE SSANGTIKEUT I SSANGKIYEOK + 0x8DD8: 0xB763, //HANGUL SYLLABLE SSANGTIKEUT I KIYEOKSIOS + 0x8DD9: 0xB765, //HANGUL SYLLABLE SSANGTIKEUT I NIEUNCIEUC + 0x8DDA: 0xB766, //HANGUL SYLLABLE SSANGTIKEUT I NIEUNHIEUH + 0x8DDB: 0xB767, //HANGUL SYLLABLE SSANGTIKEUT I TIKEUT + 0x8DDC: 0xB769, //HANGUL SYLLABLE SSANGTIKEUT I RIEULKIYEOK + 0x8DDD: 0xB76A, //HANGUL SYLLABLE SSANGTIKEUT I RIEULMIEUM + 0x8DDE: 0xB76B, //HANGUL SYLLABLE SSANGTIKEUT I RIEULPIEUP + 0x8DDF: 0xB76C, //HANGUL SYLLABLE SSANGTIKEUT I RIEULSIOS + 0x8DE0: 0xB76D, //HANGUL SYLLABLE SSANGTIKEUT I RIEULTHIEUTH + 0x8DE1: 0xB76E, //HANGUL SYLLABLE SSANGTIKEUT I RIEULPHIEUPH + 0x8DE2: 0xB76F, //HANGUL SYLLABLE SSANGTIKEUT I RIEULHIEUH + 0x8DE3: 0xB772, //HANGUL SYLLABLE SSANGTIKEUT I PIEUPSIOS + 0x8DE4: 0xB774, //HANGUL SYLLABLE SSANGTIKEUT I SSANGSIOS + 0x8DE5: 0xB776, //HANGUL SYLLABLE SSANGTIKEUT I CIEUC + 0x8DE6: 0xB777, //HANGUL SYLLABLE SSANGTIKEUT I CHIEUCH + 0x8DE7: 0xB778, //HANGUL SYLLABLE SSANGTIKEUT I KHIEUKH + 0x8DE8: 0xB779, //HANGUL SYLLABLE SSANGTIKEUT I THIEUTH + 0x8DE9: 0xB77A, //HANGUL SYLLABLE SSANGTIKEUT I PHIEUPH + 0x8DEA: 0xB77B, //HANGUL SYLLABLE SSANGTIKEUT I HIEUH + 0x8DEB: 0xB77E, //HANGUL SYLLABLE RIEUL A SSANGKIYEOK + 0x8DEC: 0xB77F, //HANGUL SYLLABLE RIEUL A KIYEOKSIOS + 0x8DED: 0xB781, //HANGUL SYLLABLE RIEUL A NIEUNCIEUC + 0x8DEE: 0xB782, //HANGUL SYLLABLE RIEUL A NIEUNHIEUH + 0x8DEF: 0xB783, //HANGUL SYLLABLE RIEUL A TIKEUT + 0x8DF0: 0xB785, //HANGUL SYLLABLE RIEUL A RIEULKIYEOK + 0x8DF1: 0xB786, //HANGUL SYLLABLE RIEUL A RIEULMIEUM + 0x8DF2: 0xB787, //HANGUL SYLLABLE RIEUL A RIEULPIEUP + 0x8DF3: 0xB788, //HANGUL SYLLABLE RIEUL A RIEULSIOS + 0x8DF4: 0xB789, //HANGUL SYLLABLE RIEUL A RIEULTHIEUTH + 0x8DF5: 0xB78A, //HANGUL SYLLABLE RIEUL A RIEULPHIEUPH + 0x8DF6: 0xB78B, //HANGUL SYLLABLE RIEUL A RIEULHIEUH + 0x8DF7: 0xB78E, //HANGUL SYLLABLE RIEUL A PIEUPSIOS + 0x8DF8: 0xB793, //HANGUL SYLLABLE RIEUL A CHIEUCH + 0x8DF9: 0xB794, //HANGUL SYLLABLE RIEUL A KHIEUKH + 0x8DFA: 0xB795, //HANGUL SYLLABLE RIEUL A THIEUTH + 0x8DFB: 0xB79A, //HANGUL SYLLABLE RIEUL AE SSANGKIYEOK + 0x8DFC: 0xB79B, //HANGUL SYLLABLE RIEUL AE KIYEOKSIOS + 0x8DFD: 0xB79D, //HANGUL SYLLABLE RIEUL AE NIEUNCIEUC + 0x8DFE: 0xB79E, //HANGUL SYLLABLE RIEUL AE NIEUNHIEUH + 0x8E41: 0xB79F, //HANGUL SYLLABLE RIEUL AE TIKEUT + 0x8E42: 0xB7A1, //HANGUL SYLLABLE RIEUL AE RIEULKIYEOK + 0x8E43: 0xB7A2, //HANGUL SYLLABLE RIEUL AE RIEULMIEUM + 0x8E44: 0xB7A3, //HANGUL SYLLABLE RIEUL AE RIEULPIEUP + 0x8E45: 0xB7A4, //HANGUL SYLLABLE RIEUL AE RIEULSIOS + 0x8E46: 0xB7A5, //HANGUL SYLLABLE RIEUL AE RIEULTHIEUTH + 0x8E47: 0xB7A6, //HANGUL SYLLABLE RIEUL AE RIEULPHIEUPH + 0x8E48: 0xB7A7, //HANGUL SYLLABLE RIEUL AE RIEULHIEUH + 0x8E49: 0xB7AA, //HANGUL SYLLABLE RIEUL AE PIEUPSIOS + 0x8E4A: 0xB7AE, //HANGUL SYLLABLE RIEUL AE CIEUC + 0x8E4B: 0xB7AF, //HANGUL SYLLABLE RIEUL AE CHIEUCH + 0x8E4C: 0xB7B0, //HANGUL SYLLABLE RIEUL AE KHIEUKH + 0x8E4D: 0xB7B1, //HANGUL SYLLABLE RIEUL AE THIEUTH + 0x8E4E: 0xB7B2, //HANGUL SYLLABLE RIEUL AE PHIEUPH + 0x8E4F: 0xB7B3, //HANGUL SYLLABLE RIEUL AE HIEUH + 0x8E50: 0xB7B6, //HANGUL SYLLABLE RIEUL YA SSANGKIYEOK + 0x8E51: 0xB7B7, //HANGUL SYLLABLE RIEUL YA KIYEOKSIOS + 0x8E52: 0xB7B9, //HANGUL SYLLABLE RIEUL YA NIEUNCIEUC + 0x8E53: 0xB7BA, //HANGUL SYLLABLE RIEUL YA NIEUNHIEUH + 0x8E54: 0xB7BB, //HANGUL SYLLABLE RIEUL YA TIKEUT + 0x8E55: 0xB7BC, //HANGUL SYLLABLE RIEUL YA RIEUL + 0x8E56: 0xB7BD, //HANGUL SYLLABLE RIEUL YA RIEULKIYEOK + 0x8E57: 0xB7BE, //HANGUL SYLLABLE RIEUL YA RIEULMIEUM + 0x8E58: 0xB7BF, //HANGUL SYLLABLE RIEUL YA RIEULPIEUP + 0x8E59: 0xB7C0, //HANGUL SYLLABLE RIEUL YA RIEULSIOS + 0x8E5A: 0xB7C1, //HANGUL SYLLABLE RIEUL YA RIEULTHIEUTH + 0x8E61: 0xB7C2, //HANGUL SYLLABLE RIEUL YA RIEULPHIEUPH + 0x8E62: 0xB7C3, //HANGUL SYLLABLE RIEUL YA RIEULHIEUH + 0x8E63: 0xB7C4, //HANGUL SYLLABLE RIEUL YA MIEUM + 0x8E64: 0xB7C5, //HANGUL SYLLABLE RIEUL YA PIEUP + 0x8E65: 0xB7C6, //HANGUL SYLLABLE RIEUL YA PIEUPSIOS + 0x8E66: 0xB7C8, //HANGUL SYLLABLE RIEUL YA SSANGSIOS + 0x8E67: 0xB7CA, //HANGUL SYLLABLE RIEUL YA CIEUC + 0x8E68: 0xB7CB, //HANGUL SYLLABLE RIEUL YA CHIEUCH + 0x8E69: 0xB7CC, //HANGUL SYLLABLE RIEUL YA KHIEUKH + 0x8E6A: 0xB7CD, //HANGUL SYLLABLE RIEUL YA THIEUTH + 0x8E6B: 0xB7CE, //HANGUL SYLLABLE RIEUL YA PHIEUPH + 0x8E6C: 0xB7CF, //HANGUL SYLLABLE RIEUL YA HIEUH + 0x8E6D: 0xB7D0, //HANGUL SYLLABLE RIEUL YAE + 0x8E6E: 0xB7D1, //HANGUL SYLLABLE RIEUL YAE KIYEOK + 0x8E6F: 0xB7D2, //HANGUL SYLLABLE RIEUL YAE SSANGKIYEOK + 0x8E70: 0xB7D3, //HANGUL SYLLABLE RIEUL YAE KIYEOKSIOS + 0x8E71: 0xB7D4, //HANGUL SYLLABLE RIEUL YAE NIEUN + 0x8E72: 0xB7D5, //HANGUL SYLLABLE RIEUL YAE NIEUNCIEUC + 0x8E73: 0xB7D6, //HANGUL SYLLABLE RIEUL YAE NIEUNHIEUH + 0x8E74: 0xB7D7, //HANGUL SYLLABLE RIEUL YAE TIKEUT + 0x8E75: 0xB7D8, //HANGUL SYLLABLE RIEUL YAE RIEUL + 0x8E76: 0xB7D9, //HANGUL SYLLABLE RIEUL YAE RIEULKIYEOK + 0x8E77: 0xB7DA, //HANGUL SYLLABLE RIEUL YAE RIEULMIEUM + 0x8E78: 0xB7DB, //HANGUL SYLLABLE RIEUL YAE RIEULPIEUP + 0x8E79: 0xB7DC, //HANGUL SYLLABLE RIEUL YAE RIEULSIOS + 0x8E7A: 0xB7DD, //HANGUL SYLLABLE RIEUL YAE RIEULTHIEUTH + 0x8E81: 0xB7DE, //HANGUL SYLLABLE RIEUL YAE RIEULPHIEUPH + 0x8E82: 0xB7DF, //HANGUL SYLLABLE RIEUL YAE RIEULHIEUH + 0x8E83: 0xB7E0, //HANGUL SYLLABLE RIEUL YAE MIEUM + 0x8E84: 0xB7E1, //HANGUL SYLLABLE RIEUL YAE PIEUP + 0x8E85: 0xB7E2, //HANGUL SYLLABLE RIEUL YAE PIEUPSIOS + 0x8E86: 0xB7E3, //HANGUL SYLLABLE RIEUL YAE SIOS + 0x8E87: 0xB7E4, //HANGUL SYLLABLE RIEUL YAE SSANGSIOS + 0x8E88: 0xB7E5, //HANGUL SYLLABLE RIEUL YAE IEUNG + 0x8E89: 0xB7E6, //HANGUL SYLLABLE RIEUL YAE CIEUC + 0x8E8A: 0xB7E7, //HANGUL SYLLABLE RIEUL YAE CHIEUCH + 0x8E8B: 0xB7E8, //HANGUL SYLLABLE RIEUL YAE KHIEUKH + 0x8E8C: 0xB7E9, //HANGUL SYLLABLE RIEUL YAE THIEUTH + 0x8E8D: 0xB7EA, //HANGUL SYLLABLE RIEUL YAE PHIEUPH + 0x8E8E: 0xB7EB, //HANGUL SYLLABLE RIEUL YAE HIEUH + 0x8E8F: 0xB7EE, //HANGUL SYLLABLE RIEUL EO SSANGKIYEOK + 0x8E90: 0xB7EF, //HANGUL SYLLABLE RIEUL EO KIYEOKSIOS + 0x8E91: 0xB7F1, //HANGUL SYLLABLE RIEUL EO NIEUNCIEUC + 0x8E92: 0xB7F2, //HANGUL SYLLABLE RIEUL EO NIEUNHIEUH + 0x8E93: 0xB7F3, //HANGUL SYLLABLE RIEUL EO TIKEUT + 0x8E94: 0xB7F5, //HANGUL SYLLABLE RIEUL EO RIEULKIYEOK + 0x8E95: 0xB7F6, //HANGUL SYLLABLE RIEUL EO RIEULMIEUM + 0x8E96: 0xB7F7, //HANGUL SYLLABLE RIEUL EO RIEULPIEUP + 0x8E97: 0xB7F8, //HANGUL SYLLABLE RIEUL EO RIEULSIOS + 0x8E98: 0xB7F9, //HANGUL SYLLABLE RIEUL EO RIEULTHIEUTH + 0x8E99: 0xB7FA, //HANGUL SYLLABLE RIEUL EO RIEULPHIEUPH + 0x8E9A: 0xB7FB, //HANGUL SYLLABLE RIEUL EO RIEULHIEUH + 0x8E9B: 0xB7FE, //HANGUL SYLLABLE RIEUL EO PIEUPSIOS + 0x8E9C: 0xB802, //HANGUL SYLLABLE RIEUL EO CIEUC + 0x8E9D: 0xB803, //HANGUL SYLLABLE RIEUL EO CHIEUCH + 0x8E9E: 0xB804, //HANGUL SYLLABLE RIEUL EO KHIEUKH + 0x8E9F: 0xB805, //HANGUL SYLLABLE RIEUL EO THIEUTH + 0x8EA0: 0xB806, //HANGUL SYLLABLE RIEUL EO PHIEUPH + 0x8EA1: 0xB80A, //HANGUL SYLLABLE RIEUL E SSANGKIYEOK + 0x8EA2: 0xB80B, //HANGUL SYLLABLE RIEUL E KIYEOKSIOS + 0x8EA3: 0xB80D, //HANGUL SYLLABLE RIEUL E NIEUNCIEUC + 0x8EA4: 0xB80E, //HANGUL SYLLABLE RIEUL E NIEUNHIEUH + 0x8EA5: 0xB80F, //HANGUL SYLLABLE RIEUL E TIKEUT + 0x8EA6: 0xB811, //HANGUL SYLLABLE RIEUL E RIEULKIYEOK + 0x8EA7: 0xB812, //HANGUL SYLLABLE RIEUL E RIEULMIEUM + 0x8EA8: 0xB813, //HANGUL SYLLABLE RIEUL E RIEULPIEUP + 0x8EA9: 0xB814, //HANGUL SYLLABLE RIEUL E RIEULSIOS + 0x8EAA: 0xB815, //HANGUL SYLLABLE RIEUL E RIEULTHIEUTH + 0x8EAB: 0xB816, //HANGUL SYLLABLE RIEUL E RIEULPHIEUPH + 0x8EAC: 0xB817, //HANGUL SYLLABLE RIEUL E RIEULHIEUH + 0x8EAD: 0xB81A, //HANGUL SYLLABLE RIEUL E PIEUPSIOS + 0x8EAE: 0xB81C, //HANGUL SYLLABLE RIEUL E SSANGSIOS + 0x8EAF: 0xB81E, //HANGUL SYLLABLE RIEUL E CIEUC + 0x8EB0: 0xB81F, //HANGUL SYLLABLE RIEUL E CHIEUCH + 0x8EB1: 0xB820, //HANGUL SYLLABLE RIEUL E KHIEUKH + 0x8EB2: 0xB821, //HANGUL SYLLABLE RIEUL E THIEUTH + 0x8EB3: 0xB822, //HANGUL SYLLABLE RIEUL E PHIEUPH + 0x8EB4: 0xB823, //HANGUL SYLLABLE RIEUL E HIEUH + 0x8EB5: 0xB826, //HANGUL SYLLABLE RIEUL YEO SSANGKIYEOK + 0x8EB6: 0xB827, //HANGUL SYLLABLE RIEUL YEO KIYEOKSIOS + 0x8EB7: 0xB829, //HANGUL SYLLABLE RIEUL YEO NIEUNCIEUC + 0x8EB8: 0xB82A, //HANGUL SYLLABLE RIEUL YEO NIEUNHIEUH + 0x8EB9: 0xB82B, //HANGUL SYLLABLE RIEUL YEO TIKEUT + 0x8EBA: 0xB82D, //HANGUL SYLLABLE RIEUL YEO RIEULKIYEOK + 0x8EBB: 0xB82E, //HANGUL SYLLABLE RIEUL YEO RIEULMIEUM + 0x8EBC: 0xB82F, //HANGUL SYLLABLE RIEUL YEO RIEULPIEUP + 0x8EBD: 0xB830, //HANGUL SYLLABLE RIEUL YEO RIEULSIOS + 0x8EBE: 0xB831, //HANGUL SYLLABLE RIEUL YEO RIEULTHIEUTH + 0x8EBF: 0xB832, //HANGUL SYLLABLE RIEUL YEO RIEULPHIEUPH + 0x8EC0: 0xB833, //HANGUL SYLLABLE RIEUL YEO RIEULHIEUH + 0x8EC1: 0xB836, //HANGUL SYLLABLE RIEUL YEO PIEUPSIOS + 0x8EC2: 0xB83A, //HANGUL SYLLABLE RIEUL YEO CIEUC + 0x8EC3: 0xB83B, //HANGUL SYLLABLE RIEUL YEO CHIEUCH + 0x8EC4: 0xB83C, //HANGUL SYLLABLE RIEUL YEO KHIEUKH + 0x8EC5: 0xB83D, //HANGUL SYLLABLE RIEUL YEO THIEUTH + 0x8EC6: 0xB83E, //HANGUL SYLLABLE RIEUL YEO PHIEUPH + 0x8EC7: 0xB83F, //HANGUL SYLLABLE RIEUL YEO HIEUH + 0x8EC8: 0xB841, //HANGUL SYLLABLE RIEUL YE KIYEOK + 0x8EC9: 0xB842, //HANGUL SYLLABLE RIEUL YE SSANGKIYEOK + 0x8ECA: 0xB843, //HANGUL SYLLABLE RIEUL YE KIYEOKSIOS + 0x8ECB: 0xB845, //HANGUL SYLLABLE RIEUL YE NIEUNCIEUC + 0x8ECC: 0xB846, //HANGUL SYLLABLE RIEUL YE NIEUNHIEUH + 0x8ECD: 0xB847, //HANGUL SYLLABLE RIEUL YE TIKEUT + 0x8ECE: 0xB848, //HANGUL SYLLABLE RIEUL YE RIEUL + 0x8ECF: 0xB849, //HANGUL SYLLABLE RIEUL YE RIEULKIYEOK + 0x8ED0: 0xB84A, //HANGUL SYLLABLE RIEUL YE RIEULMIEUM + 0x8ED1: 0xB84B, //HANGUL SYLLABLE RIEUL YE RIEULPIEUP + 0x8ED2: 0xB84C, //HANGUL SYLLABLE RIEUL YE RIEULSIOS + 0x8ED3: 0xB84D, //HANGUL SYLLABLE RIEUL YE RIEULTHIEUTH + 0x8ED4: 0xB84E, //HANGUL SYLLABLE RIEUL YE RIEULPHIEUPH + 0x8ED5: 0xB84F, //HANGUL SYLLABLE RIEUL YE RIEULHIEUH + 0x8ED6: 0xB850, //HANGUL SYLLABLE RIEUL YE MIEUM + 0x8ED7: 0xB852, //HANGUL SYLLABLE RIEUL YE PIEUPSIOS + 0x8ED8: 0xB854, //HANGUL SYLLABLE RIEUL YE SSANGSIOS + 0x8ED9: 0xB855, //HANGUL SYLLABLE RIEUL YE IEUNG + 0x8EDA: 0xB856, //HANGUL SYLLABLE RIEUL YE CIEUC + 0x8EDB: 0xB857, //HANGUL SYLLABLE RIEUL YE CHIEUCH + 0x8EDC: 0xB858, //HANGUL SYLLABLE RIEUL YE KHIEUKH + 0x8EDD: 0xB859, //HANGUL SYLLABLE RIEUL YE THIEUTH + 0x8EDE: 0xB85A, //HANGUL SYLLABLE RIEUL YE PHIEUPH + 0x8EDF: 0xB85B, //HANGUL SYLLABLE RIEUL YE HIEUH + 0x8EE0: 0xB85E, //HANGUL SYLLABLE RIEUL O SSANGKIYEOK + 0x8EE1: 0xB85F, //HANGUL SYLLABLE RIEUL O KIYEOKSIOS + 0x8EE2: 0xB861, //HANGUL SYLLABLE RIEUL O NIEUNCIEUC + 0x8EE3: 0xB862, //HANGUL SYLLABLE RIEUL O NIEUNHIEUH + 0x8EE4: 0xB863, //HANGUL SYLLABLE RIEUL O TIKEUT + 0x8EE5: 0xB865, //HANGUL SYLLABLE RIEUL O RIEULKIYEOK + 0x8EE6: 0xB866, //HANGUL SYLLABLE RIEUL O RIEULMIEUM + 0x8EE7: 0xB867, //HANGUL SYLLABLE RIEUL O RIEULPIEUP + 0x8EE8: 0xB868, //HANGUL SYLLABLE RIEUL O RIEULSIOS + 0x8EE9: 0xB869, //HANGUL SYLLABLE RIEUL O RIEULTHIEUTH + 0x8EEA: 0xB86A, //HANGUL SYLLABLE RIEUL O RIEULPHIEUPH + 0x8EEB: 0xB86B, //HANGUL SYLLABLE RIEUL O RIEULHIEUH + 0x8EEC: 0xB86E, //HANGUL SYLLABLE RIEUL O PIEUPSIOS + 0x8EED: 0xB870, //HANGUL SYLLABLE RIEUL O SSANGSIOS + 0x8EEE: 0xB872, //HANGUL SYLLABLE RIEUL O CIEUC + 0x8EEF: 0xB873, //HANGUL SYLLABLE RIEUL O CHIEUCH + 0x8EF0: 0xB874, //HANGUL SYLLABLE RIEUL O KHIEUKH + 0x8EF1: 0xB875, //HANGUL SYLLABLE RIEUL O THIEUTH + 0x8EF2: 0xB876, //HANGUL SYLLABLE RIEUL O PHIEUPH + 0x8EF3: 0xB877, //HANGUL SYLLABLE RIEUL O HIEUH + 0x8EF4: 0xB879, //HANGUL SYLLABLE RIEUL WA KIYEOK + 0x8EF5: 0xB87A, //HANGUL SYLLABLE RIEUL WA SSANGKIYEOK + 0x8EF6: 0xB87B, //HANGUL SYLLABLE RIEUL WA KIYEOKSIOS + 0x8EF7: 0xB87D, //HANGUL SYLLABLE RIEUL WA NIEUNCIEUC + 0x8EF8: 0xB87E, //HANGUL SYLLABLE RIEUL WA NIEUNHIEUH + 0x8EF9: 0xB87F, //HANGUL SYLLABLE RIEUL WA TIKEUT + 0x8EFA: 0xB880, //HANGUL SYLLABLE RIEUL WA RIEUL + 0x8EFB: 0xB881, //HANGUL SYLLABLE RIEUL WA RIEULKIYEOK + 0x8EFC: 0xB882, //HANGUL SYLLABLE RIEUL WA RIEULMIEUM + 0x8EFD: 0xB883, //HANGUL SYLLABLE RIEUL WA RIEULPIEUP + 0x8EFE: 0xB884, //HANGUL SYLLABLE RIEUL WA RIEULSIOS + 0x8F41: 0xB885, //HANGUL SYLLABLE RIEUL WA RIEULTHIEUTH + 0x8F42: 0xB886, //HANGUL SYLLABLE RIEUL WA RIEULPHIEUPH + 0x8F43: 0xB887, //HANGUL SYLLABLE RIEUL WA RIEULHIEUH + 0x8F44: 0xB888, //HANGUL SYLLABLE RIEUL WA MIEUM + 0x8F45: 0xB889, //HANGUL SYLLABLE RIEUL WA PIEUP + 0x8F46: 0xB88A, //HANGUL SYLLABLE RIEUL WA PIEUPSIOS + 0x8F47: 0xB88B, //HANGUL SYLLABLE RIEUL WA SIOS + 0x8F48: 0xB88C, //HANGUL SYLLABLE RIEUL WA SSANGSIOS + 0x8F49: 0xB88E, //HANGUL SYLLABLE RIEUL WA CIEUC + 0x8F4A: 0xB88F, //HANGUL SYLLABLE RIEUL WA CHIEUCH + 0x8F4B: 0xB890, //HANGUL SYLLABLE RIEUL WA KHIEUKH + 0x8F4C: 0xB891, //HANGUL SYLLABLE RIEUL WA THIEUTH + 0x8F4D: 0xB892, //HANGUL SYLLABLE RIEUL WA PHIEUPH + 0x8F4E: 0xB893, //HANGUL SYLLABLE RIEUL WA HIEUH + 0x8F4F: 0xB894, //HANGUL SYLLABLE RIEUL WAE + 0x8F50: 0xB895, //HANGUL SYLLABLE RIEUL WAE KIYEOK + 0x8F51: 0xB896, //HANGUL SYLLABLE RIEUL WAE SSANGKIYEOK + 0x8F52: 0xB897, //HANGUL SYLLABLE RIEUL WAE KIYEOKSIOS + 0x8F53: 0xB898, //HANGUL SYLLABLE RIEUL WAE NIEUN + 0x8F54: 0xB899, //HANGUL SYLLABLE RIEUL WAE NIEUNCIEUC + 0x8F55: 0xB89A, //HANGUL SYLLABLE RIEUL WAE NIEUNHIEUH + 0x8F56: 0xB89B, //HANGUL SYLLABLE RIEUL WAE TIKEUT + 0x8F57: 0xB89C, //HANGUL SYLLABLE RIEUL WAE RIEUL + 0x8F58: 0xB89D, //HANGUL SYLLABLE RIEUL WAE RIEULKIYEOK + 0x8F59: 0xB89E, //HANGUL SYLLABLE RIEUL WAE RIEULMIEUM + 0x8F5A: 0xB89F, //HANGUL SYLLABLE RIEUL WAE RIEULPIEUP + 0x8F61: 0xB8A0, //HANGUL SYLLABLE RIEUL WAE RIEULSIOS + 0x8F62: 0xB8A1, //HANGUL SYLLABLE RIEUL WAE RIEULTHIEUTH + 0x8F63: 0xB8A2, //HANGUL SYLLABLE RIEUL WAE RIEULPHIEUPH + 0x8F64: 0xB8A3, //HANGUL SYLLABLE RIEUL WAE RIEULHIEUH + 0x8F65: 0xB8A4, //HANGUL SYLLABLE RIEUL WAE MIEUM + 0x8F66: 0xB8A5, //HANGUL SYLLABLE RIEUL WAE PIEUP + 0x8F67: 0xB8A6, //HANGUL SYLLABLE RIEUL WAE PIEUPSIOS + 0x8F68: 0xB8A7, //HANGUL SYLLABLE RIEUL WAE SIOS + 0x8F69: 0xB8A9, //HANGUL SYLLABLE RIEUL WAE IEUNG + 0x8F6A: 0xB8AA, //HANGUL SYLLABLE RIEUL WAE CIEUC + 0x8F6B: 0xB8AB, //HANGUL SYLLABLE RIEUL WAE CHIEUCH + 0x8F6C: 0xB8AC, //HANGUL SYLLABLE RIEUL WAE KHIEUKH + 0x8F6D: 0xB8AD, //HANGUL SYLLABLE RIEUL WAE THIEUTH + 0x8F6E: 0xB8AE, //HANGUL SYLLABLE RIEUL WAE PHIEUPH + 0x8F6F: 0xB8AF, //HANGUL SYLLABLE RIEUL WAE HIEUH + 0x8F70: 0xB8B1, //HANGUL SYLLABLE RIEUL OE KIYEOK + 0x8F71: 0xB8B2, //HANGUL SYLLABLE RIEUL OE SSANGKIYEOK + 0x8F72: 0xB8B3, //HANGUL SYLLABLE RIEUL OE KIYEOKSIOS + 0x8F73: 0xB8B5, //HANGUL SYLLABLE RIEUL OE NIEUNCIEUC + 0x8F74: 0xB8B6, //HANGUL SYLLABLE RIEUL OE NIEUNHIEUH + 0x8F75: 0xB8B7, //HANGUL SYLLABLE RIEUL OE TIKEUT + 0x8F76: 0xB8B9, //HANGUL SYLLABLE RIEUL OE RIEULKIYEOK + 0x8F77: 0xB8BA, //HANGUL SYLLABLE RIEUL OE RIEULMIEUM + 0x8F78: 0xB8BB, //HANGUL SYLLABLE RIEUL OE RIEULPIEUP + 0x8F79: 0xB8BC, //HANGUL SYLLABLE RIEUL OE RIEULSIOS + 0x8F7A: 0xB8BD, //HANGUL SYLLABLE RIEUL OE RIEULTHIEUTH + 0x8F81: 0xB8BE, //HANGUL SYLLABLE RIEUL OE RIEULPHIEUPH + 0x8F82: 0xB8BF, //HANGUL SYLLABLE RIEUL OE RIEULHIEUH + 0x8F83: 0xB8C2, //HANGUL SYLLABLE RIEUL OE PIEUPSIOS + 0x8F84: 0xB8C4, //HANGUL SYLLABLE RIEUL OE SSANGSIOS + 0x8F85: 0xB8C6, //HANGUL SYLLABLE RIEUL OE CIEUC + 0x8F86: 0xB8C7, //HANGUL SYLLABLE RIEUL OE CHIEUCH + 0x8F87: 0xB8C8, //HANGUL SYLLABLE RIEUL OE KHIEUKH + 0x8F88: 0xB8C9, //HANGUL SYLLABLE RIEUL OE THIEUTH + 0x8F89: 0xB8CA, //HANGUL SYLLABLE RIEUL OE PHIEUPH + 0x8F8A: 0xB8CB, //HANGUL SYLLABLE RIEUL OE HIEUH + 0x8F8B: 0xB8CD, //HANGUL SYLLABLE RIEUL YO KIYEOK + 0x8F8C: 0xB8CE, //HANGUL SYLLABLE RIEUL YO SSANGKIYEOK + 0x8F8D: 0xB8CF, //HANGUL SYLLABLE RIEUL YO KIYEOKSIOS + 0x8F8E: 0xB8D1, //HANGUL SYLLABLE RIEUL YO NIEUNCIEUC + 0x8F8F: 0xB8D2, //HANGUL SYLLABLE RIEUL YO NIEUNHIEUH + 0x8F90: 0xB8D3, //HANGUL SYLLABLE RIEUL YO TIKEUT + 0x8F91: 0xB8D5, //HANGUL SYLLABLE RIEUL YO RIEULKIYEOK + 0x8F92: 0xB8D6, //HANGUL SYLLABLE RIEUL YO RIEULMIEUM + 0x8F93: 0xB8D7, //HANGUL SYLLABLE RIEUL YO RIEULPIEUP + 0x8F94: 0xB8D8, //HANGUL SYLLABLE RIEUL YO RIEULSIOS + 0x8F95: 0xB8D9, //HANGUL SYLLABLE RIEUL YO RIEULTHIEUTH + 0x8F96: 0xB8DA, //HANGUL SYLLABLE RIEUL YO RIEULPHIEUPH + 0x8F97: 0xB8DB, //HANGUL SYLLABLE RIEUL YO RIEULHIEUH + 0x8F98: 0xB8DC, //HANGUL SYLLABLE RIEUL YO MIEUM + 0x8F99: 0xB8DE, //HANGUL SYLLABLE RIEUL YO PIEUPSIOS + 0x8F9A: 0xB8E0, //HANGUL SYLLABLE RIEUL YO SSANGSIOS + 0x8F9B: 0xB8E2, //HANGUL SYLLABLE RIEUL YO CIEUC + 0x8F9C: 0xB8E3, //HANGUL SYLLABLE RIEUL YO CHIEUCH + 0x8F9D: 0xB8E4, //HANGUL SYLLABLE RIEUL YO KHIEUKH + 0x8F9E: 0xB8E5, //HANGUL SYLLABLE RIEUL YO THIEUTH + 0x8F9F: 0xB8E6, //HANGUL SYLLABLE RIEUL YO PHIEUPH + 0x8FA0: 0xB8E7, //HANGUL SYLLABLE RIEUL YO HIEUH + 0x8FA1: 0xB8EA, //HANGUL SYLLABLE RIEUL U SSANGKIYEOK + 0x8FA2: 0xB8EB, //HANGUL SYLLABLE RIEUL U KIYEOKSIOS + 0x8FA3: 0xB8ED, //HANGUL SYLLABLE RIEUL U NIEUNCIEUC + 0x8FA4: 0xB8EE, //HANGUL SYLLABLE RIEUL U NIEUNHIEUH + 0x8FA5: 0xB8EF, //HANGUL SYLLABLE RIEUL U TIKEUT + 0x8FA6: 0xB8F1, //HANGUL SYLLABLE RIEUL U RIEULKIYEOK + 0x8FA7: 0xB8F2, //HANGUL SYLLABLE RIEUL U RIEULMIEUM + 0x8FA8: 0xB8F3, //HANGUL SYLLABLE RIEUL U RIEULPIEUP + 0x8FA9: 0xB8F4, //HANGUL SYLLABLE RIEUL U RIEULSIOS + 0x8FAA: 0xB8F5, //HANGUL SYLLABLE RIEUL U RIEULTHIEUTH + 0x8FAB: 0xB8F6, //HANGUL SYLLABLE RIEUL U RIEULPHIEUPH + 0x8FAC: 0xB8F7, //HANGUL SYLLABLE RIEUL U RIEULHIEUH + 0x8FAD: 0xB8FA, //HANGUL SYLLABLE RIEUL U PIEUPSIOS + 0x8FAE: 0xB8FC, //HANGUL SYLLABLE RIEUL U SSANGSIOS + 0x8FAF: 0xB8FE, //HANGUL SYLLABLE RIEUL U CIEUC + 0x8FB0: 0xB8FF, //HANGUL SYLLABLE RIEUL U CHIEUCH + 0x8FB1: 0xB900, //HANGUL SYLLABLE RIEUL U KHIEUKH + 0x8FB2: 0xB901, //HANGUL SYLLABLE RIEUL U THIEUTH + 0x8FB3: 0xB902, //HANGUL SYLLABLE RIEUL U PHIEUPH + 0x8FB4: 0xB903, //HANGUL SYLLABLE RIEUL U HIEUH + 0x8FB5: 0xB905, //HANGUL SYLLABLE RIEUL WEO KIYEOK + 0x8FB6: 0xB906, //HANGUL SYLLABLE RIEUL WEO SSANGKIYEOK + 0x8FB7: 0xB907, //HANGUL SYLLABLE RIEUL WEO KIYEOKSIOS + 0x8FB8: 0xB908, //HANGUL SYLLABLE RIEUL WEO NIEUN + 0x8FB9: 0xB909, //HANGUL SYLLABLE RIEUL WEO NIEUNCIEUC + 0x8FBA: 0xB90A, //HANGUL SYLLABLE RIEUL WEO NIEUNHIEUH + 0x8FBB: 0xB90B, //HANGUL SYLLABLE RIEUL WEO TIKEUT + 0x8FBC: 0xB90C, //HANGUL SYLLABLE RIEUL WEO RIEUL + 0x8FBD: 0xB90D, //HANGUL SYLLABLE RIEUL WEO RIEULKIYEOK + 0x8FBE: 0xB90E, //HANGUL SYLLABLE RIEUL WEO RIEULMIEUM + 0x8FBF: 0xB90F, //HANGUL SYLLABLE RIEUL WEO RIEULPIEUP + 0x8FC0: 0xB910, //HANGUL SYLLABLE RIEUL WEO RIEULSIOS + 0x8FC1: 0xB911, //HANGUL SYLLABLE RIEUL WEO RIEULTHIEUTH + 0x8FC2: 0xB912, //HANGUL SYLLABLE RIEUL WEO RIEULPHIEUPH + 0x8FC3: 0xB913, //HANGUL SYLLABLE RIEUL WEO RIEULHIEUH + 0x8FC4: 0xB914, //HANGUL SYLLABLE RIEUL WEO MIEUM + 0x8FC5: 0xB915, //HANGUL SYLLABLE RIEUL WEO PIEUP + 0x8FC6: 0xB916, //HANGUL SYLLABLE RIEUL WEO PIEUPSIOS + 0x8FC7: 0xB917, //HANGUL SYLLABLE RIEUL WEO SIOS + 0x8FC8: 0xB919, //HANGUL SYLLABLE RIEUL WEO IEUNG + 0x8FC9: 0xB91A, //HANGUL SYLLABLE RIEUL WEO CIEUC + 0x8FCA: 0xB91B, //HANGUL SYLLABLE RIEUL WEO CHIEUCH + 0x8FCB: 0xB91C, //HANGUL SYLLABLE RIEUL WEO KHIEUKH + 0x8FCC: 0xB91D, //HANGUL SYLLABLE RIEUL WEO THIEUTH + 0x8FCD: 0xB91E, //HANGUL SYLLABLE RIEUL WEO PHIEUPH + 0x8FCE: 0xB91F, //HANGUL SYLLABLE RIEUL WEO HIEUH + 0x8FCF: 0xB921, //HANGUL SYLLABLE RIEUL WE KIYEOK + 0x8FD0: 0xB922, //HANGUL SYLLABLE RIEUL WE SSANGKIYEOK + 0x8FD1: 0xB923, //HANGUL SYLLABLE RIEUL WE KIYEOKSIOS + 0x8FD2: 0xB924, //HANGUL SYLLABLE RIEUL WE NIEUN + 0x8FD3: 0xB925, //HANGUL SYLLABLE RIEUL WE NIEUNCIEUC + 0x8FD4: 0xB926, //HANGUL SYLLABLE RIEUL WE NIEUNHIEUH + 0x8FD5: 0xB927, //HANGUL SYLLABLE RIEUL WE TIKEUT + 0x8FD6: 0xB928, //HANGUL SYLLABLE RIEUL WE RIEUL + 0x8FD7: 0xB929, //HANGUL SYLLABLE RIEUL WE RIEULKIYEOK + 0x8FD8: 0xB92A, //HANGUL SYLLABLE RIEUL WE RIEULMIEUM + 0x8FD9: 0xB92B, //HANGUL SYLLABLE RIEUL WE RIEULPIEUP + 0x8FDA: 0xB92C, //HANGUL SYLLABLE RIEUL WE RIEULSIOS + 0x8FDB: 0xB92D, //HANGUL SYLLABLE RIEUL WE RIEULTHIEUTH + 0x8FDC: 0xB92E, //HANGUL SYLLABLE RIEUL WE RIEULPHIEUPH + 0x8FDD: 0xB92F, //HANGUL SYLLABLE RIEUL WE RIEULHIEUH + 0x8FDE: 0xB930, //HANGUL SYLLABLE RIEUL WE MIEUM + 0x8FDF: 0xB931, //HANGUL SYLLABLE RIEUL WE PIEUP + 0x8FE0: 0xB932, //HANGUL SYLLABLE RIEUL WE PIEUPSIOS + 0x8FE1: 0xB933, //HANGUL SYLLABLE RIEUL WE SIOS + 0x8FE2: 0xB934, //HANGUL SYLLABLE RIEUL WE SSANGSIOS + 0x8FE3: 0xB935, //HANGUL SYLLABLE RIEUL WE IEUNG + 0x8FE4: 0xB936, //HANGUL SYLLABLE RIEUL WE CIEUC + 0x8FE5: 0xB937, //HANGUL SYLLABLE RIEUL WE CHIEUCH + 0x8FE6: 0xB938, //HANGUL SYLLABLE RIEUL WE KHIEUKH + 0x8FE7: 0xB939, //HANGUL SYLLABLE RIEUL WE THIEUTH + 0x8FE8: 0xB93A, //HANGUL SYLLABLE RIEUL WE PHIEUPH + 0x8FE9: 0xB93B, //HANGUL SYLLABLE RIEUL WE HIEUH + 0x8FEA: 0xB93E, //HANGUL SYLLABLE RIEUL WI SSANGKIYEOK + 0x8FEB: 0xB93F, //HANGUL SYLLABLE RIEUL WI KIYEOKSIOS + 0x8FEC: 0xB941, //HANGUL SYLLABLE RIEUL WI NIEUNCIEUC + 0x8FED: 0xB942, //HANGUL SYLLABLE RIEUL WI NIEUNHIEUH + 0x8FEE: 0xB943, //HANGUL SYLLABLE RIEUL WI TIKEUT + 0x8FEF: 0xB945, //HANGUL SYLLABLE RIEUL WI RIEULKIYEOK + 0x8FF0: 0xB946, //HANGUL SYLLABLE RIEUL WI RIEULMIEUM + 0x8FF1: 0xB947, //HANGUL SYLLABLE RIEUL WI RIEULPIEUP + 0x8FF2: 0xB948, //HANGUL SYLLABLE RIEUL WI RIEULSIOS + 0x8FF3: 0xB949, //HANGUL SYLLABLE RIEUL WI RIEULTHIEUTH + 0x8FF4: 0xB94A, //HANGUL SYLLABLE RIEUL WI RIEULPHIEUPH + 0x8FF5: 0xB94B, //HANGUL SYLLABLE RIEUL WI RIEULHIEUH + 0x8FF6: 0xB94D, //HANGUL SYLLABLE RIEUL WI PIEUP + 0x8FF7: 0xB94E, //HANGUL SYLLABLE RIEUL WI PIEUPSIOS + 0x8FF8: 0xB950, //HANGUL SYLLABLE RIEUL WI SSANGSIOS + 0x8FF9: 0xB952, //HANGUL SYLLABLE RIEUL WI CIEUC + 0x8FFA: 0xB953, //HANGUL SYLLABLE RIEUL WI CHIEUCH + 0x8FFB: 0xB954, //HANGUL SYLLABLE RIEUL WI KHIEUKH + 0x8FFC: 0xB955, //HANGUL SYLLABLE RIEUL WI THIEUTH + 0x8FFD: 0xB956, //HANGUL SYLLABLE RIEUL WI PHIEUPH + 0x8FFE: 0xB957, //HANGUL SYLLABLE RIEUL WI HIEUH + 0x9041: 0xB95A, //HANGUL SYLLABLE RIEUL YU SSANGKIYEOK + 0x9042: 0xB95B, //HANGUL SYLLABLE RIEUL YU KIYEOKSIOS + 0x9043: 0xB95D, //HANGUL SYLLABLE RIEUL YU NIEUNCIEUC + 0x9044: 0xB95E, //HANGUL SYLLABLE RIEUL YU NIEUNHIEUH + 0x9045: 0xB95F, //HANGUL SYLLABLE RIEUL YU TIKEUT + 0x9046: 0xB961, //HANGUL SYLLABLE RIEUL YU RIEULKIYEOK + 0x9047: 0xB962, //HANGUL SYLLABLE RIEUL YU RIEULMIEUM + 0x9048: 0xB963, //HANGUL SYLLABLE RIEUL YU RIEULPIEUP + 0x9049: 0xB964, //HANGUL SYLLABLE RIEUL YU RIEULSIOS + 0x904A: 0xB965, //HANGUL SYLLABLE RIEUL YU RIEULTHIEUTH + 0x904B: 0xB966, //HANGUL SYLLABLE RIEUL YU RIEULPHIEUPH + 0x904C: 0xB967, //HANGUL SYLLABLE RIEUL YU RIEULHIEUH + 0x904D: 0xB96A, //HANGUL SYLLABLE RIEUL YU PIEUPSIOS + 0x904E: 0xB96C, //HANGUL SYLLABLE RIEUL YU SSANGSIOS + 0x904F: 0xB96E, //HANGUL SYLLABLE RIEUL YU CIEUC + 0x9050: 0xB96F, //HANGUL SYLLABLE RIEUL YU CHIEUCH + 0x9051: 0xB970, //HANGUL SYLLABLE RIEUL YU KHIEUKH + 0x9052: 0xB971, //HANGUL SYLLABLE RIEUL YU THIEUTH + 0x9053: 0xB972, //HANGUL SYLLABLE RIEUL YU PHIEUPH + 0x9054: 0xB973, //HANGUL SYLLABLE RIEUL YU HIEUH + 0x9055: 0xB976, //HANGUL SYLLABLE RIEUL EU SSANGKIYEOK + 0x9056: 0xB977, //HANGUL SYLLABLE RIEUL EU KIYEOKSIOS + 0x9057: 0xB979, //HANGUL SYLLABLE RIEUL EU NIEUNCIEUC + 0x9058: 0xB97A, //HANGUL SYLLABLE RIEUL EU NIEUNHIEUH + 0x9059: 0xB97B, //HANGUL SYLLABLE RIEUL EU TIKEUT + 0x905A: 0xB97D, //HANGUL SYLLABLE RIEUL EU RIEULKIYEOK + 0x9061: 0xB97E, //HANGUL SYLLABLE RIEUL EU RIEULMIEUM + 0x9062: 0xB97F, //HANGUL SYLLABLE RIEUL EU RIEULPIEUP + 0x9063: 0xB980, //HANGUL SYLLABLE RIEUL EU RIEULSIOS + 0x9064: 0xB981, //HANGUL SYLLABLE RIEUL EU RIEULTHIEUTH + 0x9065: 0xB982, //HANGUL SYLLABLE RIEUL EU RIEULPHIEUPH + 0x9066: 0xB983, //HANGUL SYLLABLE RIEUL EU RIEULHIEUH + 0x9067: 0xB986, //HANGUL SYLLABLE RIEUL EU PIEUPSIOS + 0x9068: 0xB988, //HANGUL SYLLABLE RIEUL EU SSANGSIOS + 0x9069: 0xB98B, //HANGUL SYLLABLE RIEUL EU CHIEUCH + 0x906A: 0xB98C, //HANGUL SYLLABLE RIEUL EU KHIEUKH + 0x906B: 0xB98F, //HANGUL SYLLABLE RIEUL EU HIEUH + 0x906C: 0xB990, //HANGUL SYLLABLE RIEUL YI + 0x906D: 0xB991, //HANGUL SYLLABLE RIEUL YI KIYEOK + 0x906E: 0xB992, //HANGUL SYLLABLE RIEUL YI SSANGKIYEOK + 0x906F: 0xB993, //HANGUL SYLLABLE RIEUL YI KIYEOKSIOS + 0x9070: 0xB994, //HANGUL SYLLABLE RIEUL YI NIEUN + 0x9071: 0xB995, //HANGUL SYLLABLE RIEUL YI NIEUNCIEUC + 0x9072: 0xB996, //HANGUL SYLLABLE RIEUL YI NIEUNHIEUH + 0x9073: 0xB997, //HANGUL SYLLABLE RIEUL YI TIKEUT + 0x9074: 0xB998, //HANGUL SYLLABLE RIEUL YI RIEUL + 0x9075: 0xB999, //HANGUL SYLLABLE RIEUL YI RIEULKIYEOK + 0x9076: 0xB99A, //HANGUL SYLLABLE RIEUL YI RIEULMIEUM + 0x9077: 0xB99B, //HANGUL SYLLABLE RIEUL YI RIEULPIEUP + 0x9078: 0xB99C, //HANGUL SYLLABLE RIEUL YI RIEULSIOS + 0x9079: 0xB99D, //HANGUL SYLLABLE RIEUL YI RIEULTHIEUTH + 0x907A: 0xB99E, //HANGUL SYLLABLE RIEUL YI RIEULPHIEUPH + 0x9081: 0xB99F, //HANGUL SYLLABLE RIEUL YI RIEULHIEUH + 0x9082: 0xB9A0, //HANGUL SYLLABLE RIEUL YI MIEUM + 0x9083: 0xB9A1, //HANGUL SYLLABLE RIEUL YI PIEUP + 0x9084: 0xB9A2, //HANGUL SYLLABLE RIEUL YI PIEUPSIOS + 0x9085: 0xB9A3, //HANGUL SYLLABLE RIEUL YI SIOS + 0x9086: 0xB9A4, //HANGUL SYLLABLE RIEUL YI SSANGSIOS + 0x9087: 0xB9A5, //HANGUL SYLLABLE RIEUL YI IEUNG + 0x9088: 0xB9A6, //HANGUL SYLLABLE RIEUL YI CIEUC + 0x9089: 0xB9A7, //HANGUL SYLLABLE RIEUL YI CHIEUCH + 0x908A: 0xB9A8, //HANGUL SYLLABLE RIEUL YI KHIEUKH + 0x908B: 0xB9A9, //HANGUL SYLLABLE RIEUL YI THIEUTH + 0x908C: 0xB9AA, //HANGUL SYLLABLE RIEUL YI PHIEUPH + 0x908D: 0xB9AB, //HANGUL SYLLABLE RIEUL YI HIEUH + 0x908E: 0xB9AE, //HANGUL SYLLABLE RIEUL I SSANGKIYEOK + 0x908F: 0xB9AF, //HANGUL SYLLABLE RIEUL I KIYEOKSIOS + 0x9090: 0xB9B1, //HANGUL SYLLABLE RIEUL I NIEUNCIEUC + 0x9091: 0xB9B2, //HANGUL SYLLABLE RIEUL I NIEUNHIEUH + 0x9092: 0xB9B3, //HANGUL SYLLABLE RIEUL I TIKEUT + 0x9093: 0xB9B5, //HANGUL SYLLABLE RIEUL I RIEULKIYEOK + 0x9094: 0xB9B6, //HANGUL SYLLABLE RIEUL I RIEULMIEUM + 0x9095: 0xB9B7, //HANGUL SYLLABLE RIEUL I RIEULPIEUP + 0x9096: 0xB9B8, //HANGUL SYLLABLE RIEUL I RIEULSIOS + 0x9097: 0xB9B9, //HANGUL SYLLABLE RIEUL I RIEULTHIEUTH + 0x9098: 0xB9BA, //HANGUL SYLLABLE RIEUL I RIEULPHIEUPH + 0x9099: 0xB9BB, //HANGUL SYLLABLE RIEUL I RIEULHIEUH + 0x909A: 0xB9BE, //HANGUL SYLLABLE RIEUL I PIEUPSIOS + 0x909B: 0xB9C0, //HANGUL SYLLABLE RIEUL I SSANGSIOS + 0x909C: 0xB9C2, //HANGUL SYLLABLE RIEUL I CIEUC + 0x909D: 0xB9C3, //HANGUL SYLLABLE RIEUL I CHIEUCH + 0x909E: 0xB9C4, //HANGUL SYLLABLE RIEUL I KHIEUKH + 0x909F: 0xB9C5, //HANGUL SYLLABLE RIEUL I THIEUTH + 0x90A0: 0xB9C6, //HANGUL SYLLABLE RIEUL I PHIEUPH + 0x90A1: 0xB9C7, //HANGUL SYLLABLE RIEUL I HIEUH + 0x90A2: 0xB9CA, //HANGUL SYLLABLE MIEUM A SSANGKIYEOK + 0x90A3: 0xB9CB, //HANGUL SYLLABLE MIEUM A KIYEOKSIOS + 0x90A4: 0xB9CD, //HANGUL SYLLABLE MIEUM A NIEUNCIEUC + 0x90A5: 0xB9D3, //HANGUL SYLLABLE MIEUM A RIEULPIEUP + 0x90A6: 0xB9D4, //HANGUL SYLLABLE MIEUM A RIEULSIOS + 0x90A7: 0xB9D5, //HANGUL SYLLABLE MIEUM A RIEULTHIEUTH + 0x90A8: 0xB9D6, //HANGUL SYLLABLE MIEUM A RIEULPHIEUPH + 0x90A9: 0xB9D7, //HANGUL SYLLABLE MIEUM A RIEULHIEUH + 0x90AA: 0xB9DA, //HANGUL SYLLABLE MIEUM A PIEUPSIOS + 0x90AB: 0xB9DC, //HANGUL SYLLABLE MIEUM A SSANGSIOS + 0x90AC: 0xB9DF, //HANGUL SYLLABLE MIEUM A CHIEUCH + 0x90AD: 0xB9E0, //HANGUL SYLLABLE MIEUM A KHIEUKH + 0x90AE: 0xB9E2, //HANGUL SYLLABLE MIEUM A PHIEUPH + 0x90AF: 0xB9E6, //HANGUL SYLLABLE MIEUM AE SSANGKIYEOK + 0x90B0: 0xB9E7, //HANGUL SYLLABLE MIEUM AE KIYEOKSIOS + 0x90B1: 0xB9E9, //HANGUL SYLLABLE MIEUM AE NIEUNCIEUC + 0x90B2: 0xB9EA, //HANGUL SYLLABLE MIEUM AE NIEUNHIEUH + 0x90B3: 0xB9EB, //HANGUL SYLLABLE MIEUM AE TIKEUT + 0x90B4: 0xB9ED, //HANGUL SYLLABLE MIEUM AE RIEULKIYEOK + 0x90B5: 0xB9EE, //HANGUL SYLLABLE MIEUM AE RIEULMIEUM + 0x90B6: 0xB9EF, //HANGUL SYLLABLE MIEUM AE RIEULPIEUP + 0x90B7: 0xB9F0, //HANGUL SYLLABLE MIEUM AE RIEULSIOS + 0x90B8: 0xB9F1, //HANGUL SYLLABLE MIEUM AE RIEULTHIEUTH + 0x90B9: 0xB9F2, //HANGUL SYLLABLE MIEUM AE RIEULPHIEUPH + 0x90BA: 0xB9F3, //HANGUL SYLLABLE MIEUM AE RIEULHIEUH + 0x90BB: 0xB9F6, //HANGUL SYLLABLE MIEUM AE PIEUPSIOS + 0x90BC: 0xB9FB, //HANGUL SYLLABLE MIEUM AE CHIEUCH + 0x90BD: 0xB9FC, //HANGUL SYLLABLE MIEUM AE KHIEUKH + 0x90BE: 0xB9FD, //HANGUL SYLLABLE MIEUM AE THIEUTH + 0x90BF: 0xB9FE, //HANGUL SYLLABLE MIEUM AE PHIEUPH + 0x90C0: 0xB9FF, //HANGUL SYLLABLE MIEUM AE HIEUH + 0x90C1: 0xBA02, //HANGUL SYLLABLE MIEUM YA SSANGKIYEOK + 0x90C2: 0xBA03, //HANGUL SYLLABLE MIEUM YA KIYEOKSIOS + 0x90C3: 0xBA04, //HANGUL SYLLABLE MIEUM YA NIEUN + 0x90C4: 0xBA05, //HANGUL SYLLABLE MIEUM YA NIEUNCIEUC + 0x90C5: 0xBA06, //HANGUL SYLLABLE MIEUM YA NIEUNHIEUH + 0x90C6: 0xBA07, //HANGUL SYLLABLE MIEUM YA TIKEUT + 0x90C7: 0xBA09, //HANGUL SYLLABLE MIEUM YA RIEULKIYEOK + 0x90C8: 0xBA0A, //HANGUL SYLLABLE MIEUM YA RIEULMIEUM + 0x90C9: 0xBA0B, //HANGUL SYLLABLE MIEUM YA RIEULPIEUP + 0x90CA: 0xBA0C, //HANGUL SYLLABLE MIEUM YA RIEULSIOS + 0x90CB: 0xBA0D, //HANGUL SYLLABLE MIEUM YA RIEULTHIEUTH + 0x90CC: 0xBA0E, //HANGUL SYLLABLE MIEUM YA RIEULPHIEUPH + 0x90CD: 0xBA0F, //HANGUL SYLLABLE MIEUM YA RIEULHIEUH + 0x90CE: 0xBA10, //HANGUL SYLLABLE MIEUM YA MIEUM + 0x90CF: 0xBA11, //HANGUL SYLLABLE MIEUM YA PIEUP + 0x90D0: 0xBA12, //HANGUL SYLLABLE MIEUM YA PIEUPSIOS + 0x90D1: 0xBA13, //HANGUL SYLLABLE MIEUM YA SIOS + 0x90D2: 0xBA14, //HANGUL SYLLABLE MIEUM YA SSANGSIOS + 0x90D3: 0xBA16, //HANGUL SYLLABLE MIEUM YA CIEUC + 0x90D4: 0xBA17, //HANGUL SYLLABLE MIEUM YA CHIEUCH + 0x90D5: 0xBA18, //HANGUL SYLLABLE MIEUM YA KHIEUKH + 0x90D6: 0xBA19, //HANGUL SYLLABLE MIEUM YA THIEUTH + 0x90D7: 0xBA1A, //HANGUL SYLLABLE MIEUM YA PHIEUPH + 0x90D8: 0xBA1B, //HANGUL SYLLABLE MIEUM YA HIEUH + 0x90D9: 0xBA1C, //HANGUL SYLLABLE MIEUM YAE + 0x90DA: 0xBA1D, //HANGUL SYLLABLE MIEUM YAE KIYEOK + 0x90DB: 0xBA1E, //HANGUL SYLLABLE MIEUM YAE SSANGKIYEOK + 0x90DC: 0xBA1F, //HANGUL SYLLABLE MIEUM YAE KIYEOKSIOS + 0x90DD: 0xBA20, //HANGUL SYLLABLE MIEUM YAE NIEUN + 0x90DE: 0xBA21, //HANGUL SYLLABLE MIEUM YAE NIEUNCIEUC + 0x90DF: 0xBA22, //HANGUL SYLLABLE MIEUM YAE NIEUNHIEUH + 0x90E0: 0xBA23, //HANGUL SYLLABLE MIEUM YAE TIKEUT + 0x90E1: 0xBA24, //HANGUL SYLLABLE MIEUM YAE RIEUL + 0x90E2: 0xBA25, //HANGUL SYLLABLE MIEUM YAE RIEULKIYEOK + 0x90E3: 0xBA26, //HANGUL SYLLABLE MIEUM YAE RIEULMIEUM + 0x90E4: 0xBA27, //HANGUL SYLLABLE MIEUM YAE RIEULPIEUP + 0x90E5: 0xBA28, //HANGUL SYLLABLE MIEUM YAE RIEULSIOS + 0x90E6: 0xBA29, //HANGUL SYLLABLE MIEUM YAE RIEULTHIEUTH + 0x90E7: 0xBA2A, //HANGUL SYLLABLE MIEUM YAE RIEULPHIEUPH + 0x90E8: 0xBA2B, //HANGUL SYLLABLE MIEUM YAE RIEULHIEUH + 0x90E9: 0xBA2C, //HANGUL SYLLABLE MIEUM YAE MIEUM + 0x90EA: 0xBA2D, //HANGUL SYLLABLE MIEUM YAE PIEUP + 0x90EB: 0xBA2E, //HANGUL SYLLABLE MIEUM YAE PIEUPSIOS + 0x90EC: 0xBA2F, //HANGUL SYLLABLE MIEUM YAE SIOS + 0x90ED: 0xBA30, //HANGUL SYLLABLE MIEUM YAE SSANGSIOS + 0x90EE: 0xBA31, //HANGUL SYLLABLE MIEUM YAE IEUNG + 0x90EF: 0xBA32, //HANGUL SYLLABLE MIEUM YAE CIEUC + 0x90F0: 0xBA33, //HANGUL SYLLABLE MIEUM YAE CHIEUCH + 0x90F1: 0xBA34, //HANGUL SYLLABLE MIEUM YAE KHIEUKH + 0x90F2: 0xBA35, //HANGUL SYLLABLE MIEUM YAE THIEUTH + 0x90F3: 0xBA36, //HANGUL SYLLABLE MIEUM YAE PHIEUPH + 0x90F4: 0xBA37, //HANGUL SYLLABLE MIEUM YAE HIEUH + 0x90F5: 0xBA3A, //HANGUL SYLLABLE MIEUM EO SSANGKIYEOK + 0x90F6: 0xBA3B, //HANGUL SYLLABLE MIEUM EO KIYEOKSIOS + 0x90F7: 0xBA3D, //HANGUL SYLLABLE MIEUM EO NIEUNCIEUC + 0x90F8: 0xBA3E, //HANGUL SYLLABLE MIEUM EO NIEUNHIEUH + 0x90F9: 0xBA3F, //HANGUL SYLLABLE MIEUM EO TIKEUT + 0x90FA: 0xBA41, //HANGUL SYLLABLE MIEUM EO RIEULKIYEOK + 0x90FB: 0xBA43, //HANGUL SYLLABLE MIEUM EO RIEULPIEUP + 0x90FC: 0xBA44, //HANGUL SYLLABLE MIEUM EO RIEULSIOS + 0x90FD: 0xBA45, //HANGUL SYLLABLE MIEUM EO RIEULTHIEUTH + 0x90FE: 0xBA46, //HANGUL SYLLABLE MIEUM EO RIEULPHIEUPH + 0x9141: 0xBA47, //HANGUL SYLLABLE MIEUM EO RIEULHIEUH + 0x9142: 0xBA4A, //HANGUL SYLLABLE MIEUM EO PIEUPSIOS + 0x9143: 0xBA4C, //HANGUL SYLLABLE MIEUM EO SSANGSIOS + 0x9144: 0xBA4F, //HANGUL SYLLABLE MIEUM EO CHIEUCH + 0x9145: 0xBA50, //HANGUL SYLLABLE MIEUM EO KHIEUKH + 0x9146: 0xBA51, //HANGUL SYLLABLE MIEUM EO THIEUTH + 0x9147: 0xBA52, //HANGUL SYLLABLE MIEUM EO PHIEUPH + 0x9148: 0xBA56, //HANGUL SYLLABLE MIEUM E SSANGKIYEOK + 0x9149: 0xBA57, //HANGUL SYLLABLE MIEUM E KIYEOKSIOS + 0x914A: 0xBA59, //HANGUL SYLLABLE MIEUM E NIEUNCIEUC + 0x914B: 0xBA5A, //HANGUL SYLLABLE MIEUM E NIEUNHIEUH + 0x914C: 0xBA5B, //HANGUL SYLLABLE MIEUM E TIKEUT + 0x914D: 0xBA5D, //HANGUL SYLLABLE MIEUM E RIEULKIYEOK + 0x914E: 0xBA5E, //HANGUL SYLLABLE MIEUM E RIEULMIEUM + 0x914F: 0xBA5F, //HANGUL SYLLABLE MIEUM E RIEULPIEUP + 0x9150: 0xBA60, //HANGUL SYLLABLE MIEUM E RIEULSIOS + 0x9151: 0xBA61, //HANGUL SYLLABLE MIEUM E RIEULTHIEUTH + 0x9152: 0xBA62, //HANGUL SYLLABLE MIEUM E RIEULPHIEUPH + 0x9153: 0xBA63, //HANGUL SYLLABLE MIEUM E RIEULHIEUH + 0x9154: 0xBA66, //HANGUL SYLLABLE MIEUM E PIEUPSIOS + 0x9155: 0xBA6A, //HANGUL SYLLABLE MIEUM E CIEUC + 0x9156: 0xBA6B, //HANGUL SYLLABLE MIEUM E CHIEUCH + 0x9157: 0xBA6C, //HANGUL SYLLABLE MIEUM E KHIEUKH + 0x9158: 0xBA6D, //HANGUL SYLLABLE MIEUM E THIEUTH + 0x9159: 0xBA6E, //HANGUL SYLLABLE MIEUM E PHIEUPH + 0x915A: 0xBA6F, //HANGUL SYLLABLE MIEUM E HIEUH + 0x9161: 0xBA72, //HANGUL SYLLABLE MIEUM YEO SSANGKIYEOK + 0x9162: 0xBA73, //HANGUL SYLLABLE MIEUM YEO KIYEOKSIOS + 0x9163: 0xBA75, //HANGUL SYLLABLE MIEUM YEO NIEUNCIEUC + 0x9164: 0xBA76, //HANGUL SYLLABLE MIEUM YEO NIEUNHIEUH + 0x9165: 0xBA77, //HANGUL SYLLABLE MIEUM YEO TIKEUT + 0x9166: 0xBA79, //HANGUL SYLLABLE MIEUM YEO RIEULKIYEOK + 0x9167: 0xBA7A, //HANGUL SYLLABLE MIEUM YEO RIEULMIEUM + 0x9168: 0xBA7B, //HANGUL SYLLABLE MIEUM YEO RIEULPIEUP + 0x9169: 0xBA7C, //HANGUL SYLLABLE MIEUM YEO RIEULSIOS + 0x916A: 0xBA7D, //HANGUL SYLLABLE MIEUM YEO RIEULTHIEUTH + 0x916B: 0xBA7E, //HANGUL SYLLABLE MIEUM YEO RIEULPHIEUPH + 0x916C: 0xBA7F, //HANGUL SYLLABLE MIEUM YEO RIEULHIEUH + 0x916D: 0xBA80, //HANGUL SYLLABLE MIEUM YEO MIEUM + 0x916E: 0xBA81, //HANGUL SYLLABLE MIEUM YEO PIEUP + 0x916F: 0xBA82, //HANGUL SYLLABLE MIEUM YEO PIEUPSIOS + 0x9170: 0xBA86, //HANGUL SYLLABLE MIEUM YEO CIEUC + 0x9171: 0xBA88, //HANGUL SYLLABLE MIEUM YEO KHIEUKH + 0x9172: 0xBA89, //HANGUL SYLLABLE MIEUM YEO THIEUTH + 0x9173: 0xBA8A, //HANGUL SYLLABLE MIEUM YEO PHIEUPH + 0x9174: 0xBA8B, //HANGUL SYLLABLE MIEUM YEO HIEUH + 0x9175: 0xBA8D, //HANGUL SYLLABLE MIEUM YE KIYEOK + 0x9176: 0xBA8E, //HANGUL SYLLABLE MIEUM YE SSANGKIYEOK + 0x9177: 0xBA8F, //HANGUL SYLLABLE MIEUM YE KIYEOKSIOS + 0x9178: 0xBA90, //HANGUL SYLLABLE MIEUM YE NIEUN + 0x9179: 0xBA91, //HANGUL SYLLABLE MIEUM YE NIEUNCIEUC + 0x917A: 0xBA92, //HANGUL SYLLABLE MIEUM YE NIEUNHIEUH + 0x9181: 0xBA93, //HANGUL SYLLABLE MIEUM YE TIKEUT + 0x9182: 0xBA94, //HANGUL SYLLABLE MIEUM YE RIEUL + 0x9183: 0xBA95, //HANGUL SYLLABLE MIEUM YE RIEULKIYEOK + 0x9184: 0xBA96, //HANGUL SYLLABLE MIEUM YE RIEULMIEUM + 0x9185: 0xBA97, //HANGUL SYLLABLE MIEUM YE RIEULPIEUP + 0x9186: 0xBA98, //HANGUL SYLLABLE MIEUM YE RIEULSIOS + 0x9187: 0xBA99, //HANGUL SYLLABLE MIEUM YE RIEULTHIEUTH + 0x9188: 0xBA9A, //HANGUL SYLLABLE MIEUM YE RIEULPHIEUPH + 0x9189: 0xBA9B, //HANGUL SYLLABLE MIEUM YE RIEULHIEUH + 0x918A: 0xBA9C, //HANGUL SYLLABLE MIEUM YE MIEUM + 0x918B: 0xBA9D, //HANGUL SYLLABLE MIEUM YE PIEUP + 0x918C: 0xBA9E, //HANGUL SYLLABLE MIEUM YE PIEUPSIOS + 0x918D: 0xBA9F, //HANGUL SYLLABLE MIEUM YE SIOS + 0x918E: 0xBAA0, //HANGUL SYLLABLE MIEUM YE SSANGSIOS + 0x918F: 0xBAA1, //HANGUL SYLLABLE MIEUM YE IEUNG + 0x9190: 0xBAA2, //HANGUL SYLLABLE MIEUM YE CIEUC + 0x9191: 0xBAA3, //HANGUL SYLLABLE MIEUM YE CHIEUCH + 0x9192: 0xBAA4, //HANGUL SYLLABLE MIEUM YE KHIEUKH + 0x9193: 0xBAA5, //HANGUL SYLLABLE MIEUM YE THIEUTH + 0x9194: 0xBAA6, //HANGUL SYLLABLE MIEUM YE PHIEUPH + 0x9195: 0xBAA7, //HANGUL SYLLABLE MIEUM YE HIEUH + 0x9196: 0xBAAA, //HANGUL SYLLABLE MIEUM O SSANGKIYEOK + 0x9197: 0xBAAD, //HANGUL SYLLABLE MIEUM O NIEUNCIEUC + 0x9198: 0xBAAE, //HANGUL SYLLABLE MIEUM O NIEUNHIEUH + 0x9199: 0xBAAF, //HANGUL SYLLABLE MIEUM O TIKEUT + 0x919A: 0xBAB1, //HANGUL SYLLABLE MIEUM O RIEULKIYEOK + 0x919B: 0xBAB3, //HANGUL SYLLABLE MIEUM O RIEULPIEUP + 0x919C: 0xBAB4, //HANGUL SYLLABLE MIEUM O RIEULSIOS + 0x919D: 0xBAB5, //HANGUL SYLLABLE MIEUM O RIEULTHIEUTH + 0x919E: 0xBAB6, //HANGUL SYLLABLE MIEUM O RIEULPHIEUPH + 0x919F: 0xBAB7, //HANGUL SYLLABLE MIEUM O RIEULHIEUH + 0x91A0: 0xBABA, //HANGUL SYLLABLE MIEUM O PIEUPSIOS + 0x91A1: 0xBABC, //HANGUL SYLLABLE MIEUM O SSANGSIOS + 0x91A2: 0xBABE, //HANGUL SYLLABLE MIEUM O CIEUC + 0x91A3: 0xBABF, //HANGUL SYLLABLE MIEUM O CHIEUCH + 0x91A4: 0xBAC0, //HANGUL SYLLABLE MIEUM O KHIEUKH + 0x91A5: 0xBAC1, //HANGUL SYLLABLE MIEUM O THIEUTH + 0x91A6: 0xBAC2, //HANGUL SYLLABLE MIEUM O PHIEUPH + 0x91A7: 0xBAC3, //HANGUL SYLLABLE MIEUM O HIEUH + 0x91A8: 0xBAC5, //HANGUL SYLLABLE MIEUM WA KIYEOK + 0x91A9: 0xBAC6, //HANGUL SYLLABLE MIEUM WA SSANGKIYEOK + 0x91AA: 0xBAC7, //HANGUL SYLLABLE MIEUM WA KIYEOKSIOS + 0x91AB: 0xBAC9, //HANGUL SYLLABLE MIEUM WA NIEUNCIEUC + 0x91AC: 0xBACA, //HANGUL SYLLABLE MIEUM WA NIEUNHIEUH + 0x91AD: 0xBACB, //HANGUL SYLLABLE MIEUM WA TIKEUT + 0x91AE: 0xBACC, //HANGUL SYLLABLE MIEUM WA RIEUL + 0x91AF: 0xBACD, //HANGUL SYLLABLE MIEUM WA RIEULKIYEOK + 0x91B0: 0xBACE, //HANGUL SYLLABLE MIEUM WA RIEULMIEUM + 0x91B1: 0xBACF, //HANGUL SYLLABLE MIEUM WA RIEULPIEUP + 0x91B2: 0xBAD0, //HANGUL SYLLABLE MIEUM WA RIEULSIOS + 0x91B3: 0xBAD1, //HANGUL SYLLABLE MIEUM WA RIEULTHIEUTH + 0x91B4: 0xBAD2, //HANGUL SYLLABLE MIEUM WA RIEULPHIEUPH + 0x91B5: 0xBAD3, //HANGUL SYLLABLE MIEUM WA RIEULHIEUH + 0x91B6: 0xBAD4, //HANGUL SYLLABLE MIEUM WA MIEUM + 0x91B7: 0xBAD5, //HANGUL SYLLABLE MIEUM WA PIEUP + 0x91B8: 0xBAD6, //HANGUL SYLLABLE MIEUM WA PIEUPSIOS + 0x91B9: 0xBAD7, //HANGUL SYLLABLE MIEUM WA SIOS + 0x91BA: 0xBADA, //HANGUL SYLLABLE MIEUM WA CIEUC + 0x91BB: 0xBADB, //HANGUL SYLLABLE MIEUM WA CHIEUCH + 0x91BC: 0xBADC, //HANGUL SYLLABLE MIEUM WA KHIEUKH + 0x91BD: 0xBADD, //HANGUL SYLLABLE MIEUM WA THIEUTH + 0x91BE: 0xBADE, //HANGUL SYLLABLE MIEUM WA PHIEUPH + 0x91BF: 0xBADF, //HANGUL SYLLABLE MIEUM WA HIEUH + 0x91C0: 0xBAE0, //HANGUL SYLLABLE MIEUM WAE + 0x91C1: 0xBAE1, //HANGUL SYLLABLE MIEUM WAE KIYEOK + 0x91C2: 0xBAE2, //HANGUL SYLLABLE MIEUM WAE SSANGKIYEOK + 0x91C3: 0xBAE3, //HANGUL SYLLABLE MIEUM WAE KIYEOKSIOS + 0x91C4: 0xBAE4, //HANGUL SYLLABLE MIEUM WAE NIEUN + 0x91C5: 0xBAE5, //HANGUL SYLLABLE MIEUM WAE NIEUNCIEUC + 0x91C6: 0xBAE6, //HANGUL SYLLABLE MIEUM WAE NIEUNHIEUH + 0x91C7: 0xBAE7, //HANGUL SYLLABLE MIEUM WAE TIKEUT + 0x91C8: 0xBAE8, //HANGUL SYLLABLE MIEUM WAE RIEUL + 0x91C9: 0xBAE9, //HANGUL SYLLABLE MIEUM WAE RIEULKIYEOK + 0x91CA: 0xBAEA, //HANGUL SYLLABLE MIEUM WAE RIEULMIEUM + 0x91CB: 0xBAEB, //HANGUL SYLLABLE MIEUM WAE RIEULPIEUP + 0x91CC: 0xBAEC, //HANGUL SYLLABLE MIEUM WAE RIEULSIOS + 0x91CD: 0xBAED, //HANGUL SYLLABLE MIEUM WAE RIEULTHIEUTH + 0x91CE: 0xBAEE, //HANGUL SYLLABLE MIEUM WAE RIEULPHIEUPH + 0x91CF: 0xBAEF, //HANGUL SYLLABLE MIEUM WAE RIEULHIEUH + 0x91D0: 0xBAF0, //HANGUL SYLLABLE MIEUM WAE MIEUM + 0x91D1: 0xBAF1, //HANGUL SYLLABLE MIEUM WAE PIEUP + 0x91D2: 0xBAF2, //HANGUL SYLLABLE MIEUM WAE PIEUPSIOS + 0x91D3: 0xBAF3, //HANGUL SYLLABLE MIEUM WAE SIOS + 0x91D4: 0xBAF4, //HANGUL SYLLABLE MIEUM WAE SSANGSIOS + 0x91D5: 0xBAF5, //HANGUL SYLLABLE MIEUM WAE IEUNG + 0x91D6: 0xBAF6, //HANGUL SYLLABLE MIEUM WAE CIEUC + 0x91D7: 0xBAF7, //HANGUL SYLLABLE MIEUM WAE CHIEUCH + 0x91D8: 0xBAF8, //HANGUL SYLLABLE MIEUM WAE KHIEUKH + 0x91D9: 0xBAF9, //HANGUL SYLLABLE MIEUM WAE THIEUTH + 0x91DA: 0xBAFA, //HANGUL SYLLABLE MIEUM WAE PHIEUPH + 0x91DB: 0xBAFB, //HANGUL SYLLABLE MIEUM WAE HIEUH + 0x91DC: 0xBAFD, //HANGUL SYLLABLE MIEUM OE KIYEOK + 0x91DD: 0xBAFE, //HANGUL SYLLABLE MIEUM OE SSANGKIYEOK + 0x91DE: 0xBAFF, //HANGUL SYLLABLE MIEUM OE KIYEOKSIOS + 0x91DF: 0xBB01, //HANGUL SYLLABLE MIEUM OE NIEUNCIEUC + 0x91E0: 0xBB02, //HANGUL SYLLABLE MIEUM OE NIEUNHIEUH + 0x91E1: 0xBB03, //HANGUL SYLLABLE MIEUM OE TIKEUT + 0x91E2: 0xBB05, //HANGUL SYLLABLE MIEUM OE RIEULKIYEOK + 0x91E3: 0xBB06, //HANGUL SYLLABLE MIEUM OE RIEULMIEUM + 0x91E4: 0xBB07, //HANGUL SYLLABLE MIEUM OE RIEULPIEUP + 0x91E5: 0xBB08, //HANGUL SYLLABLE MIEUM OE RIEULSIOS + 0x91E6: 0xBB09, //HANGUL SYLLABLE MIEUM OE RIEULTHIEUTH + 0x91E7: 0xBB0A, //HANGUL SYLLABLE MIEUM OE RIEULPHIEUPH + 0x91E8: 0xBB0B, //HANGUL SYLLABLE MIEUM OE RIEULHIEUH + 0x91E9: 0xBB0C, //HANGUL SYLLABLE MIEUM OE MIEUM + 0x91EA: 0xBB0E, //HANGUL SYLLABLE MIEUM OE PIEUPSIOS + 0x91EB: 0xBB10, //HANGUL SYLLABLE MIEUM OE SSANGSIOS + 0x91EC: 0xBB12, //HANGUL SYLLABLE MIEUM OE CIEUC + 0x91ED: 0xBB13, //HANGUL SYLLABLE MIEUM OE CHIEUCH + 0x91EE: 0xBB14, //HANGUL SYLLABLE MIEUM OE KHIEUKH + 0x91EF: 0xBB15, //HANGUL SYLLABLE MIEUM OE THIEUTH + 0x91F0: 0xBB16, //HANGUL SYLLABLE MIEUM OE PHIEUPH + 0x91F1: 0xBB17, //HANGUL SYLLABLE MIEUM OE HIEUH + 0x91F2: 0xBB19, //HANGUL SYLLABLE MIEUM YO KIYEOK + 0x91F3: 0xBB1A, //HANGUL SYLLABLE MIEUM YO SSANGKIYEOK + 0x91F4: 0xBB1B, //HANGUL SYLLABLE MIEUM YO KIYEOKSIOS + 0x91F5: 0xBB1D, //HANGUL SYLLABLE MIEUM YO NIEUNCIEUC + 0x91F6: 0xBB1E, //HANGUL SYLLABLE MIEUM YO NIEUNHIEUH + 0x91F7: 0xBB1F, //HANGUL SYLLABLE MIEUM YO TIKEUT + 0x91F8: 0xBB21, //HANGUL SYLLABLE MIEUM YO RIEULKIYEOK + 0x91F9: 0xBB22, //HANGUL SYLLABLE MIEUM YO RIEULMIEUM + 0x91FA: 0xBB23, //HANGUL SYLLABLE MIEUM YO RIEULPIEUP + 0x91FB: 0xBB24, //HANGUL SYLLABLE MIEUM YO RIEULSIOS + 0x91FC: 0xBB25, //HANGUL SYLLABLE MIEUM YO RIEULTHIEUTH + 0x91FD: 0xBB26, //HANGUL SYLLABLE MIEUM YO RIEULPHIEUPH + 0x91FE: 0xBB27, //HANGUL SYLLABLE MIEUM YO RIEULHIEUH + 0x9241: 0xBB28, //HANGUL SYLLABLE MIEUM YO MIEUM + 0x9242: 0xBB2A, //HANGUL SYLLABLE MIEUM YO PIEUPSIOS + 0x9243: 0xBB2C, //HANGUL SYLLABLE MIEUM YO SSANGSIOS + 0x9244: 0xBB2D, //HANGUL SYLLABLE MIEUM YO IEUNG + 0x9245: 0xBB2E, //HANGUL SYLLABLE MIEUM YO CIEUC + 0x9246: 0xBB2F, //HANGUL SYLLABLE MIEUM YO CHIEUCH + 0x9247: 0xBB30, //HANGUL SYLLABLE MIEUM YO KHIEUKH + 0x9248: 0xBB31, //HANGUL SYLLABLE MIEUM YO THIEUTH + 0x9249: 0xBB32, //HANGUL SYLLABLE MIEUM YO PHIEUPH + 0x924A: 0xBB33, //HANGUL SYLLABLE MIEUM YO HIEUH + 0x924B: 0xBB37, //HANGUL SYLLABLE MIEUM U KIYEOKSIOS + 0x924C: 0xBB39, //HANGUL SYLLABLE MIEUM U NIEUNCIEUC + 0x924D: 0xBB3A, //HANGUL SYLLABLE MIEUM U NIEUNHIEUH + 0x924E: 0xBB3F, //HANGUL SYLLABLE MIEUM U RIEULPIEUP + 0x924F: 0xBB40, //HANGUL SYLLABLE MIEUM U RIEULSIOS + 0x9250: 0xBB41, //HANGUL SYLLABLE MIEUM U RIEULTHIEUTH + 0x9251: 0xBB42, //HANGUL SYLLABLE MIEUM U RIEULPHIEUPH + 0x9252: 0xBB43, //HANGUL SYLLABLE MIEUM U RIEULHIEUH + 0x9253: 0xBB46, //HANGUL SYLLABLE MIEUM U PIEUPSIOS + 0x9254: 0xBB48, //HANGUL SYLLABLE MIEUM U SSANGSIOS + 0x9255: 0xBB4A, //HANGUL SYLLABLE MIEUM U CIEUC + 0x9256: 0xBB4B, //HANGUL SYLLABLE MIEUM U CHIEUCH + 0x9257: 0xBB4C, //HANGUL SYLLABLE MIEUM U KHIEUKH + 0x9258: 0xBB4E, //HANGUL SYLLABLE MIEUM U PHIEUPH + 0x9259: 0xBB51, //HANGUL SYLLABLE MIEUM WEO KIYEOK + 0x925A: 0xBB52, //HANGUL SYLLABLE MIEUM WEO SSANGKIYEOK + 0x9261: 0xBB53, //HANGUL SYLLABLE MIEUM WEO KIYEOKSIOS + 0x9262: 0xBB55, //HANGUL SYLLABLE MIEUM WEO NIEUNCIEUC + 0x9263: 0xBB56, //HANGUL SYLLABLE MIEUM WEO NIEUNHIEUH + 0x9264: 0xBB57, //HANGUL SYLLABLE MIEUM WEO TIKEUT + 0x9265: 0xBB59, //HANGUL SYLLABLE MIEUM WEO RIEULKIYEOK + 0x9266: 0xBB5A, //HANGUL SYLLABLE MIEUM WEO RIEULMIEUM + 0x9267: 0xBB5B, //HANGUL SYLLABLE MIEUM WEO RIEULPIEUP + 0x9268: 0xBB5C, //HANGUL SYLLABLE MIEUM WEO RIEULSIOS + 0x9269: 0xBB5D, //HANGUL SYLLABLE MIEUM WEO RIEULTHIEUTH + 0x926A: 0xBB5E, //HANGUL SYLLABLE MIEUM WEO RIEULPHIEUPH + 0x926B: 0xBB5F, //HANGUL SYLLABLE MIEUM WEO RIEULHIEUH + 0x926C: 0xBB60, //HANGUL SYLLABLE MIEUM WEO MIEUM + 0x926D: 0xBB62, //HANGUL SYLLABLE MIEUM WEO PIEUPSIOS + 0x926E: 0xBB64, //HANGUL SYLLABLE MIEUM WEO SSANGSIOS + 0x926F: 0xBB65, //HANGUL SYLLABLE MIEUM WEO IEUNG + 0x9270: 0xBB66, //HANGUL SYLLABLE MIEUM WEO CIEUC + 0x9271: 0xBB67, //HANGUL SYLLABLE MIEUM WEO CHIEUCH + 0x9272: 0xBB68, //HANGUL SYLLABLE MIEUM WEO KHIEUKH + 0x9273: 0xBB69, //HANGUL SYLLABLE MIEUM WEO THIEUTH + 0x9274: 0xBB6A, //HANGUL SYLLABLE MIEUM WEO PHIEUPH + 0x9275: 0xBB6B, //HANGUL SYLLABLE MIEUM WEO HIEUH + 0x9276: 0xBB6D, //HANGUL SYLLABLE MIEUM WE KIYEOK + 0x9277: 0xBB6E, //HANGUL SYLLABLE MIEUM WE SSANGKIYEOK + 0x9278: 0xBB6F, //HANGUL SYLLABLE MIEUM WE KIYEOKSIOS + 0x9279: 0xBB70, //HANGUL SYLLABLE MIEUM WE NIEUN + 0x927A: 0xBB71, //HANGUL SYLLABLE MIEUM WE NIEUNCIEUC + 0x9281: 0xBB72, //HANGUL SYLLABLE MIEUM WE NIEUNHIEUH + 0x9282: 0xBB73, //HANGUL SYLLABLE MIEUM WE TIKEUT + 0x9283: 0xBB74, //HANGUL SYLLABLE MIEUM WE RIEUL + 0x9284: 0xBB75, //HANGUL SYLLABLE MIEUM WE RIEULKIYEOK + 0x9285: 0xBB76, //HANGUL SYLLABLE MIEUM WE RIEULMIEUM + 0x9286: 0xBB77, //HANGUL SYLLABLE MIEUM WE RIEULPIEUP + 0x9287: 0xBB78, //HANGUL SYLLABLE MIEUM WE RIEULSIOS + 0x9288: 0xBB79, //HANGUL SYLLABLE MIEUM WE RIEULTHIEUTH + 0x9289: 0xBB7A, //HANGUL SYLLABLE MIEUM WE RIEULPHIEUPH + 0x928A: 0xBB7B, //HANGUL SYLLABLE MIEUM WE RIEULHIEUH + 0x928B: 0xBB7C, //HANGUL SYLLABLE MIEUM WE MIEUM + 0x928C: 0xBB7D, //HANGUL SYLLABLE MIEUM WE PIEUP + 0x928D: 0xBB7E, //HANGUL SYLLABLE MIEUM WE PIEUPSIOS + 0x928E: 0xBB7F, //HANGUL SYLLABLE MIEUM WE SIOS + 0x928F: 0xBB80, //HANGUL SYLLABLE MIEUM WE SSANGSIOS + 0x9290: 0xBB81, //HANGUL SYLLABLE MIEUM WE IEUNG + 0x9291: 0xBB82, //HANGUL SYLLABLE MIEUM WE CIEUC + 0x9292: 0xBB83, //HANGUL SYLLABLE MIEUM WE CHIEUCH + 0x9293: 0xBB84, //HANGUL SYLLABLE MIEUM WE KHIEUKH + 0x9294: 0xBB85, //HANGUL SYLLABLE MIEUM WE THIEUTH + 0x9295: 0xBB86, //HANGUL SYLLABLE MIEUM WE PHIEUPH + 0x9296: 0xBB87, //HANGUL SYLLABLE MIEUM WE HIEUH + 0x9297: 0xBB89, //HANGUL SYLLABLE MIEUM WI KIYEOK + 0x9298: 0xBB8A, //HANGUL SYLLABLE MIEUM WI SSANGKIYEOK + 0x9299: 0xBB8B, //HANGUL SYLLABLE MIEUM WI KIYEOKSIOS + 0x929A: 0xBB8D, //HANGUL SYLLABLE MIEUM WI NIEUNCIEUC + 0x929B: 0xBB8E, //HANGUL SYLLABLE MIEUM WI NIEUNHIEUH + 0x929C: 0xBB8F, //HANGUL SYLLABLE MIEUM WI TIKEUT + 0x929D: 0xBB91, //HANGUL SYLLABLE MIEUM WI RIEULKIYEOK + 0x929E: 0xBB92, //HANGUL SYLLABLE MIEUM WI RIEULMIEUM + 0x929F: 0xBB93, //HANGUL SYLLABLE MIEUM WI RIEULPIEUP + 0x92A0: 0xBB94, //HANGUL SYLLABLE MIEUM WI RIEULSIOS + 0x92A1: 0xBB95, //HANGUL SYLLABLE MIEUM WI RIEULTHIEUTH + 0x92A2: 0xBB96, //HANGUL SYLLABLE MIEUM WI RIEULPHIEUPH + 0x92A3: 0xBB97, //HANGUL SYLLABLE MIEUM WI RIEULHIEUH + 0x92A4: 0xBB98, //HANGUL SYLLABLE MIEUM WI MIEUM + 0x92A5: 0xBB99, //HANGUL SYLLABLE MIEUM WI PIEUP + 0x92A6: 0xBB9A, //HANGUL SYLLABLE MIEUM WI PIEUPSIOS + 0x92A7: 0xBB9B, //HANGUL SYLLABLE MIEUM WI SIOS + 0x92A8: 0xBB9C, //HANGUL SYLLABLE MIEUM WI SSANGSIOS + 0x92A9: 0xBB9D, //HANGUL SYLLABLE MIEUM WI IEUNG + 0x92AA: 0xBB9E, //HANGUL SYLLABLE MIEUM WI CIEUC + 0x92AB: 0xBB9F, //HANGUL SYLLABLE MIEUM WI CHIEUCH + 0x92AC: 0xBBA0, //HANGUL SYLLABLE MIEUM WI KHIEUKH + 0x92AD: 0xBBA1, //HANGUL SYLLABLE MIEUM WI THIEUTH + 0x92AE: 0xBBA2, //HANGUL SYLLABLE MIEUM WI PHIEUPH + 0x92AF: 0xBBA3, //HANGUL SYLLABLE MIEUM WI HIEUH + 0x92B0: 0xBBA5, //HANGUL SYLLABLE MIEUM YU KIYEOK + 0x92B1: 0xBBA6, //HANGUL SYLLABLE MIEUM YU SSANGKIYEOK + 0x92B2: 0xBBA7, //HANGUL SYLLABLE MIEUM YU KIYEOKSIOS + 0x92B3: 0xBBA9, //HANGUL SYLLABLE MIEUM YU NIEUNCIEUC + 0x92B4: 0xBBAA, //HANGUL SYLLABLE MIEUM YU NIEUNHIEUH + 0x92B5: 0xBBAB, //HANGUL SYLLABLE MIEUM YU TIKEUT + 0x92B6: 0xBBAD, //HANGUL SYLLABLE MIEUM YU RIEULKIYEOK + 0x92B7: 0xBBAE, //HANGUL SYLLABLE MIEUM YU RIEULMIEUM + 0x92B8: 0xBBAF, //HANGUL SYLLABLE MIEUM YU RIEULPIEUP + 0x92B9: 0xBBB0, //HANGUL SYLLABLE MIEUM YU RIEULSIOS + 0x92BA: 0xBBB1, //HANGUL SYLLABLE MIEUM YU RIEULTHIEUTH + 0x92BB: 0xBBB2, //HANGUL SYLLABLE MIEUM YU RIEULPHIEUPH + 0x92BC: 0xBBB3, //HANGUL SYLLABLE MIEUM YU RIEULHIEUH + 0x92BD: 0xBBB5, //HANGUL SYLLABLE MIEUM YU PIEUP + 0x92BE: 0xBBB6, //HANGUL SYLLABLE MIEUM YU PIEUPSIOS + 0x92BF: 0xBBB8, //HANGUL SYLLABLE MIEUM YU SSANGSIOS + 0x92C0: 0xBBB9, //HANGUL SYLLABLE MIEUM YU IEUNG + 0x92C1: 0xBBBA, //HANGUL SYLLABLE MIEUM YU CIEUC + 0x92C2: 0xBBBB, //HANGUL SYLLABLE MIEUM YU CHIEUCH + 0x92C3: 0xBBBC, //HANGUL SYLLABLE MIEUM YU KHIEUKH + 0x92C4: 0xBBBD, //HANGUL SYLLABLE MIEUM YU THIEUTH + 0x92C5: 0xBBBE, //HANGUL SYLLABLE MIEUM YU PHIEUPH + 0x92C6: 0xBBBF, //HANGUL SYLLABLE MIEUM YU HIEUH + 0x92C7: 0xBBC1, //HANGUL SYLLABLE MIEUM EU KIYEOK + 0x92C8: 0xBBC2, //HANGUL SYLLABLE MIEUM EU SSANGKIYEOK + 0x92C9: 0xBBC3, //HANGUL SYLLABLE MIEUM EU KIYEOKSIOS + 0x92CA: 0xBBC5, //HANGUL SYLLABLE MIEUM EU NIEUNCIEUC + 0x92CB: 0xBBC6, //HANGUL SYLLABLE MIEUM EU NIEUNHIEUH + 0x92CC: 0xBBC7, //HANGUL SYLLABLE MIEUM EU TIKEUT + 0x92CD: 0xBBC9, //HANGUL SYLLABLE MIEUM EU RIEULKIYEOK + 0x92CE: 0xBBCA, //HANGUL SYLLABLE MIEUM EU RIEULMIEUM + 0x92CF: 0xBBCB, //HANGUL SYLLABLE MIEUM EU RIEULPIEUP + 0x92D0: 0xBBCC, //HANGUL SYLLABLE MIEUM EU RIEULSIOS + 0x92D1: 0xBBCD, //HANGUL SYLLABLE MIEUM EU RIEULTHIEUTH + 0x92D2: 0xBBCE, //HANGUL SYLLABLE MIEUM EU RIEULPHIEUPH + 0x92D3: 0xBBCF, //HANGUL SYLLABLE MIEUM EU RIEULHIEUH + 0x92D4: 0xBBD1, //HANGUL SYLLABLE MIEUM EU PIEUP + 0x92D5: 0xBBD2, //HANGUL SYLLABLE MIEUM EU PIEUPSIOS + 0x92D6: 0xBBD4, //HANGUL SYLLABLE MIEUM EU SSANGSIOS + 0x92D7: 0xBBD5, //HANGUL SYLLABLE MIEUM EU IEUNG + 0x92D8: 0xBBD6, //HANGUL SYLLABLE MIEUM EU CIEUC + 0x92D9: 0xBBD7, //HANGUL SYLLABLE MIEUM EU CHIEUCH + 0x92DA: 0xBBD8, //HANGUL SYLLABLE MIEUM EU KHIEUKH + 0x92DB: 0xBBD9, //HANGUL SYLLABLE MIEUM EU THIEUTH + 0x92DC: 0xBBDA, //HANGUL SYLLABLE MIEUM EU PHIEUPH + 0x92DD: 0xBBDB, //HANGUL SYLLABLE MIEUM EU HIEUH + 0x92DE: 0xBBDC, //HANGUL SYLLABLE MIEUM YI + 0x92DF: 0xBBDD, //HANGUL SYLLABLE MIEUM YI KIYEOK + 0x92E0: 0xBBDE, //HANGUL SYLLABLE MIEUM YI SSANGKIYEOK + 0x92E1: 0xBBDF, //HANGUL SYLLABLE MIEUM YI KIYEOKSIOS + 0x92E2: 0xBBE0, //HANGUL SYLLABLE MIEUM YI NIEUN + 0x92E3: 0xBBE1, //HANGUL SYLLABLE MIEUM YI NIEUNCIEUC + 0x92E4: 0xBBE2, //HANGUL SYLLABLE MIEUM YI NIEUNHIEUH + 0x92E5: 0xBBE3, //HANGUL SYLLABLE MIEUM YI TIKEUT + 0x92E6: 0xBBE4, //HANGUL SYLLABLE MIEUM YI RIEUL + 0x92E7: 0xBBE5, //HANGUL SYLLABLE MIEUM YI RIEULKIYEOK + 0x92E8: 0xBBE6, //HANGUL SYLLABLE MIEUM YI RIEULMIEUM + 0x92E9: 0xBBE7, //HANGUL SYLLABLE MIEUM YI RIEULPIEUP + 0x92EA: 0xBBE8, //HANGUL SYLLABLE MIEUM YI RIEULSIOS + 0x92EB: 0xBBE9, //HANGUL SYLLABLE MIEUM YI RIEULTHIEUTH + 0x92EC: 0xBBEA, //HANGUL SYLLABLE MIEUM YI RIEULPHIEUPH + 0x92ED: 0xBBEB, //HANGUL SYLLABLE MIEUM YI RIEULHIEUH + 0x92EE: 0xBBEC, //HANGUL SYLLABLE MIEUM YI MIEUM + 0x92EF: 0xBBED, //HANGUL SYLLABLE MIEUM YI PIEUP + 0x92F0: 0xBBEE, //HANGUL SYLLABLE MIEUM YI PIEUPSIOS + 0x92F1: 0xBBEF, //HANGUL SYLLABLE MIEUM YI SIOS + 0x92F2: 0xBBF0, //HANGUL SYLLABLE MIEUM YI SSANGSIOS + 0x92F3: 0xBBF1, //HANGUL SYLLABLE MIEUM YI IEUNG + 0x92F4: 0xBBF2, //HANGUL SYLLABLE MIEUM YI CIEUC + 0x92F5: 0xBBF3, //HANGUL SYLLABLE MIEUM YI CHIEUCH + 0x92F6: 0xBBF4, //HANGUL SYLLABLE MIEUM YI KHIEUKH + 0x92F7: 0xBBF5, //HANGUL SYLLABLE MIEUM YI THIEUTH + 0x92F8: 0xBBF6, //HANGUL SYLLABLE MIEUM YI PHIEUPH + 0x92F9: 0xBBF7, //HANGUL SYLLABLE MIEUM YI HIEUH + 0x92FA: 0xBBFA, //HANGUL SYLLABLE MIEUM I SSANGKIYEOK + 0x92FB: 0xBBFB, //HANGUL SYLLABLE MIEUM I KIYEOKSIOS + 0x92FC: 0xBBFD, //HANGUL SYLLABLE MIEUM I NIEUNCIEUC + 0x92FD: 0xBBFE, //HANGUL SYLLABLE MIEUM I NIEUNHIEUH + 0x92FE: 0xBC01, //HANGUL SYLLABLE MIEUM I RIEULKIYEOK + 0x9341: 0xBC03, //HANGUL SYLLABLE MIEUM I RIEULPIEUP + 0x9342: 0xBC04, //HANGUL SYLLABLE MIEUM I RIEULSIOS + 0x9343: 0xBC05, //HANGUL SYLLABLE MIEUM I RIEULTHIEUTH + 0x9344: 0xBC06, //HANGUL SYLLABLE MIEUM I RIEULPHIEUPH + 0x9345: 0xBC07, //HANGUL SYLLABLE MIEUM I RIEULHIEUH + 0x9346: 0xBC0A, //HANGUL SYLLABLE MIEUM I PIEUPSIOS + 0x9347: 0xBC0E, //HANGUL SYLLABLE MIEUM I CIEUC + 0x9348: 0xBC10, //HANGUL SYLLABLE MIEUM I KHIEUKH + 0x9349: 0xBC12, //HANGUL SYLLABLE MIEUM I PHIEUPH + 0x934A: 0xBC13, //HANGUL SYLLABLE MIEUM I HIEUH + 0x934B: 0xBC19, //HANGUL SYLLABLE PIEUP A NIEUNCIEUC + 0x934C: 0xBC1A, //HANGUL SYLLABLE PIEUP A NIEUNHIEUH + 0x934D: 0xBC20, //HANGUL SYLLABLE PIEUP A RIEULSIOS + 0x934E: 0xBC21, //HANGUL SYLLABLE PIEUP A RIEULTHIEUTH + 0x934F: 0xBC22, //HANGUL SYLLABLE PIEUP A RIEULPHIEUPH + 0x9350: 0xBC23, //HANGUL SYLLABLE PIEUP A RIEULHIEUH + 0x9351: 0xBC26, //HANGUL SYLLABLE PIEUP A PIEUPSIOS + 0x9352: 0xBC28, //HANGUL SYLLABLE PIEUP A SSANGSIOS + 0x9353: 0xBC2A, //HANGUL SYLLABLE PIEUP A CIEUC + 0x9354: 0xBC2B, //HANGUL SYLLABLE PIEUP A CHIEUCH + 0x9355: 0xBC2C, //HANGUL SYLLABLE PIEUP A KHIEUKH + 0x9356: 0xBC2E, //HANGUL SYLLABLE PIEUP A PHIEUPH + 0x9357: 0xBC2F, //HANGUL SYLLABLE PIEUP A HIEUH + 0x9358: 0xBC32, //HANGUL SYLLABLE PIEUP AE SSANGKIYEOK + 0x9359: 0xBC33, //HANGUL SYLLABLE PIEUP AE KIYEOKSIOS + 0x935A: 0xBC35, //HANGUL SYLLABLE PIEUP AE NIEUNCIEUC + 0x9361: 0xBC36, //HANGUL SYLLABLE PIEUP AE NIEUNHIEUH + 0x9362: 0xBC37, //HANGUL SYLLABLE PIEUP AE TIKEUT + 0x9363: 0xBC39, //HANGUL SYLLABLE PIEUP AE RIEULKIYEOK + 0x9364: 0xBC3A, //HANGUL SYLLABLE PIEUP AE RIEULMIEUM + 0x9365: 0xBC3B, //HANGUL SYLLABLE PIEUP AE RIEULPIEUP + 0x9366: 0xBC3C, //HANGUL SYLLABLE PIEUP AE RIEULSIOS + 0x9367: 0xBC3D, //HANGUL SYLLABLE PIEUP AE RIEULTHIEUTH + 0x9368: 0xBC3E, //HANGUL SYLLABLE PIEUP AE RIEULPHIEUPH + 0x9369: 0xBC3F, //HANGUL SYLLABLE PIEUP AE RIEULHIEUH + 0x936A: 0xBC42, //HANGUL SYLLABLE PIEUP AE PIEUPSIOS + 0x936B: 0xBC46, //HANGUL SYLLABLE PIEUP AE CIEUC + 0x936C: 0xBC47, //HANGUL SYLLABLE PIEUP AE CHIEUCH + 0x936D: 0xBC48, //HANGUL SYLLABLE PIEUP AE KHIEUKH + 0x936E: 0xBC4A, //HANGUL SYLLABLE PIEUP AE PHIEUPH + 0x936F: 0xBC4B, //HANGUL SYLLABLE PIEUP AE HIEUH + 0x9370: 0xBC4E, //HANGUL SYLLABLE PIEUP YA SSANGKIYEOK + 0x9371: 0xBC4F, //HANGUL SYLLABLE PIEUP YA KIYEOKSIOS + 0x9372: 0xBC51, //HANGUL SYLLABLE PIEUP YA NIEUNCIEUC + 0x9373: 0xBC52, //HANGUL SYLLABLE PIEUP YA NIEUNHIEUH + 0x9374: 0xBC53, //HANGUL SYLLABLE PIEUP YA TIKEUT + 0x9375: 0xBC54, //HANGUL SYLLABLE PIEUP YA RIEUL + 0x9376: 0xBC55, //HANGUL SYLLABLE PIEUP YA RIEULKIYEOK + 0x9377: 0xBC56, //HANGUL SYLLABLE PIEUP YA RIEULMIEUM + 0x9378: 0xBC57, //HANGUL SYLLABLE PIEUP YA RIEULPIEUP + 0x9379: 0xBC58, //HANGUL SYLLABLE PIEUP YA RIEULSIOS + 0x937A: 0xBC59, //HANGUL SYLLABLE PIEUP YA RIEULTHIEUTH + 0x9381: 0xBC5A, //HANGUL SYLLABLE PIEUP YA RIEULPHIEUPH + 0x9382: 0xBC5B, //HANGUL SYLLABLE PIEUP YA RIEULHIEUH + 0x9383: 0xBC5C, //HANGUL SYLLABLE PIEUP YA MIEUM + 0x9384: 0xBC5E, //HANGUL SYLLABLE PIEUP YA PIEUPSIOS + 0x9385: 0xBC5F, //HANGUL SYLLABLE PIEUP YA SIOS + 0x9386: 0xBC60, //HANGUL SYLLABLE PIEUP YA SSANGSIOS + 0x9387: 0xBC61, //HANGUL SYLLABLE PIEUP YA IEUNG + 0x9388: 0xBC62, //HANGUL SYLLABLE PIEUP YA CIEUC + 0x9389: 0xBC63, //HANGUL SYLLABLE PIEUP YA CHIEUCH + 0x938A: 0xBC64, //HANGUL SYLLABLE PIEUP YA KHIEUKH + 0x938B: 0xBC65, //HANGUL SYLLABLE PIEUP YA THIEUTH + 0x938C: 0xBC66, //HANGUL SYLLABLE PIEUP YA PHIEUPH + 0x938D: 0xBC67, //HANGUL SYLLABLE PIEUP YA HIEUH + 0x938E: 0xBC68, //HANGUL SYLLABLE PIEUP YAE + 0x938F: 0xBC69, //HANGUL SYLLABLE PIEUP YAE KIYEOK + 0x9390: 0xBC6A, //HANGUL SYLLABLE PIEUP YAE SSANGKIYEOK + 0x9391: 0xBC6B, //HANGUL SYLLABLE PIEUP YAE KIYEOKSIOS + 0x9392: 0xBC6C, //HANGUL SYLLABLE PIEUP YAE NIEUN + 0x9393: 0xBC6D, //HANGUL SYLLABLE PIEUP YAE NIEUNCIEUC + 0x9394: 0xBC6E, //HANGUL SYLLABLE PIEUP YAE NIEUNHIEUH + 0x9395: 0xBC6F, //HANGUL SYLLABLE PIEUP YAE TIKEUT + 0x9396: 0xBC70, //HANGUL SYLLABLE PIEUP YAE RIEUL + 0x9397: 0xBC71, //HANGUL SYLLABLE PIEUP YAE RIEULKIYEOK + 0x9398: 0xBC72, //HANGUL SYLLABLE PIEUP YAE RIEULMIEUM + 0x9399: 0xBC73, //HANGUL SYLLABLE PIEUP YAE RIEULPIEUP + 0x939A: 0xBC74, //HANGUL SYLLABLE PIEUP YAE RIEULSIOS + 0x939B: 0xBC75, //HANGUL SYLLABLE PIEUP YAE RIEULTHIEUTH + 0x939C: 0xBC76, //HANGUL SYLLABLE PIEUP YAE RIEULPHIEUPH + 0x939D: 0xBC77, //HANGUL SYLLABLE PIEUP YAE RIEULHIEUH + 0x939E: 0xBC78, //HANGUL SYLLABLE PIEUP YAE MIEUM + 0x939F: 0xBC79, //HANGUL SYLLABLE PIEUP YAE PIEUP + 0x93A0: 0xBC7A, //HANGUL SYLLABLE PIEUP YAE PIEUPSIOS + 0x93A1: 0xBC7B, //HANGUL SYLLABLE PIEUP YAE SIOS + 0x93A2: 0xBC7C, //HANGUL SYLLABLE PIEUP YAE SSANGSIOS + 0x93A3: 0xBC7D, //HANGUL SYLLABLE PIEUP YAE IEUNG + 0x93A4: 0xBC7E, //HANGUL SYLLABLE PIEUP YAE CIEUC + 0x93A5: 0xBC7F, //HANGUL SYLLABLE PIEUP YAE CHIEUCH + 0x93A6: 0xBC80, //HANGUL SYLLABLE PIEUP YAE KHIEUKH + 0x93A7: 0xBC81, //HANGUL SYLLABLE PIEUP YAE THIEUTH + 0x93A8: 0xBC82, //HANGUL SYLLABLE PIEUP YAE PHIEUPH + 0x93A9: 0xBC83, //HANGUL SYLLABLE PIEUP YAE HIEUH + 0x93AA: 0xBC86, //HANGUL SYLLABLE PIEUP EO SSANGKIYEOK + 0x93AB: 0xBC87, //HANGUL SYLLABLE PIEUP EO KIYEOKSIOS + 0x93AC: 0xBC89, //HANGUL SYLLABLE PIEUP EO NIEUNCIEUC + 0x93AD: 0xBC8A, //HANGUL SYLLABLE PIEUP EO NIEUNHIEUH + 0x93AE: 0xBC8D, //HANGUL SYLLABLE PIEUP EO RIEULKIYEOK + 0x93AF: 0xBC8F, //HANGUL SYLLABLE PIEUP EO RIEULPIEUP + 0x93B0: 0xBC90, //HANGUL SYLLABLE PIEUP EO RIEULSIOS + 0x93B1: 0xBC91, //HANGUL SYLLABLE PIEUP EO RIEULTHIEUTH + 0x93B2: 0xBC92, //HANGUL SYLLABLE PIEUP EO RIEULPHIEUPH + 0x93B3: 0xBC93, //HANGUL SYLLABLE PIEUP EO RIEULHIEUH + 0x93B4: 0xBC96, //HANGUL SYLLABLE PIEUP EO PIEUPSIOS + 0x93B5: 0xBC98, //HANGUL SYLLABLE PIEUP EO SSANGSIOS + 0x93B6: 0xBC9B, //HANGUL SYLLABLE PIEUP EO CHIEUCH + 0x93B7: 0xBC9C, //HANGUL SYLLABLE PIEUP EO KHIEUKH + 0x93B8: 0xBC9D, //HANGUL SYLLABLE PIEUP EO THIEUTH + 0x93B9: 0xBC9E, //HANGUL SYLLABLE PIEUP EO PHIEUPH + 0x93BA: 0xBC9F, //HANGUL SYLLABLE PIEUP EO HIEUH + 0x93BB: 0xBCA2, //HANGUL SYLLABLE PIEUP E SSANGKIYEOK + 0x93BC: 0xBCA3, //HANGUL SYLLABLE PIEUP E KIYEOKSIOS + 0x93BD: 0xBCA5, //HANGUL SYLLABLE PIEUP E NIEUNCIEUC + 0x93BE: 0xBCA6, //HANGUL SYLLABLE PIEUP E NIEUNHIEUH + 0x93BF: 0xBCA9, //HANGUL SYLLABLE PIEUP E RIEULKIYEOK + 0x93C0: 0xBCAA, //HANGUL SYLLABLE PIEUP E RIEULMIEUM + 0x93C1: 0xBCAB, //HANGUL SYLLABLE PIEUP E RIEULPIEUP + 0x93C2: 0xBCAC, //HANGUL SYLLABLE PIEUP E RIEULSIOS + 0x93C3: 0xBCAD, //HANGUL SYLLABLE PIEUP E RIEULTHIEUTH + 0x93C4: 0xBCAE, //HANGUL SYLLABLE PIEUP E RIEULPHIEUPH + 0x93C5: 0xBCAF, //HANGUL SYLLABLE PIEUP E RIEULHIEUH + 0x93C6: 0xBCB2, //HANGUL SYLLABLE PIEUP E PIEUPSIOS + 0x93C7: 0xBCB6, //HANGUL SYLLABLE PIEUP E CIEUC + 0x93C8: 0xBCB7, //HANGUL SYLLABLE PIEUP E CHIEUCH + 0x93C9: 0xBCB8, //HANGUL SYLLABLE PIEUP E KHIEUKH + 0x93CA: 0xBCB9, //HANGUL SYLLABLE PIEUP E THIEUTH + 0x93CB: 0xBCBA, //HANGUL SYLLABLE PIEUP E PHIEUPH + 0x93CC: 0xBCBB, //HANGUL SYLLABLE PIEUP E HIEUH + 0x93CD: 0xBCBE, //HANGUL SYLLABLE PIEUP YEO SSANGKIYEOK + 0x93CE: 0xBCBF, //HANGUL SYLLABLE PIEUP YEO KIYEOKSIOS + 0x93CF: 0xBCC1, //HANGUL SYLLABLE PIEUP YEO NIEUNCIEUC + 0x93D0: 0xBCC2, //HANGUL SYLLABLE PIEUP YEO NIEUNHIEUH + 0x93D1: 0xBCC3, //HANGUL SYLLABLE PIEUP YEO TIKEUT + 0x93D2: 0xBCC5, //HANGUL SYLLABLE PIEUP YEO RIEULKIYEOK + 0x93D3: 0xBCC6, //HANGUL SYLLABLE PIEUP YEO RIEULMIEUM + 0x93D4: 0xBCC7, //HANGUL SYLLABLE PIEUP YEO RIEULPIEUP + 0x93D5: 0xBCC8, //HANGUL SYLLABLE PIEUP YEO RIEULSIOS + 0x93D6: 0xBCC9, //HANGUL SYLLABLE PIEUP YEO RIEULTHIEUTH + 0x93D7: 0xBCCA, //HANGUL SYLLABLE PIEUP YEO RIEULPHIEUPH + 0x93D8: 0xBCCB, //HANGUL SYLLABLE PIEUP YEO RIEULHIEUH + 0x93D9: 0xBCCC, //HANGUL SYLLABLE PIEUP YEO MIEUM + 0x93DA: 0xBCCE, //HANGUL SYLLABLE PIEUP YEO PIEUPSIOS + 0x93DB: 0xBCD2, //HANGUL SYLLABLE PIEUP YEO CIEUC + 0x93DC: 0xBCD3, //HANGUL SYLLABLE PIEUP YEO CHIEUCH + 0x93DD: 0xBCD4, //HANGUL SYLLABLE PIEUP YEO KHIEUKH + 0x93DE: 0xBCD6, //HANGUL SYLLABLE PIEUP YEO PHIEUPH + 0x93DF: 0xBCD7, //HANGUL SYLLABLE PIEUP YEO HIEUH + 0x93E0: 0xBCD9, //HANGUL SYLLABLE PIEUP YE KIYEOK + 0x93E1: 0xBCDA, //HANGUL SYLLABLE PIEUP YE SSANGKIYEOK + 0x93E2: 0xBCDB, //HANGUL SYLLABLE PIEUP YE KIYEOKSIOS + 0x93E3: 0xBCDD, //HANGUL SYLLABLE PIEUP YE NIEUNCIEUC + 0x93E4: 0xBCDE, //HANGUL SYLLABLE PIEUP YE NIEUNHIEUH + 0x93E5: 0xBCDF, //HANGUL SYLLABLE PIEUP YE TIKEUT + 0x93E6: 0xBCE0, //HANGUL SYLLABLE PIEUP YE RIEUL + 0x93E7: 0xBCE1, //HANGUL SYLLABLE PIEUP YE RIEULKIYEOK + 0x93E8: 0xBCE2, //HANGUL SYLLABLE PIEUP YE RIEULMIEUM + 0x93E9: 0xBCE3, //HANGUL SYLLABLE PIEUP YE RIEULPIEUP + 0x93EA: 0xBCE4, //HANGUL SYLLABLE PIEUP YE RIEULSIOS + 0x93EB: 0xBCE5, //HANGUL SYLLABLE PIEUP YE RIEULTHIEUTH + 0x93EC: 0xBCE6, //HANGUL SYLLABLE PIEUP YE RIEULPHIEUPH + 0x93ED: 0xBCE7, //HANGUL SYLLABLE PIEUP YE RIEULHIEUH + 0x93EE: 0xBCE8, //HANGUL SYLLABLE PIEUP YE MIEUM + 0x93EF: 0xBCE9, //HANGUL SYLLABLE PIEUP YE PIEUP + 0x93F0: 0xBCEA, //HANGUL SYLLABLE PIEUP YE PIEUPSIOS + 0x93F1: 0xBCEB, //HANGUL SYLLABLE PIEUP YE SIOS + 0x93F2: 0xBCEC, //HANGUL SYLLABLE PIEUP YE SSANGSIOS + 0x93F3: 0xBCED, //HANGUL SYLLABLE PIEUP YE IEUNG + 0x93F4: 0xBCEE, //HANGUL SYLLABLE PIEUP YE CIEUC + 0x93F5: 0xBCEF, //HANGUL SYLLABLE PIEUP YE CHIEUCH + 0x93F6: 0xBCF0, //HANGUL SYLLABLE PIEUP YE KHIEUKH + 0x93F7: 0xBCF1, //HANGUL SYLLABLE PIEUP YE THIEUTH + 0x93F8: 0xBCF2, //HANGUL SYLLABLE PIEUP YE PHIEUPH + 0x93F9: 0xBCF3, //HANGUL SYLLABLE PIEUP YE HIEUH + 0x93FA: 0xBCF7, //HANGUL SYLLABLE PIEUP O KIYEOKSIOS + 0x93FB: 0xBCF9, //HANGUL SYLLABLE PIEUP O NIEUNCIEUC + 0x93FC: 0xBCFA, //HANGUL SYLLABLE PIEUP O NIEUNHIEUH + 0x93FD: 0xBCFB, //HANGUL SYLLABLE PIEUP O TIKEUT + 0x93FE: 0xBCFD, //HANGUL SYLLABLE PIEUP O RIEULKIYEOK + 0x9441: 0xBCFE, //HANGUL SYLLABLE PIEUP O RIEULMIEUM + 0x9442: 0xBCFF, //HANGUL SYLLABLE PIEUP O RIEULPIEUP + 0x9443: 0xBD00, //HANGUL SYLLABLE PIEUP O RIEULSIOS + 0x9444: 0xBD01, //HANGUL SYLLABLE PIEUP O RIEULTHIEUTH + 0x9445: 0xBD02, //HANGUL SYLLABLE PIEUP O RIEULPHIEUPH + 0x9446: 0xBD03, //HANGUL SYLLABLE PIEUP O RIEULHIEUH + 0x9447: 0xBD06, //HANGUL SYLLABLE PIEUP O PIEUPSIOS + 0x9448: 0xBD08, //HANGUL SYLLABLE PIEUP O SSANGSIOS + 0x9449: 0xBD0A, //HANGUL SYLLABLE PIEUP O CIEUC + 0x944A: 0xBD0B, //HANGUL SYLLABLE PIEUP O CHIEUCH + 0x944B: 0xBD0C, //HANGUL SYLLABLE PIEUP O KHIEUKH + 0x944C: 0xBD0D, //HANGUL SYLLABLE PIEUP O THIEUTH + 0x944D: 0xBD0E, //HANGUL SYLLABLE PIEUP O PHIEUPH + 0x944E: 0xBD0F, //HANGUL SYLLABLE PIEUP O HIEUH + 0x944F: 0xBD11, //HANGUL SYLLABLE PIEUP WA KIYEOK + 0x9450: 0xBD12, //HANGUL SYLLABLE PIEUP WA SSANGKIYEOK + 0x9451: 0xBD13, //HANGUL SYLLABLE PIEUP WA KIYEOKSIOS + 0x9452: 0xBD15, //HANGUL SYLLABLE PIEUP WA NIEUNCIEUC + 0x9453: 0xBD16, //HANGUL SYLLABLE PIEUP WA NIEUNHIEUH + 0x9454: 0xBD17, //HANGUL SYLLABLE PIEUP WA TIKEUT + 0x9455: 0xBD18, //HANGUL SYLLABLE PIEUP WA RIEUL + 0x9456: 0xBD19, //HANGUL SYLLABLE PIEUP WA RIEULKIYEOK + 0x9457: 0xBD1A, //HANGUL SYLLABLE PIEUP WA RIEULMIEUM + 0x9458: 0xBD1B, //HANGUL SYLLABLE PIEUP WA RIEULPIEUP + 0x9459: 0xBD1C, //HANGUL SYLLABLE PIEUP WA RIEULSIOS + 0x945A: 0xBD1D, //HANGUL SYLLABLE PIEUP WA RIEULTHIEUTH + 0x9461: 0xBD1E, //HANGUL SYLLABLE PIEUP WA RIEULPHIEUPH + 0x9462: 0xBD1F, //HANGUL SYLLABLE PIEUP WA RIEULHIEUH + 0x9463: 0xBD20, //HANGUL SYLLABLE PIEUP WA MIEUM + 0x9464: 0xBD21, //HANGUL SYLLABLE PIEUP WA PIEUP + 0x9465: 0xBD22, //HANGUL SYLLABLE PIEUP WA PIEUPSIOS + 0x9466: 0xBD23, //HANGUL SYLLABLE PIEUP WA SIOS + 0x9467: 0xBD25, //HANGUL SYLLABLE PIEUP WA IEUNG + 0x9468: 0xBD26, //HANGUL SYLLABLE PIEUP WA CIEUC + 0x9469: 0xBD27, //HANGUL SYLLABLE PIEUP WA CHIEUCH + 0x946A: 0xBD28, //HANGUL SYLLABLE PIEUP WA KHIEUKH + 0x946B: 0xBD29, //HANGUL SYLLABLE PIEUP WA THIEUTH + 0x946C: 0xBD2A, //HANGUL SYLLABLE PIEUP WA PHIEUPH + 0x946D: 0xBD2B, //HANGUL SYLLABLE PIEUP WA HIEUH + 0x946E: 0xBD2D, //HANGUL SYLLABLE PIEUP WAE KIYEOK + 0x946F: 0xBD2E, //HANGUL SYLLABLE PIEUP WAE SSANGKIYEOK + 0x9470: 0xBD2F, //HANGUL SYLLABLE PIEUP WAE KIYEOKSIOS + 0x9471: 0xBD30, //HANGUL SYLLABLE PIEUP WAE NIEUN + 0x9472: 0xBD31, //HANGUL SYLLABLE PIEUP WAE NIEUNCIEUC + 0x9473: 0xBD32, //HANGUL SYLLABLE PIEUP WAE NIEUNHIEUH + 0x9474: 0xBD33, //HANGUL SYLLABLE PIEUP WAE TIKEUT + 0x9475: 0xBD34, //HANGUL SYLLABLE PIEUP WAE RIEUL + 0x9476: 0xBD35, //HANGUL SYLLABLE PIEUP WAE RIEULKIYEOK + 0x9477: 0xBD36, //HANGUL SYLLABLE PIEUP WAE RIEULMIEUM + 0x9478: 0xBD37, //HANGUL SYLLABLE PIEUP WAE RIEULPIEUP + 0x9479: 0xBD38, //HANGUL SYLLABLE PIEUP WAE RIEULSIOS + 0x947A: 0xBD39, //HANGUL SYLLABLE PIEUP WAE RIEULTHIEUTH + 0x9481: 0xBD3A, //HANGUL SYLLABLE PIEUP WAE RIEULPHIEUPH + 0x9482: 0xBD3B, //HANGUL SYLLABLE PIEUP WAE RIEULHIEUH + 0x9483: 0xBD3C, //HANGUL SYLLABLE PIEUP WAE MIEUM + 0x9484: 0xBD3D, //HANGUL SYLLABLE PIEUP WAE PIEUP + 0x9485: 0xBD3E, //HANGUL SYLLABLE PIEUP WAE PIEUPSIOS + 0x9486: 0xBD3F, //HANGUL SYLLABLE PIEUP WAE SIOS + 0x9487: 0xBD41, //HANGUL SYLLABLE PIEUP WAE IEUNG + 0x9488: 0xBD42, //HANGUL SYLLABLE PIEUP WAE CIEUC + 0x9489: 0xBD43, //HANGUL SYLLABLE PIEUP WAE CHIEUCH + 0x948A: 0xBD44, //HANGUL SYLLABLE PIEUP WAE KHIEUKH + 0x948B: 0xBD45, //HANGUL SYLLABLE PIEUP WAE THIEUTH + 0x948C: 0xBD46, //HANGUL SYLLABLE PIEUP WAE PHIEUPH + 0x948D: 0xBD47, //HANGUL SYLLABLE PIEUP WAE HIEUH + 0x948E: 0xBD4A, //HANGUL SYLLABLE PIEUP OE SSANGKIYEOK + 0x948F: 0xBD4B, //HANGUL SYLLABLE PIEUP OE KIYEOKSIOS + 0x9490: 0xBD4D, //HANGUL SYLLABLE PIEUP OE NIEUNCIEUC + 0x9491: 0xBD4E, //HANGUL SYLLABLE PIEUP OE NIEUNHIEUH + 0x9492: 0xBD4F, //HANGUL SYLLABLE PIEUP OE TIKEUT + 0x9493: 0xBD51, //HANGUL SYLLABLE PIEUP OE RIEULKIYEOK + 0x9494: 0xBD52, //HANGUL SYLLABLE PIEUP OE RIEULMIEUM + 0x9495: 0xBD53, //HANGUL SYLLABLE PIEUP OE RIEULPIEUP + 0x9496: 0xBD54, //HANGUL SYLLABLE PIEUP OE RIEULSIOS + 0x9497: 0xBD55, //HANGUL SYLLABLE PIEUP OE RIEULTHIEUTH + 0x9498: 0xBD56, //HANGUL SYLLABLE PIEUP OE RIEULPHIEUPH + 0x9499: 0xBD57, //HANGUL SYLLABLE PIEUP OE RIEULHIEUH + 0x949A: 0xBD5A, //HANGUL SYLLABLE PIEUP OE PIEUPSIOS + 0x949B: 0xBD5B, //HANGUL SYLLABLE PIEUP OE SIOS + 0x949C: 0xBD5C, //HANGUL SYLLABLE PIEUP OE SSANGSIOS + 0x949D: 0xBD5D, //HANGUL SYLLABLE PIEUP OE IEUNG + 0x949E: 0xBD5E, //HANGUL SYLLABLE PIEUP OE CIEUC + 0x949F: 0xBD5F, //HANGUL SYLLABLE PIEUP OE CHIEUCH + 0x94A0: 0xBD60, //HANGUL SYLLABLE PIEUP OE KHIEUKH + 0x94A1: 0xBD61, //HANGUL SYLLABLE PIEUP OE THIEUTH + 0x94A2: 0xBD62, //HANGUL SYLLABLE PIEUP OE PHIEUPH + 0x94A3: 0xBD63, //HANGUL SYLLABLE PIEUP OE HIEUH + 0x94A4: 0xBD65, //HANGUL SYLLABLE PIEUP YO KIYEOK + 0x94A5: 0xBD66, //HANGUL SYLLABLE PIEUP YO SSANGKIYEOK + 0x94A6: 0xBD67, //HANGUL SYLLABLE PIEUP YO KIYEOKSIOS + 0x94A7: 0xBD69, //HANGUL SYLLABLE PIEUP YO NIEUNCIEUC + 0x94A8: 0xBD6A, //HANGUL SYLLABLE PIEUP YO NIEUNHIEUH + 0x94A9: 0xBD6B, //HANGUL SYLLABLE PIEUP YO TIKEUT + 0x94AA: 0xBD6C, //HANGUL SYLLABLE PIEUP YO RIEUL + 0x94AB: 0xBD6D, //HANGUL SYLLABLE PIEUP YO RIEULKIYEOK + 0x94AC: 0xBD6E, //HANGUL SYLLABLE PIEUP YO RIEULMIEUM + 0x94AD: 0xBD6F, //HANGUL SYLLABLE PIEUP YO RIEULPIEUP + 0x94AE: 0xBD70, //HANGUL SYLLABLE PIEUP YO RIEULSIOS + 0x94AF: 0xBD71, //HANGUL SYLLABLE PIEUP YO RIEULTHIEUTH + 0x94B0: 0xBD72, //HANGUL SYLLABLE PIEUP YO RIEULPHIEUPH + 0x94B1: 0xBD73, //HANGUL SYLLABLE PIEUP YO RIEULHIEUH + 0x94B2: 0xBD74, //HANGUL SYLLABLE PIEUP YO MIEUM + 0x94B3: 0xBD75, //HANGUL SYLLABLE PIEUP YO PIEUP + 0x94B4: 0xBD76, //HANGUL SYLLABLE PIEUP YO PIEUPSIOS + 0x94B5: 0xBD77, //HANGUL SYLLABLE PIEUP YO SIOS + 0x94B6: 0xBD78, //HANGUL SYLLABLE PIEUP YO SSANGSIOS + 0x94B7: 0xBD79, //HANGUL SYLLABLE PIEUP YO IEUNG + 0x94B8: 0xBD7A, //HANGUL SYLLABLE PIEUP YO CIEUC + 0x94B9: 0xBD7B, //HANGUL SYLLABLE PIEUP YO CHIEUCH + 0x94BA: 0xBD7C, //HANGUL SYLLABLE PIEUP YO KHIEUKH + 0x94BB: 0xBD7D, //HANGUL SYLLABLE PIEUP YO THIEUTH + 0x94BC: 0xBD7E, //HANGUL SYLLABLE PIEUP YO PHIEUPH + 0x94BD: 0xBD7F, //HANGUL SYLLABLE PIEUP YO HIEUH + 0x94BE: 0xBD82, //HANGUL SYLLABLE PIEUP U SSANGKIYEOK + 0x94BF: 0xBD83, //HANGUL SYLLABLE PIEUP U KIYEOKSIOS + 0x94C0: 0xBD85, //HANGUL SYLLABLE PIEUP U NIEUNCIEUC + 0x94C1: 0xBD86, //HANGUL SYLLABLE PIEUP U NIEUNHIEUH + 0x94C2: 0xBD8B, //HANGUL SYLLABLE PIEUP U RIEULPIEUP + 0x94C3: 0xBD8C, //HANGUL SYLLABLE PIEUP U RIEULSIOS + 0x94C4: 0xBD8D, //HANGUL SYLLABLE PIEUP U RIEULTHIEUTH + 0x94C5: 0xBD8E, //HANGUL SYLLABLE PIEUP U RIEULPHIEUPH + 0x94C6: 0xBD8F, //HANGUL SYLLABLE PIEUP U RIEULHIEUH + 0x94C7: 0xBD92, //HANGUL SYLLABLE PIEUP U PIEUPSIOS + 0x94C8: 0xBD94, //HANGUL SYLLABLE PIEUP U SSANGSIOS + 0x94C9: 0xBD96, //HANGUL SYLLABLE PIEUP U CIEUC + 0x94CA: 0xBD97, //HANGUL SYLLABLE PIEUP U CHIEUCH + 0x94CB: 0xBD98, //HANGUL SYLLABLE PIEUP U KHIEUKH + 0x94CC: 0xBD9B, //HANGUL SYLLABLE PIEUP U HIEUH + 0x94CD: 0xBD9D, //HANGUL SYLLABLE PIEUP WEO KIYEOK + 0x94CE: 0xBD9E, //HANGUL SYLLABLE PIEUP WEO SSANGKIYEOK + 0x94CF: 0xBD9F, //HANGUL SYLLABLE PIEUP WEO KIYEOKSIOS + 0x94D0: 0xBDA0, //HANGUL SYLLABLE PIEUP WEO NIEUN + 0x94D1: 0xBDA1, //HANGUL SYLLABLE PIEUP WEO NIEUNCIEUC + 0x94D2: 0xBDA2, //HANGUL SYLLABLE PIEUP WEO NIEUNHIEUH + 0x94D3: 0xBDA3, //HANGUL SYLLABLE PIEUP WEO TIKEUT + 0x94D4: 0xBDA5, //HANGUL SYLLABLE PIEUP WEO RIEULKIYEOK + 0x94D5: 0xBDA6, //HANGUL SYLLABLE PIEUP WEO RIEULMIEUM + 0x94D6: 0xBDA7, //HANGUL SYLLABLE PIEUP WEO RIEULPIEUP + 0x94D7: 0xBDA8, //HANGUL SYLLABLE PIEUP WEO RIEULSIOS + 0x94D8: 0xBDA9, //HANGUL SYLLABLE PIEUP WEO RIEULTHIEUTH + 0x94D9: 0xBDAA, //HANGUL SYLLABLE PIEUP WEO RIEULPHIEUPH + 0x94DA: 0xBDAB, //HANGUL SYLLABLE PIEUP WEO RIEULHIEUH + 0x94DB: 0xBDAC, //HANGUL SYLLABLE PIEUP WEO MIEUM + 0x94DC: 0xBDAD, //HANGUL SYLLABLE PIEUP WEO PIEUP + 0x94DD: 0xBDAE, //HANGUL SYLLABLE PIEUP WEO PIEUPSIOS + 0x94DE: 0xBDAF, //HANGUL SYLLABLE PIEUP WEO SIOS + 0x94DF: 0xBDB1, //HANGUL SYLLABLE PIEUP WEO IEUNG + 0x94E0: 0xBDB2, //HANGUL SYLLABLE PIEUP WEO CIEUC + 0x94E1: 0xBDB3, //HANGUL SYLLABLE PIEUP WEO CHIEUCH + 0x94E2: 0xBDB4, //HANGUL SYLLABLE PIEUP WEO KHIEUKH + 0x94E3: 0xBDB5, //HANGUL SYLLABLE PIEUP WEO THIEUTH + 0x94E4: 0xBDB6, //HANGUL SYLLABLE PIEUP WEO PHIEUPH + 0x94E5: 0xBDB7, //HANGUL SYLLABLE PIEUP WEO HIEUH + 0x94E6: 0xBDB9, //HANGUL SYLLABLE PIEUP WE KIYEOK + 0x94E7: 0xBDBA, //HANGUL SYLLABLE PIEUP WE SSANGKIYEOK + 0x94E8: 0xBDBB, //HANGUL SYLLABLE PIEUP WE KIYEOKSIOS + 0x94E9: 0xBDBC, //HANGUL SYLLABLE PIEUP WE NIEUN + 0x94EA: 0xBDBD, //HANGUL SYLLABLE PIEUP WE NIEUNCIEUC + 0x94EB: 0xBDBE, //HANGUL SYLLABLE PIEUP WE NIEUNHIEUH + 0x94EC: 0xBDBF, //HANGUL SYLLABLE PIEUP WE TIKEUT + 0x94ED: 0xBDC0, //HANGUL SYLLABLE PIEUP WE RIEUL + 0x94EE: 0xBDC1, //HANGUL SYLLABLE PIEUP WE RIEULKIYEOK + 0x94EF: 0xBDC2, //HANGUL SYLLABLE PIEUP WE RIEULMIEUM + 0x94F0: 0xBDC3, //HANGUL SYLLABLE PIEUP WE RIEULPIEUP + 0x94F1: 0xBDC4, //HANGUL SYLLABLE PIEUP WE RIEULSIOS + 0x94F2: 0xBDC5, //HANGUL SYLLABLE PIEUP WE RIEULTHIEUTH + 0x94F3: 0xBDC6, //HANGUL SYLLABLE PIEUP WE RIEULPHIEUPH + 0x94F4: 0xBDC7, //HANGUL SYLLABLE PIEUP WE RIEULHIEUH + 0x94F5: 0xBDC8, //HANGUL SYLLABLE PIEUP WE MIEUM + 0x94F6: 0xBDC9, //HANGUL SYLLABLE PIEUP WE PIEUP + 0x94F7: 0xBDCA, //HANGUL SYLLABLE PIEUP WE PIEUPSIOS + 0x94F8: 0xBDCB, //HANGUL SYLLABLE PIEUP WE SIOS + 0x94F9: 0xBDCC, //HANGUL SYLLABLE PIEUP WE SSANGSIOS + 0x94FA: 0xBDCD, //HANGUL SYLLABLE PIEUP WE IEUNG + 0x94FB: 0xBDCE, //HANGUL SYLLABLE PIEUP WE CIEUC + 0x94FC: 0xBDCF, //HANGUL SYLLABLE PIEUP WE CHIEUCH + 0x94FD: 0xBDD0, //HANGUL SYLLABLE PIEUP WE KHIEUKH + 0x94FE: 0xBDD1, //HANGUL SYLLABLE PIEUP WE THIEUTH + 0x9541: 0xBDD2, //HANGUL SYLLABLE PIEUP WE PHIEUPH + 0x9542: 0xBDD3, //HANGUL SYLLABLE PIEUP WE HIEUH + 0x9543: 0xBDD6, //HANGUL SYLLABLE PIEUP WI SSANGKIYEOK + 0x9544: 0xBDD7, //HANGUL SYLLABLE PIEUP WI KIYEOKSIOS + 0x9545: 0xBDD9, //HANGUL SYLLABLE PIEUP WI NIEUNCIEUC + 0x9546: 0xBDDA, //HANGUL SYLLABLE PIEUP WI NIEUNHIEUH + 0x9547: 0xBDDB, //HANGUL SYLLABLE PIEUP WI TIKEUT + 0x9548: 0xBDDD, //HANGUL SYLLABLE PIEUP WI RIEULKIYEOK + 0x9549: 0xBDDE, //HANGUL SYLLABLE PIEUP WI RIEULMIEUM + 0x954A: 0xBDDF, //HANGUL SYLLABLE PIEUP WI RIEULPIEUP + 0x954B: 0xBDE0, //HANGUL SYLLABLE PIEUP WI RIEULSIOS + 0x954C: 0xBDE1, //HANGUL SYLLABLE PIEUP WI RIEULTHIEUTH + 0x954D: 0xBDE2, //HANGUL SYLLABLE PIEUP WI RIEULPHIEUPH + 0x954E: 0xBDE3, //HANGUL SYLLABLE PIEUP WI RIEULHIEUH + 0x954F: 0xBDE4, //HANGUL SYLLABLE PIEUP WI MIEUM + 0x9550: 0xBDE5, //HANGUL SYLLABLE PIEUP WI PIEUP + 0x9551: 0xBDE6, //HANGUL SYLLABLE PIEUP WI PIEUPSIOS + 0x9552: 0xBDE7, //HANGUL SYLLABLE PIEUP WI SIOS + 0x9553: 0xBDE8, //HANGUL SYLLABLE PIEUP WI SSANGSIOS + 0x9554: 0xBDEA, //HANGUL SYLLABLE PIEUP WI CIEUC + 0x9555: 0xBDEB, //HANGUL SYLLABLE PIEUP WI CHIEUCH + 0x9556: 0xBDEC, //HANGUL SYLLABLE PIEUP WI KHIEUKH + 0x9557: 0xBDED, //HANGUL SYLLABLE PIEUP WI THIEUTH + 0x9558: 0xBDEE, //HANGUL SYLLABLE PIEUP WI PHIEUPH + 0x9559: 0xBDEF, //HANGUL SYLLABLE PIEUP WI HIEUH + 0x955A: 0xBDF1, //HANGUL SYLLABLE PIEUP YU KIYEOK + 0x9561: 0xBDF2, //HANGUL SYLLABLE PIEUP YU SSANGKIYEOK + 0x9562: 0xBDF3, //HANGUL SYLLABLE PIEUP YU KIYEOKSIOS + 0x9563: 0xBDF5, //HANGUL SYLLABLE PIEUP YU NIEUNCIEUC + 0x9564: 0xBDF6, //HANGUL SYLLABLE PIEUP YU NIEUNHIEUH + 0x9565: 0xBDF7, //HANGUL SYLLABLE PIEUP YU TIKEUT + 0x9566: 0xBDF9, //HANGUL SYLLABLE PIEUP YU RIEULKIYEOK + 0x9567: 0xBDFA, //HANGUL SYLLABLE PIEUP YU RIEULMIEUM + 0x9568: 0xBDFB, //HANGUL SYLLABLE PIEUP YU RIEULPIEUP + 0x9569: 0xBDFC, //HANGUL SYLLABLE PIEUP YU RIEULSIOS + 0x956A: 0xBDFD, //HANGUL SYLLABLE PIEUP YU RIEULTHIEUTH + 0x956B: 0xBDFE, //HANGUL SYLLABLE PIEUP YU RIEULPHIEUPH + 0x956C: 0xBDFF, //HANGUL SYLLABLE PIEUP YU RIEULHIEUH + 0x956D: 0xBE01, //HANGUL SYLLABLE PIEUP YU PIEUP + 0x956E: 0xBE02, //HANGUL SYLLABLE PIEUP YU PIEUPSIOS + 0x956F: 0xBE04, //HANGUL SYLLABLE PIEUP YU SSANGSIOS + 0x9570: 0xBE06, //HANGUL SYLLABLE PIEUP YU CIEUC + 0x9571: 0xBE07, //HANGUL SYLLABLE PIEUP YU CHIEUCH + 0x9572: 0xBE08, //HANGUL SYLLABLE PIEUP YU KHIEUKH + 0x9573: 0xBE09, //HANGUL SYLLABLE PIEUP YU THIEUTH + 0x9574: 0xBE0A, //HANGUL SYLLABLE PIEUP YU PHIEUPH + 0x9575: 0xBE0B, //HANGUL SYLLABLE PIEUP YU HIEUH + 0x9576: 0xBE0E, //HANGUL SYLLABLE PIEUP EU SSANGKIYEOK + 0x9577: 0xBE0F, //HANGUL SYLLABLE PIEUP EU KIYEOKSIOS + 0x9578: 0xBE11, //HANGUL SYLLABLE PIEUP EU NIEUNCIEUC + 0x9579: 0xBE12, //HANGUL SYLLABLE PIEUP EU NIEUNHIEUH + 0x957A: 0xBE13, //HANGUL SYLLABLE PIEUP EU TIKEUT + 0x9581: 0xBE15, //HANGUL SYLLABLE PIEUP EU RIEULKIYEOK + 0x9582: 0xBE16, //HANGUL SYLLABLE PIEUP EU RIEULMIEUM + 0x9583: 0xBE17, //HANGUL SYLLABLE PIEUP EU RIEULPIEUP + 0x9584: 0xBE18, //HANGUL SYLLABLE PIEUP EU RIEULSIOS + 0x9585: 0xBE19, //HANGUL SYLLABLE PIEUP EU RIEULTHIEUTH + 0x9586: 0xBE1A, //HANGUL SYLLABLE PIEUP EU RIEULPHIEUPH + 0x9587: 0xBE1B, //HANGUL SYLLABLE PIEUP EU RIEULHIEUH + 0x9588: 0xBE1E, //HANGUL SYLLABLE PIEUP EU PIEUPSIOS + 0x9589: 0xBE20, //HANGUL SYLLABLE PIEUP EU SSANGSIOS + 0x958A: 0xBE21, //HANGUL SYLLABLE PIEUP EU IEUNG + 0x958B: 0xBE22, //HANGUL SYLLABLE PIEUP EU CIEUC + 0x958C: 0xBE23, //HANGUL SYLLABLE PIEUP EU CHIEUCH + 0x958D: 0xBE24, //HANGUL SYLLABLE PIEUP EU KHIEUKH + 0x958E: 0xBE25, //HANGUL SYLLABLE PIEUP EU THIEUTH + 0x958F: 0xBE26, //HANGUL SYLLABLE PIEUP EU PHIEUPH + 0x9590: 0xBE27, //HANGUL SYLLABLE PIEUP EU HIEUH + 0x9591: 0xBE28, //HANGUL SYLLABLE PIEUP YI + 0x9592: 0xBE29, //HANGUL SYLLABLE PIEUP YI KIYEOK + 0x9593: 0xBE2A, //HANGUL SYLLABLE PIEUP YI SSANGKIYEOK + 0x9594: 0xBE2B, //HANGUL SYLLABLE PIEUP YI KIYEOKSIOS + 0x9595: 0xBE2C, //HANGUL SYLLABLE PIEUP YI NIEUN + 0x9596: 0xBE2D, //HANGUL SYLLABLE PIEUP YI NIEUNCIEUC + 0x9597: 0xBE2E, //HANGUL SYLLABLE PIEUP YI NIEUNHIEUH + 0x9598: 0xBE2F, //HANGUL SYLLABLE PIEUP YI TIKEUT + 0x9599: 0xBE30, //HANGUL SYLLABLE PIEUP YI RIEUL + 0x959A: 0xBE31, //HANGUL SYLLABLE PIEUP YI RIEULKIYEOK + 0x959B: 0xBE32, //HANGUL SYLLABLE PIEUP YI RIEULMIEUM + 0x959C: 0xBE33, //HANGUL SYLLABLE PIEUP YI RIEULPIEUP + 0x959D: 0xBE34, //HANGUL SYLLABLE PIEUP YI RIEULSIOS + 0x959E: 0xBE35, //HANGUL SYLLABLE PIEUP YI RIEULTHIEUTH + 0x959F: 0xBE36, //HANGUL SYLLABLE PIEUP YI RIEULPHIEUPH + 0x95A0: 0xBE37, //HANGUL SYLLABLE PIEUP YI RIEULHIEUH + 0x95A1: 0xBE38, //HANGUL SYLLABLE PIEUP YI MIEUM + 0x95A2: 0xBE39, //HANGUL SYLLABLE PIEUP YI PIEUP + 0x95A3: 0xBE3A, //HANGUL SYLLABLE PIEUP YI PIEUPSIOS + 0x95A4: 0xBE3B, //HANGUL SYLLABLE PIEUP YI SIOS + 0x95A5: 0xBE3C, //HANGUL SYLLABLE PIEUP YI SSANGSIOS + 0x95A6: 0xBE3D, //HANGUL SYLLABLE PIEUP YI IEUNG + 0x95A7: 0xBE3E, //HANGUL SYLLABLE PIEUP YI CIEUC + 0x95A8: 0xBE3F, //HANGUL SYLLABLE PIEUP YI CHIEUCH + 0x95A9: 0xBE40, //HANGUL SYLLABLE PIEUP YI KHIEUKH + 0x95AA: 0xBE41, //HANGUL SYLLABLE PIEUP YI THIEUTH + 0x95AB: 0xBE42, //HANGUL SYLLABLE PIEUP YI PHIEUPH + 0x95AC: 0xBE43, //HANGUL SYLLABLE PIEUP YI HIEUH + 0x95AD: 0xBE46, //HANGUL SYLLABLE PIEUP I SSANGKIYEOK + 0x95AE: 0xBE47, //HANGUL SYLLABLE PIEUP I KIYEOKSIOS + 0x95AF: 0xBE49, //HANGUL SYLLABLE PIEUP I NIEUNCIEUC + 0x95B0: 0xBE4A, //HANGUL SYLLABLE PIEUP I NIEUNHIEUH + 0x95B1: 0xBE4B, //HANGUL SYLLABLE PIEUP I TIKEUT + 0x95B2: 0xBE4D, //HANGUL SYLLABLE PIEUP I RIEULKIYEOK + 0x95B3: 0xBE4F, //HANGUL SYLLABLE PIEUP I RIEULPIEUP + 0x95B4: 0xBE50, //HANGUL SYLLABLE PIEUP I RIEULSIOS + 0x95B5: 0xBE51, //HANGUL SYLLABLE PIEUP I RIEULTHIEUTH + 0x95B6: 0xBE52, //HANGUL SYLLABLE PIEUP I RIEULPHIEUPH + 0x95B7: 0xBE53, //HANGUL SYLLABLE PIEUP I RIEULHIEUH + 0x95B8: 0xBE56, //HANGUL SYLLABLE PIEUP I PIEUPSIOS + 0x95B9: 0xBE58, //HANGUL SYLLABLE PIEUP I SSANGSIOS + 0x95BA: 0xBE5C, //HANGUL SYLLABLE PIEUP I KHIEUKH + 0x95BB: 0xBE5D, //HANGUL SYLLABLE PIEUP I THIEUTH + 0x95BC: 0xBE5E, //HANGUL SYLLABLE PIEUP I PHIEUPH + 0x95BD: 0xBE5F, //HANGUL SYLLABLE PIEUP I HIEUH + 0x95BE: 0xBE62, //HANGUL SYLLABLE SSANGPIEUP A SSANGKIYEOK + 0x95BF: 0xBE63, //HANGUL SYLLABLE SSANGPIEUP A KIYEOKSIOS + 0x95C0: 0xBE65, //HANGUL SYLLABLE SSANGPIEUP A NIEUNCIEUC + 0x95C1: 0xBE66, //HANGUL SYLLABLE SSANGPIEUP A NIEUNHIEUH + 0x95C2: 0xBE67, //HANGUL SYLLABLE SSANGPIEUP A TIKEUT + 0x95C3: 0xBE69, //HANGUL SYLLABLE SSANGPIEUP A RIEULKIYEOK + 0x95C4: 0xBE6B, //HANGUL SYLLABLE SSANGPIEUP A RIEULPIEUP + 0x95C5: 0xBE6C, //HANGUL SYLLABLE SSANGPIEUP A RIEULSIOS + 0x95C6: 0xBE6D, //HANGUL SYLLABLE SSANGPIEUP A RIEULTHIEUTH + 0x95C7: 0xBE6E, //HANGUL SYLLABLE SSANGPIEUP A RIEULPHIEUPH + 0x95C8: 0xBE6F, //HANGUL SYLLABLE SSANGPIEUP A RIEULHIEUH + 0x95C9: 0xBE72, //HANGUL SYLLABLE SSANGPIEUP A PIEUPSIOS + 0x95CA: 0xBE76, //HANGUL SYLLABLE SSANGPIEUP A CIEUC + 0x95CB: 0xBE77, //HANGUL SYLLABLE SSANGPIEUP A CHIEUCH + 0x95CC: 0xBE78, //HANGUL SYLLABLE SSANGPIEUP A KHIEUKH + 0x95CD: 0xBE79, //HANGUL SYLLABLE SSANGPIEUP A THIEUTH + 0x95CE: 0xBE7A, //HANGUL SYLLABLE SSANGPIEUP A PHIEUPH + 0x95CF: 0xBE7E, //HANGUL SYLLABLE SSANGPIEUP AE SSANGKIYEOK + 0x95D0: 0xBE7F, //HANGUL SYLLABLE SSANGPIEUP AE KIYEOKSIOS + 0x95D1: 0xBE81, //HANGUL SYLLABLE SSANGPIEUP AE NIEUNCIEUC + 0x95D2: 0xBE82, //HANGUL SYLLABLE SSANGPIEUP AE NIEUNHIEUH + 0x95D3: 0xBE83, //HANGUL SYLLABLE SSANGPIEUP AE TIKEUT + 0x95D4: 0xBE85, //HANGUL SYLLABLE SSANGPIEUP AE RIEULKIYEOK + 0x95D5: 0xBE86, //HANGUL SYLLABLE SSANGPIEUP AE RIEULMIEUM + 0x95D6: 0xBE87, //HANGUL SYLLABLE SSANGPIEUP AE RIEULPIEUP + 0x95D7: 0xBE88, //HANGUL SYLLABLE SSANGPIEUP AE RIEULSIOS + 0x95D8: 0xBE89, //HANGUL SYLLABLE SSANGPIEUP AE RIEULTHIEUTH + 0x95D9: 0xBE8A, //HANGUL SYLLABLE SSANGPIEUP AE RIEULPHIEUPH + 0x95DA: 0xBE8B, //HANGUL SYLLABLE SSANGPIEUP AE RIEULHIEUH + 0x95DB: 0xBE8E, //HANGUL SYLLABLE SSANGPIEUP AE PIEUPSIOS + 0x95DC: 0xBE92, //HANGUL SYLLABLE SSANGPIEUP AE CIEUC + 0x95DD: 0xBE93, //HANGUL SYLLABLE SSANGPIEUP AE CHIEUCH + 0x95DE: 0xBE94, //HANGUL SYLLABLE SSANGPIEUP AE KHIEUKH + 0x95DF: 0xBE95, //HANGUL SYLLABLE SSANGPIEUP AE THIEUTH + 0x95E0: 0xBE96, //HANGUL SYLLABLE SSANGPIEUP AE PHIEUPH + 0x95E1: 0xBE97, //HANGUL SYLLABLE SSANGPIEUP AE HIEUH + 0x95E2: 0xBE9A, //HANGUL SYLLABLE SSANGPIEUP YA SSANGKIYEOK + 0x95E3: 0xBE9B, //HANGUL SYLLABLE SSANGPIEUP YA KIYEOKSIOS + 0x95E4: 0xBE9C, //HANGUL SYLLABLE SSANGPIEUP YA NIEUN + 0x95E5: 0xBE9D, //HANGUL SYLLABLE SSANGPIEUP YA NIEUNCIEUC + 0x95E6: 0xBE9E, //HANGUL SYLLABLE SSANGPIEUP YA NIEUNHIEUH + 0x95E7: 0xBE9F, //HANGUL SYLLABLE SSANGPIEUP YA TIKEUT + 0x95E8: 0xBEA0, //HANGUL SYLLABLE SSANGPIEUP YA RIEUL + 0x95E9: 0xBEA1, //HANGUL SYLLABLE SSANGPIEUP YA RIEULKIYEOK + 0x95EA: 0xBEA2, //HANGUL SYLLABLE SSANGPIEUP YA RIEULMIEUM + 0x95EB: 0xBEA3, //HANGUL SYLLABLE SSANGPIEUP YA RIEULPIEUP + 0x95EC: 0xBEA4, //HANGUL SYLLABLE SSANGPIEUP YA RIEULSIOS + 0x95ED: 0xBEA5, //HANGUL SYLLABLE SSANGPIEUP YA RIEULTHIEUTH + 0x95EE: 0xBEA6, //HANGUL SYLLABLE SSANGPIEUP YA RIEULPHIEUPH + 0x95EF: 0xBEA7, //HANGUL SYLLABLE SSANGPIEUP YA RIEULHIEUH + 0x95F0: 0xBEA9, //HANGUL SYLLABLE SSANGPIEUP YA PIEUP + 0x95F1: 0xBEAA, //HANGUL SYLLABLE SSANGPIEUP YA PIEUPSIOS + 0x95F2: 0xBEAB, //HANGUL SYLLABLE SSANGPIEUP YA SIOS + 0x95F3: 0xBEAC, //HANGUL SYLLABLE SSANGPIEUP YA SSANGSIOS + 0x95F4: 0xBEAD, //HANGUL SYLLABLE SSANGPIEUP YA IEUNG + 0x95F5: 0xBEAE, //HANGUL SYLLABLE SSANGPIEUP YA CIEUC + 0x95F6: 0xBEAF, //HANGUL SYLLABLE SSANGPIEUP YA CHIEUCH + 0x95F7: 0xBEB0, //HANGUL SYLLABLE SSANGPIEUP YA KHIEUKH + 0x95F8: 0xBEB1, //HANGUL SYLLABLE SSANGPIEUP YA THIEUTH + 0x95F9: 0xBEB2, //HANGUL SYLLABLE SSANGPIEUP YA PHIEUPH + 0x95FA: 0xBEB3, //HANGUL SYLLABLE SSANGPIEUP YA HIEUH + 0x95FB: 0xBEB4, //HANGUL SYLLABLE SSANGPIEUP YAE + 0x95FC: 0xBEB5, //HANGUL SYLLABLE SSANGPIEUP YAE KIYEOK + 0x95FD: 0xBEB6, //HANGUL SYLLABLE SSANGPIEUP YAE SSANGKIYEOK + 0x95FE: 0xBEB7, //HANGUL SYLLABLE SSANGPIEUP YAE KIYEOKSIOS + 0x9641: 0xBEB8, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUN + 0x9642: 0xBEB9, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUNCIEUC + 0x9643: 0xBEBA, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUNHIEUH + 0x9644: 0xBEBB, //HANGUL SYLLABLE SSANGPIEUP YAE TIKEUT + 0x9645: 0xBEBC, //HANGUL SYLLABLE SSANGPIEUP YAE RIEUL + 0x9646: 0xBEBD, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULKIYEOK + 0x9647: 0xBEBE, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULMIEUM + 0x9648: 0xBEBF, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULPIEUP + 0x9649: 0xBEC0, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULSIOS + 0x964A: 0xBEC1, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULTHIEUTH + 0x964B: 0xBEC2, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULPHIEUPH + 0x964C: 0xBEC3, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULHIEUH + 0x964D: 0xBEC4, //HANGUL SYLLABLE SSANGPIEUP YAE MIEUM + 0x964E: 0xBEC5, //HANGUL SYLLABLE SSANGPIEUP YAE PIEUP + 0x964F: 0xBEC6, //HANGUL SYLLABLE SSANGPIEUP YAE PIEUPSIOS + 0x9650: 0xBEC7, //HANGUL SYLLABLE SSANGPIEUP YAE SIOS + 0x9651: 0xBEC8, //HANGUL SYLLABLE SSANGPIEUP YAE SSANGSIOS + 0x9652: 0xBEC9, //HANGUL SYLLABLE SSANGPIEUP YAE IEUNG + 0x9653: 0xBECA, //HANGUL SYLLABLE SSANGPIEUP YAE CIEUC + 0x9654: 0xBECB, //HANGUL SYLLABLE SSANGPIEUP YAE CHIEUCH + 0x9655: 0xBECC, //HANGUL SYLLABLE SSANGPIEUP YAE KHIEUKH + 0x9656: 0xBECD, //HANGUL SYLLABLE SSANGPIEUP YAE THIEUTH + 0x9657: 0xBECE, //HANGUL SYLLABLE SSANGPIEUP YAE PHIEUPH + 0x9658: 0xBECF, //HANGUL SYLLABLE SSANGPIEUP YAE HIEUH + 0x9659: 0xBED2, //HANGUL SYLLABLE SSANGPIEUP EO SSANGKIYEOK + 0x965A: 0xBED3, //HANGUL SYLLABLE SSANGPIEUP EO KIYEOKSIOS + 0x9661: 0xBED5, //HANGUL SYLLABLE SSANGPIEUP EO NIEUNCIEUC + 0x9662: 0xBED6, //HANGUL SYLLABLE SSANGPIEUP EO NIEUNHIEUH + 0x9663: 0xBED9, //HANGUL SYLLABLE SSANGPIEUP EO RIEULKIYEOK + 0x9664: 0xBEDA, //HANGUL SYLLABLE SSANGPIEUP EO RIEULMIEUM + 0x9665: 0xBEDB, //HANGUL SYLLABLE SSANGPIEUP EO RIEULPIEUP + 0x9666: 0xBEDC, //HANGUL SYLLABLE SSANGPIEUP EO RIEULSIOS + 0x9667: 0xBEDD, //HANGUL SYLLABLE SSANGPIEUP EO RIEULTHIEUTH + 0x9668: 0xBEDE, //HANGUL SYLLABLE SSANGPIEUP EO RIEULPHIEUPH + 0x9669: 0xBEDF, //HANGUL SYLLABLE SSANGPIEUP EO RIEULHIEUH + 0x966A: 0xBEE1, //HANGUL SYLLABLE SSANGPIEUP EO PIEUP + 0x966B: 0xBEE2, //HANGUL SYLLABLE SSANGPIEUP EO PIEUPSIOS + 0x966C: 0xBEE6, //HANGUL SYLLABLE SSANGPIEUP EO CIEUC + 0x966D: 0xBEE7, //HANGUL SYLLABLE SSANGPIEUP EO CHIEUCH + 0x966E: 0xBEE8, //HANGUL SYLLABLE SSANGPIEUP EO KHIEUKH + 0x966F: 0xBEE9, //HANGUL SYLLABLE SSANGPIEUP EO THIEUTH + 0x9670: 0xBEEA, //HANGUL SYLLABLE SSANGPIEUP EO PHIEUPH + 0x9671: 0xBEEB, //HANGUL SYLLABLE SSANGPIEUP EO HIEUH + 0x9672: 0xBEED, //HANGUL SYLLABLE SSANGPIEUP E KIYEOK + 0x9673: 0xBEEE, //HANGUL SYLLABLE SSANGPIEUP E SSANGKIYEOK + 0x9674: 0xBEEF, //HANGUL SYLLABLE SSANGPIEUP E KIYEOKSIOS + 0x9675: 0xBEF0, //HANGUL SYLLABLE SSANGPIEUP E NIEUN + 0x9676: 0xBEF1, //HANGUL SYLLABLE SSANGPIEUP E NIEUNCIEUC + 0x9677: 0xBEF2, //HANGUL SYLLABLE SSANGPIEUP E NIEUNHIEUH + 0x9678: 0xBEF3, //HANGUL SYLLABLE SSANGPIEUP E TIKEUT + 0x9679: 0xBEF4, //HANGUL SYLLABLE SSANGPIEUP E RIEUL + 0x967A: 0xBEF5, //HANGUL SYLLABLE SSANGPIEUP E RIEULKIYEOK + 0x9681: 0xBEF6, //HANGUL SYLLABLE SSANGPIEUP E RIEULMIEUM + 0x9682: 0xBEF7, //HANGUL SYLLABLE SSANGPIEUP E RIEULPIEUP + 0x9683: 0xBEF8, //HANGUL SYLLABLE SSANGPIEUP E RIEULSIOS + 0x9684: 0xBEF9, //HANGUL SYLLABLE SSANGPIEUP E RIEULTHIEUTH + 0x9685: 0xBEFA, //HANGUL SYLLABLE SSANGPIEUP E RIEULPHIEUPH + 0x9686: 0xBEFB, //HANGUL SYLLABLE SSANGPIEUP E RIEULHIEUH + 0x9687: 0xBEFC, //HANGUL SYLLABLE SSANGPIEUP E MIEUM + 0x9688: 0xBEFD, //HANGUL SYLLABLE SSANGPIEUP E PIEUP + 0x9689: 0xBEFE, //HANGUL SYLLABLE SSANGPIEUP E PIEUPSIOS + 0x968A: 0xBEFF, //HANGUL SYLLABLE SSANGPIEUP E SIOS + 0x968B: 0xBF00, //HANGUL SYLLABLE SSANGPIEUP E SSANGSIOS + 0x968C: 0xBF02, //HANGUL SYLLABLE SSANGPIEUP E CIEUC + 0x968D: 0xBF03, //HANGUL SYLLABLE SSANGPIEUP E CHIEUCH + 0x968E: 0xBF04, //HANGUL SYLLABLE SSANGPIEUP E KHIEUKH + 0x968F: 0xBF05, //HANGUL SYLLABLE SSANGPIEUP E THIEUTH + 0x9690: 0xBF06, //HANGUL SYLLABLE SSANGPIEUP E PHIEUPH + 0x9691: 0xBF07, //HANGUL SYLLABLE SSANGPIEUP E HIEUH + 0x9692: 0xBF0A, //HANGUL SYLLABLE SSANGPIEUP YEO SSANGKIYEOK + 0x9693: 0xBF0B, //HANGUL SYLLABLE SSANGPIEUP YEO KIYEOKSIOS + 0x9694: 0xBF0C, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUN + 0x9695: 0xBF0D, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUNCIEUC + 0x9696: 0xBF0E, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUNHIEUH + 0x9697: 0xBF0F, //HANGUL SYLLABLE SSANGPIEUP YEO TIKEUT + 0x9698: 0xBF10, //HANGUL SYLLABLE SSANGPIEUP YEO RIEUL + 0x9699: 0xBF11, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULKIYEOK + 0x969A: 0xBF12, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULMIEUM + 0x969B: 0xBF13, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULPIEUP + 0x969C: 0xBF14, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULSIOS + 0x969D: 0xBF15, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULTHIEUTH + 0x969E: 0xBF16, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULPHIEUPH + 0x969F: 0xBF17, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULHIEUH + 0x96A0: 0xBF1A, //HANGUL SYLLABLE SSANGPIEUP YEO PIEUPSIOS + 0x96A1: 0xBF1E, //HANGUL SYLLABLE SSANGPIEUP YEO CIEUC + 0x96A2: 0xBF1F, //HANGUL SYLLABLE SSANGPIEUP YEO CHIEUCH + 0x96A3: 0xBF20, //HANGUL SYLLABLE SSANGPIEUP YEO KHIEUKH + 0x96A4: 0xBF21, //HANGUL SYLLABLE SSANGPIEUP YEO THIEUTH + 0x96A5: 0xBF22, //HANGUL SYLLABLE SSANGPIEUP YEO PHIEUPH + 0x96A6: 0xBF23, //HANGUL SYLLABLE SSANGPIEUP YEO HIEUH + 0x96A7: 0xBF24, //HANGUL SYLLABLE SSANGPIEUP YE + 0x96A8: 0xBF25, //HANGUL SYLLABLE SSANGPIEUP YE KIYEOK + 0x96A9: 0xBF26, //HANGUL SYLLABLE SSANGPIEUP YE SSANGKIYEOK + 0x96AA: 0xBF27, //HANGUL SYLLABLE SSANGPIEUP YE KIYEOKSIOS + 0x96AB: 0xBF28, //HANGUL SYLLABLE SSANGPIEUP YE NIEUN + 0x96AC: 0xBF29, //HANGUL SYLLABLE SSANGPIEUP YE NIEUNCIEUC + 0x96AD: 0xBF2A, //HANGUL SYLLABLE SSANGPIEUP YE NIEUNHIEUH + 0x96AE: 0xBF2B, //HANGUL SYLLABLE SSANGPIEUP YE TIKEUT + 0x96AF: 0xBF2C, //HANGUL SYLLABLE SSANGPIEUP YE RIEUL + 0x96B0: 0xBF2D, //HANGUL SYLLABLE SSANGPIEUP YE RIEULKIYEOK + 0x96B1: 0xBF2E, //HANGUL SYLLABLE SSANGPIEUP YE RIEULMIEUM + 0x96B2: 0xBF2F, //HANGUL SYLLABLE SSANGPIEUP YE RIEULPIEUP + 0x96B3: 0xBF30, //HANGUL SYLLABLE SSANGPIEUP YE RIEULSIOS + 0x96B4: 0xBF31, //HANGUL SYLLABLE SSANGPIEUP YE RIEULTHIEUTH + 0x96B5: 0xBF32, //HANGUL SYLLABLE SSANGPIEUP YE RIEULPHIEUPH + 0x96B6: 0xBF33, //HANGUL SYLLABLE SSANGPIEUP YE RIEULHIEUH + 0x96B7: 0xBF34, //HANGUL SYLLABLE SSANGPIEUP YE MIEUM + 0x96B8: 0xBF35, //HANGUL SYLLABLE SSANGPIEUP YE PIEUP + 0x96B9: 0xBF36, //HANGUL SYLLABLE SSANGPIEUP YE PIEUPSIOS + 0x96BA: 0xBF37, //HANGUL SYLLABLE SSANGPIEUP YE SIOS + 0x96BB: 0xBF38, //HANGUL SYLLABLE SSANGPIEUP YE SSANGSIOS + 0x96BC: 0xBF39, //HANGUL SYLLABLE SSANGPIEUP YE IEUNG + 0x96BD: 0xBF3A, //HANGUL SYLLABLE SSANGPIEUP YE CIEUC + 0x96BE: 0xBF3B, //HANGUL SYLLABLE SSANGPIEUP YE CHIEUCH + 0x96BF: 0xBF3C, //HANGUL SYLLABLE SSANGPIEUP YE KHIEUKH + 0x96C0: 0xBF3D, //HANGUL SYLLABLE SSANGPIEUP YE THIEUTH + 0x96C1: 0xBF3E, //HANGUL SYLLABLE SSANGPIEUP YE PHIEUPH + 0x96C2: 0xBF3F, //HANGUL SYLLABLE SSANGPIEUP YE HIEUH + 0x96C3: 0xBF42, //HANGUL SYLLABLE SSANGPIEUP O SSANGKIYEOK + 0x96C4: 0xBF43, //HANGUL SYLLABLE SSANGPIEUP O KIYEOKSIOS + 0x96C5: 0xBF45, //HANGUL SYLLABLE SSANGPIEUP O NIEUNCIEUC + 0x96C6: 0xBF46, //HANGUL SYLLABLE SSANGPIEUP O NIEUNHIEUH + 0x96C7: 0xBF47, //HANGUL SYLLABLE SSANGPIEUP O TIKEUT + 0x96C8: 0xBF49, //HANGUL SYLLABLE SSANGPIEUP O RIEULKIYEOK + 0x96C9: 0xBF4A, //HANGUL SYLLABLE SSANGPIEUP O RIEULMIEUM + 0x96CA: 0xBF4B, //HANGUL SYLLABLE SSANGPIEUP O RIEULPIEUP + 0x96CB: 0xBF4C, //HANGUL SYLLABLE SSANGPIEUP O RIEULSIOS + 0x96CC: 0xBF4D, //HANGUL SYLLABLE SSANGPIEUP O RIEULTHIEUTH + 0x96CD: 0xBF4E, //HANGUL SYLLABLE SSANGPIEUP O RIEULPHIEUPH + 0x96CE: 0xBF4F, //HANGUL SYLLABLE SSANGPIEUP O RIEULHIEUH + 0x96CF: 0xBF52, //HANGUL SYLLABLE SSANGPIEUP O PIEUPSIOS + 0x96D0: 0xBF53, //HANGUL SYLLABLE SSANGPIEUP O SIOS + 0x96D1: 0xBF54, //HANGUL SYLLABLE SSANGPIEUP O SSANGSIOS + 0x96D2: 0xBF56, //HANGUL SYLLABLE SSANGPIEUP O CIEUC + 0x96D3: 0xBF57, //HANGUL SYLLABLE SSANGPIEUP O CHIEUCH + 0x96D4: 0xBF58, //HANGUL SYLLABLE SSANGPIEUP O KHIEUKH + 0x96D5: 0xBF59, //HANGUL SYLLABLE SSANGPIEUP O THIEUTH + 0x96D6: 0xBF5A, //HANGUL SYLLABLE SSANGPIEUP O PHIEUPH + 0x96D7: 0xBF5B, //HANGUL SYLLABLE SSANGPIEUP O HIEUH + 0x96D8: 0xBF5C, //HANGUL SYLLABLE SSANGPIEUP WA + 0x96D9: 0xBF5D, //HANGUL SYLLABLE SSANGPIEUP WA KIYEOK + 0x96DA: 0xBF5E, //HANGUL SYLLABLE SSANGPIEUP WA SSANGKIYEOK + 0x96DB: 0xBF5F, //HANGUL SYLLABLE SSANGPIEUP WA KIYEOKSIOS + 0x96DC: 0xBF60, //HANGUL SYLLABLE SSANGPIEUP WA NIEUN + 0x96DD: 0xBF61, //HANGUL SYLLABLE SSANGPIEUP WA NIEUNCIEUC + 0x96DE: 0xBF62, //HANGUL SYLLABLE SSANGPIEUP WA NIEUNHIEUH + 0x96DF: 0xBF63, //HANGUL SYLLABLE SSANGPIEUP WA TIKEUT + 0x96E0: 0xBF64, //HANGUL SYLLABLE SSANGPIEUP WA RIEUL + 0x96E1: 0xBF65, //HANGUL SYLLABLE SSANGPIEUP WA RIEULKIYEOK + 0x96E2: 0xBF66, //HANGUL SYLLABLE SSANGPIEUP WA RIEULMIEUM + 0x96E3: 0xBF67, //HANGUL SYLLABLE SSANGPIEUP WA RIEULPIEUP + 0x96E4: 0xBF68, //HANGUL SYLLABLE SSANGPIEUP WA RIEULSIOS + 0x96E5: 0xBF69, //HANGUL SYLLABLE SSANGPIEUP WA RIEULTHIEUTH + 0x96E6: 0xBF6A, //HANGUL SYLLABLE SSANGPIEUP WA RIEULPHIEUPH + 0x96E7: 0xBF6B, //HANGUL SYLLABLE SSANGPIEUP WA RIEULHIEUH + 0x96E8: 0xBF6C, //HANGUL SYLLABLE SSANGPIEUP WA MIEUM + 0x96E9: 0xBF6D, //HANGUL SYLLABLE SSANGPIEUP WA PIEUP + 0x96EA: 0xBF6E, //HANGUL SYLLABLE SSANGPIEUP WA PIEUPSIOS + 0x96EB: 0xBF6F, //HANGUL SYLLABLE SSANGPIEUP WA SIOS + 0x96EC: 0xBF70, //HANGUL SYLLABLE SSANGPIEUP WA SSANGSIOS + 0x96ED: 0xBF71, //HANGUL SYLLABLE SSANGPIEUP WA IEUNG + 0x96EE: 0xBF72, //HANGUL SYLLABLE SSANGPIEUP WA CIEUC + 0x96EF: 0xBF73, //HANGUL SYLLABLE SSANGPIEUP WA CHIEUCH + 0x96F0: 0xBF74, //HANGUL SYLLABLE SSANGPIEUP WA KHIEUKH + 0x96F1: 0xBF75, //HANGUL SYLLABLE SSANGPIEUP WA THIEUTH + 0x96F2: 0xBF76, //HANGUL SYLLABLE SSANGPIEUP WA PHIEUPH + 0x96F3: 0xBF77, //HANGUL SYLLABLE SSANGPIEUP WA HIEUH + 0x96F4: 0xBF78, //HANGUL SYLLABLE SSANGPIEUP WAE + 0x96F5: 0xBF79, //HANGUL SYLLABLE SSANGPIEUP WAE KIYEOK + 0x96F6: 0xBF7A, //HANGUL SYLLABLE SSANGPIEUP WAE SSANGKIYEOK + 0x96F7: 0xBF7B, //HANGUL SYLLABLE SSANGPIEUP WAE KIYEOKSIOS + 0x96F8: 0xBF7C, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUN + 0x96F9: 0xBF7D, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUNCIEUC + 0x96FA: 0xBF7E, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUNHIEUH + 0x96FB: 0xBF7F, //HANGUL SYLLABLE SSANGPIEUP WAE TIKEUT + 0x96FC: 0xBF80, //HANGUL SYLLABLE SSANGPIEUP WAE RIEUL + 0x96FD: 0xBF81, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULKIYEOK + 0x96FE: 0xBF82, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULMIEUM + 0x9741: 0xBF83, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULPIEUP + 0x9742: 0xBF84, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULSIOS + 0x9743: 0xBF85, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULTHIEUTH + 0x9744: 0xBF86, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULPHIEUPH + 0x9745: 0xBF87, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULHIEUH + 0x9746: 0xBF88, //HANGUL SYLLABLE SSANGPIEUP WAE MIEUM + 0x9747: 0xBF89, //HANGUL SYLLABLE SSANGPIEUP WAE PIEUP + 0x9748: 0xBF8A, //HANGUL SYLLABLE SSANGPIEUP WAE PIEUPSIOS + 0x9749: 0xBF8B, //HANGUL SYLLABLE SSANGPIEUP WAE SIOS + 0x974A: 0xBF8C, //HANGUL SYLLABLE SSANGPIEUP WAE SSANGSIOS + 0x974B: 0xBF8D, //HANGUL SYLLABLE SSANGPIEUP WAE IEUNG + 0x974C: 0xBF8E, //HANGUL SYLLABLE SSANGPIEUP WAE CIEUC + 0x974D: 0xBF8F, //HANGUL SYLLABLE SSANGPIEUP WAE CHIEUCH + 0x974E: 0xBF90, //HANGUL SYLLABLE SSANGPIEUP WAE KHIEUKH + 0x974F: 0xBF91, //HANGUL SYLLABLE SSANGPIEUP WAE THIEUTH + 0x9750: 0xBF92, //HANGUL SYLLABLE SSANGPIEUP WAE PHIEUPH + 0x9751: 0xBF93, //HANGUL SYLLABLE SSANGPIEUP WAE HIEUH + 0x9752: 0xBF95, //HANGUL SYLLABLE SSANGPIEUP OE KIYEOK + 0x9753: 0xBF96, //HANGUL SYLLABLE SSANGPIEUP OE SSANGKIYEOK + 0x9754: 0xBF97, //HANGUL SYLLABLE SSANGPIEUP OE KIYEOKSIOS + 0x9755: 0xBF98, //HANGUL SYLLABLE SSANGPIEUP OE NIEUN + 0x9756: 0xBF99, //HANGUL SYLLABLE SSANGPIEUP OE NIEUNCIEUC + 0x9757: 0xBF9A, //HANGUL SYLLABLE SSANGPIEUP OE NIEUNHIEUH + 0x9758: 0xBF9B, //HANGUL SYLLABLE SSANGPIEUP OE TIKEUT + 0x9759: 0xBF9C, //HANGUL SYLLABLE SSANGPIEUP OE RIEUL + 0x975A: 0xBF9D, //HANGUL SYLLABLE SSANGPIEUP OE RIEULKIYEOK + 0x9761: 0xBF9E, //HANGUL SYLLABLE SSANGPIEUP OE RIEULMIEUM + 0x9762: 0xBF9F, //HANGUL SYLLABLE SSANGPIEUP OE RIEULPIEUP + 0x9763: 0xBFA0, //HANGUL SYLLABLE SSANGPIEUP OE RIEULSIOS + 0x9764: 0xBFA1, //HANGUL SYLLABLE SSANGPIEUP OE RIEULTHIEUTH + 0x9765: 0xBFA2, //HANGUL SYLLABLE SSANGPIEUP OE RIEULPHIEUPH + 0x9766: 0xBFA3, //HANGUL SYLLABLE SSANGPIEUP OE RIEULHIEUH + 0x9767: 0xBFA4, //HANGUL SYLLABLE SSANGPIEUP OE MIEUM + 0x9768: 0xBFA5, //HANGUL SYLLABLE SSANGPIEUP OE PIEUP + 0x9769: 0xBFA6, //HANGUL SYLLABLE SSANGPIEUP OE PIEUPSIOS + 0x976A: 0xBFA7, //HANGUL SYLLABLE SSANGPIEUP OE SIOS + 0x976B: 0xBFA8, //HANGUL SYLLABLE SSANGPIEUP OE SSANGSIOS + 0x976C: 0xBFA9, //HANGUL SYLLABLE SSANGPIEUP OE IEUNG + 0x976D: 0xBFAA, //HANGUL SYLLABLE SSANGPIEUP OE CIEUC + 0x976E: 0xBFAB, //HANGUL SYLLABLE SSANGPIEUP OE CHIEUCH + 0x976F: 0xBFAC, //HANGUL SYLLABLE SSANGPIEUP OE KHIEUKH + 0x9770: 0xBFAD, //HANGUL SYLLABLE SSANGPIEUP OE THIEUTH + 0x9771: 0xBFAE, //HANGUL SYLLABLE SSANGPIEUP OE PHIEUPH + 0x9772: 0xBFAF, //HANGUL SYLLABLE SSANGPIEUP OE HIEUH + 0x9773: 0xBFB1, //HANGUL SYLLABLE SSANGPIEUP YO KIYEOK + 0x9774: 0xBFB2, //HANGUL SYLLABLE SSANGPIEUP YO SSANGKIYEOK + 0x9775: 0xBFB3, //HANGUL SYLLABLE SSANGPIEUP YO KIYEOKSIOS + 0x9776: 0xBFB4, //HANGUL SYLLABLE SSANGPIEUP YO NIEUN + 0x9777: 0xBFB5, //HANGUL SYLLABLE SSANGPIEUP YO NIEUNCIEUC + 0x9778: 0xBFB6, //HANGUL SYLLABLE SSANGPIEUP YO NIEUNHIEUH + 0x9779: 0xBFB7, //HANGUL SYLLABLE SSANGPIEUP YO TIKEUT + 0x977A: 0xBFB8, //HANGUL SYLLABLE SSANGPIEUP YO RIEUL + 0x9781: 0xBFB9, //HANGUL SYLLABLE SSANGPIEUP YO RIEULKIYEOK + 0x9782: 0xBFBA, //HANGUL SYLLABLE SSANGPIEUP YO RIEULMIEUM + 0x9783: 0xBFBB, //HANGUL SYLLABLE SSANGPIEUP YO RIEULPIEUP + 0x9784: 0xBFBC, //HANGUL SYLLABLE SSANGPIEUP YO RIEULSIOS + 0x9785: 0xBFBD, //HANGUL SYLLABLE SSANGPIEUP YO RIEULTHIEUTH + 0x9786: 0xBFBE, //HANGUL SYLLABLE SSANGPIEUP YO RIEULPHIEUPH + 0x9787: 0xBFBF, //HANGUL SYLLABLE SSANGPIEUP YO RIEULHIEUH + 0x9788: 0xBFC0, //HANGUL SYLLABLE SSANGPIEUP YO MIEUM + 0x9789: 0xBFC1, //HANGUL SYLLABLE SSANGPIEUP YO PIEUP + 0x978A: 0xBFC2, //HANGUL SYLLABLE SSANGPIEUP YO PIEUPSIOS + 0x978B: 0xBFC3, //HANGUL SYLLABLE SSANGPIEUP YO SIOS + 0x978C: 0xBFC4, //HANGUL SYLLABLE SSANGPIEUP YO SSANGSIOS + 0x978D: 0xBFC6, //HANGUL SYLLABLE SSANGPIEUP YO CIEUC + 0x978E: 0xBFC7, //HANGUL SYLLABLE SSANGPIEUP YO CHIEUCH + 0x978F: 0xBFC8, //HANGUL SYLLABLE SSANGPIEUP YO KHIEUKH + 0x9790: 0xBFC9, //HANGUL SYLLABLE SSANGPIEUP YO THIEUTH + 0x9791: 0xBFCA, //HANGUL SYLLABLE SSANGPIEUP YO PHIEUPH + 0x9792: 0xBFCB, //HANGUL SYLLABLE SSANGPIEUP YO HIEUH + 0x9793: 0xBFCE, //HANGUL SYLLABLE SSANGPIEUP U SSANGKIYEOK + 0x9794: 0xBFCF, //HANGUL SYLLABLE SSANGPIEUP U KIYEOKSIOS + 0x9795: 0xBFD1, //HANGUL SYLLABLE SSANGPIEUP U NIEUNCIEUC + 0x9796: 0xBFD2, //HANGUL SYLLABLE SSANGPIEUP U NIEUNHIEUH + 0x9797: 0xBFD3, //HANGUL SYLLABLE SSANGPIEUP U TIKEUT + 0x9798: 0xBFD5, //HANGUL SYLLABLE SSANGPIEUP U RIEULKIYEOK + 0x9799: 0xBFD6, //HANGUL SYLLABLE SSANGPIEUP U RIEULMIEUM + 0x979A: 0xBFD7, //HANGUL SYLLABLE SSANGPIEUP U RIEULPIEUP + 0x979B: 0xBFD8, //HANGUL SYLLABLE SSANGPIEUP U RIEULSIOS + 0x979C: 0xBFD9, //HANGUL SYLLABLE SSANGPIEUP U RIEULTHIEUTH + 0x979D: 0xBFDA, //HANGUL SYLLABLE SSANGPIEUP U RIEULPHIEUPH + 0x979E: 0xBFDB, //HANGUL SYLLABLE SSANGPIEUP U RIEULHIEUH + 0x979F: 0xBFDD, //HANGUL SYLLABLE SSANGPIEUP U PIEUP + 0x97A0: 0xBFDE, //HANGUL SYLLABLE SSANGPIEUP U PIEUPSIOS + 0x97A1: 0xBFE0, //HANGUL SYLLABLE SSANGPIEUP U SSANGSIOS + 0x97A2: 0xBFE2, //HANGUL SYLLABLE SSANGPIEUP U CIEUC + 0x97A3: 0xBFE3, //HANGUL SYLLABLE SSANGPIEUP U CHIEUCH + 0x97A4: 0xBFE4, //HANGUL SYLLABLE SSANGPIEUP U KHIEUKH + 0x97A5: 0xBFE5, //HANGUL SYLLABLE SSANGPIEUP U THIEUTH + 0x97A6: 0xBFE6, //HANGUL SYLLABLE SSANGPIEUP U PHIEUPH + 0x97A7: 0xBFE7, //HANGUL SYLLABLE SSANGPIEUP U HIEUH + 0x97A8: 0xBFE8, //HANGUL SYLLABLE SSANGPIEUP WEO + 0x97A9: 0xBFE9, //HANGUL SYLLABLE SSANGPIEUP WEO KIYEOK + 0x97AA: 0xBFEA, //HANGUL SYLLABLE SSANGPIEUP WEO SSANGKIYEOK + 0x97AB: 0xBFEB, //HANGUL SYLLABLE SSANGPIEUP WEO KIYEOKSIOS + 0x97AC: 0xBFEC, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUN + 0x97AD: 0xBFED, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUNCIEUC + 0x97AE: 0xBFEE, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUNHIEUH + 0x97AF: 0xBFEF, //HANGUL SYLLABLE SSANGPIEUP WEO TIKEUT + 0x97B0: 0xBFF0, //HANGUL SYLLABLE SSANGPIEUP WEO RIEUL + 0x97B1: 0xBFF1, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULKIYEOK + 0x97B2: 0xBFF2, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULMIEUM + 0x97B3: 0xBFF3, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULPIEUP + 0x97B4: 0xBFF4, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULSIOS + 0x97B5: 0xBFF5, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULTHIEUTH + 0x97B6: 0xBFF6, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULPHIEUPH + 0x97B7: 0xBFF7, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULHIEUH + 0x97B8: 0xBFF8, //HANGUL SYLLABLE SSANGPIEUP WEO MIEUM + 0x97B9: 0xBFF9, //HANGUL SYLLABLE SSANGPIEUP WEO PIEUP + 0x97BA: 0xBFFA, //HANGUL SYLLABLE SSANGPIEUP WEO PIEUPSIOS + 0x97BB: 0xBFFB, //HANGUL SYLLABLE SSANGPIEUP WEO SIOS + 0x97BC: 0xBFFC, //HANGUL SYLLABLE SSANGPIEUP WEO SSANGSIOS + 0x97BD: 0xBFFD, //HANGUL SYLLABLE SSANGPIEUP WEO IEUNG + 0x97BE: 0xBFFE, //HANGUL SYLLABLE SSANGPIEUP WEO CIEUC + 0x97BF: 0xBFFF, //HANGUL SYLLABLE SSANGPIEUP WEO CHIEUCH + 0x97C0: 0xC000, //HANGUL SYLLABLE SSANGPIEUP WEO KHIEUKH + 0x97C1: 0xC001, //HANGUL SYLLABLE SSANGPIEUP WEO THIEUTH + 0x97C2: 0xC002, //HANGUL SYLLABLE SSANGPIEUP WEO PHIEUPH + 0x97C3: 0xC003, //HANGUL SYLLABLE SSANGPIEUP WEO HIEUH + 0x97C4: 0xC004, //HANGUL SYLLABLE SSANGPIEUP WE + 0x97C5: 0xC005, //HANGUL SYLLABLE SSANGPIEUP WE KIYEOK + 0x97C6: 0xC006, //HANGUL SYLLABLE SSANGPIEUP WE SSANGKIYEOK + 0x97C7: 0xC007, //HANGUL SYLLABLE SSANGPIEUP WE KIYEOKSIOS + 0x97C8: 0xC008, //HANGUL SYLLABLE SSANGPIEUP WE NIEUN + 0x97C9: 0xC009, //HANGUL SYLLABLE SSANGPIEUP WE NIEUNCIEUC + 0x97CA: 0xC00A, //HANGUL SYLLABLE SSANGPIEUP WE NIEUNHIEUH + 0x97CB: 0xC00B, //HANGUL SYLLABLE SSANGPIEUP WE TIKEUT + 0x97CC: 0xC00C, //HANGUL SYLLABLE SSANGPIEUP WE RIEUL + 0x97CD: 0xC00D, //HANGUL SYLLABLE SSANGPIEUP WE RIEULKIYEOK + 0x97CE: 0xC00E, //HANGUL SYLLABLE SSANGPIEUP WE RIEULMIEUM + 0x97CF: 0xC00F, //HANGUL SYLLABLE SSANGPIEUP WE RIEULPIEUP + 0x97D0: 0xC010, //HANGUL SYLLABLE SSANGPIEUP WE RIEULSIOS + 0x97D1: 0xC011, //HANGUL SYLLABLE SSANGPIEUP WE RIEULTHIEUTH + 0x97D2: 0xC012, //HANGUL SYLLABLE SSANGPIEUP WE RIEULPHIEUPH + 0x97D3: 0xC013, //HANGUL SYLLABLE SSANGPIEUP WE RIEULHIEUH + 0x97D4: 0xC014, //HANGUL SYLLABLE SSANGPIEUP WE MIEUM + 0x97D5: 0xC015, //HANGUL SYLLABLE SSANGPIEUP WE PIEUP + 0x97D6: 0xC016, //HANGUL SYLLABLE SSANGPIEUP WE PIEUPSIOS + 0x97D7: 0xC017, //HANGUL SYLLABLE SSANGPIEUP WE SIOS + 0x97D8: 0xC018, //HANGUL SYLLABLE SSANGPIEUP WE SSANGSIOS + 0x97D9: 0xC019, //HANGUL SYLLABLE SSANGPIEUP WE IEUNG + 0x97DA: 0xC01A, //HANGUL SYLLABLE SSANGPIEUP WE CIEUC + 0x97DB: 0xC01B, //HANGUL SYLLABLE SSANGPIEUP WE CHIEUCH + 0x97DC: 0xC01C, //HANGUL SYLLABLE SSANGPIEUP WE KHIEUKH + 0x97DD: 0xC01D, //HANGUL SYLLABLE SSANGPIEUP WE THIEUTH + 0x97DE: 0xC01E, //HANGUL SYLLABLE SSANGPIEUP WE PHIEUPH + 0x97DF: 0xC01F, //HANGUL SYLLABLE SSANGPIEUP WE HIEUH + 0x97E0: 0xC020, //HANGUL SYLLABLE SSANGPIEUP WI + 0x97E1: 0xC021, //HANGUL SYLLABLE SSANGPIEUP WI KIYEOK + 0x97E2: 0xC022, //HANGUL SYLLABLE SSANGPIEUP WI SSANGKIYEOK + 0x97E3: 0xC023, //HANGUL SYLLABLE SSANGPIEUP WI KIYEOKSIOS + 0x97E4: 0xC024, //HANGUL SYLLABLE SSANGPIEUP WI NIEUN + 0x97E5: 0xC025, //HANGUL SYLLABLE SSANGPIEUP WI NIEUNCIEUC + 0x97E6: 0xC026, //HANGUL SYLLABLE SSANGPIEUP WI NIEUNHIEUH + 0x97E7: 0xC027, //HANGUL SYLLABLE SSANGPIEUP WI TIKEUT + 0x97E8: 0xC028, //HANGUL SYLLABLE SSANGPIEUP WI RIEUL + 0x97E9: 0xC029, //HANGUL SYLLABLE SSANGPIEUP WI RIEULKIYEOK + 0x97EA: 0xC02A, //HANGUL SYLLABLE SSANGPIEUP WI RIEULMIEUM + 0x97EB: 0xC02B, //HANGUL SYLLABLE SSANGPIEUP WI RIEULPIEUP + 0x97EC: 0xC02C, //HANGUL SYLLABLE SSANGPIEUP WI RIEULSIOS + 0x97ED: 0xC02D, //HANGUL SYLLABLE SSANGPIEUP WI RIEULTHIEUTH + 0x97EE: 0xC02E, //HANGUL SYLLABLE SSANGPIEUP WI RIEULPHIEUPH + 0x97EF: 0xC02F, //HANGUL SYLLABLE SSANGPIEUP WI RIEULHIEUH + 0x97F0: 0xC030, //HANGUL SYLLABLE SSANGPIEUP WI MIEUM + 0x97F1: 0xC031, //HANGUL SYLLABLE SSANGPIEUP WI PIEUP + 0x97F2: 0xC032, //HANGUL SYLLABLE SSANGPIEUP WI PIEUPSIOS + 0x97F3: 0xC033, //HANGUL SYLLABLE SSANGPIEUP WI SIOS + 0x97F4: 0xC034, //HANGUL SYLLABLE SSANGPIEUP WI SSANGSIOS + 0x97F5: 0xC035, //HANGUL SYLLABLE SSANGPIEUP WI IEUNG + 0x97F6: 0xC036, //HANGUL SYLLABLE SSANGPIEUP WI CIEUC + 0x97F7: 0xC037, //HANGUL SYLLABLE SSANGPIEUP WI CHIEUCH + 0x97F8: 0xC038, //HANGUL SYLLABLE SSANGPIEUP WI KHIEUKH + 0x97F9: 0xC039, //HANGUL SYLLABLE SSANGPIEUP WI THIEUTH + 0x97FA: 0xC03A, //HANGUL SYLLABLE SSANGPIEUP WI PHIEUPH + 0x97FB: 0xC03B, //HANGUL SYLLABLE SSANGPIEUP WI HIEUH + 0x97FC: 0xC03D, //HANGUL SYLLABLE SSANGPIEUP YU KIYEOK + 0x97FD: 0xC03E, //HANGUL SYLLABLE SSANGPIEUP YU SSANGKIYEOK + 0x97FE: 0xC03F, //HANGUL SYLLABLE SSANGPIEUP YU KIYEOKSIOS + 0x9841: 0xC040, //HANGUL SYLLABLE SSANGPIEUP YU NIEUN + 0x9842: 0xC041, //HANGUL SYLLABLE SSANGPIEUP YU NIEUNCIEUC + 0x9843: 0xC042, //HANGUL SYLLABLE SSANGPIEUP YU NIEUNHIEUH + 0x9844: 0xC043, //HANGUL SYLLABLE SSANGPIEUP YU TIKEUT + 0x9845: 0xC044, //HANGUL SYLLABLE SSANGPIEUP YU RIEUL + 0x9846: 0xC045, //HANGUL SYLLABLE SSANGPIEUP YU RIEULKIYEOK + 0x9847: 0xC046, //HANGUL SYLLABLE SSANGPIEUP YU RIEULMIEUM + 0x9848: 0xC047, //HANGUL SYLLABLE SSANGPIEUP YU RIEULPIEUP + 0x9849: 0xC048, //HANGUL SYLLABLE SSANGPIEUP YU RIEULSIOS + 0x984A: 0xC049, //HANGUL SYLLABLE SSANGPIEUP YU RIEULTHIEUTH + 0x984B: 0xC04A, //HANGUL SYLLABLE SSANGPIEUP YU RIEULPHIEUPH + 0x984C: 0xC04B, //HANGUL SYLLABLE SSANGPIEUP YU RIEULHIEUH + 0x984D: 0xC04C, //HANGUL SYLLABLE SSANGPIEUP YU MIEUM + 0x984E: 0xC04D, //HANGUL SYLLABLE SSANGPIEUP YU PIEUP + 0x984F: 0xC04E, //HANGUL SYLLABLE SSANGPIEUP YU PIEUPSIOS + 0x9850: 0xC04F, //HANGUL SYLLABLE SSANGPIEUP YU SIOS + 0x9851: 0xC050, //HANGUL SYLLABLE SSANGPIEUP YU SSANGSIOS + 0x9852: 0xC052, //HANGUL SYLLABLE SSANGPIEUP YU CIEUC + 0x9853: 0xC053, //HANGUL SYLLABLE SSANGPIEUP YU CHIEUCH + 0x9854: 0xC054, //HANGUL SYLLABLE SSANGPIEUP YU KHIEUKH + 0x9855: 0xC055, //HANGUL SYLLABLE SSANGPIEUP YU THIEUTH + 0x9856: 0xC056, //HANGUL SYLLABLE SSANGPIEUP YU PHIEUPH + 0x9857: 0xC057, //HANGUL SYLLABLE SSANGPIEUP YU HIEUH + 0x9858: 0xC059, //HANGUL SYLLABLE SSANGPIEUP EU KIYEOK + 0x9859: 0xC05A, //HANGUL SYLLABLE SSANGPIEUP EU SSANGKIYEOK + 0x985A: 0xC05B, //HANGUL SYLLABLE SSANGPIEUP EU KIYEOKSIOS + 0x9861: 0xC05D, //HANGUL SYLLABLE SSANGPIEUP EU NIEUNCIEUC + 0x9862: 0xC05E, //HANGUL SYLLABLE SSANGPIEUP EU NIEUNHIEUH + 0x9863: 0xC05F, //HANGUL SYLLABLE SSANGPIEUP EU TIKEUT + 0x9864: 0xC061, //HANGUL SYLLABLE SSANGPIEUP EU RIEULKIYEOK + 0x9865: 0xC062, //HANGUL SYLLABLE SSANGPIEUP EU RIEULMIEUM + 0x9866: 0xC063, //HANGUL SYLLABLE SSANGPIEUP EU RIEULPIEUP + 0x9867: 0xC064, //HANGUL SYLLABLE SSANGPIEUP EU RIEULSIOS + 0x9868: 0xC065, //HANGUL SYLLABLE SSANGPIEUP EU RIEULTHIEUTH + 0x9869: 0xC066, //HANGUL SYLLABLE SSANGPIEUP EU RIEULPHIEUPH + 0x986A: 0xC067, //HANGUL SYLLABLE SSANGPIEUP EU RIEULHIEUH + 0x986B: 0xC06A, //HANGUL SYLLABLE SSANGPIEUP EU PIEUPSIOS + 0x986C: 0xC06B, //HANGUL SYLLABLE SSANGPIEUP EU SIOS + 0x986D: 0xC06C, //HANGUL SYLLABLE SSANGPIEUP EU SSANGSIOS + 0x986E: 0xC06D, //HANGUL SYLLABLE SSANGPIEUP EU IEUNG + 0x986F: 0xC06E, //HANGUL SYLLABLE SSANGPIEUP EU CIEUC + 0x9870: 0xC06F, //HANGUL SYLLABLE SSANGPIEUP EU CHIEUCH + 0x9871: 0xC070, //HANGUL SYLLABLE SSANGPIEUP EU KHIEUKH + 0x9872: 0xC071, //HANGUL SYLLABLE SSANGPIEUP EU THIEUTH + 0x9873: 0xC072, //HANGUL SYLLABLE SSANGPIEUP EU PHIEUPH + 0x9874: 0xC073, //HANGUL SYLLABLE SSANGPIEUP EU HIEUH + 0x9875: 0xC074, //HANGUL SYLLABLE SSANGPIEUP YI + 0x9876: 0xC075, //HANGUL SYLLABLE SSANGPIEUP YI KIYEOK + 0x9877: 0xC076, //HANGUL SYLLABLE SSANGPIEUP YI SSANGKIYEOK + 0x9878: 0xC077, //HANGUL SYLLABLE SSANGPIEUP YI KIYEOKSIOS + 0x9879: 0xC078, //HANGUL SYLLABLE SSANGPIEUP YI NIEUN + 0x987A: 0xC079, //HANGUL SYLLABLE SSANGPIEUP YI NIEUNCIEUC + 0x9881: 0xC07A, //HANGUL SYLLABLE SSANGPIEUP YI NIEUNHIEUH + 0x9882: 0xC07B, //HANGUL SYLLABLE SSANGPIEUP YI TIKEUT + 0x9883: 0xC07C, //HANGUL SYLLABLE SSANGPIEUP YI RIEUL + 0x9884: 0xC07D, //HANGUL SYLLABLE SSANGPIEUP YI RIEULKIYEOK + 0x9885: 0xC07E, //HANGUL SYLLABLE SSANGPIEUP YI RIEULMIEUM + 0x9886: 0xC07F, //HANGUL SYLLABLE SSANGPIEUP YI RIEULPIEUP + 0x9887: 0xC080, //HANGUL SYLLABLE SSANGPIEUP YI RIEULSIOS + 0x9888: 0xC081, //HANGUL SYLLABLE SSANGPIEUP YI RIEULTHIEUTH + 0x9889: 0xC082, //HANGUL SYLLABLE SSANGPIEUP YI RIEULPHIEUPH + 0x988A: 0xC083, //HANGUL SYLLABLE SSANGPIEUP YI RIEULHIEUH + 0x988B: 0xC084, //HANGUL SYLLABLE SSANGPIEUP YI MIEUM + 0x988C: 0xC085, //HANGUL SYLLABLE SSANGPIEUP YI PIEUP + 0x988D: 0xC086, //HANGUL SYLLABLE SSANGPIEUP YI PIEUPSIOS + 0x988E: 0xC087, //HANGUL SYLLABLE SSANGPIEUP YI SIOS + 0x988F: 0xC088, //HANGUL SYLLABLE SSANGPIEUP YI SSANGSIOS + 0x9890: 0xC089, //HANGUL SYLLABLE SSANGPIEUP YI IEUNG + 0x9891: 0xC08A, //HANGUL SYLLABLE SSANGPIEUP YI CIEUC + 0x9892: 0xC08B, //HANGUL SYLLABLE SSANGPIEUP YI CHIEUCH + 0x9893: 0xC08C, //HANGUL SYLLABLE SSANGPIEUP YI KHIEUKH + 0x9894: 0xC08D, //HANGUL SYLLABLE SSANGPIEUP YI THIEUTH + 0x9895: 0xC08E, //HANGUL SYLLABLE SSANGPIEUP YI PHIEUPH + 0x9896: 0xC08F, //HANGUL SYLLABLE SSANGPIEUP YI HIEUH + 0x9897: 0xC092, //HANGUL SYLLABLE SSANGPIEUP I SSANGKIYEOK + 0x9898: 0xC093, //HANGUL SYLLABLE SSANGPIEUP I KIYEOKSIOS + 0x9899: 0xC095, //HANGUL SYLLABLE SSANGPIEUP I NIEUNCIEUC + 0x989A: 0xC096, //HANGUL SYLLABLE SSANGPIEUP I NIEUNHIEUH + 0x989B: 0xC097, //HANGUL SYLLABLE SSANGPIEUP I TIKEUT + 0x989C: 0xC099, //HANGUL SYLLABLE SSANGPIEUP I RIEULKIYEOK + 0x989D: 0xC09A, //HANGUL SYLLABLE SSANGPIEUP I RIEULMIEUM + 0x989E: 0xC09B, //HANGUL SYLLABLE SSANGPIEUP I RIEULPIEUP + 0x989F: 0xC09C, //HANGUL SYLLABLE SSANGPIEUP I RIEULSIOS + 0x98A0: 0xC09D, //HANGUL SYLLABLE SSANGPIEUP I RIEULTHIEUTH + 0x98A1: 0xC09E, //HANGUL SYLLABLE SSANGPIEUP I RIEULPHIEUPH + 0x98A2: 0xC09F, //HANGUL SYLLABLE SSANGPIEUP I RIEULHIEUH + 0x98A3: 0xC0A2, //HANGUL SYLLABLE SSANGPIEUP I PIEUPSIOS + 0x98A4: 0xC0A4, //HANGUL SYLLABLE SSANGPIEUP I SSANGSIOS + 0x98A5: 0xC0A6, //HANGUL SYLLABLE SSANGPIEUP I CIEUC + 0x98A6: 0xC0A7, //HANGUL SYLLABLE SSANGPIEUP I CHIEUCH + 0x98A7: 0xC0A8, //HANGUL SYLLABLE SSANGPIEUP I KHIEUKH + 0x98A8: 0xC0A9, //HANGUL SYLLABLE SSANGPIEUP I THIEUTH + 0x98A9: 0xC0AA, //HANGUL SYLLABLE SSANGPIEUP I PHIEUPH + 0x98AA: 0xC0AB, //HANGUL SYLLABLE SSANGPIEUP I HIEUH + 0x98AB: 0xC0AE, //HANGUL SYLLABLE SIOS A SSANGKIYEOK + 0x98AC: 0xC0B1, //HANGUL SYLLABLE SIOS A NIEUNCIEUC + 0x98AD: 0xC0B2, //HANGUL SYLLABLE SIOS A NIEUNHIEUH + 0x98AE: 0xC0B7, //HANGUL SYLLABLE SIOS A RIEULPIEUP + 0x98AF: 0xC0B8, //HANGUL SYLLABLE SIOS A RIEULSIOS + 0x98B0: 0xC0B9, //HANGUL SYLLABLE SIOS A RIEULTHIEUTH + 0x98B1: 0xC0BA, //HANGUL SYLLABLE SIOS A RIEULPHIEUPH + 0x98B2: 0xC0BB, //HANGUL SYLLABLE SIOS A RIEULHIEUH + 0x98B3: 0xC0BE, //HANGUL SYLLABLE SIOS A PIEUPSIOS + 0x98B4: 0xC0C2, //HANGUL SYLLABLE SIOS A CIEUC + 0x98B5: 0xC0C3, //HANGUL SYLLABLE SIOS A CHIEUCH + 0x98B6: 0xC0C4, //HANGUL SYLLABLE SIOS A KHIEUKH + 0x98B7: 0xC0C6, //HANGUL SYLLABLE SIOS A PHIEUPH + 0x98B8: 0xC0C7, //HANGUL SYLLABLE SIOS A HIEUH + 0x98B9: 0xC0CA, //HANGUL SYLLABLE SIOS AE SSANGKIYEOK + 0x98BA: 0xC0CB, //HANGUL SYLLABLE SIOS AE KIYEOKSIOS + 0x98BB: 0xC0CD, //HANGUL SYLLABLE SIOS AE NIEUNCIEUC + 0x98BC: 0xC0CE, //HANGUL SYLLABLE SIOS AE NIEUNHIEUH + 0x98BD: 0xC0CF, //HANGUL SYLLABLE SIOS AE TIKEUT + 0x98BE: 0xC0D1, //HANGUL SYLLABLE SIOS AE RIEULKIYEOK + 0x98BF: 0xC0D2, //HANGUL SYLLABLE SIOS AE RIEULMIEUM + 0x98C0: 0xC0D3, //HANGUL SYLLABLE SIOS AE RIEULPIEUP + 0x98C1: 0xC0D4, //HANGUL SYLLABLE SIOS AE RIEULSIOS + 0x98C2: 0xC0D5, //HANGUL SYLLABLE SIOS AE RIEULTHIEUTH + 0x98C3: 0xC0D6, //HANGUL SYLLABLE SIOS AE RIEULPHIEUPH + 0x98C4: 0xC0D7, //HANGUL SYLLABLE SIOS AE RIEULHIEUH + 0x98C5: 0xC0DA, //HANGUL SYLLABLE SIOS AE PIEUPSIOS + 0x98C6: 0xC0DE, //HANGUL SYLLABLE SIOS AE CIEUC + 0x98C7: 0xC0DF, //HANGUL SYLLABLE SIOS AE CHIEUCH + 0x98C8: 0xC0E0, //HANGUL SYLLABLE SIOS AE KHIEUKH + 0x98C9: 0xC0E1, //HANGUL SYLLABLE SIOS AE THIEUTH + 0x98CA: 0xC0E2, //HANGUL SYLLABLE SIOS AE PHIEUPH + 0x98CB: 0xC0E3, //HANGUL SYLLABLE SIOS AE HIEUH + 0x98CC: 0xC0E6, //HANGUL SYLLABLE SIOS YA SSANGKIYEOK + 0x98CD: 0xC0E7, //HANGUL SYLLABLE SIOS YA KIYEOKSIOS + 0x98CE: 0xC0E9, //HANGUL SYLLABLE SIOS YA NIEUNCIEUC + 0x98CF: 0xC0EA, //HANGUL SYLLABLE SIOS YA NIEUNHIEUH + 0x98D0: 0xC0EB, //HANGUL SYLLABLE SIOS YA TIKEUT + 0x98D1: 0xC0ED, //HANGUL SYLLABLE SIOS YA RIEULKIYEOK + 0x98D2: 0xC0EE, //HANGUL SYLLABLE SIOS YA RIEULMIEUM + 0x98D3: 0xC0EF, //HANGUL SYLLABLE SIOS YA RIEULPIEUP + 0x98D4: 0xC0F0, //HANGUL SYLLABLE SIOS YA RIEULSIOS + 0x98D5: 0xC0F1, //HANGUL SYLLABLE SIOS YA RIEULTHIEUTH + 0x98D6: 0xC0F2, //HANGUL SYLLABLE SIOS YA RIEULPHIEUPH + 0x98D7: 0xC0F3, //HANGUL SYLLABLE SIOS YA RIEULHIEUH + 0x98D8: 0xC0F6, //HANGUL SYLLABLE SIOS YA PIEUPSIOS + 0x98D9: 0xC0F8, //HANGUL SYLLABLE SIOS YA SSANGSIOS + 0x98DA: 0xC0FA, //HANGUL SYLLABLE SIOS YA CIEUC + 0x98DB: 0xC0FB, //HANGUL SYLLABLE SIOS YA CHIEUCH + 0x98DC: 0xC0FC, //HANGUL SYLLABLE SIOS YA KHIEUKH + 0x98DD: 0xC0FD, //HANGUL SYLLABLE SIOS YA THIEUTH + 0x98DE: 0xC0FE, //HANGUL SYLLABLE SIOS YA PHIEUPH + 0x98DF: 0xC0FF, //HANGUL SYLLABLE SIOS YA HIEUH + 0x98E0: 0xC101, //HANGUL SYLLABLE SIOS YAE KIYEOK + 0x98E1: 0xC102, //HANGUL SYLLABLE SIOS YAE SSANGKIYEOK + 0x98E2: 0xC103, //HANGUL SYLLABLE SIOS YAE KIYEOKSIOS + 0x98E3: 0xC105, //HANGUL SYLLABLE SIOS YAE NIEUNCIEUC + 0x98E4: 0xC106, //HANGUL SYLLABLE SIOS YAE NIEUNHIEUH + 0x98E5: 0xC107, //HANGUL SYLLABLE SIOS YAE TIKEUT + 0x98E6: 0xC109, //HANGUL SYLLABLE SIOS YAE RIEULKIYEOK + 0x98E7: 0xC10A, //HANGUL SYLLABLE SIOS YAE RIEULMIEUM + 0x98E8: 0xC10B, //HANGUL SYLLABLE SIOS YAE RIEULPIEUP + 0x98E9: 0xC10C, //HANGUL SYLLABLE SIOS YAE RIEULSIOS + 0x98EA: 0xC10D, //HANGUL SYLLABLE SIOS YAE RIEULTHIEUTH + 0x98EB: 0xC10E, //HANGUL SYLLABLE SIOS YAE RIEULPHIEUPH + 0x98EC: 0xC10F, //HANGUL SYLLABLE SIOS YAE RIEULHIEUH + 0x98ED: 0xC111, //HANGUL SYLLABLE SIOS YAE PIEUP + 0x98EE: 0xC112, //HANGUL SYLLABLE SIOS YAE PIEUPSIOS + 0x98EF: 0xC113, //HANGUL SYLLABLE SIOS YAE SIOS + 0x98F0: 0xC114, //HANGUL SYLLABLE SIOS YAE SSANGSIOS + 0x98F1: 0xC116, //HANGUL SYLLABLE SIOS YAE CIEUC + 0x98F2: 0xC117, //HANGUL SYLLABLE SIOS YAE CHIEUCH + 0x98F3: 0xC118, //HANGUL SYLLABLE SIOS YAE KHIEUKH + 0x98F4: 0xC119, //HANGUL SYLLABLE SIOS YAE THIEUTH + 0x98F5: 0xC11A, //HANGUL SYLLABLE SIOS YAE PHIEUPH + 0x98F6: 0xC11B, //HANGUL SYLLABLE SIOS YAE HIEUH + 0x98F7: 0xC121, //HANGUL SYLLABLE SIOS EO NIEUNCIEUC + 0x98F8: 0xC122, //HANGUL SYLLABLE SIOS EO NIEUNHIEUH + 0x98F9: 0xC125, //HANGUL SYLLABLE SIOS EO RIEULKIYEOK + 0x98FA: 0xC128, //HANGUL SYLLABLE SIOS EO RIEULSIOS + 0x98FB: 0xC129, //HANGUL SYLLABLE SIOS EO RIEULTHIEUTH + 0x98FC: 0xC12A, //HANGUL SYLLABLE SIOS EO RIEULPHIEUPH + 0x98FD: 0xC12B, //HANGUL SYLLABLE SIOS EO RIEULHIEUH + 0x98FE: 0xC12E, //HANGUL SYLLABLE SIOS EO PIEUPSIOS + 0x9941: 0xC132, //HANGUL SYLLABLE SIOS EO CIEUC + 0x9942: 0xC133, //HANGUL SYLLABLE SIOS EO CHIEUCH + 0x9943: 0xC134, //HANGUL SYLLABLE SIOS EO KHIEUKH + 0x9944: 0xC135, //HANGUL SYLLABLE SIOS EO THIEUTH + 0x9945: 0xC137, //HANGUL SYLLABLE SIOS EO HIEUH + 0x9946: 0xC13A, //HANGUL SYLLABLE SIOS E SSANGKIYEOK + 0x9947: 0xC13B, //HANGUL SYLLABLE SIOS E KIYEOKSIOS + 0x9948: 0xC13D, //HANGUL SYLLABLE SIOS E NIEUNCIEUC + 0x9949: 0xC13E, //HANGUL SYLLABLE SIOS E NIEUNHIEUH + 0x994A: 0xC13F, //HANGUL SYLLABLE SIOS E TIKEUT + 0x994B: 0xC141, //HANGUL SYLLABLE SIOS E RIEULKIYEOK + 0x994C: 0xC142, //HANGUL SYLLABLE SIOS E RIEULMIEUM + 0x994D: 0xC143, //HANGUL SYLLABLE SIOS E RIEULPIEUP + 0x994E: 0xC144, //HANGUL SYLLABLE SIOS E RIEULSIOS + 0x994F: 0xC145, //HANGUL SYLLABLE SIOS E RIEULTHIEUTH + 0x9950: 0xC146, //HANGUL SYLLABLE SIOS E RIEULPHIEUPH + 0x9951: 0xC147, //HANGUL SYLLABLE SIOS E RIEULHIEUH + 0x9952: 0xC14A, //HANGUL SYLLABLE SIOS E PIEUPSIOS + 0x9953: 0xC14E, //HANGUL SYLLABLE SIOS E CIEUC + 0x9954: 0xC14F, //HANGUL SYLLABLE SIOS E CHIEUCH + 0x9955: 0xC150, //HANGUL SYLLABLE SIOS E KHIEUKH + 0x9956: 0xC151, //HANGUL SYLLABLE SIOS E THIEUTH + 0x9957: 0xC152, //HANGUL SYLLABLE SIOS E PHIEUPH + 0x9958: 0xC153, //HANGUL SYLLABLE SIOS E HIEUH + 0x9959: 0xC156, //HANGUL SYLLABLE SIOS YEO SSANGKIYEOK + 0x995A: 0xC157, //HANGUL SYLLABLE SIOS YEO KIYEOKSIOS + 0x9961: 0xC159, //HANGUL SYLLABLE SIOS YEO NIEUNCIEUC + 0x9962: 0xC15A, //HANGUL SYLLABLE SIOS YEO NIEUNHIEUH + 0x9963: 0xC15B, //HANGUL SYLLABLE SIOS YEO TIKEUT + 0x9964: 0xC15D, //HANGUL SYLLABLE SIOS YEO RIEULKIYEOK + 0x9965: 0xC15E, //HANGUL SYLLABLE SIOS YEO RIEULMIEUM + 0x9966: 0xC15F, //HANGUL SYLLABLE SIOS YEO RIEULPIEUP + 0x9967: 0xC160, //HANGUL SYLLABLE SIOS YEO RIEULSIOS + 0x9968: 0xC161, //HANGUL SYLLABLE SIOS YEO RIEULTHIEUTH + 0x9969: 0xC162, //HANGUL SYLLABLE SIOS YEO RIEULPHIEUPH + 0x996A: 0xC163, //HANGUL SYLLABLE SIOS YEO RIEULHIEUH + 0x996B: 0xC166, //HANGUL SYLLABLE SIOS YEO PIEUPSIOS + 0x996C: 0xC16A, //HANGUL SYLLABLE SIOS YEO CIEUC + 0x996D: 0xC16B, //HANGUL SYLLABLE SIOS YEO CHIEUCH + 0x996E: 0xC16C, //HANGUL SYLLABLE SIOS YEO KHIEUKH + 0x996F: 0xC16D, //HANGUL SYLLABLE SIOS YEO THIEUTH + 0x9970: 0xC16E, //HANGUL SYLLABLE SIOS YEO PHIEUPH + 0x9971: 0xC16F, //HANGUL SYLLABLE SIOS YEO HIEUH + 0x9972: 0xC171, //HANGUL SYLLABLE SIOS YE KIYEOK + 0x9973: 0xC172, //HANGUL SYLLABLE SIOS YE SSANGKIYEOK + 0x9974: 0xC173, //HANGUL SYLLABLE SIOS YE KIYEOKSIOS + 0x9975: 0xC175, //HANGUL SYLLABLE SIOS YE NIEUNCIEUC + 0x9976: 0xC176, //HANGUL SYLLABLE SIOS YE NIEUNHIEUH + 0x9977: 0xC177, //HANGUL SYLLABLE SIOS YE TIKEUT + 0x9978: 0xC179, //HANGUL SYLLABLE SIOS YE RIEULKIYEOK + 0x9979: 0xC17A, //HANGUL SYLLABLE SIOS YE RIEULMIEUM + 0x997A: 0xC17B, //HANGUL SYLLABLE SIOS YE RIEULPIEUP + 0x9981: 0xC17C, //HANGUL SYLLABLE SIOS YE RIEULSIOS + 0x9982: 0xC17D, //HANGUL SYLLABLE SIOS YE RIEULTHIEUTH + 0x9983: 0xC17E, //HANGUL SYLLABLE SIOS YE RIEULPHIEUPH + 0x9984: 0xC17F, //HANGUL SYLLABLE SIOS YE RIEULHIEUH + 0x9985: 0xC180, //HANGUL SYLLABLE SIOS YE MIEUM + 0x9986: 0xC181, //HANGUL SYLLABLE SIOS YE PIEUP + 0x9987: 0xC182, //HANGUL SYLLABLE SIOS YE PIEUPSIOS + 0x9988: 0xC183, //HANGUL SYLLABLE SIOS YE SIOS + 0x9989: 0xC184, //HANGUL SYLLABLE SIOS YE SSANGSIOS + 0x998A: 0xC186, //HANGUL SYLLABLE SIOS YE CIEUC + 0x998B: 0xC187, //HANGUL SYLLABLE SIOS YE CHIEUCH + 0x998C: 0xC188, //HANGUL SYLLABLE SIOS YE KHIEUKH + 0x998D: 0xC189, //HANGUL SYLLABLE SIOS YE THIEUTH + 0x998E: 0xC18A, //HANGUL SYLLABLE SIOS YE PHIEUPH + 0x998F: 0xC18B, //HANGUL SYLLABLE SIOS YE HIEUH + 0x9990: 0xC18F, //HANGUL SYLLABLE SIOS O KIYEOKSIOS + 0x9991: 0xC191, //HANGUL SYLLABLE SIOS O NIEUNCIEUC + 0x9992: 0xC192, //HANGUL SYLLABLE SIOS O NIEUNHIEUH + 0x9993: 0xC193, //HANGUL SYLLABLE SIOS O TIKEUT + 0x9994: 0xC195, //HANGUL SYLLABLE SIOS O RIEULKIYEOK + 0x9995: 0xC197, //HANGUL SYLLABLE SIOS O RIEULPIEUP + 0x9996: 0xC198, //HANGUL SYLLABLE SIOS O RIEULSIOS + 0x9997: 0xC199, //HANGUL SYLLABLE SIOS O RIEULTHIEUTH + 0x9998: 0xC19A, //HANGUL SYLLABLE SIOS O RIEULPHIEUPH + 0x9999: 0xC19B, //HANGUL SYLLABLE SIOS O RIEULHIEUH + 0x999A: 0xC19E, //HANGUL SYLLABLE SIOS O PIEUPSIOS + 0x999B: 0xC1A0, //HANGUL SYLLABLE SIOS O SSANGSIOS + 0x999C: 0xC1A2, //HANGUL SYLLABLE SIOS O CIEUC + 0x999D: 0xC1A3, //HANGUL SYLLABLE SIOS O CHIEUCH + 0x999E: 0xC1A4, //HANGUL SYLLABLE SIOS O KHIEUKH + 0x999F: 0xC1A6, //HANGUL SYLLABLE SIOS O PHIEUPH + 0x99A0: 0xC1A7, //HANGUL SYLLABLE SIOS O HIEUH + 0x99A1: 0xC1AA, //HANGUL SYLLABLE SIOS WA SSANGKIYEOK + 0x99A2: 0xC1AB, //HANGUL SYLLABLE SIOS WA KIYEOKSIOS + 0x99A3: 0xC1AD, //HANGUL SYLLABLE SIOS WA NIEUNCIEUC + 0x99A4: 0xC1AE, //HANGUL SYLLABLE SIOS WA NIEUNHIEUH + 0x99A5: 0xC1AF, //HANGUL SYLLABLE SIOS WA TIKEUT + 0x99A6: 0xC1B1, //HANGUL SYLLABLE SIOS WA RIEULKIYEOK + 0x99A7: 0xC1B2, //HANGUL SYLLABLE SIOS WA RIEULMIEUM + 0x99A8: 0xC1B3, //HANGUL SYLLABLE SIOS WA RIEULPIEUP + 0x99A9: 0xC1B4, //HANGUL SYLLABLE SIOS WA RIEULSIOS + 0x99AA: 0xC1B5, //HANGUL SYLLABLE SIOS WA RIEULTHIEUTH + 0x99AB: 0xC1B6, //HANGUL SYLLABLE SIOS WA RIEULPHIEUPH + 0x99AC: 0xC1B7, //HANGUL SYLLABLE SIOS WA RIEULHIEUH + 0x99AD: 0xC1B8, //HANGUL SYLLABLE SIOS WA MIEUM + 0x99AE: 0xC1B9, //HANGUL SYLLABLE SIOS WA PIEUP + 0x99AF: 0xC1BA, //HANGUL SYLLABLE SIOS WA PIEUPSIOS + 0x99B0: 0xC1BB, //HANGUL SYLLABLE SIOS WA SIOS + 0x99B1: 0xC1BC, //HANGUL SYLLABLE SIOS WA SSANGSIOS + 0x99B2: 0xC1BE, //HANGUL SYLLABLE SIOS WA CIEUC + 0x99B3: 0xC1BF, //HANGUL SYLLABLE SIOS WA CHIEUCH + 0x99B4: 0xC1C0, //HANGUL SYLLABLE SIOS WA KHIEUKH + 0x99B5: 0xC1C1, //HANGUL SYLLABLE SIOS WA THIEUTH + 0x99B6: 0xC1C2, //HANGUL SYLLABLE SIOS WA PHIEUPH + 0x99B7: 0xC1C3, //HANGUL SYLLABLE SIOS WA HIEUH + 0x99B8: 0xC1C5, //HANGUL SYLLABLE SIOS WAE KIYEOK + 0x99B9: 0xC1C6, //HANGUL SYLLABLE SIOS WAE SSANGKIYEOK + 0x99BA: 0xC1C7, //HANGUL SYLLABLE SIOS WAE KIYEOKSIOS + 0x99BB: 0xC1C9, //HANGUL SYLLABLE SIOS WAE NIEUNCIEUC + 0x99BC: 0xC1CA, //HANGUL SYLLABLE SIOS WAE NIEUNHIEUH + 0x99BD: 0xC1CB, //HANGUL SYLLABLE SIOS WAE TIKEUT + 0x99BE: 0xC1CD, //HANGUL SYLLABLE SIOS WAE RIEULKIYEOK + 0x99BF: 0xC1CE, //HANGUL SYLLABLE SIOS WAE RIEULMIEUM + 0x99C0: 0xC1CF, //HANGUL SYLLABLE SIOS WAE RIEULPIEUP + 0x99C1: 0xC1D0, //HANGUL SYLLABLE SIOS WAE RIEULSIOS + 0x99C2: 0xC1D1, //HANGUL SYLLABLE SIOS WAE RIEULTHIEUTH + 0x99C3: 0xC1D2, //HANGUL SYLLABLE SIOS WAE RIEULPHIEUPH + 0x99C4: 0xC1D3, //HANGUL SYLLABLE SIOS WAE RIEULHIEUH + 0x99C5: 0xC1D5, //HANGUL SYLLABLE SIOS WAE PIEUP + 0x99C6: 0xC1D6, //HANGUL SYLLABLE SIOS WAE PIEUPSIOS + 0x99C7: 0xC1D9, //HANGUL SYLLABLE SIOS WAE IEUNG + 0x99C8: 0xC1DA, //HANGUL SYLLABLE SIOS WAE CIEUC + 0x99C9: 0xC1DB, //HANGUL SYLLABLE SIOS WAE CHIEUCH + 0x99CA: 0xC1DC, //HANGUL SYLLABLE SIOS WAE KHIEUKH + 0x99CB: 0xC1DD, //HANGUL SYLLABLE SIOS WAE THIEUTH + 0x99CC: 0xC1DE, //HANGUL SYLLABLE SIOS WAE PHIEUPH + 0x99CD: 0xC1DF, //HANGUL SYLLABLE SIOS WAE HIEUH + 0x99CE: 0xC1E1, //HANGUL SYLLABLE SIOS OE KIYEOK + 0x99CF: 0xC1E2, //HANGUL SYLLABLE SIOS OE SSANGKIYEOK + 0x99D0: 0xC1E3, //HANGUL SYLLABLE SIOS OE KIYEOKSIOS + 0x99D1: 0xC1E5, //HANGUL SYLLABLE SIOS OE NIEUNCIEUC + 0x99D2: 0xC1E6, //HANGUL SYLLABLE SIOS OE NIEUNHIEUH + 0x99D3: 0xC1E7, //HANGUL SYLLABLE SIOS OE TIKEUT + 0x99D4: 0xC1E9, //HANGUL SYLLABLE SIOS OE RIEULKIYEOK + 0x99D5: 0xC1EA, //HANGUL SYLLABLE SIOS OE RIEULMIEUM + 0x99D6: 0xC1EB, //HANGUL SYLLABLE SIOS OE RIEULPIEUP + 0x99D7: 0xC1EC, //HANGUL SYLLABLE SIOS OE RIEULSIOS + 0x99D8: 0xC1ED, //HANGUL SYLLABLE SIOS OE RIEULTHIEUTH + 0x99D9: 0xC1EE, //HANGUL SYLLABLE SIOS OE RIEULPHIEUPH + 0x99DA: 0xC1EF, //HANGUL SYLLABLE SIOS OE RIEULHIEUH + 0x99DB: 0xC1F2, //HANGUL SYLLABLE SIOS OE PIEUPSIOS + 0x99DC: 0xC1F4, //HANGUL SYLLABLE SIOS OE SSANGSIOS + 0x99DD: 0xC1F5, //HANGUL SYLLABLE SIOS OE IEUNG + 0x99DE: 0xC1F6, //HANGUL SYLLABLE SIOS OE CIEUC + 0x99DF: 0xC1F7, //HANGUL SYLLABLE SIOS OE CHIEUCH + 0x99E0: 0xC1F8, //HANGUL SYLLABLE SIOS OE KHIEUKH + 0x99E1: 0xC1F9, //HANGUL SYLLABLE SIOS OE THIEUTH + 0x99E2: 0xC1FA, //HANGUL SYLLABLE SIOS OE PHIEUPH + 0x99E3: 0xC1FB, //HANGUL SYLLABLE SIOS OE HIEUH + 0x99E4: 0xC1FE, //HANGUL SYLLABLE SIOS YO SSANGKIYEOK + 0x99E5: 0xC1FF, //HANGUL SYLLABLE SIOS YO KIYEOKSIOS + 0x99E6: 0xC201, //HANGUL SYLLABLE SIOS YO NIEUNCIEUC + 0x99E7: 0xC202, //HANGUL SYLLABLE SIOS YO NIEUNHIEUH + 0x99E8: 0xC203, //HANGUL SYLLABLE SIOS YO TIKEUT + 0x99E9: 0xC205, //HANGUL SYLLABLE SIOS YO RIEULKIYEOK + 0x99EA: 0xC206, //HANGUL SYLLABLE SIOS YO RIEULMIEUM + 0x99EB: 0xC207, //HANGUL SYLLABLE SIOS YO RIEULPIEUP + 0x99EC: 0xC208, //HANGUL SYLLABLE SIOS YO RIEULSIOS + 0x99ED: 0xC209, //HANGUL SYLLABLE SIOS YO RIEULTHIEUTH + 0x99EE: 0xC20A, //HANGUL SYLLABLE SIOS YO RIEULPHIEUPH + 0x99EF: 0xC20B, //HANGUL SYLLABLE SIOS YO RIEULHIEUH + 0x99F0: 0xC20E, //HANGUL SYLLABLE SIOS YO PIEUPSIOS + 0x99F1: 0xC210, //HANGUL SYLLABLE SIOS YO SSANGSIOS + 0x99F2: 0xC212, //HANGUL SYLLABLE SIOS YO CIEUC + 0x99F3: 0xC213, //HANGUL SYLLABLE SIOS YO CHIEUCH + 0x99F4: 0xC214, //HANGUL SYLLABLE SIOS YO KHIEUKH + 0x99F5: 0xC215, //HANGUL SYLLABLE SIOS YO THIEUTH + 0x99F6: 0xC216, //HANGUL SYLLABLE SIOS YO PHIEUPH + 0x99F7: 0xC217, //HANGUL SYLLABLE SIOS YO HIEUH + 0x99F8: 0xC21A, //HANGUL SYLLABLE SIOS U SSANGKIYEOK + 0x99F9: 0xC21B, //HANGUL SYLLABLE SIOS U KIYEOKSIOS + 0x99FA: 0xC21D, //HANGUL SYLLABLE SIOS U NIEUNCIEUC + 0x99FB: 0xC21E, //HANGUL SYLLABLE SIOS U NIEUNHIEUH + 0x99FC: 0xC221, //HANGUL SYLLABLE SIOS U RIEULKIYEOK + 0x99FD: 0xC222, //HANGUL SYLLABLE SIOS U RIEULMIEUM + 0x99FE: 0xC223, //HANGUL SYLLABLE SIOS U RIEULPIEUP + 0x9A41: 0xC224, //HANGUL SYLLABLE SIOS U RIEULSIOS + 0x9A42: 0xC225, //HANGUL SYLLABLE SIOS U RIEULTHIEUTH + 0x9A43: 0xC226, //HANGUL SYLLABLE SIOS U RIEULPHIEUPH + 0x9A44: 0xC227, //HANGUL SYLLABLE SIOS U RIEULHIEUH + 0x9A45: 0xC22A, //HANGUL SYLLABLE SIOS U PIEUPSIOS + 0x9A46: 0xC22C, //HANGUL SYLLABLE SIOS U SSANGSIOS + 0x9A47: 0xC22E, //HANGUL SYLLABLE SIOS U CIEUC + 0x9A48: 0xC230, //HANGUL SYLLABLE SIOS U KHIEUKH + 0x9A49: 0xC233, //HANGUL SYLLABLE SIOS U HIEUH + 0x9A4A: 0xC235, //HANGUL SYLLABLE SIOS WEO KIYEOK + 0x9A4B: 0xC236, //HANGUL SYLLABLE SIOS WEO SSANGKIYEOK + 0x9A4C: 0xC237, //HANGUL SYLLABLE SIOS WEO KIYEOKSIOS + 0x9A4D: 0xC238, //HANGUL SYLLABLE SIOS WEO NIEUN + 0x9A4E: 0xC239, //HANGUL SYLLABLE SIOS WEO NIEUNCIEUC + 0x9A4F: 0xC23A, //HANGUL SYLLABLE SIOS WEO NIEUNHIEUH + 0x9A50: 0xC23B, //HANGUL SYLLABLE SIOS WEO TIKEUT + 0x9A51: 0xC23C, //HANGUL SYLLABLE SIOS WEO RIEUL + 0x9A52: 0xC23D, //HANGUL SYLLABLE SIOS WEO RIEULKIYEOK + 0x9A53: 0xC23E, //HANGUL SYLLABLE SIOS WEO RIEULMIEUM + 0x9A54: 0xC23F, //HANGUL SYLLABLE SIOS WEO RIEULPIEUP + 0x9A55: 0xC240, //HANGUL SYLLABLE SIOS WEO RIEULSIOS + 0x9A56: 0xC241, //HANGUL SYLLABLE SIOS WEO RIEULTHIEUTH + 0x9A57: 0xC242, //HANGUL SYLLABLE SIOS WEO RIEULPHIEUPH + 0x9A58: 0xC243, //HANGUL SYLLABLE SIOS WEO RIEULHIEUH + 0x9A59: 0xC244, //HANGUL SYLLABLE SIOS WEO MIEUM + 0x9A5A: 0xC245, //HANGUL SYLLABLE SIOS WEO PIEUP + 0x9A61: 0xC246, //HANGUL SYLLABLE SIOS WEO PIEUPSIOS + 0x9A62: 0xC247, //HANGUL SYLLABLE SIOS WEO SIOS + 0x9A63: 0xC249, //HANGUL SYLLABLE SIOS WEO IEUNG + 0x9A64: 0xC24A, //HANGUL SYLLABLE SIOS WEO CIEUC + 0x9A65: 0xC24B, //HANGUL SYLLABLE SIOS WEO CHIEUCH + 0x9A66: 0xC24C, //HANGUL SYLLABLE SIOS WEO KHIEUKH + 0x9A67: 0xC24D, //HANGUL SYLLABLE SIOS WEO THIEUTH + 0x9A68: 0xC24E, //HANGUL SYLLABLE SIOS WEO PHIEUPH + 0x9A69: 0xC24F, //HANGUL SYLLABLE SIOS WEO HIEUH + 0x9A6A: 0xC252, //HANGUL SYLLABLE SIOS WE SSANGKIYEOK + 0x9A6B: 0xC253, //HANGUL SYLLABLE SIOS WE KIYEOKSIOS + 0x9A6C: 0xC255, //HANGUL SYLLABLE SIOS WE NIEUNCIEUC + 0x9A6D: 0xC256, //HANGUL SYLLABLE SIOS WE NIEUNHIEUH + 0x9A6E: 0xC257, //HANGUL SYLLABLE SIOS WE TIKEUT + 0x9A6F: 0xC259, //HANGUL SYLLABLE SIOS WE RIEULKIYEOK + 0x9A70: 0xC25A, //HANGUL SYLLABLE SIOS WE RIEULMIEUM + 0x9A71: 0xC25B, //HANGUL SYLLABLE SIOS WE RIEULPIEUP + 0x9A72: 0xC25C, //HANGUL SYLLABLE SIOS WE RIEULSIOS + 0x9A73: 0xC25D, //HANGUL SYLLABLE SIOS WE RIEULTHIEUTH + 0x9A74: 0xC25E, //HANGUL SYLLABLE SIOS WE RIEULPHIEUPH + 0x9A75: 0xC25F, //HANGUL SYLLABLE SIOS WE RIEULHIEUH + 0x9A76: 0xC261, //HANGUL SYLLABLE SIOS WE PIEUP + 0x9A77: 0xC262, //HANGUL SYLLABLE SIOS WE PIEUPSIOS + 0x9A78: 0xC263, //HANGUL SYLLABLE SIOS WE SIOS + 0x9A79: 0xC264, //HANGUL SYLLABLE SIOS WE SSANGSIOS + 0x9A7A: 0xC266, //HANGUL SYLLABLE SIOS WE CIEUC + 0x9A81: 0xC267, //HANGUL SYLLABLE SIOS WE CHIEUCH + 0x9A82: 0xC268, //HANGUL SYLLABLE SIOS WE KHIEUKH + 0x9A83: 0xC269, //HANGUL SYLLABLE SIOS WE THIEUTH + 0x9A84: 0xC26A, //HANGUL SYLLABLE SIOS WE PHIEUPH + 0x9A85: 0xC26B, //HANGUL SYLLABLE SIOS WE HIEUH + 0x9A86: 0xC26E, //HANGUL SYLLABLE SIOS WI SSANGKIYEOK + 0x9A87: 0xC26F, //HANGUL SYLLABLE SIOS WI KIYEOKSIOS + 0x9A88: 0xC271, //HANGUL SYLLABLE SIOS WI NIEUNCIEUC + 0x9A89: 0xC272, //HANGUL SYLLABLE SIOS WI NIEUNHIEUH + 0x9A8A: 0xC273, //HANGUL SYLLABLE SIOS WI TIKEUT + 0x9A8B: 0xC275, //HANGUL SYLLABLE SIOS WI RIEULKIYEOK + 0x9A8C: 0xC276, //HANGUL SYLLABLE SIOS WI RIEULMIEUM + 0x9A8D: 0xC277, //HANGUL SYLLABLE SIOS WI RIEULPIEUP + 0x9A8E: 0xC278, //HANGUL SYLLABLE SIOS WI RIEULSIOS + 0x9A8F: 0xC279, //HANGUL SYLLABLE SIOS WI RIEULTHIEUTH + 0x9A90: 0xC27A, //HANGUL SYLLABLE SIOS WI RIEULPHIEUPH + 0x9A91: 0xC27B, //HANGUL SYLLABLE SIOS WI RIEULHIEUH + 0x9A92: 0xC27E, //HANGUL SYLLABLE SIOS WI PIEUPSIOS + 0x9A93: 0xC280, //HANGUL SYLLABLE SIOS WI SSANGSIOS + 0x9A94: 0xC282, //HANGUL SYLLABLE SIOS WI CIEUC + 0x9A95: 0xC283, //HANGUL SYLLABLE SIOS WI CHIEUCH + 0x9A96: 0xC284, //HANGUL SYLLABLE SIOS WI KHIEUKH + 0x9A97: 0xC285, //HANGUL SYLLABLE SIOS WI THIEUTH + 0x9A98: 0xC286, //HANGUL SYLLABLE SIOS WI PHIEUPH + 0x9A99: 0xC287, //HANGUL SYLLABLE SIOS WI HIEUH + 0x9A9A: 0xC28A, //HANGUL SYLLABLE SIOS YU SSANGKIYEOK + 0x9A9B: 0xC28B, //HANGUL SYLLABLE SIOS YU KIYEOKSIOS + 0x9A9C: 0xC28C, //HANGUL SYLLABLE SIOS YU NIEUN + 0x9A9D: 0xC28D, //HANGUL SYLLABLE SIOS YU NIEUNCIEUC + 0x9A9E: 0xC28E, //HANGUL SYLLABLE SIOS YU NIEUNHIEUH + 0x9A9F: 0xC28F, //HANGUL SYLLABLE SIOS YU TIKEUT + 0x9AA0: 0xC291, //HANGUL SYLLABLE SIOS YU RIEULKIYEOK + 0x9AA1: 0xC292, //HANGUL SYLLABLE SIOS YU RIEULMIEUM + 0x9AA2: 0xC293, //HANGUL SYLLABLE SIOS YU RIEULPIEUP + 0x9AA3: 0xC294, //HANGUL SYLLABLE SIOS YU RIEULSIOS + 0x9AA4: 0xC295, //HANGUL SYLLABLE SIOS YU RIEULTHIEUTH + 0x9AA5: 0xC296, //HANGUL SYLLABLE SIOS YU RIEULPHIEUPH + 0x9AA6: 0xC297, //HANGUL SYLLABLE SIOS YU RIEULHIEUH + 0x9AA7: 0xC299, //HANGUL SYLLABLE SIOS YU PIEUP + 0x9AA8: 0xC29A, //HANGUL SYLLABLE SIOS YU PIEUPSIOS + 0x9AA9: 0xC29C, //HANGUL SYLLABLE SIOS YU SSANGSIOS + 0x9AAA: 0xC29E, //HANGUL SYLLABLE SIOS YU CIEUC + 0x9AAB: 0xC29F, //HANGUL SYLLABLE SIOS YU CHIEUCH + 0x9AAC: 0xC2A0, //HANGUL SYLLABLE SIOS YU KHIEUKH + 0x9AAD: 0xC2A1, //HANGUL SYLLABLE SIOS YU THIEUTH + 0x9AAE: 0xC2A2, //HANGUL SYLLABLE SIOS YU PHIEUPH + 0x9AAF: 0xC2A3, //HANGUL SYLLABLE SIOS YU HIEUH + 0x9AB0: 0xC2A6, //HANGUL SYLLABLE SIOS EU SSANGKIYEOK + 0x9AB1: 0xC2A7, //HANGUL SYLLABLE SIOS EU KIYEOKSIOS + 0x9AB2: 0xC2A9, //HANGUL SYLLABLE SIOS EU NIEUNCIEUC + 0x9AB3: 0xC2AA, //HANGUL SYLLABLE SIOS EU NIEUNHIEUH + 0x9AB4: 0xC2AB, //HANGUL SYLLABLE SIOS EU TIKEUT + 0x9AB5: 0xC2AE, //HANGUL SYLLABLE SIOS EU RIEULMIEUM + 0x9AB6: 0xC2AF, //HANGUL SYLLABLE SIOS EU RIEULPIEUP + 0x9AB7: 0xC2B0, //HANGUL SYLLABLE SIOS EU RIEULSIOS + 0x9AB8: 0xC2B1, //HANGUL SYLLABLE SIOS EU RIEULTHIEUTH + 0x9AB9: 0xC2B2, //HANGUL SYLLABLE SIOS EU RIEULPHIEUPH + 0x9ABA: 0xC2B3, //HANGUL SYLLABLE SIOS EU RIEULHIEUH + 0x9ABB: 0xC2B6, //HANGUL SYLLABLE SIOS EU PIEUPSIOS + 0x9ABC: 0xC2B8, //HANGUL SYLLABLE SIOS EU SSANGSIOS + 0x9ABD: 0xC2BA, //HANGUL SYLLABLE SIOS EU CIEUC + 0x9ABE: 0xC2BB, //HANGUL SYLLABLE SIOS EU CHIEUCH + 0x9ABF: 0xC2BC, //HANGUL SYLLABLE SIOS EU KHIEUKH + 0x9AC0: 0xC2BD, //HANGUL SYLLABLE SIOS EU THIEUTH + 0x9AC1: 0xC2BE, //HANGUL SYLLABLE SIOS EU PHIEUPH + 0x9AC2: 0xC2BF, //HANGUL SYLLABLE SIOS EU HIEUH + 0x9AC3: 0xC2C0, //HANGUL SYLLABLE SIOS YI + 0x9AC4: 0xC2C1, //HANGUL SYLLABLE SIOS YI KIYEOK + 0x9AC5: 0xC2C2, //HANGUL SYLLABLE SIOS YI SSANGKIYEOK + 0x9AC6: 0xC2C3, //HANGUL SYLLABLE SIOS YI KIYEOKSIOS + 0x9AC7: 0xC2C4, //HANGUL SYLLABLE SIOS YI NIEUN + 0x9AC8: 0xC2C5, //HANGUL SYLLABLE SIOS YI NIEUNCIEUC + 0x9AC9: 0xC2C6, //HANGUL SYLLABLE SIOS YI NIEUNHIEUH + 0x9ACA: 0xC2C7, //HANGUL SYLLABLE SIOS YI TIKEUT + 0x9ACB: 0xC2C8, //HANGUL SYLLABLE SIOS YI RIEUL + 0x9ACC: 0xC2C9, //HANGUL SYLLABLE SIOS YI RIEULKIYEOK + 0x9ACD: 0xC2CA, //HANGUL SYLLABLE SIOS YI RIEULMIEUM + 0x9ACE: 0xC2CB, //HANGUL SYLLABLE SIOS YI RIEULPIEUP + 0x9ACF: 0xC2CC, //HANGUL SYLLABLE SIOS YI RIEULSIOS + 0x9AD0: 0xC2CD, //HANGUL SYLLABLE SIOS YI RIEULTHIEUTH + 0x9AD1: 0xC2CE, //HANGUL SYLLABLE SIOS YI RIEULPHIEUPH + 0x9AD2: 0xC2CF, //HANGUL SYLLABLE SIOS YI RIEULHIEUH + 0x9AD3: 0xC2D0, //HANGUL SYLLABLE SIOS YI MIEUM + 0x9AD4: 0xC2D1, //HANGUL SYLLABLE SIOS YI PIEUP + 0x9AD5: 0xC2D2, //HANGUL SYLLABLE SIOS YI PIEUPSIOS + 0x9AD6: 0xC2D3, //HANGUL SYLLABLE SIOS YI SIOS + 0x9AD7: 0xC2D4, //HANGUL SYLLABLE SIOS YI SSANGSIOS + 0x9AD8: 0xC2D5, //HANGUL SYLLABLE SIOS YI IEUNG + 0x9AD9: 0xC2D6, //HANGUL SYLLABLE SIOS YI CIEUC + 0x9ADA: 0xC2D7, //HANGUL SYLLABLE SIOS YI CHIEUCH + 0x9ADB: 0xC2D8, //HANGUL SYLLABLE SIOS YI KHIEUKH + 0x9ADC: 0xC2D9, //HANGUL SYLLABLE SIOS YI THIEUTH + 0x9ADD: 0xC2DA, //HANGUL SYLLABLE SIOS YI PHIEUPH + 0x9ADE: 0xC2DB, //HANGUL SYLLABLE SIOS YI HIEUH + 0x9ADF: 0xC2DE, //HANGUL SYLLABLE SIOS I SSANGKIYEOK + 0x9AE0: 0xC2DF, //HANGUL SYLLABLE SIOS I KIYEOKSIOS + 0x9AE1: 0xC2E1, //HANGUL SYLLABLE SIOS I NIEUNCIEUC + 0x9AE2: 0xC2E2, //HANGUL SYLLABLE SIOS I NIEUNHIEUH + 0x9AE3: 0xC2E5, //HANGUL SYLLABLE SIOS I RIEULKIYEOK + 0x9AE4: 0xC2E6, //HANGUL SYLLABLE SIOS I RIEULMIEUM + 0x9AE5: 0xC2E7, //HANGUL SYLLABLE SIOS I RIEULPIEUP + 0x9AE6: 0xC2E8, //HANGUL SYLLABLE SIOS I RIEULSIOS + 0x9AE7: 0xC2E9, //HANGUL SYLLABLE SIOS I RIEULTHIEUTH + 0x9AE8: 0xC2EA, //HANGUL SYLLABLE SIOS I RIEULPHIEUPH + 0x9AE9: 0xC2EE, //HANGUL SYLLABLE SIOS I PIEUPSIOS + 0x9AEA: 0xC2F0, //HANGUL SYLLABLE SIOS I SSANGSIOS + 0x9AEB: 0xC2F2, //HANGUL SYLLABLE SIOS I CIEUC + 0x9AEC: 0xC2F3, //HANGUL SYLLABLE SIOS I CHIEUCH + 0x9AED: 0xC2F4, //HANGUL SYLLABLE SIOS I KHIEUKH + 0x9AEE: 0xC2F5, //HANGUL SYLLABLE SIOS I THIEUTH + 0x9AEF: 0xC2F7, //HANGUL SYLLABLE SIOS I HIEUH + 0x9AF0: 0xC2FA, //HANGUL SYLLABLE SSANGSIOS A SSANGKIYEOK + 0x9AF1: 0xC2FD, //HANGUL SYLLABLE SSANGSIOS A NIEUNCIEUC + 0x9AF2: 0xC2FE, //HANGUL SYLLABLE SSANGSIOS A NIEUNHIEUH + 0x9AF3: 0xC2FF, //HANGUL SYLLABLE SSANGSIOS A TIKEUT + 0x9AF4: 0xC301, //HANGUL SYLLABLE SSANGSIOS A RIEULKIYEOK + 0x9AF5: 0xC302, //HANGUL SYLLABLE SSANGSIOS A RIEULMIEUM + 0x9AF6: 0xC303, //HANGUL SYLLABLE SSANGSIOS A RIEULPIEUP + 0x9AF7: 0xC304, //HANGUL SYLLABLE SSANGSIOS A RIEULSIOS + 0x9AF8: 0xC305, //HANGUL SYLLABLE SSANGSIOS A RIEULTHIEUTH + 0x9AF9: 0xC306, //HANGUL SYLLABLE SSANGSIOS A RIEULPHIEUPH + 0x9AFA: 0xC307, //HANGUL SYLLABLE SSANGSIOS A RIEULHIEUH + 0x9AFB: 0xC30A, //HANGUL SYLLABLE SSANGSIOS A PIEUPSIOS + 0x9AFC: 0xC30B, //HANGUL SYLLABLE SSANGSIOS A SIOS + 0x9AFD: 0xC30E, //HANGUL SYLLABLE SSANGSIOS A CIEUC + 0x9AFE: 0xC30F, //HANGUL SYLLABLE SSANGSIOS A CHIEUCH + 0x9B41: 0xC310, //HANGUL SYLLABLE SSANGSIOS A KHIEUKH + 0x9B42: 0xC311, //HANGUL SYLLABLE SSANGSIOS A THIEUTH + 0x9B43: 0xC312, //HANGUL SYLLABLE SSANGSIOS A PHIEUPH + 0x9B44: 0xC316, //HANGUL SYLLABLE SSANGSIOS AE SSANGKIYEOK + 0x9B45: 0xC317, //HANGUL SYLLABLE SSANGSIOS AE KIYEOKSIOS + 0x9B46: 0xC319, //HANGUL SYLLABLE SSANGSIOS AE NIEUNCIEUC + 0x9B47: 0xC31A, //HANGUL SYLLABLE SSANGSIOS AE NIEUNHIEUH + 0x9B48: 0xC31B, //HANGUL SYLLABLE SSANGSIOS AE TIKEUT + 0x9B49: 0xC31D, //HANGUL SYLLABLE SSANGSIOS AE RIEULKIYEOK + 0x9B4A: 0xC31E, //HANGUL SYLLABLE SSANGSIOS AE RIEULMIEUM + 0x9B4B: 0xC31F, //HANGUL SYLLABLE SSANGSIOS AE RIEULPIEUP + 0x9B4C: 0xC320, //HANGUL SYLLABLE SSANGSIOS AE RIEULSIOS + 0x9B4D: 0xC321, //HANGUL SYLLABLE SSANGSIOS AE RIEULTHIEUTH + 0x9B4E: 0xC322, //HANGUL SYLLABLE SSANGSIOS AE RIEULPHIEUPH + 0x9B4F: 0xC323, //HANGUL SYLLABLE SSANGSIOS AE RIEULHIEUH + 0x9B50: 0xC326, //HANGUL SYLLABLE SSANGSIOS AE PIEUPSIOS + 0x9B51: 0xC327, //HANGUL SYLLABLE SSANGSIOS AE SIOS + 0x9B52: 0xC32A, //HANGUL SYLLABLE SSANGSIOS AE CIEUC + 0x9B53: 0xC32B, //HANGUL SYLLABLE SSANGSIOS AE CHIEUCH + 0x9B54: 0xC32C, //HANGUL SYLLABLE SSANGSIOS AE KHIEUKH + 0x9B55: 0xC32D, //HANGUL SYLLABLE SSANGSIOS AE THIEUTH + 0x9B56: 0xC32E, //HANGUL SYLLABLE SSANGSIOS AE PHIEUPH + 0x9B57: 0xC32F, //HANGUL SYLLABLE SSANGSIOS AE HIEUH + 0x9B58: 0xC330, //HANGUL SYLLABLE SSANGSIOS YA + 0x9B59: 0xC331, //HANGUL SYLLABLE SSANGSIOS YA KIYEOK + 0x9B5A: 0xC332, //HANGUL SYLLABLE SSANGSIOS YA SSANGKIYEOK + 0x9B61: 0xC333, //HANGUL SYLLABLE SSANGSIOS YA KIYEOKSIOS + 0x9B62: 0xC334, //HANGUL SYLLABLE SSANGSIOS YA NIEUN + 0x9B63: 0xC335, //HANGUL SYLLABLE SSANGSIOS YA NIEUNCIEUC + 0x9B64: 0xC336, //HANGUL SYLLABLE SSANGSIOS YA NIEUNHIEUH + 0x9B65: 0xC337, //HANGUL SYLLABLE SSANGSIOS YA TIKEUT + 0x9B66: 0xC338, //HANGUL SYLLABLE SSANGSIOS YA RIEUL + 0x9B67: 0xC339, //HANGUL SYLLABLE SSANGSIOS YA RIEULKIYEOK + 0x9B68: 0xC33A, //HANGUL SYLLABLE SSANGSIOS YA RIEULMIEUM + 0x9B69: 0xC33B, //HANGUL SYLLABLE SSANGSIOS YA RIEULPIEUP + 0x9B6A: 0xC33C, //HANGUL SYLLABLE SSANGSIOS YA RIEULSIOS + 0x9B6B: 0xC33D, //HANGUL SYLLABLE SSANGSIOS YA RIEULTHIEUTH + 0x9B6C: 0xC33E, //HANGUL SYLLABLE SSANGSIOS YA RIEULPHIEUPH + 0x9B6D: 0xC33F, //HANGUL SYLLABLE SSANGSIOS YA RIEULHIEUH + 0x9B6E: 0xC340, //HANGUL SYLLABLE SSANGSIOS YA MIEUM + 0x9B6F: 0xC341, //HANGUL SYLLABLE SSANGSIOS YA PIEUP + 0x9B70: 0xC342, //HANGUL SYLLABLE SSANGSIOS YA PIEUPSIOS + 0x9B71: 0xC343, //HANGUL SYLLABLE SSANGSIOS YA SIOS + 0x9B72: 0xC344, //HANGUL SYLLABLE SSANGSIOS YA SSANGSIOS + 0x9B73: 0xC346, //HANGUL SYLLABLE SSANGSIOS YA CIEUC + 0x9B74: 0xC347, //HANGUL SYLLABLE SSANGSIOS YA CHIEUCH + 0x9B75: 0xC348, //HANGUL SYLLABLE SSANGSIOS YA KHIEUKH + 0x9B76: 0xC349, //HANGUL SYLLABLE SSANGSIOS YA THIEUTH + 0x9B77: 0xC34A, //HANGUL SYLLABLE SSANGSIOS YA PHIEUPH + 0x9B78: 0xC34B, //HANGUL SYLLABLE SSANGSIOS YA HIEUH + 0x9B79: 0xC34C, //HANGUL SYLLABLE SSANGSIOS YAE + 0x9B7A: 0xC34D, //HANGUL SYLLABLE SSANGSIOS YAE KIYEOK + 0x9B81: 0xC34E, //HANGUL SYLLABLE SSANGSIOS YAE SSANGKIYEOK + 0x9B82: 0xC34F, //HANGUL SYLLABLE SSANGSIOS YAE KIYEOKSIOS + 0x9B83: 0xC350, //HANGUL SYLLABLE SSANGSIOS YAE NIEUN + 0x9B84: 0xC351, //HANGUL SYLLABLE SSANGSIOS YAE NIEUNCIEUC + 0x9B85: 0xC352, //HANGUL SYLLABLE SSANGSIOS YAE NIEUNHIEUH + 0x9B86: 0xC353, //HANGUL SYLLABLE SSANGSIOS YAE TIKEUT + 0x9B87: 0xC354, //HANGUL SYLLABLE SSANGSIOS YAE RIEUL + 0x9B88: 0xC355, //HANGUL SYLLABLE SSANGSIOS YAE RIEULKIYEOK + 0x9B89: 0xC356, //HANGUL SYLLABLE SSANGSIOS YAE RIEULMIEUM + 0x9B8A: 0xC357, //HANGUL SYLLABLE SSANGSIOS YAE RIEULPIEUP + 0x9B8B: 0xC358, //HANGUL SYLLABLE SSANGSIOS YAE RIEULSIOS + 0x9B8C: 0xC359, //HANGUL SYLLABLE SSANGSIOS YAE RIEULTHIEUTH + 0x9B8D: 0xC35A, //HANGUL SYLLABLE SSANGSIOS YAE RIEULPHIEUPH + 0x9B8E: 0xC35B, //HANGUL SYLLABLE SSANGSIOS YAE RIEULHIEUH + 0x9B8F: 0xC35C, //HANGUL SYLLABLE SSANGSIOS YAE MIEUM + 0x9B90: 0xC35D, //HANGUL SYLLABLE SSANGSIOS YAE PIEUP + 0x9B91: 0xC35E, //HANGUL SYLLABLE SSANGSIOS YAE PIEUPSIOS + 0x9B92: 0xC35F, //HANGUL SYLLABLE SSANGSIOS YAE SIOS + 0x9B93: 0xC360, //HANGUL SYLLABLE SSANGSIOS YAE SSANGSIOS + 0x9B94: 0xC361, //HANGUL SYLLABLE SSANGSIOS YAE IEUNG + 0x9B95: 0xC362, //HANGUL SYLLABLE SSANGSIOS YAE CIEUC + 0x9B96: 0xC363, //HANGUL SYLLABLE SSANGSIOS YAE CHIEUCH + 0x9B97: 0xC364, //HANGUL SYLLABLE SSANGSIOS YAE KHIEUKH + 0x9B98: 0xC365, //HANGUL SYLLABLE SSANGSIOS YAE THIEUTH + 0x9B99: 0xC366, //HANGUL SYLLABLE SSANGSIOS YAE PHIEUPH + 0x9B9A: 0xC367, //HANGUL SYLLABLE SSANGSIOS YAE HIEUH + 0x9B9B: 0xC36A, //HANGUL SYLLABLE SSANGSIOS EO SSANGKIYEOK + 0x9B9C: 0xC36B, //HANGUL SYLLABLE SSANGSIOS EO KIYEOKSIOS + 0x9B9D: 0xC36D, //HANGUL SYLLABLE SSANGSIOS EO NIEUNCIEUC + 0x9B9E: 0xC36E, //HANGUL SYLLABLE SSANGSIOS EO NIEUNHIEUH + 0x9B9F: 0xC36F, //HANGUL SYLLABLE SSANGSIOS EO TIKEUT + 0x9BA0: 0xC371, //HANGUL SYLLABLE SSANGSIOS EO RIEULKIYEOK + 0x9BA1: 0xC373, //HANGUL SYLLABLE SSANGSIOS EO RIEULPIEUP + 0x9BA2: 0xC374, //HANGUL SYLLABLE SSANGSIOS EO RIEULSIOS + 0x9BA3: 0xC375, //HANGUL SYLLABLE SSANGSIOS EO RIEULTHIEUTH + 0x9BA4: 0xC376, //HANGUL SYLLABLE SSANGSIOS EO RIEULPHIEUPH + 0x9BA5: 0xC377, //HANGUL SYLLABLE SSANGSIOS EO RIEULHIEUH + 0x9BA6: 0xC37A, //HANGUL SYLLABLE SSANGSIOS EO PIEUPSIOS + 0x9BA7: 0xC37B, //HANGUL SYLLABLE SSANGSIOS EO SIOS + 0x9BA8: 0xC37E, //HANGUL SYLLABLE SSANGSIOS EO CIEUC + 0x9BA9: 0xC37F, //HANGUL SYLLABLE SSANGSIOS EO CHIEUCH + 0x9BAA: 0xC380, //HANGUL SYLLABLE SSANGSIOS EO KHIEUKH + 0x9BAB: 0xC381, //HANGUL SYLLABLE SSANGSIOS EO THIEUTH + 0x9BAC: 0xC382, //HANGUL SYLLABLE SSANGSIOS EO PHIEUPH + 0x9BAD: 0xC383, //HANGUL SYLLABLE SSANGSIOS EO HIEUH + 0x9BAE: 0xC385, //HANGUL SYLLABLE SSANGSIOS E KIYEOK + 0x9BAF: 0xC386, //HANGUL SYLLABLE SSANGSIOS E SSANGKIYEOK + 0x9BB0: 0xC387, //HANGUL SYLLABLE SSANGSIOS E KIYEOKSIOS + 0x9BB1: 0xC389, //HANGUL SYLLABLE SSANGSIOS E NIEUNCIEUC + 0x9BB2: 0xC38A, //HANGUL SYLLABLE SSANGSIOS E NIEUNHIEUH + 0x9BB3: 0xC38B, //HANGUL SYLLABLE SSANGSIOS E TIKEUT + 0x9BB4: 0xC38D, //HANGUL SYLLABLE SSANGSIOS E RIEULKIYEOK + 0x9BB5: 0xC38E, //HANGUL SYLLABLE SSANGSIOS E RIEULMIEUM + 0x9BB6: 0xC38F, //HANGUL SYLLABLE SSANGSIOS E RIEULPIEUP + 0x9BB7: 0xC390, //HANGUL SYLLABLE SSANGSIOS E RIEULSIOS + 0x9BB8: 0xC391, //HANGUL SYLLABLE SSANGSIOS E RIEULTHIEUTH + 0x9BB9: 0xC392, //HANGUL SYLLABLE SSANGSIOS E RIEULPHIEUPH + 0x9BBA: 0xC393, //HANGUL SYLLABLE SSANGSIOS E RIEULHIEUH + 0x9BBB: 0xC394, //HANGUL SYLLABLE SSANGSIOS E MIEUM + 0x9BBC: 0xC395, //HANGUL SYLLABLE SSANGSIOS E PIEUP + 0x9BBD: 0xC396, //HANGUL SYLLABLE SSANGSIOS E PIEUPSIOS + 0x9BBE: 0xC397, //HANGUL SYLLABLE SSANGSIOS E SIOS + 0x9BBF: 0xC398, //HANGUL SYLLABLE SSANGSIOS E SSANGSIOS + 0x9BC0: 0xC399, //HANGUL SYLLABLE SSANGSIOS E IEUNG + 0x9BC1: 0xC39A, //HANGUL SYLLABLE SSANGSIOS E CIEUC + 0x9BC2: 0xC39B, //HANGUL SYLLABLE SSANGSIOS E CHIEUCH + 0x9BC3: 0xC39C, //HANGUL SYLLABLE SSANGSIOS E KHIEUKH + 0x9BC4: 0xC39D, //HANGUL SYLLABLE SSANGSIOS E THIEUTH + 0x9BC5: 0xC39E, //HANGUL SYLLABLE SSANGSIOS E PHIEUPH + 0x9BC6: 0xC39F, //HANGUL SYLLABLE SSANGSIOS E HIEUH + 0x9BC7: 0xC3A0, //HANGUL SYLLABLE SSANGSIOS YEO + 0x9BC8: 0xC3A1, //HANGUL SYLLABLE SSANGSIOS YEO KIYEOK + 0x9BC9: 0xC3A2, //HANGUL SYLLABLE SSANGSIOS YEO SSANGKIYEOK + 0x9BCA: 0xC3A3, //HANGUL SYLLABLE SSANGSIOS YEO KIYEOKSIOS + 0x9BCB: 0xC3A4, //HANGUL SYLLABLE SSANGSIOS YEO NIEUN + 0x9BCC: 0xC3A5, //HANGUL SYLLABLE SSANGSIOS YEO NIEUNCIEUC + 0x9BCD: 0xC3A6, //HANGUL SYLLABLE SSANGSIOS YEO NIEUNHIEUH + 0x9BCE: 0xC3A7, //HANGUL SYLLABLE SSANGSIOS YEO TIKEUT + 0x9BCF: 0xC3A8, //HANGUL SYLLABLE SSANGSIOS YEO RIEUL + 0x9BD0: 0xC3A9, //HANGUL SYLLABLE SSANGSIOS YEO RIEULKIYEOK + 0x9BD1: 0xC3AA, //HANGUL SYLLABLE SSANGSIOS YEO RIEULMIEUM + 0x9BD2: 0xC3AB, //HANGUL SYLLABLE SSANGSIOS YEO RIEULPIEUP + 0x9BD3: 0xC3AC, //HANGUL SYLLABLE SSANGSIOS YEO RIEULSIOS + 0x9BD4: 0xC3AD, //HANGUL SYLLABLE SSANGSIOS YEO RIEULTHIEUTH + 0x9BD5: 0xC3AE, //HANGUL SYLLABLE SSANGSIOS YEO RIEULPHIEUPH + 0x9BD6: 0xC3AF, //HANGUL SYLLABLE SSANGSIOS YEO RIEULHIEUH + 0x9BD7: 0xC3B0, //HANGUL SYLLABLE SSANGSIOS YEO MIEUM + 0x9BD8: 0xC3B1, //HANGUL SYLLABLE SSANGSIOS YEO PIEUP + 0x9BD9: 0xC3B2, //HANGUL SYLLABLE SSANGSIOS YEO PIEUPSIOS + 0x9BDA: 0xC3B3, //HANGUL SYLLABLE SSANGSIOS YEO SIOS + 0x9BDB: 0xC3B4, //HANGUL SYLLABLE SSANGSIOS YEO SSANGSIOS + 0x9BDC: 0xC3B5, //HANGUL SYLLABLE SSANGSIOS YEO IEUNG + 0x9BDD: 0xC3B6, //HANGUL SYLLABLE SSANGSIOS YEO CIEUC + 0x9BDE: 0xC3B7, //HANGUL SYLLABLE SSANGSIOS YEO CHIEUCH + 0x9BDF: 0xC3B8, //HANGUL SYLLABLE SSANGSIOS YEO KHIEUKH + 0x9BE0: 0xC3B9, //HANGUL SYLLABLE SSANGSIOS YEO THIEUTH + 0x9BE1: 0xC3BA, //HANGUL SYLLABLE SSANGSIOS YEO PHIEUPH + 0x9BE2: 0xC3BB, //HANGUL SYLLABLE SSANGSIOS YEO HIEUH + 0x9BE3: 0xC3BC, //HANGUL SYLLABLE SSANGSIOS YE + 0x9BE4: 0xC3BD, //HANGUL SYLLABLE SSANGSIOS YE KIYEOK + 0x9BE5: 0xC3BE, //HANGUL SYLLABLE SSANGSIOS YE SSANGKIYEOK + 0x9BE6: 0xC3BF, //HANGUL SYLLABLE SSANGSIOS YE KIYEOKSIOS + 0x9BE7: 0xC3C1, //HANGUL SYLLABLE SSANGSIOS YE NIEUNCIEUC + 0x9BE8: 0xC3C2, //HANGUL SYLLABLE SSANGSIOS YE NIEUNHIEUH + 0x9BE9: 0xC3C3, //HANGUL SYLLABLE SSANGSIOS YE TIKEUT + 0x9BEA: 0xC3C4, //HANGUL SYLLABLE SSANGSIOS YE RIEUL + 0x9BEB: 0xC3C5, //HANGUL SYLLABLE SSANGSIOS YE RIEULKIYEOK + 0x9BEC: 0xC3C6, //HANGUL SYLLABLE SSANGSIOS YE RIEULMIEUM + 0x9BED: 0xC3C7, //HANGUL SYLLABLE SSANGSIOS YE RIEULPIEUP + 0x9BEE: 0xC3C8, //HANGUL SYLLABLE SSANGSIOS YE RIEULSIOS + 0x9BEF: 0xC3C9, //HANGUL SYLLABLE SSANGSIOS YE RIEULTHIEUTH + 0x9BF0: 0xC3CA, //HANGUL SYLLABLE SSANGSIOS YE RIEULPHIEUPH + 0x9BF1: 0xC3CB, //HANGUL SYLLABLE SSANGSIOS YE RIEULHIEUH + 0x9BF2: 0xC3CC, //HANGUL SYLLABLE SSANGSIOS YE MIEUM + 0x9BF3: 0xC3CD, //HANGUL SYLLABLE SSANGSIOS YE PIEUP + 0x9BF4: 0xC3CE, //HANGUL SYLLABLE SSANGSIOS YE PIEUPSIOS + 0x9BF5: 0xC3CF, //HANGUL SYLLABLE SSANGSIOS YE SIOS + 0x9BF6: 0xC3D0, //HANGUL SYLLABLE SSANGSIOS YE SSANGSIOS + 0x9BF7: 0xC3D1, //HANGUL SYLLABLE SSANGSIOS YE IEUNG + 0x9BF8: 0xC3D2, //HANGUL SYLLABLE SSANGSIOS YE CIEUC + 0x9BF9: 0xC3D3, //HANGUL SYLLABLE SSANGSIOS YE CHIEUCH + 0x9BFA: 0xC3D4, //HANGUL SYLLABLE SSANGSIOS YE KHIEUKH + 0x9BFB: 0xC3D5, //HANGUL SYLLABLE SSANGSIOS YE THIEUTH + 0x9BFC: 0xC3D6, //HANGUL SYLLABLE SSANGSIOS YE PHIEUPH + 0x9BFD: 0xC3D7, //HANGUL SYLLABLE SSANGSIOS YE HIEUH + 0x9BFE: 0xC3DA, //HANGUL SYLLABLE SSANGSIOS O SSANGKIYEOK + 0x9C41: 0xC3DB, //HANGUL SYLLABLE SSANGSIOS O KIYEOKSIOS + 0x9C42: 0xC3DD, //HANGUL SYLLABLE SSANGSIOS O NIEUNCIEUC + 0x9C43: 0xC3DE, //HANGUL SYLLABLE SSANGSIOS O NIEUNHIEUH + 0x9C44: 0xC3E1, //HANGUL SYLLABLE SSANGSIOS O RIEULKIYEOK + 0x9C45: 0xC3E3, //HANGUL SYLLABLE SSANGSIOS O RIEULPIEUP + 0x9C46: 0xC3E4, //HANGUL SYLLABLE SSANGSIOS O RIEULSIOS + 0x9C47: 0xC3E5, //HANGUL SYLLABLE SSANGSIOS O RIEULTHIEUTH + 0x9C48: 0xC3E6, //HANGUL SYLLABLE SSANGSIOS O RIEULPHIEUPH + 0x9C49: 0xC3E7, //HANGUL SYLLABLE SSANGSIOS O RIEULHIEUH + 0x9C4A: 0xC3EA, //HANGUL SYLLABLE SSANGSIOS O PIEUPSIOS + 0x9C4B: 0xC3EB, //HANGUL SYLLABLE SSANGSIOS O SIOS + 0x9C4C: 0xC3EC, //HANGUL SYLLABLE SSANGSIOS O SSANGSIOS + 0x9C4D: 0xC3EE, //HANGUL SYLLABLE SSANGSIOS O CIEUC + 0x9C4E: 0xC3EF, //HANGUL SYLLABLE SSANGSIOS O CHIEUCH + 0x9C4F: 0xC3F0, //HANGUL SYLLABLE SSANGSIOS O KHIEUKH + 0x9C50: 0xC3F1, //HANGUL SYLLABLE SSANGSIOS O THIEUTH + 0x9C51: 0xC3F2, //HANGUL SYLLABLE SSANGSIOS O PHIEUPH + 0x9C52: 0xC3F3, //HANGUL SYLLABLE SSANGSIOS O HIEUH + 0x9C53: 0xC3F6, //HANGUL SYLLABLE SSANGSIOS WA SSANGKIYEOK + 0x9C54: 0xC3F7, //HANGUL SYLLABLE SSANGSIOS WA KIYEOKSIOS + 0x9C55: 0xC3F9, //HANGUL SYLLABLE SSANGSIOS WA NIEUNCIEUC + 0x9C56: 0xC3FA, //HANGUL SYLLABLE SSANGSIOS WA NIEUNHIEUH + 0x9C57: 0xC3FB, //HANGUL SYLLABLE SSANGSIOS WA TIKEUT + 0x9C58: 0xC3FC, //HANGUL SYLLABLE SSANGSIOS WA RIEUL + 0x9C59: 0xC3FD, //HANGUL SYLLABLE SSANGSIOS WA RIEULKIYEOK + 0x9C5A: 0xC3FE, //HANGUL SYLLABLE SSANGSIOS WA RIEULMIEUM + 0x9C61: 0xC3FF, //HANGUL SYLLABLE SSANGSIOS WA RIEULPIEUP + 0x9C62: 0xC400, //HANGUL SYLLABLE SSANGSIOS WA RIEULSIOS + 0x9C63: 0xC401, //HANGUL SYLLABLE SSANGSIOS WA RIEULTHIEUTH + 0x9C64: 0xC402, //HANGUL SYLLABLE SSANGSIOS WA RIEULPHIEUPH + 0x9C65: 0xC403, //HANGUL SYLLABLE SSANGSIOS WA RIEULHIEUH + 0x9C66: 0xC404, //HANGUL SYLLABLE SSANGSIOS WA MIEUM + 0x9C67: 0xC405, //HANGUL SYLLABLE SSANGSIOS WA PIEUP + 0x9C68: 0xC406, //HANGUL SYLLABLE SSANGSIOS WA PIEUPSIOS + 0x9C69: 0xC407, //HANGUL SYLLABLE SSANGSIOS WA SIOS + 0x9C6A: 0xC409, //HANGUL SYLLABLE SSANGSIOS WA IEUNG + 0x9C6B: 0xC40A, //HANGUL SYLLABLE SSANGSIOS WA CIEUC + 0x9C6C: 0xC40B, //HANGUL SYLLABLE SSANGSIOS WA CHIEUCH + 0x9C6D: 0xC40C, //HANGUL SYLLABLE SSANGSIOS WA KHIEUKH + 0x9C6E: 0xC40D, //HANGUL SYLLABLE SSANGSIOS WA THIEUTH + 0x9C6F: 0xC40E, //HANGUL SYLLABLE SSANGSIOS WA PHIEUPH + 0x9C70: 0xC40F, //HANGUL SYLLABLE SSANGSIOS WA HIEUH + 0x9C71: 0xC411, //HANGUL SYLLABLE SSANGSIOS WAE KIYEOK + 0x9C72: 0xC412, //HANGUL SYLLABLE SSANGSIOS WAE SSANGKIYEOK + 0x9C73: 0xC413, //HANGUL SYLLABLE SSANGSIOS WAE KIYEOKSIOS + 0x9C74: 0xC414, //HANGUL SYLLABLE SSANGSIOS WAE NIEUN + 0x9C75: 0xC415, //HANGUL SYLLABLE SSANGSIOS WAE NIEUNCIEUC + 0x9C76: 0xC416, //HANGUL SYLLABLE SSANGSIOS WAE NIEUNHIEUH + 0x9C77: 0xC417, //HANGUL SYLLABLE SSANGSIOS WAE TIKEUT + 0x9C78: 0xC418, //HANGUL SYLLABLE SSANGSIOS WAE RIEUL + 0x9C79: 0xC419, //HANGUL SYLLABLE SSANGSIOS WAE RIEULKIYEOK + 0x9C7A: 0xC41A, //HANGUL SYLLABLE SSANGSIOS WAE RIEULMIEUM + 0x9C81: 0xC41B, //HANGUL SYLLABLE SSANGSIOS WAE RIEULPIEUP + 0x9C82: 0xC41C, //HANGUL SYLLABLE SSANGSIOS WAE RIEULSIOS + 0x9C83: 0xC41D, //HANGUL SYLLABLE SSANGSIOS WAE RIEULTHIEUTH + 0x9C84: 0xC41E, //HANGUL SYLLABLE SSANGSIOS WAE RIEULPHIEUPH + 0x9C85: 0xC41F, //HANGUL SYLLABLE SSANGSIOS WAE RIEULHIEUH + 0x9C86: 0xC420, //HANGUL SYLLABLE SSANGSIOS WAE MIEUM + 0x9C87: 0xC421, //HANGUL SYLLABLE SSANGSIOS WAE PIEUP + 0x9C88: 0xC422, //HANGUL SYLLABLE SSANGSIOS WAE PIEUPSIOS + 0x9C89: 0xC423, //HANGUL SYLLABLE SSANGSIOS WAE SIOS + 0x9C8A: 0xC425, //HANGUL SYLLABLE SSANGSIOS WAE IEUNG + 0x9C8B: 0xC426, //HANGUL SYLLABLE SSANGSIOS WAE CIEUC + 0x9C8C: 0xC427, //HANGUL SYLLABLE SSANGSIOS WAE CHIEUCH + 0x9C8D: 0xC428, //HANGUL SYLLABLE SSANGSIOS WAE KHIEUKH + 0x9C8E: 0xC429, //HANGUL SYLLABLE SSANGSIOS WAE THIEUTH + 0x9C8F: 0xC42A, //HANGUL SYLLABLE SSANGSIOS WAE PHIEUPH + 0x9C90: 0xC42B, //HANGUL SYLLABLE SSANGSIOS WAE HIEUH + 0x9C91: 0xC42D, //HANGUL SYLLABLE SSANGSIOS OE KIYEOK + 0x9C92: 0xC42E, //HANGUL SYLLABLE SSANGSIOS OE SSANGKIYEOK + 0x9C93: 0xC42F, //HANGUL SYLLABLE SSANGSIOS OE KIYEOKSIOS + 0x9C94: 0xC431, //HANGUL SYLLABLE SSANGSIOS OE NIEUNCIEUC + 0x9C95: 0xC432, //HANGUL SYLLABLE SSANGSIOS OE NIEUNHIEUH + 0x9C96: 0xC433, //HANGUL SYLLABLE SSANGSIOS OE TIKEUT + 0x9C97: 0xC435, //HANGUL SYLLABLE SSANGSIOS OE RIEULKIYEOK + 0x9C98: 0xC436, //HANGUL SYLLABLE SSANGSIOS OE RIEULMIEUM + 0x9C99: 0xC437, //HANGUL SYLLABLE SSANGSIOS OE RIEULPIEUP + 0x9C9A: 0xC438, //HANGUL SYLLABLE SSANGSIOS OE RIEULSIOS + 0x9C9B: 0xC439, //HANGUL SYLLABLE SSANGSIOS OE RIEULTHIEUTH + 0x9C9C: 0xC43A, //HANGUL SYLLABLE SSANGSIOS OE RIEULPHIEUPH + 0x9C9D: 0xC43B, //HANGUL SYLLABLE SSANGSIOS OE RIEULHIEUH + 0x9C9E: 0xC43E, //HANGUL SYLLABLE SSANGSIOS OE PIEUPSIOS + 0x9C9F: 0xC43F, //HANGUL SYLLABLE SSANGSIOS OE SIOS + 0x9CA0: 0xC440, //HANGUL SYLLABLE SSANGSIOS OE SSANGSIOS + 0x9CA1: 0xC441, //HANGUL SYLLABLE SSANGSIOS OE IEUNG + 0x9CA2: 0xC442, //HANGUL SYLLABLE SSANGSIOS OE CIEUC + 0x9CA3: 0xC443, //HANGUL SYLLABLE SSANGSIOS OE CHIEUCH + 0x9CA4: 0xC444, //HANGUL SYLLABLE SSANGSIOS OE KHIEUKH + 0x9CA5: 0xC445, //HANGUL SYLLABLE SSANGSIOS OE THIEUTH + 0x9CA6: 0xC446, //HANGUL SYLLABLE SSANGSIOS OE PHIEUPH + 0x9CA7: 0xC447, //HANGUL SYLLABLE SSANGSIOS OE HIEUH + 0x9CA8: 0xC449, //HANGUL SYLLABLE SSANGSIOS YO KIYEOK + 0x9CA9: 0xC44A, //HANGUL SYLLABLE SSANGSIOS YO SSANGKIYEOK + 0x9CAA: 0xC44B, //HANGUL SYLLABLE SSANGSIOS YO KIYEOKSIOS + 0x9CAB: 0xC44C, //HANGUL SYLLABLE SSANGSIOS YO NIEUN + 0x9CAC: 0xC44D, //HANGUL SYLLABLE SSANGSIOS YO NIEUNCIEUC + 0x9CAD: 0xC44E, //HANGUL SYLLABLE SSANGSIOS YO NIEUNHIEUH + 0x9CAE: 0xC44F, //HANGUL SYLLABLE SSANGSIOS YO TIKEUT + 0x9CAF: 0xC450, //HANGUL SYLLABLE SSANGSIOS YO RIEUL + 0x9CB0: 0xC451, //HANGUL SYLLABLE SSANGSIOS YO RIEULKIYEOK + 0x9CB1: 0xC452, //HANGUL SYLLABLE SSANGSIOS YO RIEULMIEUM + 0x9CB2: 0xC453, //HANGUL SYLLABLE SSANGSIOS YO RIEULPIEUP + 0x9CB3: 0xC454, //HANGUL SYLLABLE SSANGSIOS YO RIEULSIOS + 0x9CB4: 0xC455, //HANGUL SYLLABLE SSANGSIOS YO RIEULTHIEUTH + 0x9CB5: 0xC456, //HANGUL SYLLABLE SSANGSIOS YO RIEULPHIEUPH + 0x9CB6: 0xC457, //HANGUL SYLLABLE SSANGSIOS YO RIEULHIEUH + 0x9CB7: 0xC458, //HANGUL SYLLABLE SSANGSIOS YO MIEUM + 0x9CB8: 0xC459, //HANGUL SYLLABLE SSANGSIOS YO PIEUP + 0x9CB9: 0xC45A, //HANGUL SYLLABLE SSANGSIOS YO PIEUPSIOS + 0x9CBA: 0xC45B, //HANGUL SYLLABLE SSANGSIOS YO SIOS + 0x9CBB: 0xC45C, //HANGUL SYLLABLE SSANGSIOS YO SSANGSIOS + 0x9CBC: 0xC45D, //HANGUL SYLLABLE SSANGSIOS YO IEUNG + 0x9CBD: 0xC45E, //HANGUL SYLLABLE SSANGSIOS YO CIEUC + 0x9CBE: 0xC45F, //HANGUL SYLLABLE SSANGSIOS YO CHIEUCH + 0x9CBF: 0xC460, //HANGUL SYLLABLE SSANGSIOS YO KHIEUKH + 0x9CC0: 0xC461, //HANGUL SYLLABLE SSANGSIOS YO THIEUTH + 0x9CC1: 0xC462, //HANGUL SYLLABLE SSANGSIOS YO PHIEUPH + 0x9CC2: 0xC463, //HANGUL SYLLABLE SSANGSIOS YO HIEUH + 0x9CC3: 0xC466, //HANGUL SYLLABLE SSANGSIOS U SSANGKIYEOK + 0x9CC4: 0xC467, //HANGUL SYLLABLE SSANGSIOS U KIYEOKSIOS + 0x9CC5: 0xC469, //HANGUL SYLLABLE SSANGSIOS U NIEUNCIEUC + 0x9CC6: 0xC46A, //HANGUL SYLLABLE SSANGSIOS U NIEUNHIEUH + 0x9CC7: 0xC46B, //HANGUL SYLLABLE SSANGSIOS U TIKEUT + 0x9CC8: 0xC46D, //HANGUL SYLLABLE SSANGSIOS U RIEULKIYEOK + 0x9CC9: 0xC46E, //HANGUL SYLLABLE SSANGSIOS U RIEULMIEUM + 0x9CCA: 0xC46F, //HANGUL SYLLABLE SSANGSIOS U RIEULPIEUP + 0x9CCB: 0xC470, //HANGUL SYLLABLE SSANGSIOS U RIEULSIOS + 0x9CCC: 0xC471, //HANGUL SYLLABLE SSANGSIOS U RIEULTHIEUTH + 0x9CCD: 0xC472, //HANGUL SYLLABLE SSANGSIOS U RIEULPHIEUPH + 0x9CCE: 0xC473, //HANGUL SYLLABLE SSANGSIOS U RIEULHIEUH + 0x9CCF: 0xC476, //HANGUL SYLLABLE SSANGSIOS U PIEUPSIOS + 0x9CD0: 0xC477, //HANGUL SYLLABLE SSANGSIOS U SIOS + 0x9CD1: 0xC478, //HANGUL SYLLABLE SSANGSIOS U SSANGSIOS + 0x9CD2: 0xC47A, //HANGUL SYLLABLE SSANGSIOS U CIEUC + 0x9CD3: 0xC47B, //HANGUL SYLLABLE SSANGSIOS U CHIEUCH + 0x9CD4: 0xC47C, //HANGUL SYLLABLE SSANGSIOS U KHIEUKH + 0x9CD5: 0xC47D, //HANGUL SYLLABLE SSANGSIOS U THIEUTH + 0x9CD6: 0xC47E, //HANGUL SYLLABLE SSANGSIOS U PHIEUPH + 0x9CD7: 0xC47F, //HANGUL SYLLABLE SSANGSIOS U HIEUH + 0x9CD8: 0xC481, //HANGUL SYLLABLE SSANGSIOS WEO KIYEOK + 0x9CD9: 0xC482, //HANGUL SYLLABLE SSANGSIOS WEO SSANGKIYEOK + 0x9CDA: 0xC483, //HANGUL SYLLABLE SSANGSIOS WEO KIYEOKSIOS + 0x9CDB: 0xC484, //HANGUL SYLLABLE SSANGSIOS WEO NIEUN + 0x9CDC: 0xC485, //HANGUL SYLLABLE SSANGSIOS WEO NIEUNCIEUC + 0x9CDD: 0xC486, //HANGUL SYLLABLE SSANGSIOS WEO NIEUNHIEUH + 0x9CDE: 0xC487, //HANGUL SYLLABLE SSANGSIOS WEO TIKEUT + 0x9CDF: 0xC488, //HANGUL SYLLABLE SSANGSIOS WEO RIEUL + 0x9CE0: 0xC489, //HANGUL SYLLABLE SSANGSIOS WEO RIEULKIYEOK + 0x9CE1: 0xC48A, //HANGUL SYLLABLE SSANGSIOS WEO RIEULMIEUM + 0x9CE2: 0xC48B, //HANGUL SYLLABLE SSANGSIOS WEO RIEULPIEUP + 0x9CE3: 0xC48C, //HANGUL SYLLABLE SSANGSIOS WEO RIEULSIOS + 0x9CE4: 0xC48D, //HANGUL SYLLABLE SSANGSIOS WEO RIEULTHIEUTH + 0x9CE5: 0xC48E, //HANGUL SYLLABLE SSANGSIOS WEO RIEULPHIEUPH + 0x9CE6: 0xC48F, //HANGUL SYLLABLE SSANGSIOS WEO RIEULHIEUH + 0x9CE7: 0xC490, //HANGUL SYLLABLE SSANGSIOS WEO MIEUM + 0x9CE8: 0xC491, //HANGUL SYLLABLE SSANGSIOS WEO PIEUP + 0x9CE9: 0xC492, //HANGUL SYLLABLE SSANGSIOS WEO PIEUPSIOS + 0x9CEA: 0xC493, //HANGUL SYLLABLE SSANGSIOS WEO SIOS + 0x9CEB: 0xC495, //HANGUL SYLLABLE SSANGSIOS WEO IEUNG + 0x9CEC: 0xC496, //HANGUL SYLLABLE SSANGSIOS WEO CIEUC + 0x9CED: 0xC497, //HANGUL SYLLABLE SSANGSIOS WEO CHIEUCH + 0x9CEE: 0xC498, //HANGUL SYLLABLE SSANGSIOS WEO KHIEUKH + 0x9CEF: 0xC499, //HANGUL SYLLABLE SSANGSIOS WEO THIEUTH + 0x9CF0: 0xC49A, //HANGUL SYLLABLE SSANGSIOS WEO PHIEUPH + 0x9CF1: 0xC49B, //HANGUL SYLLABLE SSANGSIOS WEO HIEUH + 0x9CF2: 0xC49D, //HANGUL SYLLABLE SSANGSIOS WE KIYEOK + 0x9CF3: 0xC49E, //HANGUL SYLLABLE SSANGSIOS WE SSANGKIYEOK + 0x9CF4: 0xC49F, //HANGUL SYLLABLE SSANGSIOS WE KIYEOKSIOS + 0x9CF5: 0xC4A0, //HANGUL SYLLABLE SSANGSIOS WE NIEUN + 0x9CF6: 0xC4A1, //HANGUL SYLLABLE SSANGSIOS WE NIEUNCIEUC + 0x9CF7: 0xC4A2, //HANGUL SYLLABLE SSANGSIOS WE NIEUNHIEUH + 0x9CF8: 0xC4A3, //HANGUL SYLLABLE SSANGSIOS WE TIKEUT + 0x9CF9: 0xC4A4, //HANGUL SYLLABLE SSANGSIOS WE RIEUL + 0x9CFA: 0xC4A5, //HANGUL SYLLABLE SSANGSIOS WE RIEULKIYEOK + 0x9CFB: 0xC4A6, //HANGUL SYLLABLE SSANGSIOS WE RIEULMIEUM + 0x9CFC: 0xC4A7, //HANGUL SYLLABLE SSANGSIOS WE RIEULPIEUP + 0x9CFD: 0xC4A8, //HANGUL SYLLABLE SSANGSIOS WE RIEULSIOS + 0x9CFE: 0xC4A9, //HANGUL SYLLABLE SSANGSIOS WE RIEULTHIEUTH + 0x9D41: 0xC4AA, //HANGUL SYLLABLE SSANGSIOS WE RIEULPHIEUPH + 0x9D42: 0xC4AB, //HANGUL SYLLABLE SSANGSIOS WE RIEULHIEUH + 0x9D43: 0xC4AC, //HANGUL SYLLABLE SSANGSIOS WE MIEUM + 0x9D44: 0xC4AD, //HANGUL SYLLABLE SSANGSIOS WE PIEUP + 0x9D45: 0xC4AE, //HANGUL SYLLABLE SSANGSIOS WE PIEUPSIOS + 0x9D46: 0xC4AF, //HANGUL SYLLABLE SSANGSIOS WE SIOS + 0x9D47: 0xC4B0, //HANGUL SYLLABLE SSANGSIOS WE SSANGSIOS + 0x9D48: 0xC4B1, //HANGUL SYLLABLE SSANGSIOS WE IEUNG + 0x9D49: 0xC4B2, //HANGUL SYLLABLE SSANGSIOS WE CIEUC + 0x9D4A: 0xC4B3, //HANGUL SYLLABLE SSANGSIOS WE CHIEUCH + 0x9D4B: 0xC4B4, //HANGUL SYLLABLE SSANGSIOS WE KHIEUKH + 0x9D4C: 0xC4B5, //HANGUL SYLLABLE SSANGSIOS WE THIEUTH + 0x9D4D: 0xC4B6, //HANGUL SYLLABLE SSANGSIOS WE PHIEUPH + 0x9D4E: 0xC4B7, //HANGUL SYLLABLE SSANGSIOS WE HIEUH + 0x9D4F: 0xC4B9, //HANGUL SYLLABLE SSANGSIOS WI KIYEOK + 0x9D50: 0xC4BA, //HANGUL SYLLABLE SSANGSIOS WI SSANGKIYEOK + 0x9D51: 0xC4BB, //HANGUL SYLLABLE SSANGSIOS WI KIYEOKSIOS + 0x9D52: 0xC4BD, //HANGUL SYLLABLE SSANGSIOS WI NIEUNCIEUC + 0x9D53: 0xC4BE, //HANGUL SYLLABLE SSANGSIOS WI NIEUNHIEUH + 0x9D54: 0xC4BF, //HANGUL SYLLABLE SSANGSIOS WI TIKEUT + 0x9D55: 0xC4C0, //HANGUL SYLLABLE SSANGSIOS WI RIEUL + 0x9D56: 0xC4C1, //HANGUL SYLLABLE SSANGSIOS WI RIEULKIYEOK + 0x9D57: 0xC4C2, //HANGUL SYLLABLE SSANGSIOS WI RIEULMIEUM + 0x9D58: 0xC4C3, //HANGUL SYLLABLE SSANGSIOS WI RIEULPIEUP + 0x9D59: 0xC4C4, //HANGUL SYLLABLE SSANGSIOS WI RIEULSIOS + 0x9D5A: 0xC4C5, //HANGUL SYLLABLE SSANGSIOS WI RIEULTHIEUTH + 0x9D61: 0xC4C6, //HANGUL SYLLABLE SSANGSIOS WI RIEULPHIEUPH + 0x9D62: 0xC4C7, //HANGUL SYLLABLE SSANGSIOS WI RIEULHIEUH + 0x9D63: 0xC4C8, //HANGUL SYLLABLE SSANGSIOS WI MIEUM + 0x9D64: 0xC4C9, //HANGUL SYLLABLE SSANGSIOS WI PIEUP + 0x9D65: 0xC4CA, //HANGUL SYLLABLE SSANGSIOS WI PIEUPSIOS + 0x9D66: 0xC4CB, //HANGUL SYLLABLE SSANGSIOS WI SIOS + 0x9D67: 0xC4CC, //HANGUL SYLLABLE SSANGSIOS WI SSANGSIOS + 0x9D68: 0xC4CD, //HANGUL SYLLABLE SSANGSIOS WI IEUNG + 0x9D69: 0xC4CE, //HANGUL SYLLABLE SSANGSIOS WI CIEUC + 0x9D6A: 0xC4CF, //HANGUL SYLLABLE SSANGSIOS WI CHIEUCH + 0x9D6B: 0xC4D0, //HANGUL SYLLABLE SSANGSIOS WI KHIEUKH + 0x9D6C: 0xC4D1, //HANGUL SYLLABLE SSANGSIOS WI THIEUTH + 0x9D6D: 0xC4D2, //HANGUL SYLLABLE SSANGSIOS WI PHIEUPH + 0x9D6E: 0xC4D3, //HANGUL SYLLABLE SSANGSIOS WI HIEUH + 0x9D6F: 0xC4D4, //HANGUL SYLLABLE SSANGSIOS YU + 0x9D70: 0xC4D5, //HANGUL SYLLABLE SSANGSIOS YU KIYEOK + 0x9D71: 0xC4D6, //HANGUL SYLLABLE SSANGSIOS YU SSANGKIYEOK + 0x9D72: 0xC4D7, //HANGUL SYLLABLE SSANGSIOS YU KIYEOKSIOS + 0x9D73: 0xC4D8, //HANGUL SYLLABLE SSANGSIOS YU NIEUN + 0x9D74: 0xC4D9, //HANGUL SYLLABLE SSANGSIOS YU NIEUNCIEUC + 0x9D75: 0xC4DA, //HANGUL SYLLABLE SSANGSIOS YU NIEUNHIEUH + 0x9D76: 0xC4DB, //HANGUL SYLLABLE SSANGSIOS YU TIKEUT + 0x9D77: 0xC4DC, //HANGUL SYLLABLE SSANGSIOS YU RIEUL + 0x9D78: 0xC4DD, //HANGUL SYLLABLE SSANGSIOS YU RIEULKIYEOK + 0x9D79: 0xC4DE, //HANGUL SYLLABLE SSANGSIOS YU RIEULMIEUM + 0x9D7A: 0xC4DF, //HANGUL SYLLABLE SSANGSIOS YU RIEULPIEUP + 0x9D81: 0xC4E0, //HANGUL SYLLABLE SSANGSIOS YU RIEULSIOS + 0x9D82: 0xC4E1, //HANGUL SYLLABLE SSANGSIOS YU RIEULTHIEUTH + 0x9D83: 0xC4E2, //HANGUL SYLLABLE SSANGSIOS YU RIEULPHIEUPH + 0x9D84: 0xC4E3, //HANGUL SYLLABLE SSANGSIOS YU RIEULHIEUH + 0x9D85: 0xC4E4, //HANGUL SYLLABLE SSANGSIOS YU MIEUM + 0x9D86: 0xC4E5, //HANGUL SYLLABLE SSANGSIOS YU PIEUP + 0x9D87: 0xC4E6, //HANGUL SYLLABLE SSANGSIOS YU PIEUPSIOS + 0x9D88: 0xC4E7, //HANGUL SYLLABLE SSANGSIOS YU SIOS + 0x9D89: 0xC4E8, //HANGUL SYLLABLE SSANGSIOS YU SSANGSIOS + 0x9D8A: 0xC4EA, //HANGUL SYLLABLE SSANGSIOS YU CIEUC + 0x9D8B: 0xC4EB, //HANGUL SYLLABLE SSANGSIOS YU CHIEUCH + 0x9D8C: 0xC4EC, //HANGUL SYLLABLE SSANGSIOS YU KHIEUKH + 0x9D8D: 0xC4ED, //HANGUL SYLLABLE SSANGSIOS YU THIEUTH + 0x9D8E: 0xC4EE, //HANGUL SYLLABLE SSANGSIOS YU PHIEUPH + 0x9D8F: 0xC4EF, //HANGUL SYLLABLE SSANGSIOS YU HIEUH + 0x9D90: 0xC4F2, //HANGUL SYLLABLE SSANGSIOS EU SSANGKIYEOK + 0x9D91: 0xC4F3, //HANGUL SYLLABLE SSANGSIOS EU KIYEOKSIOS + 0x9D92: 0xC4F5, //HANGUL SYLLABLE SSANGSIOS EU NIEUNCIEUC + 0x9D93: 0xC4F6, //HANGUL SYLLABLE SSANGSIOS EU NIEUNHIEUH + 0x9D94: 0xC4F7, //HANGUL SYLLABLE SSANGSIOS EU TIKEUT + 0x9D95: 0xC4F9, //HANGUL SYLLABLE SSANGSIOS EU RIEULKIYEOK + 0x9D96: 0xC4FB, //HANGUL SYLLABLE SSANGSIOS EU RIEULPIEUP + 0x9D97: 0xC4FC, //HANGUL SYLLABLE SSANGSIOS EU RIEULSIOS + 0x9D98: 0xC4FD, //HANGUL SYLLABLE SSANGSIOS EU RIEULTHIEUTH + 0x9D99: 0xC4FE, //HANGUL SYLLABLE SSANGSIOS EU RIEULPHIEUPH + 0x9D9A: 0xC502, //HANGUL SYLLABLE SSANGSIOS EU PIEUPSIOS + 0x9D9B: 0xC503, //HANGUL SYLLABLE SSANGSIOS EU SIOS + 0x9D9C: 0xC504, //HANGUL SYLLABLE SSANGSIOS EU SSANGSIOS + 0x9D9D: 0xC505, //HANGUL SYLLABLE SSANGSIOS EU IEUNG + 0x9D9E: 0xC506, //HANGUL SYLLABLE SSANGSIOS EU CIEUC + 0x9D9F: 0xC507, //HANGUL SYLLABLE SSANGSIOS EU CHIEUCH + 0x9DA0: 0xC508, //HANGUL SYLLABLE SSANGSIOS EU KHIEUKH + 0x9DA1: 0xC509, //HANGUL SYLLABLE SSANGSIOS EU THIEUTH + 0x9DA2: 0xC50A, //HANGUL SYLLABLE SSANGSIOS EU PHIEUPH + 0x9DA3: 0xC50B, //HANGUL SYLLABLE SSANGSIOS EU HIEUH + 0x9DA4: 0xC50D, //HANGUL SYLLABLE SSANGSIOS YI KIYEOK + 0x9DA5: 0xC50E, //HANGUL SYLLABLE SSANGSIOS YI SSANGKIYEOK + 0x9DA6: 0xC50F, //HANGUL SYLLABLE SSANGSIOS YI KIYEOKSIOS + 0x9DA7: 0xC511, //HANGUL SYLLABLE SSANGSIOS YI NIEUNCIEUC + 0x9DA8: 0xC512, //HANGUL SYLLABLE SSANGSIOS YI NIEUNHIEUH + 0x9DA9: 0xC513, //HANGUL SYLLABLE SSANGSIOS YI TIKEUT + 0x9DAA: 0xC515, //HANGUL SYLLABLE SSANGSIOS YI RIEULKIYEOK + 0x9DAB: 0xC516, //HANGUL SYLLABLE SSANGSIOS YI RIEULMIEUM + 0x9DAC: 0xC517, //HANGUL SYLLABLE SSANGSIOS YI RIEULPIEUP + 0x9DAD: 0xC518, //HANGUL SYLLABLE SSANGSIOS YI RIEULSIOS + 0x9DAE: 0xC519, //HANGUL SYLLABLE SSANGSIOS YI RIEULTHIEUTH + 0x9DAF: 0xC51A, //HANGUL SYLLABLE SSANGSIOS YI RIEULPHIEUPH + 0x9DB0: 0xC51B, //HANGUL SYLLABLE SSANGSIOS YI RIEULHIEUH + 0x9DB1: 0xC51D, //HANGUL SYLLABLE SSANGSIOS YI PIEUP + 0x9DB2: 0xC51E, //HANGUL SYLLABLE SSANGSIOS YI PIEUPSIOS + 0x9DB3: 0xC51F, //HANGUL SYLLABLE SSANGSIOS YI SIOS + 0x9DB4: 0xC520, //HANGUL SYLLABLE SSANGSIOS YI SSANGSIOS + 0x9DB5: 0xC521, //HANGUL SYLLABLE SSANGSIOS YI IEUNG + 0x9DB6: 0xC522, //HANGUL SYLLABLE SSANGSIOS YI CIEUC + 0x9DB7: 0xC523, //HANGUL SYLLABLE SSANGSIOS YI CHIEUCH + 0x9DB8: 0xC524, //HANGUL SYLLABLE SSANGSIOS YI KHIEUKH + 0x9DB9: 0xC525, //HANGUL SYLLABLE SSANGSIOS YI THIEUTH + 0x9DBA: 0xC526, //HANGUL SYLLABLE SSANGSIOS YI PHIEUPH + 0x9DBB: 0xC527, //HANGUL SYLLABLE SSANGSIOS YI HIEUH + 0x9DBC: 0xC52A, //HANGUL SYLLABLE SSANGSIOS I SSANGKIYEOK + 0x9DBD: 0xC52B, //HANGUL SYLLABLE SSANGSIOS I KIYEOKSIOS + 0x9DBE: 0xC52D, //HANGUL SYLLABLE SSANGSIOS I NIEUNCIEUC + 0x9DBF: 0xC52E, //HANGUL SYLLABLE SSANGSIOS I NIEUNHIEUH + 0x9DC0: 0xC52F, //HANGUL SYLLABLE SSANGSIOS I TIKEUT + 0x9DC1: 0xC531, //HANGUL SYLLABLE SSANGSIOS I RIEULKIYEOK + 0x9DC2: 0xC532, //HANGUL SYLLABLE SSANGSIOS I RIEULMIEUM + 0x9DC3: 0xC533, //HANGUL SYLLABLE SSANGSIOS I RIEULPIEUP + 0x9DC4: 0xC534, //HANGUL SYLLABLE SSANGSIOS I RIEULSIOS + 0x9DC5: 0xC535, //HANGUL SYLLABLE SSANGSIOS I RIEULTHIEUTH + 0x9DC6: 0xC536, //HANGUL SYLLABLE SSANGSIOS I RIEULPHIEUPH + 0x9DC7: 0xC537, //HANGUL SYLLABLE SSANGSIOS I RIEULHIEUH + 0x9DC8: 0xC53A, //HANGUL SYLLABLE SSANGSIOS I PIEUPSIOS + 0x9DC9: 0xC53C, //HANGUL SYLLABLE SSANGSIOS I SSANGSIOS + 0x9DCA: 0xC53E, //HANGUL SYLLABLE SSANGSIOS I CIEUC + 0x9DCB: 0xC53F, //HANGUL SYLLABLE SSANGSIOS I CHIEUCH + 0x9DCC: 0xC540, //HANGUL SYLLABLE SSANGSIOS I KHIEUKH + 0x9DCD: 0xC541, //HANGUL SYLLABLE SSANGSIOS I THIEUTH + 0x9DCE: 0xC542, //HANGUL SYLLABLE SSANGSIOS I PHIEUPH + 0x9DCF: 0xC543, //HANGUL SYLLABLE SSANGSIOS I HIEUH + 0x9DD0: 0xC546, //HANGUL SYLLABLE IEUNG A SSANGKIYEOK + 0x9DD1: 0xC547, //HANGUL SYLLABLE IEUNG A KIYEOKSIOS + 0x9DD2: 0xC54B, //HANGUL SYLLABLE IEUNG A TIKEUT + 0x9DD3: 0xC54F, //HANGUL SYLLABLE IEUNG A RIEULPIEUP + 0x9DD4: 0xC550, //HANGUL SYLLABLE IEUNG A RIEULSIOS + 0x9DD5: 0xC551, //HANGUL SYLLABLE IEUNG A RIEULTHIEUTH + 0x9DD6: 0xC552, //HANGUL SYLLABLE IEUNG A RIEULPHIEUPH + 0x9DD7: 0xC556, //HANGUL SYLLABLE IEUNG A PIEUPSIOS + 0x9DD8: 0xC55A, //HANGUL SYLLABLE IEUNG A CIEUC + 0x9DD9: 0xC55B, //HANGUL SYLLABLE IEUNG A CHIEUCH + 0x9DDA: 0xC55C, //HANGUL SYLLABLE IEUNG A KHIEUKH + 0x9DDB: 0xC55F, //HANGUL SYLLABLE IEUNG A HIEUH + 0x9DDC: 0xC562, //HANGUL SYLLABLE IEUNG AE SSANGKIYEOK + 0x9DDD: 0xC563, //HANGUL SYLLABLE IEUNG AE KIYEOKSIOS + 0x9DDE: 0xC565, //HANGUL SYLLABLE IEUNG AE NIEUNCIEUC + 0x9DDF: 0xC566, //HANGUL SYLLABLE IEUNG AE NIEUNHIEUH + 0x9DE0: 0xC567, //HANGUL SYLLABLE IEUNG AE TIKEUT + 0x9DE1: 0xC569, //HANGUL SYLLABLE IEUNG AE RIEULKIYEOK + 0x9DE2: 0xC56A, //HANGUL SYLLABLE IEUNG AE RIEULMIEUM + 0x9DE3: 0xC56B, //HANGUL SYLLABLE IEUNG AE RIEULPIEUP + 0x9DE4: 0xC56C, //HANGUL SYLLABLE IEUNG AE RIEULSIOS + 0x9DE5: 0xC56D, //HANGUL SYLLABLE IEUNG AE RIEULTHIEUTH + 0x9DE6: 0xC56E, //HANGUL SYLLABLE IEUNG AE RIEULPHIEUPH + 0x9DE7: 0xC56F, //HANGUL SYLLABLE IEUNG AE RIEULHIEUH + 0x9DE8: 0xC572, //HANGUL SYLLABLE IEUNG AE PIEUPSIOS + 0x9DE9: 0xC576, //HANGUL SYLLABLE IEUNG AE CIEUC + 0x9DEA: 0xC577, //HANGUL SYLLABLE IEUNG AE CHIEUCH + 0x9DEB: 0xC578, //HANGUL SYLLABLE IEUNG AE KHIEUKH + 0x9DEC: 0xC579, //HANGUL SYLLABLE IEUNG AE THIEUTH + 0x9DED: 0xC57A, //HANGUL SYLLABLE IEUNG AE PHIEUPH + 0x9DEE: 0xC57B, //HANGUL SYLLABLE IEUNG AE HIEUH + 0x9DEF: 0xC57E, //HANGUL SYLLABLE IEUNG YA SSANGKIYEOK + 0x9DF0: 0xC57F, //HANGUL SYLLABLE IEUNG YA KIYEOKSIOS + 0x9DF1: 0xC581, //HANGUL SYLLABLE IEUNG YA NIEUNCIEUC + 0x9DF2: 0xC582, //HANGUL SYLLABLE IEUNG YA NIEUNHIEUH + 0x9DF3: 0xC583, //HANGUL SYLLABLE IEUNG YA TIKEUT + 0x9DF4: 0xC585, //HANGUL SYLLABLE IEUNG YA RIEULKIYEOK + 0x9DF5: 0xC586, //HANGUL SYLLABLE IEUNG YA RIEULMIEUM + 0x9DF6: 0xC588, //HANGUL SYLLABLE IEUNG YA RIEULSIOS + 0x9DF7: 0xC589, //HANGUL SYLLABLE IEUNG YA RIEULTHIEUTH + 0x9DF8: 0xC58A, //HANGUL SYLLABLE IEUNG YA RIEULPHIEUPH + 0x9DF9: 0xC58B, //HANGUL SYLLABLE IEUNG YA RIEULHIEUH + 0x9DFA: 0xC58E, //HANGUL SYLLABLE IEUNG YA PIEUPSIOS + 0x9DFB: 0xC590, //HANGUL SYLLABLE IEUNG YA SSANGSIOS + 0x9DFC: 0xC592, //HANGUL SYLLABLE IEUNG YA CIEUC + 0x9DFD: 0xC593, //HANGUL SYLLABLE IEUNG YA CHIEUCH + 0x9DFE: 0xC594, //HANGUL SYLLABLE IEUNG YA KHIEUKH + 0x9E41: 0xC596, //HANGUL SYLLABLE IEUNG YA PHIEUPH + 0x9E42: 0xC599, //HANGUL SYLLABLE IEUNG YAE KIYEOK + 0x9E43: 0xC59A, //HANGUL SYLLABLE IEUNG YAE SSANGKIYEOK + 0x9E44: 0xC59B, //HANGUL SYLLABLE IEUNG YAE KIYEOKSIOS + 0x9E45: 0xC59D, //HANGUL SYLLABLE IEUNG YAE NIEUNCIEUC + 0x9E46: 0xC59E, //HANGUL SYLLABLE IEUNG YAE NIEUNHIEUH + 0x9E47: 0xC59F, //HANGUL SYLLABLE IEUNG YAE TIKEUT + 0x9E48: 0xC5A1, //HANGUL SYLLABLE IEUNG YAE RIEULKIYEOK + 0x9E49: 0xC5A2, //HANGUL SYLLABLE IEUNG YAE RIEULMIEUM + 0x9E4A: 0xC5A3, //HANGUL SYLLABLE IEUNG YAE RIEULPIEUP + 0x9E4B: 0xC5A4, //HANGUL SYLLABLE IEUNG YAE RIEULSIOS + 0x9E4C: 0xC5A5, //HANGUL SYLLABLE IEUNG YAE RIEULTHIEUTH + 0x9E4D: 0xC5A6, //HANGUL SYLLABLE IEUNG YAE RIEULPHIEUPH + 0x9E4E: 0xC5A7, //HANGUL SYLLABLE IEUNG YAE RIEULHIEUH + 0x9E4F: 0xC5A8, //HANGUL SYLLABLE IEUNG YAE MIEUM + 0x9E50: 0xC5AA, //HANGUL SYLLABLE IEUNG YAE PIEUPSIOS + 0x9E51: 0xC5AB, //HANGUL SYLLABLE IEUNG YAE SIOS + 0x9E52: 0xC5AC, //HANGUL SYLLABLE IEUNG YAE SSANGSIOS + 0x9E53: 0xC5AD, //HANGUL SYLLABLE IEUNG YAE IEUNG + 0x9E54: 0xC5AE, //HANGUL SYLLABLE IEUNG YAE CIEUC + 0x9E55: 0xC5AF, //HANGUL SYLLABLE IEUNG YAE CHIEUCH + 0x9E56: 0xC5B0, //HANGUL SYLLABLE IEUNG YAE KHIEUKH + 0x9E57: 0xC5B1, //HANGUL SYLLABLE IEUNG YAE THIEUTH + 0x9E58: 0xC5B2, //HANGUL SYLLABLE IEUNG YAE PHIEUPH + 0x9E59: 0xC5B3, //HANGUL SYLLABLE IEUNG YAE HIEUH + 0x9E5A: 0xC5B6, //HANGUL SYLLABLE IEUNG EO SSANGKIYEOK + 0x9E61: 0xC5B7, //HANGUL SYLLABLE IEUNG EO KIYEOKSIOS + 0x9E62: 0xC5BA, //HANGUL SYLLABLE IEUNG EO NIEUNHIEUH + 0x9E63: 0xC5BF, //HANGUL SYLLABLE IEUNG EO RIEULPIEUP + 0x9E64: 0xC5C0, //HANGUL SYLLABLE IEUNG EO RIEULSIOS + 0x9E65: 0xC5C1, //HANGUL SYLLABLE IEUNG EO RIEULTHIEUTH + 0x9E66: 0xC5C2, //HANGUL SYLLABLE IEUNG EO RIEULPHIEUPH + 0x9E67: 0xC5C3, //HANGUL SYLLABLE IEUNG EO RIEULHIEUH + 0x9E68: 0xC5CB, //HANGUL SYLLABLE IEUNG EO CHIEUCH + 0x9E69: 0xC5CD, //HANGUL SYLLABLE IEUNG EO THIEUTH + 0x9E6A: 0xC5CF, //HANGUL SYLLABLE IEUNG EO HIEUH + 0x9E6B: 0xC5D2, //HANGUL SYLLABLE IEUNG E SSANGKIYEOK + 0x9E6C: 0xC5D3, //HANGUL SYLLABLE IEUNG E KIYEOKSIOS + 0x9E6D: 0xC5D5, //HANGUL SYLLABLE IEUNG E NIEUNCIEUC + 0x9E6E: 0xC5D6, //HANGUL SYLLABLE IEUNG E NIEUNHIEUH + 0x9E6F: 0xC5D7, //HANGUL SYLLABLE IEUNG E TIKEUT + 0x9E70: 0xC5D9, //HANGUL SYLLABLE IEUNG E RIEULKIYEOK + 0x9E71: 0xC5DA, //HANGUL SYLLABLE IEUNG E RIEULMIEUM + 0x9E72: 0xC5DB, //HANGUL SYLLABLE IEUNG E RIEULPIEUP + 0x9E73: 0xC5DC, //HANGUL SYLLABLE IEUNG E RIEULSIOS + 0x9E74: 0xC5DD, //HANGUL SYLLABLE IEUNG E RIEULTHIEUTH + 0x9E75: 0xC5DE, //HANGUL SYLLABLE IEUNG E RIEULPHIEUPH + 0x9E76: 0xC5DF, //HANGUL SYLLABLE IEUNG E RIEULHIEUH + 0x9E77: 0xC5E2, //HANGUL SYLLABLE IEUNG E PIEUPSIOS + 0x9E78: 0xC5E4, //HANGUL SYLLABLE IEUNG E SSANGSIOS + 0x9E79: 0xC5E6, //HANGUL SYLLABLE IEUNG E CIEUC + 0x9E7A: 0xC5E7, //HANGUL SYLLABLE IEUNG E CHIEUCH + 0x9E81: 0xC5E8, //HANGUL SYLLABLE IEUNG E KHIEUKH + 0x9E82: 0xC5E9, //HANGUL SYLLABLE IEUNG E THIEUTH + 0x9E83: 0xC5EA, //HANGUL SYLLABLE IEUNG E PHIEUPH + 0x9E84: 0xC5EB, //HANGUL SYLLABLE IEUNG E HIEUH + 0x9E85: 0xC5EF, //HANGUL SYLLABLE IEUNG YEO KIYEOKSIOS + 0x9E86: 0xC5F1, //HANGUL SYLLABLE IEUNG YEO NIEUNCIEUC + 0x9E87: 0xC5F2, //HANGUL SYLLABLE IEUNG YEO NIEUNHIEUH + 0x9E88: 0xC5F3, //HANGUL SYLLABLE IEUNG YEO TIKEUT + 0x9E89: 0xC5F5, //HANGUL SYLLABLE IEUNG YEO RIEULKIYEOK + 0x9E8A: 0xC5F8, //HANGUL SYLLABLE IEUNG YEO RIEULSIOS + 0x9E8B: 0xC5F9, //HANGUL SYLLABLE IEUNG YEO RIEULTHIEUTH + 0x9E8C: 0xC5FA, //HANGUL SYLLABLE IEUNG YEO RIEULPHIEUPH + 0x9E8D: 0xC5FB, //HANGUL SYLLABLE IEUNG YEO RIEULHIEUH + 0x9E8E: 0xC602, //HANGUL SYLLABLE IEUNG YEO CIEUC + 0x9E8F: 0xC603, //HANGUL SYLLABLE IEUNG YEO CHIEUCH + 0x9E90: 0xC604, //HANGUL SYLLABLE IEUNG YEO KHIEUKH + 0x9E91: 0xC609, //HANGUL SYLLABLE IEUNG YE KIYEOK + 0x9E92: 0xC60A, //HANGUL SYLLABLE IEUNG YE SSANGKIYEOK + 0x9E93: 0xC60B, //HANGUL SYLLABLE IEUNG YE KIYEOKSIOS + 0x9E94: 0xC60D, //HANGUL SYLLABLE IEUNG YE NIEUNCIEUC + 0x9E95: 0xC60E, //HANGUL SYLLABLE IEUNG YE NIEUNHIEUH + 0x9E96: 0xC60F, //HANGUL SYLLABLE IEUNG YE TIKEUT + 0x9E97: 0xC611, //HANGUL SYLLABLE IEUNG YE RIEULKIYEOK + 0x9E98: 0xC612, //HANGUL SYLLABLE IEUNG YE RIEULMIEUM + 0x9E99: 0xC613, //HANGUL SYLLABLE IEUNG YE RIEULPIEUP + 0x9E9A: 0xC614, //HANGUL SYLLABLE IEUNG YE RIEULSIOS + 0x9E9B: 0xC615, //HANGUL SYLLABLE IEUNG YE RIEULTHIEUTH + 0x9E9C: 0xC616, //HANGUL SYLLABLE IEUNG YE RIEULPHIEUPH + 0x9E9D: 0xC617, //HANGUL SYLLABLE IEUNG YE RIEULHIEUH + 0x9E9E: 0xC61A, //HANGUL SYLLABLE IEUNG YE PIEUPSIOS + 0x9E9F: 0xC61D, //HANGUL SYLLABLE IEUNG YE IEUNG + 0x9EA0: 0xC61E, //HANGUL SYLLABLE IEUNG YE CIEUC + 0x9EA1: 0xC61F, //HANGUL SYLLABLE IEUNG YE CHIEUCH + 0x9EA2: 0xC620, //HANGUL SYLLABLE IEUNG YE KHIEUKH + 0x9EA3: 0xC621, //HANGUL SYLLABLE IEUNG YE THIEUTH + 0x9EA4: 0xC622, //HANGUL SYLLABLE IEUNG YE PHIEUPH + 0x9EA5: 0xC623, //HANGUL SYLLABLE IEUNG YE HIEUH + 0x9EA6: 0xC626, //HANGUL SYLLABLE IEUNG O SSANGKIYEOK + 0x9EA7: 0xC627, //HANGUL SYLLABLE IEUNG O KIYEOKSIOS + 0x9EA8: 0xC629, //HANGUL SYLLABLE IEUNG O NIEUNCIEUC + 0x9EA9: 0xC62A, //HANGUL SYLLABLE IEUNG O NIEUNHIEUH + 0x9EAA: 0xC62B, //HANGUL SYLLABLE IEUNG O TIKEUT + 0x9EAB: 0xC62F, //HANGUL SYLLABLE IEUNG O RIEULPIEUP + 0x9EAC: 0xC631, //HANGUL SYLLABLE IEUNG O RIEULTHIEUTH + 0x9EAD: 0xC632, //HANGUL SYLLABLE IEUNG O RIEULPHIEUPH + 0x9EAE: 0xC636, //HANGUL SYLLABLE IEUNG O PIEUPSIOS + 0x9EAF: 0xC638, //HANGUL SYLLABLE IEUNG O SSANGSIOS + 0x9EB0: 0xC63A, //HANGUL SYLLABLE IEUNG O CIEUC + 0x9EB1: 0xC63C, //HANGUL SYLLABLE IEUNG O KHIEUKH + 0x9EB2: 0xC63D, //HANGUL SYLLABLE IEUNG O THIEUTH + 0x9EB3: 0xC63E, //HANGUL SYLLABLE IEUNG O PHIEUPH + 0x9EB4: 0xC63F, //HANGUL SYLLABLE IEUNG O HIEUH + 0x9EB5: 0xC642, //HANGUL SYLLABLE IEUNG WA SSANGKIYEOK + 0x9EB6: 0xC643, //HANGUL SYLLABLE IEUNG WA KIYEOKSIOS + 0x9EB7: 0xC645, //HANGUL SYLLABLE IEUNG WA NIEUNCIEUC + 0x9EB8: 0xC646, //HANGUL SYLLABLE IEUNG WA NIEUNHIEUH + 0x9EB9: 0xC647, //HANGUL SYLLABLE IEUNG WA TIKEUT + 0x9EBA: 0xC649, //HANGUL SYLLABLE IEUNG WA RIEULKIYEOK + 0x9EBB: 0xC64A, //HANGUL SYLLABLE IEUNG WA RIEULMIEUM + 0x9EBC: 0xC64B, //HANGUL SYLLABLE IEUNG WA RIEULPIEUP + 0x9EBD: 0xC64C, //HANGUL SYLLABLE IEUNG WA RIEULSIOS + 0x9EBE: 0xC64D, //HANGUL SYLLABLE IEUNG WA RIEULTHIEUTH + 0x9EBF: 0xC64E, //HANGUL SYLLABLE IEUNG WA RIEULPHIEUPH + 0x9EC0: 0xC64F, //HANGUL SYLLABLE IEUNG WA RIEULHIEUH + 0x9EC1: 0xC652, //HANGUL SYLLABLE IEUNG WA PIEUPSIOS + 0x9EC2: 0xC656, //HANGUL SYLLABLE IEUNG WA CIEUC + 0x9EC3: 0xC657, //HANGUL SYLLABLE IEUNG WA CHIEUCH + 0x9EC4: 0xC658, //HANGUL SYLLABLE IEUNG WA KHIEUKH + 0x9EC5: 0xC659, //HANGUL SYLLABLE IEUNG WA THIEUTH + 0x9EC6: 0xC65A, //HANGUL SYLLABLE IEUNG WA PHIEUPH + 0x9EC7: 0xC65B, //HANGUL SYLLABLE IEUNG WA HIEUH + 0x9EC8: 0xC65E, //HANGUL SYLLABLE IEUNG WAE SSANGKIYEOK + 0x9EC9: 0xC65F, //HANGUL SYLLABLE IEUNG WAE KIYEOKSIOS + 0x9ECA: 0xC661, //HANGUL SYLLABLE IEUNG WAE NIEUNCIEUC + 0x9ECB: 0xC662, //HANGUL SYLLABLE IEUNG WAE NIEUNHIEUH + 0x9ECC: 0xC663, //HANGUL SYLLABLE IEUNG WAE TIKEUT + 0x9ECD: 0xC664, //HANGUL SYLLABLE IEUNG WAE RIEUL + 0x9ECE: 0xC665, //HANGUL SYLLABLE IEUNG WAE RIEULKIYEOK + 0x9ECF: 0xC666, //HANGUL SYLLABLE IEUNG WAE RIEULMIEUM + 0x9ED0: 0xC667, //HANGUL SYLLABLE IEUNG WAE RIEULPIEUP + 0x9ED1: 0xC668, //HANGUL SYLLABLE IEUNG WAE RIEULSIOS + 0x9ED2: 0xC669, //HANGUL SYLLABLE IEUNG WAE RIEULTHIEUTH + 0x9ED3: 0xC66A, //HANGUL SYLLABLE IEUNG WAE RIEULPHIEUPH + 0x9ED4: 0xC66B, //HANGUL SYLLABLE IEUNG WAE RIEULHIEUH + 0x9ED5: 0xC66D, //HANGUL SYLLABLE IEUNG WAE PIEUP + 0x9ED6: 0xC66E, //HANGUL SYLLABLE IEUNG WAE PIEUPSIOS + 0x9ED7: 0xC670, //HANGUL SYLLABLE IEUNG WAE SSANGSIOS + 0x9ED8: 0xC672, //HANGUL SYLLABLE IEUNG WAE CIEUC + 0x9ED9: 0xC673, //HANGUL SYLLABLE IEUNG WAE CHIEUCH + 0x9EDA: 0xC674, //HANGUL SYLLABLE IEUNG WAE KHIEUKH + 0x9EDB: 0xC675, //HANGUL SYLLABLE IEUNG WAE THIEUTH + 0x9EDC: 0xC676, //HANGUL SYLLABLE IEUNG WAE PHIEUPH + 0x9EDD: 0xC677, //HANGUL SYLLABLE IEUNG WAE HIEUH + 0x9EDE: 0xC67A, //HANGUL SYLLABLE IEUNG OE SSANGKIYEOK + 0x9EDF: 0xC67B, //HANGUL SYLLABLE IEUNG OE KIYEOKSIOS + 0x9EE0: 0xC67D, //HANGUL SYLLABLE IEUNG OE NIEUNCIEUC + 0x9EE1: 0xC67E, //HANGUL SYLLABLE IEUNG OE NIEUNHIEUH + 0x9EE2: 0xC67F, //HANGUL SYLLABLE IEUNG OE TIKEUT + 0x9EE3: 0xC681, //HANGUL SYLLABLE IEUNG OE RIEULKIYEOK + 0x9EE4: 0xC682, //HANGUL SYLLABLE IEUNG OE RIEULMIEUM + 0x9EE5: 0xC683, //HANGUL SYLLABLE IEUNG OE RIEULPIEUP + 0x9EE6: 0xC684, //HANGUL SYLLABLE IEUNG OE RIEULSIOS + 0x9EE7: 0xC685, //HANGUL SYLLABLE IEUNG OE RIEULTHIEUTH + 0x9EE8: 0xC686, //HANGUL SYLLABLE IEUNG OE RIEULPHIEUPH + 0x9EE9: 0xC687, //HANGUL SYLLABLE IEUNG OE RIEULHIEUH + 0x9EEA: 0xC68A, //HANGUL SYLLABLE IEUNG OE PIEUPSIOS + 0x9EEB: 0xC68C, //HANGUL SYLLABLE IEUNG OE SSANGSIOS + 0x9EEC: 0xC68E, //HANGUL SYLLABLE IEUNG OE CIEUC + 0x9EED: 0xC68F, //HANGUL SYLLABLE IEUNG OE CHIEUCH + 0x9EEE: 0xC690, //HANGUL SYLLABLE IEUNG OE KHIEUKH + 0x9EEF: 0xC691, //HANGUL SYLLABLE IEUNG OE THIEUTH + 0x9EF0: 0xC692, //HANGUL SYLLABLE IEUNG OE PHIEUPH + 0x9EF1: 0xC693, //HANGUL SYLLABLE IEUNG OE HIEUH + 0x9EF2: 0xC696, //HANGUL SYLLABLE IEUNG YO SSANGKIYEOK + 0x9EF3: 0xC697, //HANGUL SYLLABLE IEUNG YO KIYEOKSIOS + 0x9EF4: 0xC699, //HANGUL SYLLABLE IEUNG YO NIEUNCIEUC + 0x9EF5: 0xC69A, //HANGUL SYLLABLE IEUNG YO NIEUNHIEUH + 0x9EF6: 0xC69B, //HANGUL SYLLABLE IEUNG YO TIKEUT + 0x9EF7: 0xC69D, //HANGUL SYLLABLE IEUNG YO RIEULKIYEOK + 0x9EF8: 0xC69E, //HANGUL SYLLABLE IEUNG YO RIEULMIEUM + 0x9EF9: 0xC69F, //HANGUL SYLLABLE IEUNG YO RIEULPIEUP + 0x9EFA: 0xC6A0, //HANGUL SYLLABLE IEUNG YO RIEULSIOS + 0x9EFB: 0xC6A1, //HANGUL SYLLABLE IEUNG YO RIEULTHIEUTH + 0x9EFC: 0xC6A2, //HANGUL SYLLABLE IEUNG YO RIEULPHIEUPH + 0x9EFD: 0xC6A3, //HANGUL SYLLABLE IEUNG YO RIEULHIEUH + 0x9EFE: 0xC6A6, //HANGUL SYLLABLE IEUNG YO PIEUPSIOS + 0x9F41: 0xC6A8, //HANGUL SYLLABLE IEUNG YO SSANGSIOS + 0x9F42: 0xC6AA, //HANGUL SYLLABLE IEUNG YO CIEUC + 0x9F43: 0xC6AB, //HANGUL SYLLABLE IEUNG YO CHIEUCH + 0x9F44: 0xC6AC, //HANGUL SYLLABLE IEUNG YO KHIEUKH + 0x9F45: 0xC6AD, //HANGUL SYLLABLE IEUNG YO THIEUTH + 0x9F46: 0xC6AE, //HANGUL SYLLABLE IEUNG YO PHIEUPH + 0x9F47: 0xC6AF, //HANGUL SYLLABLE IEUNG YO HIEUH + 0x9F48: 0xC6B2, //HANGUL SYLLABLE IEUNG U SSANGKIYEOK + 0x9F49: 0xC6B3, //HANGUL SYLLABLE IEUNG U KIYEOKSIOS + 0x9F4A: 0xC6B5, //HANGUL SYLLABLE IEUNG U NIEUNCIEUC + 0x9F4B: 0xC6B6, //HANGUL SYLLABLE IEUNG U NIEUNHIEUH + 0x9F4C: 0xC6B7, //HANGUL SYLLABLE IEUNG U TIKEUT + 0x9F4D: 0xC6BB, //HANGUL SYLLABLE IEUNG U RIEULPIEUP + 0x9F4E: 0xC6BC, //HANGUL SYLLABLE IEUNG U RIEULSIOS + 0x9F4F: 0xC6BD, //HANGUL SYLLABLE IEUNG U RIEULTHIEUTH + 0x9F50: 0xC6BE, //HANGUL SYLLABLE IEUNG U RIEULPHIEUPH + 0x9F51: 0xC6BF, //HANGUL SYLLABLE IEUNG U RIEULHIEUH + 0x9F52: 0xC6C2, //HANGUL SYLLABLE IEUNG U PIEUPSIOS + 0x9F53: 0xC6C4, //HANGUL SYLLABLE IEUNG U SSANGSIOS + 0x9F54: 0xC6C6, //HANGUL SYLLABLE IEUNG U CIEUC + 0x9F55: 0xC6C7, //HANGUL SYLLABLE IEUNG U CHIEUCH + 0x9F56: 0xC6C8, //HANGUL SYLLABLE IEUNG U KHIEUKH + 0x9F57: 0xC6C9, //HANGUL SYLLABLE IEUNG U THIEUTH + 0x9F58: 0xC6CA, //HANGUL SYLLABLE IEUNG U PHIEUPH + 0x9F59: 0xC6CB, //HANGUL SYLLABLE IEUNG U HIEUH + 0x9F5A: 0xC6CE, //HANGUL SYLLABLE IEUNG WEO SSANGKIYEOK + 0x9F61: 0xC6CF, //HANGUL SYLLABLE IEUNG WEO KIYEOKSIOS + 0x9F62: 0xC6D1, //HANGUL SYLLABLE IEUNG WEO NIEUNCIEUC + 0x9F63: 0xC6D2, //HANGUL SYLLABLE IEUNG WEO NIEUNHIEUH + 0x9F64: 0xC6D3, //HANGUL SYLLABLE IEUNG WEO TIKEUT + 0x9F65: 0xC6D5, //HANGUL SYLLABLE IEUNG WEO RIEULKIYEOK + 0x9F66: 0xC6D6, //HANGUL SYLLABLE IEUNG WEO RIEULMIEUM + 0x9F67: 0xC6D7, //HANGUL SYLLABLE IEUNG WEO RIEULPIEUP + 0x9F68: 0xC6D8, //HANGUL SYLLABLE IEUNG WEO RIEULSIOS + 0x9F69: 0xC6D9, //HANGUL SYLLABLE IEUNG WEO RIEULTHIEUTH + 0x9F6A: 0xC6DA, //HANGUL SYLLABLE IEUNG WEO RIEULPHIEUPH + 0x9F6B: 0xC6DB, //HANGUL SYLLABLE IEUNG WEO RIEULHIEUH + 0x9F6C: 0xC6DE, //HANGUL SYLLABLE IEUNG WEO PIEUPSIOS + 0x9F6D: 0xC6DF, //HANGUL SYLLABLE IEUNG WEO SIOS + 0x9F6E: 0xC6E2, //HANGUL SYLLABLE IEUNG WEO CIEUC + 0x9F6F: 0xC6E3, //HANGUL SYLLABLE IEUNG WEO CHIEUCH + 0x9F70: 0xC6E4, //HANGUL SYLLABLE IEUNG WEO KHIEUKH + 0x9F71: 0xC6E5, //HANGUL SYLLABLE IEUNG WEO THIEUTH + 0x9F72: 0xC6E6, //HANGUL SYLLABLE IEUNG WEO PHIEUPH + 0x9F73: 0xC6E7, //HANGUL SYLLABLE IEUNG WEO HIEUH + 0x9F74: 0xC6EA, //HANGUL SYLLABLE IEUNG WE SSANGKIYEOK + 0x9F75: 0xC6EB, //HANGUL SYLLABLE IEUNG WE KIYEOKSIOS + 0x9F76: 0xC6ED, //HANGUL SYLLABLE IEUNG WE NIEUNCIEUC + 0x9F77: 0xC6EE, //HANGUL SYLLABLE IEUNG WE NIEUNHIEUH + 0x9F78: 0xC6EF, //HANGUL SYLLABLE IEUNG WE TIKEUT + 0x9F79: 0xC6F1, //HANGUL SYLLABLE IEUNG WE RIEULKIYEOK + 0x9F7A: 0xC6F2, //HANGUL SYLLABLE IEUNG WE RIEULMIEUM + 0x9F81: 0xC6F3, //HANGUL SYLLABLE IEUNG WE RIEULPIEUP + 0x9F82: 0xC6F4, //HANGUL SYLLABLE IEUNG WE RIEULSIOS + 0x9F83: 0xC6F5, //HANGUL SYLLABLE IEUNG WE RIEULTHIEUTH + 0x9F84: 0xC6F6, //HANGUL SYLLABLE IEUNG WE RIEULPHIEUPH + 0x9F85: 0xC6F7, //HANGUL SYLLABLE IEUNG WE RIEULHIEUH + 0x9F86: 0xC6FA, //HANGUL SYLLABLE IEUNG WE PIEUPSIOS + 0x9F87: 0xC6FB, //HANGUL SYLLABLE IEUNG WE SIOS + 0x9F88: 0xC6FC, //HANGUL SYLLABLE IEUNG WE SSANGSIOS + 0x9F89: 0xC6FE, //HANGUL SYLLABLE IEUNG WE CIEUC + 0x9F8A: 0xC6FF, //HANGUL SYLLABLE IEUNG WE CHIEUCH + 0x9F8B: 0xC700, //HANGUL SYLLABLE IEUNG WE KHIEUKH + 0x9F8C: 0xC701, //HANGUL SYLLABLE IEUNG WE THIEUTH + 0x9F8D: 0xC702, //HANGUL SYLLABLE IEUNG WE PHIEUPH + 0x9F8E: 0xC703, //HANGUL SYLLABLE IEUNG WE HIEUH + 0x9F8F: 0xC706, //HANGUL SYLLABLE IEUNG WI SSANGKIYEOK + 0x9F90: 0xC707, //HANGUL SYLLABLE IEUNG WI KIYEOKSIOS + 0x9F91: 0xC709, //HANGUL SYLLABLE IEUNG WI NIEUNCIEUC + 0x9F92: 0xC70A, //HANGUL SYLLABLE IEUNG WI NIEUNHIEUH + 0x9F93: 0xC70B, //HANGUL SYLLABLE IEUNG WI TIKEUT + 0x9F94: 0xC70D, //HANGUL SYLLABLE IEUNG WI RIEULKIYEOK + 0x9F95: 0xC70E, //HANGUL SYLLABLE IEUNG WI RIEULMIEUM + 0x9F96: 0xC70F, //HANGUL SYLLABLE IEUNG WI RIEULPIEUP + 0x9F97: 0xC710, //HANGUL SYLLABLE IEUNG WI RIEULSIOS + 0x9F98: 0xC711, //HANGUL SYLLABLE IEUNG WI RIEULTHIEUTH + 0x9F99: 0xC712, //HANGUL SYLLABLE IEUNG WI RIEULPHIEUPH + 0x9F9A: 0xC713, //HANGUL SYLLABLE IEUNG WI RIEULHIEUH + 0x9F9B: 0xC716, //HANGUL SYLLABLE IEUNG WI PIEUPSIOS + 0x9F9C: 0xC718, //HANGUL SYLLABLE IEUNG WI SSANGSIOS + 0x9F9D: 0xC71A, //HANGUL SYLLABLE IEUNG WI CIEUC + 0x9F9E: 0xC71B, //HANGUL SYLLABLE IEUNG WI CHIEUCH + 0x9F9F: 0xC71C, //HANGUL SYLLABLE IEUNG WI KHIEUKH + 0x9FA0: 0xC71D, //HANGUL SYLLABLE IEUNG WI THIEUTH + 0x9FA1: 0xC71E, //HANGUL SYLLABLE IEUNG WI PHIEUPH + 0x9FA2: 0xC71F, //HANGUL SYLLABLE IEUNG WI HIEUH + 0x9FA3: 0xC722, //HANGUL SYLLABLE IEUNG YU SSANGKIYEOK + 0x9FA4: 0xC723, //HANGUL SYLLABLE IEUNG YU KIYEOKSIOS + 0x9FA5: 0xC725, //HANGUL SYLLABLE IEUNG YU NIEUNCIEUC + 0x9FA6: 0xC726, //HANGUL SYLLABLE IEUNG YU NIEUNHIEUH + 0x9FA7: 0xC727, //HANGUL SYLLABLE IEUNG YU TIKEUT + 0x9FA8: 0xC729, //HANGUL SYLLABLE IEUNG YU RIEULKIYEOK + 0x9FA9: 0xC72A, //HANGUL SYLLABLE IEUNG YU RIEULMIEUM + 0x9FAA: 0xC72B, //HANGUL SYLLABLE IEUNG YU RIEULPIEUP + 0x9FAB: 0xC72C, //HANGUL SYLLABLE IEUNG YU RIEULSIOS + 0x9FAC: 0xC72D, //HANGUL SYLLABLE IEUNG YU RIEULTHIEUTH + 0x9FAD: 0xC72E, //HANGUL SYLLABLE IEUNG YU RIEULPHIEUPH + 0x9FAE: 0xC72F, //HANGUL SYLLABLE IEUNG YU RIEULHIEUH + 0x9FAF: 0xC732, //HANGUL SYLLABLE IEUNG YU PIEUPSIOS + 0x9FB0: 0xC734, //HANGUL SYLLABLE IEUNG YU SSANGSIOS + 0x9FB1: 0xC736, //HANGUL SYLLABLE IEUNG YU CIEUC + 0x9FB2: 0xC738, //HANGUL SYLLABLE IEUNG YU KHIEUKH + 0x9FB3: 0xC739, //HANGUL SYLLABLE IEUNG YU THIEUTH + 0x9FB4: 0xC73A, //HANGUL SYLLABLE IEUNG YU PHIEUPH + 0x9FB5: 0xC73B, //HANGUL SYLLABLE IEUNG YU HIEUH + 0x9FB6: 0xC73E, //HANGUL SYLLABLE IEUNG EU SSANGKIYEOK + 0x9FB7: 0xC73F, //HANGUL SYLLABLE IEUNG EU KIYEOKSIOS + 0x9FB8: 0xC741, //HANGUL SYLLABLE IEUNG EU NIEUNCIEUC + 0x9FB9: 0xC742, //HANGUL SYLLABLE IEUNG EU NIEUNHIEUH + 0x9FBA: 0xC743, //HANGUL SYLLABLE IEUNG EU TIKEUT + 0x9FBB: 0xC745, //HANGUL SYLLABLE IEUNG EU RIEULKIYEOK + 0x9FBC: 0xC746, //HANGUL SYLLABLE IEUNG EU RIEULMIEUM + 0x9FBD: 0xC747, //HANGUL SYLLABLE IEUNG EU RIEULPIEUP + 0x9FBE: 0xC748, //HANGUL SYLLABLE IEUNG EU RIEULSIOS + 0x9FBF: 0xC749, //HANGUL SYLLABLE IEUNG EU RIEULTHIEUTH + 0x9FC0: 0xC74B, //HANGUL SYLLABLE IEUNG EU RIEULHIEUH + 0x9FC1: 0xC74E, //HANGUL SYLLABLE IEUNG EU PIEUPSIOS + 0x9FC2: 0xC750, //HANGUL SYLLABLE IEUNG EU SSANGSIOS + 0x9FC3: 0xC759, //HANGUL SYLLABLE IEUNG YI KIYEOK + 0x9FC4: 0xC75A, //HANGUL SYLLABLE IEUNG YI SSANGKIYEOK + 0x9FC5: 0xC75B, //HANGUL SYLLABLE IEUNG YI KIYEOKSIOS + 0x9FC6: 0xC75D, //HANGUL SYLLABLE IEUNG YI NIEUNCIEUC + 0x9FC7: 0xC75E, //HANGUL SYLLABLE IEUNG YI NIEUNHIEUH + 0x9FC8: 0xC75F, //HANGUL SYLLABLE IEUNG YI TIKEUT + 0x9FC9: 0xC761, //HANGUL SYLLABLE IEUNG YI RIEULKIYEOK + 0x9FCA: 0xC762, //HANGUL SYLLABLE IEUNG YI RIEULMIEUM + 0x9FCB: 0xC763, //HANGUL SYLLABLE IEUNG YI RIEULPIEUP + 0x9FCC: 0xC764, //HANGUL SYLLABLE IEUNG YI RIEULSIOS + 0x9FCD: 0xC765, //HANGUL SYLLABLE IEUNG YI RIEULTHIEUTH + 0x9FCE: 0xC766, //HANGUL SYLLABLE IEUNG YI RIEULPHIEUPH + 0x9FCF: 0xC767, //HANGUL SYLLABLE IEUNG YI RIEULHIEUH + 0x9FD0: 0xC769, //HANGUL SYLLABLE IEUNG YI PIEUP + 0x9FD1: 0xC76A, //HANGUL SYLLABLE IEUNG YI PIEUPSIOS + 0x9FD2: 0xC76C, //HANGUL SYLLABLE IEUNG YI SSANGSIOS + 0x9FD3: 0xC76D, //HANGUL SYLLABLE IEUNG YI IEUNG + 0x9FD4: 0xC76E, //HANGUL SYLLABLE IEUNG YI CIEUC + 0x9FD5: 0xC76F, //HANGUL SYLLABLE IEUNG YI CHIEUCH + 0x9FD6: 0xC770, //HANGUL SYLLABLE IEUNG YI KHIEUKH + 0x9FD7: 0xC771, //HANGUL SYLLABLE IEUNG YI THIEUTH + 0x9FD8: 0xC772, //HANGUL SYLLABLE IEUNG YI PHIEUPH + 0x9FD9: 0xC773, //HANGUL SYLLABLE IEUNG YI HIEUH + 0x9FDA: 0xC776, //HANGUL SYLLABLE IEUNG I SSANGKIYEOK + 0x9FDB: 0xC777, //HANGUL SYLLABLE IEUNG I KIYEOKSIOS + 0x9FDC: 0xC779, //HANGUL SYLLABLE IEUNG I NIEUNCIEUC + 0x9FDD: 0xC77A, //HANGUL SYLLABLE IEUNG I NIEUNHIEUH + 0x9FDE: 0xC77B, //HANGUL SYLLABLE IEUNG I TIKEUT + 0x9FDF: 0xC77F, //HANGUL SYLLABLE IEUNG I RIEULPIEUP + 0x9FE0: 0xC780, //HANGUL SYLLABLE IEUNG I RIEULSIOS + 0x9FE1: 0xC781, //HANGUL SYLLABLE IEUNG I RIEULTHIEUTH + 0x9FE2: 0xC782, //HANGUL SYLLABLE IEUNG I RIEULPHIEUPH + 0x9FE3: 0xC786, //HANGUL SYLLABLE IEUNG I PIEUPSIOS + 0x9FE4: 0xC78B, //HANGUL SYLLABLE IEUNG I CHIEUCH + 0x9FE5: 0xC78C, //HANGUL SYLLABLE IEUNG I KHIEUKH + 0x9FE6: 0xC78D, //HANGUL SYLLABLE IEUNG I THIEUTH + 0x9FE7: 0xC78F, //HANGUL SYLLABLE IEUNG I HIEUH + 0x9FE8: 0xC792, //HANGUL SYLLABLE CIEUC A SSANGKIYEOK + 0x9FE9: 0xC793, //HANGUL SYLLABLE CIEUC A KIYEOKSIOS + 0x9FEA: 0xC795, //HANGUL SYLLABLE CIEUC A NIEUNCIEUC + 0x9FEB: 0xC799, //HANGUL SYLLABLE CIEUC A RIEULKIYEOK + 0x9FEC: 0xC79B, //HANGUL SYLLABLE CIEUC A RIEULPIEUP + 0x9FED: 0xC79C, //HANGUL SYLLABLE CIEUC A RIEULSIOS + 0x9FEE: 0xC79D, //HANGUL SYLLABLE CIEUC A RIEULTHIEUTH + 0x9FEF: 0xC79E, //HANGUL SYLLABLE CIEUC A RIEULPHIEUPH + 0x9FF0: 0xC79F, //HANGUL SYLLABLE CIEUC A RIEULHIEUH + 0x9FF1: 0xC7A2, //HANGUL SYLLABLE CIEUC A PIEUPSIOS + 0x9FF2: 0xC7A7, //HANGUL SYLLABLE CIEUC A CHIEUCH + 0x9FF3: 0xC7A8, //HANGUL SYLLABLE CIEUC A KHIEUKH + 0x9FF4: 0xC7A9, //HANGUL SYLLABLE CIEUC A THIEUTH + 0x9FF5: 0xC7AA, //HANGUL SYLLABLE CIEUC A PHIEUPH + 0x9FF6: 0xC7AB, //HANGUL SYLLABLE CIEUC A HIEUH + 0x9FF7: 0xC7AE, //HANGUL SYLLABLE CIEUC AE SSANGKIYEOK + 0x9FF8: 0xC7AF, //HANGUL SYLLABLE CIEUC AE KIYEOKSIOS + 0x9FF9: 0xC7B1, //HANGUL SYLLABLE CIEUC AE NIEUNCIEUC + 0x9FFA: 0xC7B2, //HANGUL SYLLABLE CIEUC AE NIEUNHIEUH + 0x9FFB: 0xC7B3, //HANGUL SYLLABLE CIEUC AE TIKEUT + 0x9FFC: 0xC7B5, //HANGUL SYLLABLE CIEUC AE RIEULKIYEOK + 0x9FFD: 0xC7B6, //HANGUL SYLLABLE CIEUC AE RIEULMIEUM + 0x9FFE: 0xC7B7, //HANGUL SYLLABLE CIEUC AE RIEULPIEUP + 0xA041: 0xC7B8, //HANGUL SYLLABLE CIEUC AE RIEULSIOS + 0xA042: 0xC7B9, //HANGUL SYLLABLE CIEUC AE RIEULTHIEUTH + 0xA043: 0xC7BA, //HANGUL SYLLABLE CIEUC AE RIEULPHIEUPH + 0xA044: 0xC7BB, //HANGUL SYLLABLE CIEUC AE RIEULHIEUH + 0xA045: 0xC7BE, //HANGUL SYLLABLE CIEUC AE PIEUPSIOS + 0xA046: 0xC7C2, //HANGUL SYLLABLE CIEUC AE CIEUC + 0xA047: 0xC7C3, //HANGUL SYLLABLE CIEUC AE CHIEUCH + 0xA048: 0xC7C4, //HANGUL SYLLABLE CIEUC AE KHIEUKH + 0xA049: 0xC7C5, //HANGUL SYLLABLE CIEUC AE THIEUTH + 0xA04A: 0xC7C6, //HANGUL SYLLABLE CIEUC AE PHIEUPH + 0xA04B: 0xC7C7, //HANGUL SYLLABLE CIEUC AE HIEUH + 0xA04C: 0xC7CA, //HANGUL SYLLABLE CIEUC YA SSANGKIYEOK + 0xA04D: 0xC7CB, //HANGUL SYLLABLE CIEUC YA KIYEOKSIOS + 0xA04E: 0xC7CD, //HANGUL SYLLABLE CIEUC YA NIEUNCIEUC + 0xA04F: 0xC7CF, //HANGUL SYLLABLE CIEUC YA TIKEUT + 0xA050: 0xC7D1, //HANGUL SYLLABLE CIEUC YA RIEULKIYEOK + 0xA051: 0xC7D2, //HANGUL SYLLABLE CIEUC YA RIEULMIEUM + 0xA052: 0xC7D3, //HANGUL SYLLABLE CIEUC YA RIEULPIEUP + 0xA053: 0xC7D4, //HANGUL SYLLABLE CIEUC YA RIEULSIOS + 0xA054: 0xC7D5, //HANGUL SYLLABLE CIEUC YA RIEULTHIEUTH + 0xA055: 0xC7D6, //HANGUL SYLLABLE CIEUC YA RIEULPHIEUPH + 0xA056: 0xC7D7, //HANGUL SYLLABLE CIEUC YA RIEULHIEUH + 0xA057: 0xC7D9, //HANGUL SYLLABLE CIEUC YA PIEUP + 0xA058: 0xC7DA, //HANGUL SYLLABLE CIEUC YA PIEUPSIOS + 0xA059: 0xC7DB, //HANGUL SYLLABLE CIEUC YA SIOS + 0xA05A: 0xC7DC, //HANGUL SYLLABLE CIEUC YA SSANGSIOS + 0xA061: 0xC7DE, //HANGUL SYLLABLE CIEUC YA CIEUC + 0xA062: 0xC7DF, //HANGUL SYLLABLE CIEUC YA CHIEUCH + 0xA063: 0xC7E0, //HANGUL SYLLABLE CIEUC YA KHIEUKH + 0xA064: 0xC7E1, //HANGUL SYLLABLE CIEUC YA THIEUTH + 0xA065: 0xC7E2, //HANGUL SYLLABLE CIEUC YA PHIEUPH + 0xA066: 0xC7E3, //HANGUL SYLLABLE CIEUC YA HIEUH + 0xA067: 0xC7E5, //HANGUL SYLLABLE CIEUC YAE KIYEOK + 0xA068: 0xC7E6, //HANGUL SYLLABLE CIEUC YAE SSANGKIYEOK + 0xA069: 0xC7E7, //HANGUL SYLLABLE CIEUC YAE KIYEOKSIOS + 0xA06A: 0xC7E9, //HANGUL SYLLABLE CIEUC YAE NIEUNCIEUC + 0xA06B: 0xC7EA, //HANGUL SYLLABLE CIEUC YAE NIEUNHIEUH + 0xA06C: 0xC7EB, //HANGUL SYLLABLE CIEUC YAE TIKEUT + 0xA06D: 0xC7ED, //HANGUL SYLLABLE CIEUC YAE RIEULKIYEOK + 0xA06E: 0xC7EE, //HANGUL SYLLABLE CIEUC YAE RIEULMIEUM + 0xA06F: 0xC7EF, //HANGUL SYLLABLE CIEUC YAE RIEULPIEUP + 0xA070: 0xC7F0, //HANGUL SYLLABLE CIEUC YAE RIEULSIOS + 0xA071: 0xC7F1, //HANGUL SYLLABLE CIEUC YAE RIEULTHIEUTH + 0xA072: 0xC7F2, //HANGUL SYLLABLE CIEUC YAE RIEULPHIEUPH + 0xA073: 0xC7F3, //HANGUL SYLLABLE CIEUC YAE RIEULHIEUH + 0xA074: 0xC7F4, //HANGUL SYLLABLE CIEUC YAE MIEUM + 0xA075: 0xC7F5, //HANGUL SYLLABLE CIEUC YAE PIEUP + 0xA076: 0xC7F6, //HANGUL SYLLABLE CIEUC YAE PIEUPSIOS + 0xA077: 0xC7F7, //HANGUL SYLLABLE CIEUC YAE SIOS + 0xA078: 0xC7F8, //HANGUL SYLLABLE CIEUC YAE SSANGSIOS + 0xA079: 0xC7F9, //HANGUL SYLLABLE CIEUC YAE IEUNG + 0xA07A: 0xC7FA, //HANGUL SYLLABLE CIEUC YAE CIEUC + 0xA081: 0xC7FB, //HANGUL SYLLABLE CIEUC YAE CHIEUCH + 0xA082: 0xC7FC, //HANGUL SYLLABLE CIEUC YAE KHIEUKH + 0xA083: 0xC7FD, //HANGUL SYLLABLE CIEUC YAE THIEUTH + 0xA084: 0xC7FE, //HANGUL SYLLABLE CIEUC YAE PHIEUPH + 0xA085: 0xC7FF, //HANGUL SYLLABLE CIEUC YAE HIEUH + 0xA086: 0xC802, //HANGUL SYLLABLE CIEUC EO SSANGKIYEOK + 0xA087: 0xC803, //HANGUL SYLLABLE CIEUC EO KIYEOKSIOS + 0xA088: 0xC805, //HANGUL SYLLABLE CIEUC EO NIEUNCIEUC + 0xA089: 0xC806, //HANGUL SYLLABLE CIEUC EO NIEUNHIEUH + 0xA08A: 0xC807, //HANGUL SYLLABLE CIEUC EO TIKEUT + 0xA08B: 0xC809, //HANGUL SYLLABLE CIEUC EO RIEULKIYEOK + 0xA08C: 0xC80B, //HANGUL SYLLABLE CIEUC EO RIEULPIEUP + 0xA08D: 0xC80C, //HANGUL SYLLABLE CIEUC EO RIEULSIOS + 0xA08E: 0xC80D, //HANGUL SYLLABLE CIEUC EO RIEULTHIEUTH + 0xA08F: 0xC80E, //HANGUL SYLLABLE CIEUC EO RIEULPHIEUPH + 0xA090: 0xC80F, //HANGUL SYLLABLE CIEUC EO RIEULHIEUH + 0xA091: 0xC812, //HANGUL SYLLABLE CIEUC EO PIEUPSIOS + 0xA092: 0xC814, //HANGUL SYLLABLE CIEUC EO SSANGSIOS + 0xA093: 0xC817, //HANGUL SYLLABLE CIEUC EO CHIEUCH + 0xA094: 0xC818, //HANGUL SYLLABLE CIEUC EO KHIEUKH + 0xA095: 0xC819, //HANGUL SYLLABLE CIEUC EO THIEUTH + 0xA096: 0xC81A, //HANGUL SYLLABLE CIEUC EO PHIEUPH + 0xA097: 0xC81B, //HANGUL SYLLABLE CIEUC EO HIEUH + 0xA098: 0xC81E, //HANGUL SYLLABLE CIEUC E SSANGKIYEOK + 0xA099: 0xC81F, //HANGUL SYLLABLE CIEUC E KIYEOKSIOS + 0xA09A: 0xC821, //HANGUL SYLLABLE CIEUC E NIEUNCIEUC + 0xA09B: 0xC822, //HANGUL SYLLABLE CIEUC E NIEUNHIEUH + 0xA09C: 0xC823, //HANGUL SYLLABLE CIEUC E TIKEUT + 0xA09D: 0xC825, //HANGUL SYLLABLE CIEUC E RIEULKIYEOK + 0xA09E: 0xC826, //HANGUL SYLLABLE CIEUC E RIEULMIEUM + 0xA09F: 0xC827, //HANGUL SYLLABLE CIEUC E RIEULPIEUP + 0xA0A0: 0xC828, //HANGUL SYLLABLE CIEUC E RIEULSIOS + 0xA0A1: 0xC829, //HANGUL SYLLABLE CIEUC E RIEULTHIEUTH + 0xA0A2: 0xC82A, //HANGUL SYLLABLE CIEUC E RIEULPHIEUPH + 0xA0A3: 0xC82B, //HANGUL SYLLABLE CIEUC E RIEULHIEUH + 0xA0A4: 0xC82E, //HANGUL SYLLABLE CIEUC E PIEUPSIOS + 0xA0A5: 0xC830, //HANGUL SYLLABLE CIEUC E SSANGSIOS + 0xA0A6: 0xC832, //HANGUL SYLLABLE CIEUC E CIEUC + 0xA0A7: 0xC833, //HANGUL SYLLABLE CIEUC E CHIEUCH + 0xA0A8: 0xC834, //HANGUL SYLLABLE CIEUC E KHIEUKH + 0xA0A9: 0xC835, //HANGUL SYLLABLE CIEUC E THIEUTH + 0xA0AA: 0xC836, //HANGUL SYLLABLE CIEUC E PHIEUPH + 0xA0AB: 0xC837, //HANGUL SYLLABLE CIEUC E HIEUH + 0xA0AC: 0xC839, //HANGUL SYLLABLE CIEUC YEO KIYEOK + 0xA0AD: 0xC83A, //HANGUL SYLLABLE CIEUC YEO SSANGKIYEOK + 0xA0AE: 0xC83B, //HANGUL SYLLABLE CIEUC YEO KIYEOKSIOS + 0xA0AF: 0xC83D, //HANGUL SYLLABLE CIEUC YEO NIEUNCIEUC + 0xA0B0: 0xC83E, //HANGUL SYLLABLE CIEUC YEO NIEUNHIEUH + 0xA0B1: 0xC83F, //HANGUL SYLLABLE CIEUC YEO TIKEUT + 0xA0B2: 0xC841, //HANGUL SYLLABLE CIEUC YEO RIEULKIYEOK + 0xA0B3: 0xC842, //HANGUL SYLLABLE CIEUC YEO RIEULMIEUM + 0xA0B4: 0xC843, //HANGUL SYLLABLE CIEUC YEO RIEULPIEUP + 0xA0B5: 0xC844, //HANGUL SYLLABLE CIEUC YEO RIEULSIOS + 0xA0B6: 0xC845, //HANGUL SYLLABLE CIEUC YEO RIEULTHIEUTH + 0xA0B7: 0xC846, //HANGUL SYLLABLE CIEUC YEO RIEULPHIEUPH + 0xA0B8: 0xC847, //HANGUL SYLLABLE CIEUC YEO RIEULHIEUH + 0xA0B9: 0xC84A, //HANGUL SYLLABLE CIEUC YEO PIEUPSIOS + 0xA0BA: 0xC84B, //HANGUL SYLLABLE CIEUC YEO SIOS + 0xA0BB: 0xC84E, //HANGUL SYLLABLE CIEUC YEO CIEUC + 0xA0BC: 0xC84F, //HANGUL SYLLABLE CIEUC YEO CHIEUCH + 0xA0BD: 0xC850, //HANGUL SYLLABLE CIEUC YEO KHIEUKH + 0xA0BE: 0xC851, //HANGUL SYLLABLE CIEUC YEO THIEUTH + 0xA0BF: 0xC852, //HANGUL SYLLABLE CIEUC YEO PHIEUPH + 0xA0C0: 0xC853, //HANGUL SYLLABLE CIEUC YEO HIEUH + 0xA0C1: 0xC855, //HANGUL SYLLABLE CIEUC YE KIYEOK + 0xA0C2: 0xC856, //HANGUL SYLLABLE CIEUC YE SSANGKIYEOK + 0xA0C3: 0xC857, //HANGUL SYLLABLE CIEUC YE KIYEOKSIOS + 0xA0C4: 0xC858, //HANGUL SYLLABLE CIEUC YE NIEUN + 0xA0C5: 0xC859, //HANGUL SYLLABLE CIEUC YE NIEUNCIEUC + 0xA0C6: 0xC85A, //HANGUL SYLLABLE CIEUC YE NIEUNHIEUH + 0xA0C7: 0xC85B, //HANGUL SYLLABLE CIEUC YE TIKEUT + 0xA0C8: 0xC85C, //HANGUL SYLLABLE CIEUC YE RIEUL + 0xA0C9: 0xC85D, //HANGUL SYLLABLE CIEUC YE RIEULKIYEOK + 0xA0CA: 0xC85E, //HANGUL SYLLABLE CIEUC YE RIEULMIEUM + 0xA0CB: 0xC85F, //HANGUL SYLLABLE CIEUC YE RIEULPIEUP + 0xA0CC: 0xC860, //HANGUL SYLLABLE CIEUC YE RIEULSIOS + 0xA0CD: 0xC861, //HANGUL SYLLABLE CIEUC YE RIEULTHIEUTH + 0xA0CE: 0xC862, //HANGUL SYLLABLE CIEUC YE RIEULPHIEUPH + 0xA0CF: 0xC863, //HANGUL SYLLABLE CIEUC YE RIEULHIEUH + 0xA0D0: 0xC864, //HANGUL SYLLABLE CIEUC YE MIEUM + 0xA0D1: 0xC865, //HANGUL SYLLABLE CIEUC YE PIEUP + 0xA0D2: 0xC866, //HANGUL SYLLABLE CIEUC YE PIEUPSIOS + 0xA0D3: 0xC867, //HANGUL SYLLABLE CIEUC YE SIOS + 0xA0D4: 0xC868, //HANGUL SYLLABLE CIEUC YE SSANGSIOS + 0xA0D5: 0xC869, //HANGUL SYLLABLE CIEUC YE IEUNG + 0xA0D6: 0xC86A, //HANGUL SYLLABLE CIEUC YE CIEUC + 0xA0D7: 0xC86B, //HANGUL SYLLABLE CIEUC YE CHIEUCH + 0xA0D8: 0xC86C, //HANGUL SYLLABLE CIEUC YE KHIEUKH + 0xA0D9: 0xC86D, //HANGUL SYLLABLE CIEUC YE THIEUTH + 0xA0DA: 0xC86E, //HANGUL SYLLABLE CIEUC YE PHIEUPH + 0xA0DB: 0xC86F, //HANGUL SYLLABLE CIEUC YE HIEUH + 0xA0DC: 0xC872, //HANGUL SYLLABLE CIEUC O SSANGKIYEOK + 0xA0DD: 0xC873, //HANGUL SYLLABLE CIEUC O KIYEOKSIOS + 0xA0DE: 0xC875, //HANGUL SYLLABLE CIEUC O NIEUNCIEUC + 0xA0DF: 0xC876, //HANGUL SYLLABLE CIEUC O NIEUNHIEUH + 0xA0E0: 0xC877, //HANGUL SYLLABLE CIEUC O TIKEUT + 0xA0E1: 0xC879, //HANGUL SYLLABLE CIEUC O RIEULKIYEOK + 0xA0E2: 0xC87B, //HANGUL SYLLABLE CIEUC O RIEULPIEUP + 0xA0E3: 0xC87C, //HANGUL SYLLABLE CIEUC O RIEULSIOS + 0xA0E4: 0xC87D, //HANGUL SYLLABLE CIEUC O RIEULTHIEUTH + 0xA0E5: 0xC87E, //HANGUL SYLLABLE CIEUC O RIEULPHIEUPH + 0xA0E6: 0xC87F, //HANGUL SYLLABLE CIEUC O RIEULHIEUH + 0xA0E7: 0xC882, //HANGUL SYLLABLE CIEUC O PIEUPSIOS + 0xA0E8: 0xC884, //HANGUL SYLLABLE CIEUC O SSANGSIOS + 0xA0E9: 0xC888, //HANGUL SYLLABLE CIEUC O KHIEUKH + 0xA0EA: 0xC889, //HANGUL SYLLABLE CIEUC O THIEUTH + 0xA0EB: 0xC88A, //HANGUL SYLLABLE CIEUC O PHIEUPH + 0xA0EC: 0xC88E, //HANGUL SYLLABLE CIEUC WA SSANGKIYEOK + 0xA0ED: 0xC88F, //HANGUL SYLLABLE CIEUC WA KIYEOKSIOS + 0xA0EE: 0xC890, //HANGUL SYLLABLE CIEUC WA NIEUN + 0xA0EF: 0xC891, //HANGUL SYLLABLE CIEUC WA NIEUNCIEUC + 0xA0F0: 0xC892, //HANGUL SYLLABLE CIEUC WA NIEUNHIEUH + 0xA0F1: 0xC893, //HANGUL SYLLABLE CIEUC WA TIKEUT + 0xA0F2: 0xC895, //HANGUL SYLLABLE CIEUC WA RIEULKIYEOK + 0xA0F3: 0xC896, //HANGUL SYLLABLE CIEUC WA RIEULMIEUM + 0xA0F4: 0xC897, //HANGUL SYLLABLE CIEUC WA RIEULPIEUP + 0xA0F5: 0xC898, //HANGUL SYLLABLE CIEUC WA RIEULSIOS + 0xA0F6: 0xC899, //HANGUL SYLLABLE CIEUC WA RIEULTHIEUTH + 0xA0F7: 0xC89A, //HANGUL SYLLABLE CIEUC WA RIEULPHIEUPH + 0xA0F8: 0xC89B, //HANGUL SYLLABLE CIEUC WA RIEULHIEUH + 0xA0F9: 0xC89C, //HANGUL SYLLABLE CIEUC WA MIEUM + 0xA0FA: 0xC89E, //HANGUL SYLLABLE CIEUC WA PIEUPSIOS + 0xA0FB: 0xC8A0, //HANGUL SYLLABLE CIEUC WA SSANGSIOS + 0xA0FC: 0xC8A2, //HANGUL SYLLABLE CIEUC WA CIEUC + 0xA0FD: 0xC8A3, //HANGUL SYLLABLE CIEUC WA CHIEUCH + 0xA0FE: 0xC8A4, //HANGUL SYLLABLE CIEUC WA KHIEUKH + 0xA141: 0xC8A5, //HANGUL SYLLABLE CIEUC WA THIEUTH + 0xA142: 0xC8A6, //HANGUL SYLLABLE CIEUC WA PHIEUPH + 0xA143: 0xC8A7, //HANGUL SYLLABLE CIEUC WA HIEUH + 0xA144: 0xC8A9, //HANGUL SYLLABLE CIEUC WAE KIYEOK + 0xA145: 0xC8AA, //HANGUL SYLLABLE CIEUC WAE SSANGKIYEOK + 0xA146: 0xC8AB, //HANGUL SYLLABLE CIEUC WAE KIYEOKSIOS + 0xA147: 0xC8AC, //HANGUL SYLLABLE CIEUC WAE NIEUN + 0xA148: 0xC8AD, //HANGUL SYLLABLE CIEUC WAE NIEUNCIEUC + 0xA149: 0xC8AE, //HANGUL SYLLABLE CIEUC WAE NIEUNHIEUH + 0xA14A: 0xC8AF, //HANGUL SYLLABLE CIEUC WAE TIKEUT + 0xA14B: 0xC8B0, //HANGUL SYLLABLE CIEUC WAE RIEUL + 0xA14C: 0xC8B1, //HANGUL SYLLABLE CIEUC WAE RIEULKIYEOK + 0xA14D: 0xC8B2, //HANGUL SYLLABLE CIEUC WAE RIEULMIEUM + 0xA14E: 0xC8B3, //HANGUL SYLLABLE CIEUC WAE RIEULPIEUP + 0xA14F: 0xC8B4, //HANGUL SYLLABLE CIEUC WAE RIEULSIOS + 0xA150: 0xC8B5, //HANGUL SYLLABLE CIEUC WAE RIEULTHIEUTH + 0xA151: 0xC8B6, //HANGUL SYLLABLE CIEUC WAE RIEULPHIEUPH + 0xA152: 0xC8B7, //HANGUL SYLLABLE CIEUC WAE RIEULHIEUH + 0xA153: 0xC8B8, //HANGUL SYLLABLE CIEUC WAE MIEUM + 0xA154: 0xC8B9, //HANGUL SYLLABLE CIEUC WAE PIEUP + 0xA155: 0xC8BA, //HANGUL SYLLABLE CIEUC WAE PIEUPSIOS + 0xA156: 0xC8BB, //HANGUL SYLLABLE CIEUC WAE SIOS + 0xA157: 0xC8BE, //HANGUL SYLLABLE CIEUC WAE CIEUC + 0xA158: 0xC8BF, //HANGUL SYLLABLE CIEUC WAE CHIEUCH + 0xA159: 0xC8C0, //HANGUL SYLLABLE CIEUC WAE KHIEUKH + 0xA15A: 0xC8C1, //HANGUL SYLLABLE CIEUC WAE THIEUTH + 0xA161: 0xC8C2, //HANGUL SYLLABLE CIEUC WAE PHIEUPH + 0xA162: 0xC8C3, //HANGUL SYLLABLE CIEUC WAE HIEUH + 0xA163: 0xC8C5, //HANGUL SYLLABLE CIEUC OE KIYEOK + 0xA164: 0xC8C6, //HANGUL SYLLABLE CIEUC OE SSANGKIYEOK + 0xA165: 0xC8C7, //HANGUL SYLLABLE CIEUC OE KIYEOKSIOS + 0xA166: 0xC8C9, //HANGUL SYLLABLE CIEUC OE NIEUNCIEUC + 0xA167: 0xC8CA, //HANGUL SYLLABLE CIEUC OE NIEUNHIEUH + 0xA168: 0xC8CB, //HANGUL SYLLABLE CIEUC OE TIKEUT + 0xA169: 0xC8CD, //HANGUL SYLLABLE CIEUC OE RIEULKIYEOK + 0xA16A: 0xC8CE, //HANGUL SYLLABLE CIEUC OE RIEULMIEUM + 0xA16B: 0xC8CF, //HANGUL SYLLABLE CIEUC OE RIEULPIEUP + 0xA16C: 0xC8D0, //HANGUL SYLLABLE CIEUC OE RIEULSIOS + 0xA16D: 0xC8D1, //HANGUL SYLLABLE CIEUC OE RIEULTHIEUTH + 0xA16E: 0xC8D2, //HANGUL SYLLABLE CIEUC OE RIEULPHIEUPH + 0xA16F: 0xC8D3, //HANGUL SYLLABLE CIEUC OE RIEULHIEUH + 0xA170: 0xC8D6, //HANGUL SYLLABLE CIEUC OE PIEUPSIOS + 0xA171: 0xC8D8, //HANGUL SYLLABLE CIEUC OE SSANGSIOS + 0xA172: 0xC8DA, //HANGUL SYLLABLE CIEUC OE CIEUC + 0xA173: 0xC8DB, //HANGUL SYLLABLE CIEUC OE CHIEUCH + 0xA174: 0xC8DC, //HANGUL SYLLABLE CIEUC OE KHIEUKH + 0xA175: 0xC8DD, //HANGUL SYLLABLE CIEUC OE THIEUTH + 0xA176: 0xC8DE, //HANGUL SYLLABLE CIEUC OE PHIEUPH + 0xA177: 0xC8DF, //HANGUL SYLLABLE CIEUC OE HIEUH + 0xA178: 0xC8E2, //HANGUL SYLLABLE CIEUC YO SSANGKIYEOK + 0xA179: 0xC8E3, //HANGUL SYLLABLE CIEUC YO KIYEOKSIOS + 0xA17A: 0xC8E5, //HANGUL SYLLABLE CIEUC YO NIEUNCIEUC + 0xA181: 0xC8E6, //HANGUL SYLLABLE CIEUC YO NIEUNHIEUH + 0xA182: 0xC8E7, //HANGUL SYLLABLE CIEUC YO TIKEUT + 0xA183: 0xC8E8, //HANGUL SYLLABLE CIEUC YO RIEUL + 0xA184: 0xC8E9, //HANGUL SYLLABLE CIEUC YO RIEULKIYEOK + 0xA185: 0xC8EA, //HANGUL SYLLABLE CIEUC YO RIEULMIEUM + 0xA186: 0xC8EB, //HANGUL SYLLABLE CIEUC YO RIEULPIEUP + 0xA187: 0xC8EC, //HANGUL SYLLABLE CIEUC YO RIEULSIOS + 0xA188: 0xC8ED, //HANGUL SYLLABLE CIEUC YO RIEULTHIEUTH + 0xA189: 0xC8EE, //HANGUL SYLLABLE CIEUC YO RIEULPHIEUPH + 0xA18A: 0xC8EF, //HANGUL SYLLABLE CIEUC YO RIEULHIEUH + 0xA18B: 0xC8F0, //HANGUL SYLLABLE CIEUC YO MIEUM + 0xA18C: 0xC8F1, //HANGUL SYLLABLE CIEUC YO PIEUP + 0xA18D: 0xC8F2, //HANGUL SYLLABLE CIEUC YO PIEUPSIOS + 0xA18E: 0xC8F3, //HANGUL SYLLABLE CIEUC YO SIOS + 0xA18F: 0xC8F4, //HANGUL SYLLABLE CIEUC YO SSANGSIOS + 0xA190: 0xC8F6, //HANGUL SYLLABLE CIEUC YO CIEUC + 0xA191: 0xC8F7, //HANGUL SYLLABLE CIEUC YO CHIEUCH + 0xA192: 0xC8F8, //HANGUL SYLLABLE CIEUC YO KHIEUKH + 0xA193: 0xC8F9, //HANGUL SYLLABLE CIEUC YO THIEUTH + 0xA194: 0xC8FA, //HANGUL SYLLABLE CIEUC YO PHIEUPH + 0xA195: 0xC8FB, //HANGUL SYLLABLE CIEUC YO HIEUH + 0xA196: 0xC8FE, //HANGUL SYLLABLE CIEUC U SSANGKIYEOK + 0xA197: 0xC8FF, //HANGUL SYLLABLE CIEUC U KIYEOKSIOS + 0xA198: 0xC901, //HANGUL SYLLABLE CIEUC U NIEUNCIEUC + 0xA199: 0xC902, //HANGUL SYLLABLE CIEUC U NIEUNHIEUH + 0xA19A: 0xC903, //HANGUL SYLLABLE CIEUC U TIKEUT + 0xA19B: 0xC907, //HANGUL SYLLABLE CIEUC U RIEULPIEUP + 0xA19C: 0xC908, //HANGUL SYLLABLE CIEUC U RIEULSIOS + 0xA19D: 0xC909, //HANGUL SYLLABLE CIEUC U RIEULTHIEUTH + 0xA19E: 0xC90A, //HANGUL SYLLABLE CIEUC U RIEULPHIEUPH + 0xA19F: 0xC90B, //HANGUL SYLLABLE CIEUC U RIEULHIEUH + 0xA1A0: 0xC90E, //HANGUL SYLLABLE CIEUC U PIEUPSIOS + 0xA1A1: 0x3000, //IDEOGRAPHIC SPACE + 0xA1A2: 0x3001, //IDEOGRAPHIC COMMA + 0xA1A3: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA1A4: 0x00B7, //MIDDLE DOT + 0xA1A5: 0x2025, //TWO DOT LEADER + 0xA1A6: 0x2026, //HORIZONTAL ELLIPSIS + 0xA1A7: 0x00A8, //DIAERESIS + 0xA1A8: 0x3003, //DITTO MARK + 0xA1A9: 0x00AD, //SOFT HYPHEN + 0xA1AA: 0x2015, //HORIZONTAL BAR + 0xA1AB: 0x2225, //PARALLEL TO + 0xA1AC: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA1AD: 0x223C, //TILDE OPERATOR + 0xA1AE: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1AF: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1B0: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1B1: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1B2: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA1B3: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA1B4: 0x3008, //LEFT ANGLE BRACKET + 0xA1B5: 0x3009, //RIGHT ANGLE BRACKET + 0xA1B6: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA1B7: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA1B8: 0x300C, //LEFT CORNER BRACKET + 0xA1B9: 0x300D, //RIGHT CORNER BRACKET + 0xA1BA: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA1BB: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA1BC: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA1BD: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA1BE: 0x00B1, //PLUS-MINUS SIGN + 0xA1BF: 0x00D7, //MULTIPLICATION SIGN + 0xA1C0: 0x00F7, //DIVISION SIGN + 0xA1C1: 0x2260, //NOT EQUAL TO + 0xA1C2: 0x2264, //LESS-THAN OR EQUAL TO + 0xA1C3: 0x2265, //GREATER-THAN OR EQUAL TO + 0xA1C4: 0x221E, //INFINITY + 0xA1C5: 0x2234, //THEREFORE + 0xA1C6: 0x00B0, //DEGREE SIGN + 0xA1C7: 0x2032, //PRIME + 0xA1C8: 0x2033, //DOUBLE PRIME + 0xA1C9: 0x2103, //DEGREE CELSIUS + 0xA1CA: 0x212B, //ANGSTROM SIGN + 0xA1CB: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA1CC: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA1CD: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA1CE: 0x2642, //MALE SIGN + 0xA1CF: 0x2640, //FEMALE SIGN + 0xA1D0: 0x2220, //ANGLE + 0xA1D1: 0x22A5, //UP TACK + 0xA1D2: 0x2312, //ARC + 0xA1D3: 0x2202, //PARTIAL DIFFERENTIAL + 0xA1D4: 0x2207, //NABLA + 0xA1D5: 0x2261, //IDENTICAL TO + 0xA1D6: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA1D7: 0x00A7, //SECTION SIGN + 0xA1D8: 0x203B, //REFERENCE MARK + 0xA1D9: 0x2606, //WHITE STAR + 0xA1DA: 0x2605, //BLACK STAR + 0xA1DB: 0x25CB, //WHITE CIRCLE + 0xA1DC: 0x25CF, //BLACK CIRCLE + 0xA1DD: 0x25CE, //BULLSEYE + 0xA1DE: 0x25C7, //WHITE DIAMOND + 0xA1DF: 0x25C6, //BLACK DIAMOND + 0xA1E0: 0x25A1, //WHITE SQUARE + 0xA1E1: 0x25A0, //BLACK SQUARE + 0xA1E2: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1E3: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1E4: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA1E5: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA1E6: 0x2192, //RIGHTWARDS ARROW + 0xA1E7: 0x2190, //LEFTWARDS ARROW + 0xA1E8: 0x2191, //UPWARDS ARROW + 0xA1E9: 0x2193, //DOWNWARDS ARROW + 0xA1EA: 0x2194, //LEFT RIGHT ARROW + 0xA1EB: 0x3013, //GETA MARK + 0xA1EC: 0x226A, //MUCH LESS-THAN + 0xA1ED: 0x226B, //MUCH GREATER-THAN + 0xA1EE: 0x221A, //SQUARE ROOT + 0xA1EF: 0x223D, //REVERSED TILDE + 0xA1F0: 0x221D, //PROPORTIONAL TO + 0xA1F1: 0x2235, //BECAUSE + 0xA1F2: 0x222B, //INTEGRAL + 0xA1F3: 0x222C, //DOUBLE INTEGRAL + 0xA1F4: 0x2208, //ELEMENT OF + 0xA1F5: 0x220B, //CONTAINS AS MEMBER + 0xA1F6: 0x2286, //SUBSET OF OR EQUAL TO + 0xA1F7: 0x2287, //SUPERSET OF OR EQUAL TO + 0xA1F8: 0x2282, //SUBSET OF + 0xA1F9: 0x2283, //SUPERSET OF + 0xA1FA: 0x222A, //UNION + 0xA1FB: 0x2229, //INTERSECTION + 0xA1FC: 0x2227, //LOGICAL AND + 0xA1FD: 0x2228, //LOGICAL OR + 0xA1FE: 0xFFE2, //FULLWIDTH NOT SIGN + 0xA241: 0xC910, //HANGUL SYLLABLE CIEUC U SSANGSIOS + 0xA242: 0xC912, //HANGUL SYLLABLE CIEUC U CIEUC + 0xA243: 0xC913, //HANGUL SYLLABLE CIEUC U CHIEUCH + 0xA244: 0xC914, //HANGUL SYLLABLE CIEUC U KHIEUKH + 0xA245: 0xC915, //HANGUL SYLLABLE CIEUC U THIEUTH + 0xA246: 0xC916, //HANGUL SYLLABLE CIEUC U PHIEUPH + 0xA247: 0xC917, //HANGUL SYLLABLE CIEUC U HIEUH + 0xA248: 0xC919, //HANGUL SYLLABLE CIEUC WEO KIYEOK + 0xA249: 0xC91A, //HANGUL SYLLABLE CIEUC WEO SSANGKIYEOK + 0xA24A: 0xC91B, //HANGUL SYLLABLE CIEUC WEO KIYEOKSIOS + 0xA24B: 0xC91C, //HANGUL SYLLABLE CIEUC WEO NIEUN + 0xA24C: 0xC91D, //HANGUL SYLLABLE CIEUC WEO NIEUNCIEUC + 0xA24D: 0xC91E, //HANGUL SYLLABLE CIEUC WEO NIEUNHIEUH + 0xA24E: 0xC91F, //HANGUL SYLLABLE CIEUC WEO TIKEUT + 0xA24F: 0xC920, //HANGUL SYLLABLE CIEUC WEO RIEUL + 0xA250: 0xC921, //HANGUL SYLLABLE CIEUC WEO RIEULKIYEOK + 0xA251: 0xC922, //HANGUL SYLLABLE CIEUC WEO RIEULMIEUM + 0xA252: 0xC923, //HANGUL SYLLABLE CIEUC WEO RIEULPIEUP + 0xA253: 0xC924, //HANGUL SYLLABLE CIEUC WEO RIEULSIOS + 0xA254: 0xC925, //HANGUL SYLLABLE CIEUC WEO RIEULTHIEUTH + 0xA255: 0xC926, //HANGUL SYLLABLE CIEUC WEO RIEULPHIEUPH + 0xA256: 0xC927, //HANGUL SYLLABLE CIEUC WEO RIEULHIEUH + 0xA257: 0xC928, //HANGUL SYLLABLE CIEUC WEO MIEUM + 0xA258: 0xC929, //HANGUL SYLLABLE CIEUC WEO PIEUP + 0xA259: 0xC92A, //HANGUL SYLLABLE CIEUC WEO PIEUPSIOS + 0xA25A: 0xC92B, //HANGUL SYLLABLE CIEUC WEO SIOS + 0xA261: 0xC92D, //HANGUL SYLLABLE CIEUC WEO IEUNG + 0xA262: 0xC92E, //HANGUL SYLLABLE CIEUC WEO CIEUC + 0xA263: 0xC92F, //HANGUL SYLLABLE CIEUC WEO CHIEUCH + 0xA264: 0xC930, //HANGUL SYLLABLE CIEUC WEO KHIEUKH + 0xA265: 0xC931, //HANGUL SYLLABLE CIEUC WEO THIEUTH + 0xA266: 0xC932, //HANGUL SYLLABLE CIEUC WEO PHIEUPH + 0xA267: 0xC933, //HANGUL SYLLABLE CIEUC WEO HIEUH + 0xA268: 0xC935, //HANGUL SYLLABLE CIEUC WE KIYEOK + 0xA269: 0xC936, //HANGUL SYLLABLE CIEUC WE SSANGKIYEOK + 0xA26A: 0xC937, //HANGUL SYLLABLE CIEUC WE KIYEOKSIOS + 0xA26B: 0xC938, //HANGUL SYLLABLE CIEUC WE NIEUN + 0xA26C: 0xC939, //HANGUL SYLLABLE CIEUC WE NIEUNCIEUC + 0xA26D: 0xC93A, //HANGUL SYLLABLE CIEUC WE NIEUNHIEUH + 0xA26E: 0xC93B, //HANGUL SYLLABLE CIEUC WE TIKEUT + 0xA26F: 0xC93C, //HANGUL SYLLABLE CIEUC WE RIEUL + 0xA270: 0xC93D, //HANGUL SYLLABLE CIEUC WE RIEULKIYEOK + 0xA271: 0xC93E, //HANGUL SYLLABLE CIEUC WE RIEULMIEUM + 0xA272: 0xC93F, //HANGUL SYLLABLE CIEUC WE RIEULPIEUP + 0xA273: 0xC940, //HANGUL SYLLABLE CIEUC WE RIEULSIOS + 0xA274: 0xC941, //HANGUL SYLLABLE CIEUC WE RIEULTHIEUTH + 0xA275: 0xC942, //HANGUL SYLLABLE CIEUC WE RIEULPHIEUPH + 0xA276: 0xC943, //HANGUL SYLLABLE CIEUC WE RIEULHIEUH + 0xA277: 0xC944, //HANGUL SYLLABLE CIEUC WE MIEUM + 0xA278: 0xC945, //HANGUL SYLLABLE CIEUC WE PIEUP + 0xA279: 0xC946, //HANGUL SYLLABLE CIEUC WE PIEUPSIOS + 0xA27A: 0xC947, //HANGUL SYLLABLE CIEUC WE SIOS + 0xA281: 0xC948, //HANGUL SYLLABLE CIEUC WE SSANGSIOS + 0xA282: 0xC949, //HANGUL SYLLABLE CIEUC WE IEUNG + 0xA283: 0xC94A, //HANGUL SYLLABLE CIEUC WE CIEUC + 0xA284: 0xC94B, //HANGUL SYLLABLE CIEUC WE CHIEUCH + 0xA285: 0xC94C, //HANGUL SYLLABLE CIEUC WE KHIEUKH + 0xA286: 0xC94D, //HANGUL SYLLABLE CIEUC WE THIEUTH + 0xA287: 0xC94E, //HANGUL SYLLABLE CIEUC WE PHIEUPH + 0xA288: 0xC94F, //HANGUL SYLLABLE CIEUC WE HIEUH + 0xA289: 0xC952, //HANGUL SYLLABLE CIEUC WI SSANGKIYEOK + 0xA28A: 0xC953, //HANGUL SYLLABLE CIEUC WI KIYEOKSIOS + 0xA28B: 0xC955, //HANGUL SYLLABLE CIEUC WI NIEUNCIEUC + 0xA28C: 0xC956, //HANGUL SYLLABLE CIEUC WI NIEUNHIEUH + 0xA28D: 0xC957, //HANGUL SYLLABLE CIEUC WI TIKEUT + 0xA28E: 0xC959, //HANGUL SYLLABLE CIEUC WI RIEULKIYEOK + 0xA28F: 0xC95A, //HANGUL SYLLABLE CIEUC WI RIEULMIEUM + 0xA290: 0xC95B, //HANGUL SYLLABLE CIEUC WI RIEULPIEUP + 0xA291: 0xC95C, //HANGUL SYLLABLE CIEUC WI RIEULSIOS + 0xA292: 0xC95D, //HANGUL SYLLABLE CIEUC WI RIEULTHIEUTH + 0xA293: 0xC95E, //HANGUL SYLLABLE CIEUC WI RIEULPHIEUPH + 0xA294: 0xC95F, //HANGUL SYLLABLE CIEUC WI RIEULHIEUH + 0xA295: 0xC962, //HANGUL SYLLABLE CIEUC WI PIEUPSIOS + 0xA296: 0xC964, //HANGUL SYLLABLE CIEUC WI SSANGSIOS + 0xA297: 0xC965, //HANGUL SYLLABLE CIEUC WI IEUNG + 0xA298: 0xC966, //HANGUL SYLLABLE CIEUC WI CIEUC + 0xA299: 0xC967, //HANGUL SYLLABLE CIEUC WI CHIEUCH + 0xA29A: 0xC968, //HANGUL SYLLABLE CIEUC WI KHIEUKH + 0xA29B: 0xC969, //HANGUL SYLLABLE CIEUC WI THIEUTH + 0xA29C: 0xC96A, //HANGUL SYLLABLE CIEUC WI PHIEUPH + 0xA29D: 0xC96B, //HANGUL SYLLABLE CIEUC WI HIEUH + 0xA29E: 0xC96D, //HANGUL SYLLABLE CIEUC YU KIYEOK + 0xA29F: 0xC96E, //HANGUL SYLLABLE CIEUC YU SSANGKIYEOK + 0xA2A0: 0xC96F, //HANGUL SYLLABLE CIEUC YU KIYEOKSIOS + 0xA2A1: 0x21D2, //RIGHTWARDS DOUBLE ARROW + 0xA2A2: 0x21D4, //LEFT RIGHT DOUBLE ARROW + 0xA2A3: 0x2200, //FOR ALL + 0xA2A4: 0x2203, //THERE EXISTS + 0xA2A5: 0x00B4, //ACUTE ACCENT + 0xA2A6: 0xFF5E, //FULLWIDTH TILDE + 0xA2A7: 0x02C7, //CARON + 0xA2A8: 0x02D8, //BREVE + 0xA2A9: 0x02DD, //DOUBLE ACUTE ACCENT + 0xA2AA: 0x02DA, //RING ABOVE + 0xA2AB: 0x02D9, //DOT ABOVE + 0xA2AC: 0x00B8, //CEDILLA + 0xA2AD: 0x02DB, //OGONEK + 0xA2AE: 0x00A1, //INVERTED EXCLAMATION MARK + 0xA2AF: 0x00BF, //INVERTED QUESTION MARK + 0xA2B0: 0x02D0, //MODIFIER LETTER TRIANGULAR COLON + 0xA2B1: 0x222E, //CONTOUR INTEGRAL + 0xA2B2: 0x2211, //N-ARY SUMMATION + 0xA2B3: 0x220F, //N-ARY PRODUCT + 0xA2B4: 0x00A4, //CURRENCY SIGN + 0xA2B5: 0x2109, //DEGREE FAHRENHEIT + 0xA2B6: 0x2030, //PER MILLE SIGN + 0xA2B7: 0x25C1, //WHITE LEFT-POINTING TRIANGLE + 0xA2B8: 0x25C0, //BLACK LEFT-POINTING TRIANGLE + 0xA2B9: 0x25B7, //WHITE RIGHT-POINTING TRIANGLE + 0xA2BA: 0x25B6, //BLACK RIGHT-POINTING TRIANGLE + 0xA2BB: 0x2664, //WHITE SPADE SUIT + 0xA2BC: 0x2660, //BLACK SPADE SUIT + 0xA2BD: 0x2661, //WHITE HEART SUIT + 0xA2BE: 0x2665, //BLACK HEART SUIT + 0xA2BF: 0x2667, //WHITE CLUB SUIT + 0xA2C0: 0x2663, //BLACK CLUB SUIT + 0xA2C1: 0x2299, //CIRCLED DOT OPERATOR + 0xA2C2: 0x25C8, //WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND + 0xA2C3: 0x25A3, //WHITE SQUARE CONTAINING BLACK SMALL SQUARE + 0xA2C4: 0x25D0, //CIRCLE WITH LEFT HALF BLACK + 0xA2C5: 0x25D1, //CIRCLE WITH RIGHT HALF BLACK + 0xA2C6: 0x2592, //MEDIUM SHADE + 0xA2C7: 0x25A4, //SQUARE WITH HORIZONTAL FILL + 0xA2C8: 0x25A5, //SQUARE WITH VERTICAL FILL + 0xA2C9: 0x25A8, //SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL + 0xA2CA: 0x25A7, //SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL + 0xA2CB: 0x25A6, //SQUARE WITH ORTHOGONAL CROSSHATCH FILL + 0xA2CC: 0x25A9, //SQUARE WITH DIAGONAL CROSSHATCH FILL + 0xA2CD: 0x2668, //HOT SPRINGS + 0xA2CE: 0x260F, //WHITE TELEPHONE + 0xA2CF: 0x260E, //BLACK TELEPHONE + 0xA2D0: 0x261C, //WHITE LEFT POINTING INDEX + 0xA2D1: 0x261E, //WHITE RIGHT POINTING INDEX + 0xA2D2: 0x00B6, //PILCROW SIGN + 0xA2D3: 0x2020, //DAGGER + 0xA2D4: 0x2021, //DOUBLE DAGGER + 0xA2D5: 0x2195, //UP DOWN ARROW + 0xA2D6: 0x2197, //NORTH EAST ARROW + 0xA2D7: 0x2199, //SOUTH WEST ARROW + 0xA2D8: 0x2196, //NORTH WEST ARROW + 0xA2D9: 0x2198, //SOUTH EAST ARROW + 0xA2DA: 0x266D, //MUSIC FLAT SIGN + 0xA2DB: 0x2669, //QUARTER NOTE + 0xA2DC: 0x266A, //EIGHTH NOTE + 0xA2DD: 0x266C, //BEAMED SIXTEENTH NOTES + 0xA2DE: 0x327F, //KOREAN STANDARD SYMBOL + 0xA2DF: 0x321C, //PARENTHESIZED HANGUL CIEUC U + 0xA2E0: 0x2116, //NUMERO SIGN + 0xA2E1: 0x33C7, //SQUARE CO + 0xA2E2: 0x2122, //TRADE MARK SIGN + 0xA2E3: 0x33C2, //SQUARE AM + 0xA2E4: 0x33D8, //SQUARE PM + 0xA2E5: 0x2121, //TELEPHONE SIGN + 0xA2E6: 0x20AC, //EURO SIGN + 0xA2E7: 0x00AE, //REGISTERED SIGN + 0xA341: 0xC971, //HANGUL SYLLABLE CIEUC YU NIEUNCIEUC + 0xA342: 0xC972, //HANGUL SYLLABLE CIEUC YU NIEUNHIEUH + 0xA343: 0xC973, //HANGUL SYLLABLE CIEUC YU TIKEUT + 0xA344: 0xC975, //HANGUL SYLLABLE CIEUC YU RIEULKIYEOK + 0xA345: 0xC976, //HANGUL SYLLABLE CIEUC YU RIEULMIEUM + 0xA346: 0xC977, //HANGUL SYLLABLE CIEUC YU RIEULPIEUP + 0xA347: 0xC978, //HANGUL SYLLABLE CIEUC YU RIEULSIOS + 0xA348: 0xC979, //HANGUL SYLLABLE CIEUC YU RIEULTHIEUTH + 0xA349: 0xC97A, //HANGUL SYLLABLE CIEUC YU RIEULPHIEUPH + 0xA34A: 0xC97B, //HANGUL SYLLABLE CIEUC YU RIEULHIEUH + 0xA34B: 0xC97D, //HANGUL SYLLABLE CIEUC YU PIEUP + 0xA34C: 0xC97E, //HANGUL SYLLABLE CIEUC YU PIEUPSIOS + 0xA34D: 0xC97F, //HANGUL SYLLABLE CIEUC YU SIOS + 0xA34E: 0xC980, //HANGUL SYLLABLE CIEUC YU SSANGSIOS + 0xA34F: 0xC981, //HANGUL SYLLABLE CIEUC YU IEUNG + 0xA350: 0xC982, //HANGUL SYLLABLE CIEUC YU CIEUC + 0xA351: 0xC983, //HANGUL SYLLABLE CIEUC YU CHIEUCH + 0xA352: 0xC984, //HANGUL SYLLABLE CIEUC YU KHIEUKH + 0xA353: 0xC985, //HANGUL SYLLABLE CIEUC YU THIEUTH + 0xA354: 0xC986, //HANGUL SYLLABLE CIEUC YU PHIEUPH + 0xA355: 0xC987, //HANGUL SYLLABLE CIEUC YU HIEUH + 0xA356: 0xC98A, //HANGUL SYLLABLE CIEUC EU SSANGKIYEOK + 0xA357: 0xC98B, //HANGUL SYLLABLE CIEUC EU KIYEOKSIOS + 0xA358: 0xC98D, //HANGUL SYLLABLE CIEUC EU NIEUNCIEUC + 0xA359: 0xC98E, //HANGUL SYLLABLE CIEUC EU NIEUNHIEUH + 0xA35A: 0xC98F, //HANGUL SYLLABLE CIEUC EU TIKEUT + 0xA361: 0xC991, //HANGUL SYLLABLE CIEUC EU RIEULKIYEOK + 0xA362: 0xC992, //HANGUL SYLLABLE CIEUC EU RIEULMIEUM + 0xA363: 0xC993, //HANGUL SYLLABLE CIEUC EU RIEULPIEUP + 0xA364: 0xC994, //HANGUL SYLLABLE CIEUC EU RIEULSIOS + 0xA365: 0xC995, //HANGUL SYLLABLE CIEUC EU RIEULTHIEUTH + 0xA366: 0xC996, //HANGUL SYLLABLE CIEUC EU RIEULPHIEUPH + 0xA367: 0xC997, //HANGUL SYLLABLE CIEUC EU RIEULHIEUH + 0xA368: 0xC99A, //HANGUL SYLLABLE CIEUC EU PIEUPSIOS + 0xA369: 0xC99C, //HANGUL SYLLABLE CIEUC EU SSANGSIOS + 0xA36A: 0xC99E, //HANGUL SYLLABLE CIEUC EU CIEUC + 0xA36B: 0xC99F, //HANGUL SYLLABLE CIEUC EU CHIEUCH + 0xA36C: 0xC9A0, //HANGUL SYLLABLE CIEUC EU KHIEUKH + 0xA36D: 0xC9A1, //HANGUL SYLLABLE CIEUC EU THIEUTH + 0xA36E: 0xC9A2, //HANGUL SYLLABLE CIEUC EU PHIEUPH + 0xA36F: 0xC9A3, //HANGUL SYLLABLE CIEUC EU HIEUH + 0xA370: 0xC9A4, //HANGUL SYLLABLE CIEUC YI + 0xA371: 0xC9A5, //HANGUL SYLLABLE CIEUC YI KIYEOK + 0xA372: 0xC9A6, //HANGUL SYLLABLE CIEUC YI SSANGKIYEOK + 0xA373: 0xC9A7, //HANGUL SYLLABLE CIEUC YI KIYEOKSIOS + 0xA374: 0xC9A8, //HANGUL SYLLABLE CIEUC YI NIEUN + 0xA375: 0xC9A9, //HANGUL SYLLABLE CIEUC YI NIEUNCIEUC + 0xA376: 0xC9AA, //HANGUL SYLLABLE CIEUC YI NIEUNHIEUH + 0xA377: 0xC9AB, //HANGUL SYLLABLE CIEUC YI TIKEUT + 0xA378: 0xC9AC, //HANGUL SYLLABLE CIEUC YI RIEUL + 0xA379: 0xC9AD, //HANGUL SYLLABLE CIEUC YI RIEULKIYEOK + 0xA37A: 0xC9AE, //HANGUL SYLLABLE CIEUC YI RIEULMIEUM + 0xA381: 0xC9AF, //HANGUL SYLLABLE CIEUC YI RIEULPIEUP + 0xA382: 0xC9B0, //HANGUL SYLLABLE CIEUC YI RIEULSIOS + 0xA383: 0xC9B1, //HANGUL SYLLABLE CIEUC YI RIEULTHIEUTH + 0xA384: 0xC9B2, //HANGUL SYLLABLE CIEUC YI RIEULPHIEUPH + 0xA385: 0xC9B3, //HANGUL SYLLABLE CIEUC YI RIEULHIEUH + 0xA386: 0xC9B4, //HANGUL SYLLABLE CIEUC YI MIEUM + 0xA387: 0xC9B5, //HANGUL SYLLABLE CIEUC YI PIEUP + 0xA388: 0xC9B6, //HANGUL SYLLABLE CIEUC YI PIEUPSIOS + 0xA389: 0xC9B7, //HANGUL SYLLABLE CIEUC YI SIOS + 0xA38A: 0xC9B8, //HANGUL SYLLABLE CIEUC YI SSANGSIOS + 0xA38B: 0xC9B9, //HANGUL SYLLABLE CIEUC YI IEUNG + 0xA38C: 0xC9BA, //HANGUL SYLLABLE CIEUC YI CIEUC + 0xA38D: 0xC9BB, //HANGUL SYLLABLE CIEUC YI CHIEUCH + 0xA38E: 0xC9BC, //HANGUL SYLLABLE CIEUC YI KHIEUKH + 0xA38F: 0xC9BD, //HANGUL SYLLABLE CIEUC YI THIEUTH + 0xA390: 0xC9BE, //HANGUL SYLLABLE CIEUC YI PHIEUPH + 0xA391: 0xC9BF, //HANGUL SYLLABLE CIEUC YI HIEUH + 0xA392: 0xC9C2, //HANGUL SYLLABLE CIEUC I SSANGKIYEOK + 0xA393: 0xC9C3, //HANGUL SYLLABLE CIEUC I KIYEOKSIOS + 0xA394: 0xC9C5, //HANGUL SYLLABLE CIEUC I NIEUNCIEUC + 0xA395: 0xC9C6, //HANGUL SYLLABLE CIEUC I NIEUNHIEUH + 0xA396: 0xC9C9, //HANGUL SYLLABLE CIEUC I RIEULKIYEOK + 0xA397: 0xC9CB, //HANGUL SYLLABLE CIEUC I RIEULPIEUP + 0xA398: 0xC9CC, //HANGUL SYLLABLE CIEUC I RIEULSIOS + 0xA399: 0xC9CD, //HANGUL SYLLABLE CIEUC I RIEULTHIEUTH + 0xA39A: 0xC9CE, //HANGUL SYLLABLE CIEUC I RIEULPHIEUPH + 0xA39B: 0xC9CF, //HANGUL SYLLABLE CIEUC I RIEULHIEUH + 0xA39C: 0xC9D2, //HANGUL SYLLABLE CIEUC I PIEUPSIOS + 0xA39D: 0xC9D4, //HANGUL SYLLABLE CIEUC I SSANGSIOS + 0xA39E: 0xC9D7, //HANGUL SYLLABLE CIEUC I CHIEUCH + 0xA39F: 0xC9D8, //HANGUL SYLLABLE CIEUC I KHIEUKH + 0xA3A0: 0xC9DB, //HANGUL SYLLABLE CIEUC I HIEUH + 0xA3A1: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA3A2: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xA3A3: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA3A4: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA3A5: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA3A6: 0xFF06, //FULLWIDTH AMPERSAND + 0xA3A7: 0xFF07, //FULLWIDTH APOSTROPHE + 0xA3A8: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA3A9: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA3AA: 0xFF0A, //FULLWIDTH ASTERISK + 0xA3AB: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA3AC: 0xFF0C, //FULLWIDTH COMMA + 0xA3AD: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA3AE: 0xFF0E, //FULLWIDTH FULL STOP + 0xA3AF: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA3B0: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA3B1: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA3B2: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA3B3: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA3B4: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA3B5: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA3B6: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA3B7: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA3B8: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA3B9: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA3BA: 0xFF1A, //FULLWIDTH COLON + 0xA3BB: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA3BC: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA3BD: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA3BE: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA3BF: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA3C0: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA3C1: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA3C2: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA3C3: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA3C4: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA3C5: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA3C6: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA3C7: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA3C8: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA3C9: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA3CA: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA3CB: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA3CC: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA3CD: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA3CE: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA3CF: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA3D0: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA3D1: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA3D2: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA3D3: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA3D4: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA3D5: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA3D6: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA3D7: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA3D8: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA3D9: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA3DA: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA3DB: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0xA3DC: 0xFFE6, //FULLWIDTH WON SIGN + 0xA3DD: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0xA3DE: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0xA3DF: 0xFF3F, //FULLWIDTH LOW LINE + 0xA3E0: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0xA3E1: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA3E2: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA3E3: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA3E4: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA3E5: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA3E6: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA3E7: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA3E8: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA3E9: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA3EA: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA3EB: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA3EC: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA3ED: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA3EE: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA3EF: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA3F0: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA3F1: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA3F2: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA3F3: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA3F4: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA3F5: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA3F6: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA3F7: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA3F8: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA3F9: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA3FA: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA3FB: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA3FC: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA3FD: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA3FE: 0xFFE3, //FULLWIDTH MACRON + 0xA441: 0xC9DE, //HANGUL SYLLABLE SSANGCIEUC A SSANGKIYEOK + 0xA442: 0xC9DF, //HANGUL SYLLABLE SSANGCIEUC A KIYEOKSIOS + 0xA443: 0xC9E1, //HANGUL SYLLABLE SSANGCIEUC A NIEUNCIEUC + 0xA444: 0xC9E3, //HANGUL SYLLABLE SSANGCIEUC A TIKEUT + 0xA445: 0xC9E5, //HANGUL SYLLABLE SSANGCIEUC A RIEULKIYEOK + 0xA446: 0xC9E6, //HANGUL SYLLABLE SSANGCIEUC A RIEULMIEUM + 0xA447: 0xC9E8, //HANGUL SYLLABLE SSANGCIEUC A RIEULSIOS + 0xA448: 0xC9E9, //HANGUL SYLLABLE SSANGCIEUC A RIEULTHIEUTH + 0xA449: 0xC9EA, //HANGUL SYLLABLE SSANGCIEUC A RIEULPHIEUPH + 0xA44A: 0xC9EB, //HANGUL SYLLABLE SSANGCIEUC A RIEULHIEUH + 0xA44B: 0xC9EE, //HANGUL SYLLABLE SSANGCIEUC A PIEUPSIOS + 0xA44C: 0xC9F2, //HANGUL SYLLABLE SSANGCIEUC A CIEUC + 0xA44D: 0xC9F3, //HANGUL SYLLABLE SSANGCIEUC A CHIEUCH + 0xA44E: 0xC9F4, //HANGUL SYLLABLE SSANGCIEUC A KHIEUKH + 0xA44F: 0xC9F5, //HANGUL SYLLABLE SSANGCIEUC A THIEUTH + 0xA450: 0xC9F6, //HANGUL SYLLABLE SSANGCIEUC A PHIEUPH + 0xA451: 0xC9F7, //HANGUL SYLLABLE SSANGCIEUC A HIEUH + 0xA452: 0xC9FA, //HANGUL SYLLABLE SSANGCIEUC AE SSANGKIYEOK + 0xA453: 0xC9FB, //HANGUL SYLLABLE SSANGCIEUC AE KIYEOKSIOS + 0xA454: 0xC9FD, //HANGUL SYLLABLE SSANGCIEUC AE NIEUNCIEUC + 0xA455: 0xC9FE, //HANGUL SYLLABLE SSANGCIEUC AE NIEUNHIEUH + 0xA456: 0xC9FF, //HANGUL SYLLABLE SSANGCIEUC AE TIKEUT + 0xA457: 0xCA01, //HANGUL SYLLABLE SSANGCIEUC AE RIEULKIYEOK + 0xA458: 0xCA02, //HANGUL SYLLABLE SSANGCIEUC AE RIEULMIEUM + 0xA459: 0xCA03, //HANGUL SYLLABLE SSANGCIEUC AE RIEULPIEUP + 0xA45A: 0xCA04, //HANGUL SYLLABLE SSANGCIEUC AE RIEULSIOS + 0xA461: 0xCA05, //HANGUL SYLLABLE SSANGCIEUC AE RIEULTHIEUTH + 0xA462: 0xCA06, //HANGUL SYLLABLE SSANGCIEUC AE RIEULPHIEUPH + 0xA463: 0xCA07, //HANGUL SYLLABLE SSANGCIEUC AE RIEULHIEUH + 0xA464: 0xCA0A, //HANGUL SYLLABLE SSANGCIEUC AE PIEUPSIOS + 0xA465: 0xCA0E, //HANGUL SYLLABLE SSANGCIEUC AE CIEUC + 0xA466: 0xCA0F, //HANGUL SYLLABLE SSANGCIEUC AE CHIEUCH + 0xA467: 0xCA10, //HANGUL SYLLABLE SSANGCIEUC AE KHIEUKH + 0xA468: 0xCA11, //HANGUL SYLLABLE SSANGCIEUC AE THIEUTH + 0xA469: 0xCA12, //HANGUL SYLLABLE SSANGCIEUC AE PHIEUPH + 0xA46A: 0xCA13, //HANGUL SYLLABLE SSANGCIEUC AE HIEUH + 0xA46B: 0xCA15, //HANGUL SYLLABLE SSANGCIEUC YA KIYEOK + 0xA46C: 0xCA16, //HANGUL SYLLABLE SSANGCIEUC YA SSANGKIYEOK + 0xA46D: 0xCA17, //HANGUL SYLLABLE SSANGCIEUC YA KIYEOKSIOS + 0xA46E: 0xCA19, //HANGUL SYLLABLE SSANGCIEUC YA NIEUNCIEUC + 0xA46F: 0xCA1A, //HANGUL SYLLABLE SSANGCIEUC YA NIEUNHIEUH + 0xA470: 0xCA1B, //HANGUL SYLLABLE SSANGCIEUC YA TIKEUT + 0xA471: 0xCA1C, //HANGUL SYLLABLE SSANGCIEUC YA RIEUL + 0xA472: 0xCA1D, //HANGUL SYLLABLE SSANGCIEUC YA RIEULKIYEOK + 0xA473: 0xCA1E, //HANGUL SYLLABLE SSANGCIEUC YA RIEULMIEUM + 0xA474: 0xCA1F, //HANGUL SYLLABLE SSANGCIEUC YA RIEULPIEUP + 0xA475: 0xCA20, //HANGUL SYLLABLE SSANGCIEUC YA RIEULSIOS + 0xA476: 0xCA21, //HANGUL SYLLABLE SSANGCIEUC YA RIEULTHIEUTH + 0xA477: 0xCA22, //HANGUL SYLLABLE SSANGCIEUC YA RIEULPHIEUPH + 0xA478: 0xCA23, //HANGUL SYLLABLE SSANGCIEUC YA RIEULHIEUH + 0xA479: 0xCA24, //HANGUL SYLLABLE SSANGCIEUC YA MIEUM + 0xA47A: 0xCA25, //HANGUL SYLLABLE SSANGCIEUC YA PIEUP + 0xA481: 0xCA26, //HANGUL SYLLABLE SSANGCIEUC YA PIEUPSIOS + 0xA482: 0xCA27, //HANGUL SYLLABLE SSANGCIEUC YA SIOS + 0xA483: 0xCA28, //HANGUL SYLLABLE SSANGCIEUC YA SSANGSIOS + 0xA484: 0xCA2A, //HANGUL SYLLABLE SSANGCIEUC YA CIEUC + 0xA485: 0xCA2B, //HANGUL SYLLABLE SSANGCIEUC YA CHIEUCH + 0xA486: 0xCA2C, //HANGUL SYLLABLE SSANGCIEUC YA KHIEUKH + 0xA487: 0xCA2D, //HANGUL SYLLABLE SSANGCIEUC YA THIEUTH + 0xA488: 0xCA2E, //HANGUL SYLLABLE SSANGCIEUC YA PHIEUPH + 0xA489: 0xCA2F, //HANGUL SYLLABLE SSANGCIEUC YA HIEUH + 0xA48A: 0xCA30, //HANGUL SYLLABLE SSANGCIEUC YAE + 0xA48B: 0xCA31, //HANGUL SYLLABLE SSANGCIEUC YAE KIYEOK + 0xA48C: 0xCA32, //HANGUL SYLLABLE SSANGCIEUC YAE SSANGKIYEOK + 0xA48D: 0xCA33, //HANGUL SYLLABLE SSANGCIEUC YAE KIYEOKSIOS + 0xA48E: 0xCA34, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUN + 0xA48F: 0xCA35, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUNCIEUC + 0xA490: 0xCA36, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUNHIEUH + 0xA491: 0xCA37, //HANGUL SYLLABLE SSANGCIEUC YAE TIKEUT + 0xA492: 0xCA38, //HANGUL SYLLABLE SSANGCIEUC YAE RIEUL + 0xA493: 0xCA39, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULKIYEOK + 0xA494: 0xCA3A, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULMIEUM + 0xA495: 0xCA3B, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULPIEUP + 0xA496: 0xCA3C, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULSIOS + 0xA497: 0xCA3D, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULTHIEUTH + 0xA498: 0xCA3E, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULPHIEUPH + 0xA499: 0xCA3F, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULHIEUH + 0xA49A: 0xCA40, //HANGUL SYLLABLE SSANGCIEUC YAE MIEUM + 0xA49B: 0xCA41, //HANGUL SYLLABLE SSANGCIEUC YAE PIEUP + 0xA49C: 0xCA42, //HANGUL SYLLABLE SSANGCIEUC YAE PIEUPSIOS + 0xA49D: 0xCA43, //HANGUL SYLLABLE SSANGCIEUC YAE SIOS + 0xA49E: 0xCA44, //HANGUL SYLLABLE SSANGCIEUC YAE SSANGSIOS + 0xA49F: 0xCA45, //HANGUL SYLLABLE SSANGCIEUC YAE IEUNG + 0xA4A0: 0xCA46, //HANGUL SYLLABLE SSANGCIEUC YAE CIEUC + 0xA4A1: 0x3131, //HANGUL LETTER KIYEOK + 0xA4A2: 0x3132, //HANGUL LETTER SSANGKIYEOK + 0xA4A3: 0x3133, //HANGUL LETTER KIYEOK-SIOS + 0xA4A4: 0x3134, //HANGUL LETTER NIEUN + 0xA4A5: 0x3135, //HANGUL LETTER NIEUN-CIEUC + 0xA4A6: 0x3136, //HANGUL LETTER NIEUN-HIEUH + 0xA4A7: 0x3137, //HANGUL LETTER TIKEUT + 0xA4A8: 0x3138, //HANGUL LETTER SSANGTIKEUT + 0xA4A9: 0x3139, //HANGUL LETTER RIEUL + 0xA4AA: 0x313A, //HANGUL LETTER RIEUL-KIYEOK + 0xA4AB: 0x313B, //HANGUL LETTER RIEUL-MIEUM + 0xA4AC: 0x313C, //HANGUL LETTER RIEUL-PIEUP + 0xA4AD: 0x313D, //HANGUL LETTER RIEUL-SIOS + 0xA4AE: 0x313E, //HANGUL LETTER RIEUL-THIEUTH + 0xA4AF: 0x313F, //HANGUL LETTER RIEUL-PHIEUPH + 0xA4B0: 0x3140, //HANGUL LETTER RIEUL-HIEUH + 0xA4B1: 0x3141, //HANGUL LETTER MIEUM + 0xA4B2: 0x3142, //HANGUL LETTER PIEUP + 0xA4B3: 0x3143, //HANGUL LETTER SSANGPIEUP + 0xA4B4: 0x3144, //HANGUL LETTER PIEUP-SIOS + 0xA4B5: 0x3145, //HANGUL LETTER SIOS + 0xA4B6: 0x3146, //HANGUL LETTER SSANGSIOS + 0xA4B7: 0x3147, //HANGUL LETTER IEUNG + 0xA4B8: 0x3148, //HANGUL LETTER CIEUC + 0xA4B9: 0x3149, //HANGUL LETTER SSANGCIEUC + 0xA4BA: 0x314A, //HANGUL LETTER CHIEUCH + 0xA4BB: 0x314B, //HANGUL LETTER KHIEUKH + 0xA4BC: 0x314C, //HANGUL LETTER THIEUTH + 0xA4BD: 0x314D, //HANGUL LETTER PHIEUPH + 0xA4BE: 0x314E, //HANGUL LETTER HIEUH + 0xA4BF: 0x314F, //HANGUL LETTER A + 0xA4C0: 0x3150, //HANGUL LETTER AE + 0xA4C1: 0x3151, //HANGUL LETTER YA + 0xA4C2: 0x3152, //HANGUL LETTER YAE + 0xA4C3: 0x3153, //HANGUL LETTER EO + 0xA4C4: 0x3154, //HANGUL LETTER E + 0xA4C5: 0x3155, //HANGUL LETTER YEO + 0xA4C6: 0x3156, //HANGUL LETTER YE + 0xA4C7: 0x3157, //HANGUL LETTER O + 0xA4C8: 0x3158, //HANGUL LETTER WA + 0xA4C9: 0x3159, //HANGUL LETTER WAE + 0xA4CA: 0x315A, //HANGUL LETTER OE + 0xA4CB: 0x315B, //HANGUL LETTER YO + 0xA4CC: 0x315C, //HANGUL LETTER U + 0xA4CD: 0x315D, //HANGUL LETTER WEO + 0xA4CE: 0x315E, //HANGUL LETTER WE + 0xA4CF: 0x315F, //HANGUL LETTER WI + 0xA4D0: 0x3160, //HANGUL LETTER YU + 0xA4D1: 0x3161, //HANGUL LETTER EU + 0xA4D2: 0x3162, //HANGUL LETTER YI + 0xA4D3: 0x3163, //HANGUL LETTER I + 0xA4D4: 0x3164, //HANGUL FILLER + 0xA4D5: 0x3165, //HANGUL LETTER SSANGNIEUN + 0xA4D6: 0x3166, //HANGUL LETTER NIEUN-TIKEUT + 0xA4D7: 0x3167, //HANGUL LETTER NIEUN-SIOS + 0xA4D8: 0x3168, //HANGUL LETTER NIEUN-PANSIOS + 0xA4D9: 0x3169, //HANGUL LETTER RIEUL-KIYEOK-SIOS + 0xA4DA: 0x316A, //HANGUL LETTER RIEUL-TIKEUT + 0xA4DB: 0x316B, //HANGUL LETTER RIEUL-PIEUP-SIOS + 0xA4DC: 0x316C, //HANGUL LETTER RIEUL-PANSIOS + 0xA4DD: 0x316D, //HANGUL LETTER RIEUL-YEORINHIEUH + 0xA4DE: 0x316E, //HANGUL LETTER MIEUM-PIEUP + 0xA4DF: 0x316F, //HANGUL LETTER MIEUM-SIOS + 0xA4E0: 0x3170, //HANGUL LETTER MIEUM-PANSIOS + 0xA4E1: 0x3171, //HANGUL LETTER KAPYEOUNMIEUM + 0xA4E2: 0x3172, //HANGUL LETTER PIEUP-KIYEOK + 0xA4E3: 0x3173, //HANGUL LETTER PIEUP-TIKEUT + 0xA4E4: 0x3174, //HANGUL LETTER PIEUP-SIOS-KIYEOK + 0xA4E5: 0x3175, //HANGUL LETTER PIEUP-SIOS-TIKEUT + 0xA4E6: 0x3176, //HANGUL LETTER PIEUP-CIEUC + 0xA4E7: 0x3177, //HANGUL LETTER PIEUP-THIEUTH + 0xA4E8: 0x3178, //HANGUL LETTER KAPYEOUNPIEUP + 0xA4E9: 0x3179, //HANGUL LETTER KAPYEOUNSSANGPIEUP + 0xA4EA: 0x317A, //HANGUL LETTER SIOS-KIYEOK + 0xA4EB: 0x317B, //HANGUL LETTER SIOS-NIEUN + 0xA4EC: 0x317C, //HANGUL LETTER SIOS-TIKEUT + 0xA4ED: 0x317D, //HANGUL LETTER SIOS-PIEUP + 0xA4EE: 0x317E, //HANGUL LETTER SIOS-CIEUC + 0xA4EF: 0x317F, //HANGUL LETTER PANSIOS + 0xA4F0: 0x3180, //HANGUL LETTER SSANGIEUNG + 0xA4F1: 0x3181, //HANGUL LETTER YESIEUNG + 0xA4F2: 0x3182, //HANGUL LETTER YESIEUNG-SIOS + 0xA4F3: 0x3183, //HANGUL LETTER YESIEUNG-PANSIOS + 0xA4F4: 0x3184, //HANGUL LETTER KAPYEOUNPHIEUPH + 0xA4F5: 0x3185, //HANGUL LETTER SSANGHIEUH + 0xA4F6: 0x3186, //HANGUL LETTER YEORINHIEUH + 0xA4F7: 0x3187, //HANGUL LETTER YO-YA + 0xA4F8: 0x3188, //HANGUL LETTER YO-YAE + 0xA4F9: 0x3189, //HANGUL LETTER YO-I + 0xA4FA: 0x318A, //HANGUL LETTER YU-YEO + 0xA4FB: 0x318B, //HANGUL LETTER YU-YE + 0xA4FC: 0x318C, //HANGUL LETTER YU-I + 0xA4FD: 0x318D, //HANGUL LETTER ARAEA + 0xA4FE: 0x318E, //HANGUL LETTER ARAEAE + 0xA541: 0xCA47, //HANGUL SYLLABLE SSANGCIEUC YAE CHIEUCH + 0xA542: 0xCA48, //HANGUL SYLLABLE SSANGCIEUC YAE KHIEUKH + 0xA543: 0xCA49, //HANGUL SYLLABLE SSANGCIEUC YAE THIEUTH + 0xA544: 0xCA4A, //HANGUL SYLLABLE SSANGCIEUC YAE PHIEUPH + 0xA545: 0xCA4B, //HANGUL SYLLABLE SSANGCIEUC YAE HIEUH + 0xA546: 0xCA4E, //HANGUL SYLLABLE SSANGCIEUC EO SSANGKIYEOK + 0xA547: 0xCA4F, //HANGUL SYLLABLE SSANGCIEUC EO KIYEOKSIOS + 0xA548: 0xCA51, //HANGUL SYLLABLE SSANGCIEUC EO NIEUNCIEUC + 0xA549: 0xCA52, //HANGUL SYLLABLE SSANGCIEUC EO NIEUNHIEUH + 0xA54A: 0xCA53, //HANGUL SYLLABLE SSANGCIEUC EO TIKEUT + 0xA54B: 0xCA55, //HANGUL SYLLABLE SSANGCIEUC EO RIEULKIYEOK + 0xA54C: 0xCA56, //HANGUL SYLLABLE SSANGCIEUC EO RIEULMIEUM + 0xA54D: 0xCA57, //HANGUL SYLLABLE SSANGCIEUC EO RIEULPIEUP + 0xA54E: 0xCA58, //HANGUL SYLLABLE SSANGCIEUC EO RIEULSIOS + 0xA54F: 0xCA59, //HANGUL SYLLABLE SSANGCIEUC EO RIEULTHIEUTH + 0xA550: 0xCA5A, //HANGUL SYLLABLE SSANGCIEUC EO RIEULPHIEUPH + 0xA551: 0xCA5B, //HANGUL SYLLABLE SSANGCIEUC EO RIEULHIEUH + 0xA552: 0xCA5E, //HANGUL SYLLABLE SSANGCIEUC EO PIEUPSIOS + 0xA553: 0xCA62, //HANGUL SYLLABLE SSANGCIEUC EO CIEUC + 0xA554: 0xCA63, //HANGUL SYLLABLE SSANGCIEUC EO CHIEUCH + 0xA555: 0xCA64, //HANGUL SYLLABLE SSANGCIEUC EO KHIEUKH + 0xA556: 0xCA65, //HANGUL SYLLABLE SSANGCIEUC EO THIEUTH + 0xA557: 0xCA66, //HANGUL SYLLABLE SSANGCIEUC EO PHIEUPH + 0xA558: 0xCA67, //HANGUL SYLLABLE SSANGCIEUC EO HIEUH + 0xA559: 0xCA69, //HANGUL SYLLABLE SSANGCIEUC E KIYEOK + 0xA55A: 0xCA6A, //HANGUL SYLLABLE SSANGCIEUC E SSANGKIYEOK + 0xA561: 0xCA6B, //HANGUL SYLLABLE SSANGCIEUC E KIYEOKSIOS + 0xA562: 0xCA6C, //HANGUL SYLLABLE SSANGCIEUC E NIEUN + 0xA563: 0xCA6D, //HANGUL SYLLABLE SSANGCIEUC E NIEUNCIEUC + 0xA564: 0xCA6E, //HANGUL SYLLABLE SSANGCIEUC E NIEUNHIEUH + 0xA565: 0xCA6F, //HANGUL SYLLABLE SSANGCIEUC E TIKEUT + 0xA566: 0xCA70, //HANGUL SYLLABLE SSANGCIEUC E RIEUL + 0xA567: 0xCA71, //HANGUL SYLLABLE SSANGCIEUC E RIEULKIYEOK + 0xA568: 0xCA72, //HANGUL SYLLABLE SSANGCIEUC E RIEULMIEUM + 0xA569: 0xCA73, //HANGUL SYLLABLE SSANGCIEUC E RIEULPIEUP + 0xA56A: 0xCA74, //HANGUL SYLLABLE SSANGCIEUC E RIEULSIOS + 0xA56B: 0xCA75, //HANGUL SYLLABLE SSANGCIEUC E RIEULTHIEUTH + 0xA56C: 0xCA76, //HANGUL SYLLABLE SSANGCIEUC E RIEULPHIEUPH + 0xA56D: 0xCA77, //HANGUL SYLLABLE SSANGCIEUC E RIEULHIEUH + 0xA56E: 0xCA78, //HANGUL SYLLABLE SSANGCIEUC E MIEUM + 0xA56F: 0xCA79, //HANGUL SYLLABLE SSANGCIEUC E PIEUP + 0xA570: 0xCA7A, //HANGUL SYLLABLE SSANGCIEUC E PIEUPSIOS + 0xA571: 0xCA7B, //HANGUL SYLLABLE SSANGCIEUC E SIOS + 0xA572: 0xCA7C, //HANGUL SYLLABLE SSANGCIEUC E SSANGSIOS + 0xA573: 0xCA7E, //HANGUL SYLLABLE SSANGCIEUC E CIEUC + 0xA574: 0xCA7F, //HANGUL SYLLABLE SSANGCIEUC E CHIEUCH + 0xA575: 0xCA80, //HANGUL SYLLABLE SSANGCIEUC E KHIEUKH + 0xA576: 0xCA81, //HANGUL SYLLABLE SSANGCIEUC E THIEUTH + 0xA577: 0xCA82, //HANGUL SYLLABLE SSANGCIEUC E PHIEUPH + 0xA578: 0xCA83, //HANGUL SYLLABLE SSANGCIEUC E HIEUH + 0xA579: 0xCA85, //HANGUL SYLLABLE SSANGCIEUC YEO KIYEOK + 0xA57A: 0xCA86, //HANGUL SYLLABLE SSANGCIEUC YEO SSANGKIYEOK + 0xA581: 0xCA87, //HANGUL SYLLABLE SSANGCIEUC YEO KIYEOKSIOS + 0xA582: 0xCA88, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUN + 0xA583: 0xCA89, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUNCIEUC + 0xA584: 0xCA8A, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUNHIEUH + 0xA585: 0xCA8B, //HANGUL SYLLABLE SSANGCIEUC YEO TIKEUT + 0xA586: 0xCA8C, //HANGUL SYLLABLE SSANGCIEUC YEO RIEUL + 0xA587: 0xCA8D, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULKIYEOK + 0xA588: 0xCA8E, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULMIEUM + 0xA589: 0xCA8F, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULPIEUP + 0xA58A: 0xCA90, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULSIOS + 0xA58B: 0xCA91, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULTHIEUTH + 0xA58C: 0xCA92, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULPHIEUPH + 0xA58D: 0xCA93, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULHIEUH + 0xA58E: 0xCA94, //HANGUL SYLLABLE SSANGCIEUC YEO MIEUM + 0xA58F: 0xCA95, //HANGUL SYLLABLE SSANGCIEUC YEO PIEUP + 0xA590: 0xCA96, //HANGUL SYLLABLE SSANGCIEUC YEO PIEUPSIOS + 0xA591: 0xCA97, //HANGUL SYLLABLE SSANGCIEUC YEO SIOS + 0xA592: 0xCA99, //HANGUL SYLLABLE SSANGCIEUC YEO IEUNG + 0xA593: 0xCA9A, //HANGUL SYLLABLE SSANGCIEUC YEO CIEUC + 0xA594: 0xCA9B, //HANGUL SYLLABLE SSANGCIEUC YEO CHIEUCH + 0xA595: 0xCA9C, //HANGUL SYLLABLE SSANGCIEUC YEO KHIEUKH + 0xA596: 0xCA9D, //HANGUL SYLLABLE SSANGCIEUC YEO THIEUTH + 0xA597: 0xCA9E, //HANGUL SYLLABLE SSANGCIEUC YEO PHIEUPH + 0xA598: 0xCA9F, //HANGUL SYLLABLE SSANGCIEUC YEO HIEUH + 0xA599: 0xCAA0, //HANGUL SYLLABLE SSANGCIEUC YE + 0xA59A: 0xCAA1, //HANGUL SYLLABLE SSANGCIEUC YE KIYEOK + 0xA59B: 0xCAA2, //HANGUL SYLLABLE SSANGCIEUC YE SSANGKIYEOK + 0xA59C: 0xCAA3, //HANGUL SYLLABLE SSANGCIEUC YE KIYEOKSIOS + 0xA59D: 0xCAA4, //HANGUL SYLLABLE SSANGCIEUC YE NIEUN + 0xA59E: 0xCAA5, //HANGUL SYLLABLE SSANGCIEUC YE NIEUNCIEUC + 0xA59F: 0xCAA6, //HANGUL SYLLABLE SSANGCIEUC YE NIEUNHIEUH + 0xA5A0: 0xCAA7, //HANGUL SYLLABLE SSANGCIEUC YE TIKEUT + 0xA5A1: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xA5A2: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xA5A3: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xA5A4: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xA5A5: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xA5A6: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xA5A7: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xA5A8: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xA5A9: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xA5AA: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xA5B0: 0x2160, //ROMAN NUMERAL ONE + 0xA5B1: 0x2161, //ROMAN NUMERAL TWO + 0xA5B2: 0x2162, //ROMAN NUMERAL THREE + 0xA5B3: 0x2163, //ROMAN NUMERAL FOUR + 0xA5B4: 0x2164, //ROMAN NUMERAL FIVE + 0xA5B5: 0x2165, //ROMAN NUMERAL SIX + 0xA5B6: 0x2166, //ROMAN NUMERAL SEVEN + 0xA5B7: 0x2167, //ROMAN NUMERAL EIGHT + 0xA5B8: 0x2168, //ROMAN NUMERAL NINE + 0xA5B9: 0x2169, //ROMAN NUMERAL TEN + 0xA5C1: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA5C2: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA5C3: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA5C4: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA5C5: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA5C6: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA5C7: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA5C8: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA5C9: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA5CA: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA5CB: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA5CC: 0x039C, //GREEK CAPITAL LETTER MU + 0xA5CD: 0x039D, //GREEK CAPITAL LETTER NU + 0xA5CE: 0x039E, //GREEK CAPITAL LETTER XI + 0xA5CF: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA5D0: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA5D1: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA5D2: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA5D3: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA5D4: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA5D5: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA5D6: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA5D7: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA5D8: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA5E1: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA5E2: 0x03B2, //GREEK SMALL LETTER BETA + 0xA5E3: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA5E4: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA5E5: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA5E6: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA5E7: 0x03B7, //GREEK SMALL LETTER ETA + 0xA5E8: 0x03B8, //GREEK SMALL LETTER THETA + 0xA5E9: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA5EA: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA5EB: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA5EC: 0x03BC, //GREEK SMALL LETTER MU + 0xA5ED: 0x03BD, //GREEK SMALL LETTER NU + 0xA5EE: 0x03BE, //GREEK SMALL LETTER XI + 0xA5EF: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA5F0: 0x03C0, //GREEK SMALL LETTER PI + 0xA5F1: 0x03C1, //GREEK SMALL LETTER RHO + 0xA5F2: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA5F3: 0x03C4, //GREEK SMALL LETTER TAU + 0xA5F4: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA5F5: 0x03C6, //GREEK SMALL LETTER PHI + 0xA5F6: 0x03C7, //GREEK SMALL LETTER CHI + 0xA5F7: 0x03C8, //GREEK SMALL LETTER PSI + 0xA5F8: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA641: 0xCAA8, //HANGUL SYLLABLE SSANGCIEUC YE RIEUL + 0xA642: 0xCAA9, //HANGUL SYLLABLE SSANGCIEUC YE RIEULKIYEOK + 0xA643: 0xCAAA, //HANGUL SYLLABLE SSANGCIEUC YE RIEULMIEUM + 0xA644: 0xCAAB, //HANGUL SYLLABLE SSANGCIEUC YE RIEULPIEUP + 0xA645: 0xCAAC, //HANGUL SYLLABLE SSANGCIEUC YE RIEULSIOS + 0xA646: 0xCAAD, //HANGUL SYLLABLE SSANGCIEUC YE RIEULTHIEUTH + 0xA647: 0xCAAE, //HANGUL SYLLABLE SSANGCIEUC YE RIEULPHIEUPH + 0xA648: 0xCAAF, //HANGUL SYLLABLE SSANGCIEUC YE RIEULHIEUH + 0xA649: 0xCAB0, //HANGUL SYLLABLE SSANGCIEUC YE MIEUM + 0xA64A: 0xCAB1, //HANGUL SYLLABLE SSANGCIEUC YE PIEUP + 0xA64B: 0xCAB2, //HANGUL SYLLABLE SSANGCIEUC YE PIEUPSIOS + 0xA64C: 0xCAB3, //HANGUL SYLLABLE SSANGCIEUC YE SIOS + 0xA64D: 0xCAB4, //HANGUL SYLLABLE SSANGCIEUC YE SSANGSIOS + 0xA64E: 0xCAB5, //HANGUL SYLLABLE SSANGCIEUC YE IEUNG + 0xA64F: 0xCAB6, //HANGUL SYLLABLE SSANGCIEUC YE CIEUC + 0xA650: 0xCAB7, //HANGUL SYLLABLE SSANGCIEUC YE CHIEUCH + 0xA651: 0xCAB8, //HANGUL SYLLABLE SSANGCIEUC YE KHIEUKH + 0xA652: 0xCAB9, //HANGUL SYLLABLE SSANGCIEUC YE THIEUTH + 0xA653: 0xCABA, //HANGUL SYLLABLE SSANGCIEUC YE PHIEUPH + 0xA654: 0xCABB, //HANGUL SYLLABLE SSANGCIEUC YE HIEUH + 0xA655: 0xCABE, //HANGUL SYLLABLE SSANGCIEUC O SSANGKIYEOK + 0xA656: 0xCABF, //HANGUL SYLLABLE SSANGCIEUC O KIYEOKSIOS + 0xA657: 0xCAC1, //HANGUL SYLLABLE SSANGCIEUC O NIEUNCIEUC + 0xA658: 0xCAC2, //HANGUL SYLLABLE SSANGCIEUC O NIEUNHIEUH + 0xA659: 0xCAC3, //HANGUL SYLLABLE SSANGCIEUC O TIKEUT + 0xA65A: 0xCAC5, //HANGUL SYLLABLE SSANGCIEUC O RIEULKIYEOK + 0xA661: 0xCAC6, //HANGUL SYLLABLE SSANGCIEUC O RIEULMIEUM + 0xA662: 0xCAC7, //HANGUL SYLLABLE SSANGCIEUC O RIEULPIEUP + 0xA663: 0xCAC8, //HANGUL SYLLABLE SSANGCIEUC O RIEULSIOS + 0xA664: 0xCAC9, //HANGUL SYLLABLE SSANGCIEUC O RIEULTHIEUTH + 0xA665: 0xCACA, //HANGUL SYLLABLE SSANGCIEUC O RIEULPHIEUPH + 0xA666: 0xCACB, //HANGUL SYLLABLE SSANGCIEUC O RIEULHIEUH + 0xA667: 0xCACE, //HANGUL SYLLABLE SSANGCIEUC O PIEUPSIOS + 0xA668: 0xCAD0, //HANGUL SYLLABLE SSANGCIEUC O SSANGSIOS + 0xA669: 0xCAD2, //HANGUL SYLLABLE SSANGCIEUC O CIEUC + 0xA66A: 0xCAD4, //HANGUL SYLLABLE SSANGCIEUC O KHIEUKH + 0xA66B: 0xCAD5, //HANGUL SYLLABLE SSANGCIEUC O THIEUTH + 0xA66C: 0xCAD6, //HANGUL SYLLABLE SSANGCIEUC O PHIEUPH + 0xA66D: 0xCAD7, //HANGUL SYLLABLE SSANGCIEUC O HIEUH + 0xA66E: 0xCADA, //HANGUL SYLLABLE SSANGCIEUC WA SSANGKIYEOK + 0xA66F: 0xCADB, //HANGUL SYLLABLE SSANGCIEUC WA KIYEOKSIOS + 0xA670: 0xCADC, //HANGUL SYLLABLE SSANGCIEUC WA NIEUN + 0xA671: 0xCADD, //HANGUL SYLLABLE SSANGCIEUC WA NIEUNCIEUC + 0xA672: 0xCADE, //HANGUL SYLLABLE SSANGCIEUC WA NIEUNHIEUH + 0xA673: 0xCADF, //HANGUL SYLLABLE SSANGCIEUC WA TIKEUT + 0xA674: 0xCAE1, //HANGUL SYLLABLE SSANGCIEUC WA RIEULKIYEOK + 0xA675: 0xCAE2, //HANGUL SYLLABLE SSANGCIEUC WA RIEULMIEUM + 0xA676: 0xCAE3, //HANGUL SYLLABLE SSANGCIEUC WA RIEULPIEUP + 0xA677: 0xCAE4, //HANGUL SYLLABLE SSANGCIEUC WA RIEULSIOS + 0xA678: 0xCAE5, //HANGUL SYLLABLE SSANGCIEUC WA RIEULTHIEUTH + 0xA679: 0xCAE6, //HANGUL SYLLABLE SSANGCIEUC WA RIEULPHIEUPH + 0xA67A: 0xCAE7, //HANGUL SYLLABLE SSANGCIEUC WA RIEULHIEUH + 0xA681: 0xCAE8, //HANGUL SYLLABLE SSANGCIEUC WA MIEUM + 0xA682: 0xCAE9, //HANGUL SYLLABLE SSANGCIEUC WA PIEUP + 0xA683: 0xCAEA, //HANGUL SYLLABLE SSANGCIEUC WA PIEUPSIOS + 0xA684: 0xCAEB, //HANGUL SYLLABLE SSANGCIEUC WA SIOS + 0xA685: 0xCAED, //HANGUL SYLLABLE SSANGCIEUC WA IEUNG + 0xA686: 0xCAEE, //HANGUL SYLLABLE SSANGCIEUC WA CIEUC + 0xA687: 0xCAEF, //HANGUL SYLLABLE SSANGCIEUC WA CHIEUCH + 0xA688: 0xCAF0, //HANGUL SYLLABLE SSANGCIEUC WA KHIEUKH + 0xA689: 0xCAF1, //HANGUL SYLLABLE SSANGCIEUC WA THIEUTH + 0xA68A: 0xCAF2, //HANGUL SYLLABLE SSANGCIEUC WA PHIEUPH + 0xA68B: 0xCAF3, //HANGUL SYLLABLE SSANGCIEUC WA HIEUH + 0xA68C: 0xCAF5, //HANGUL SYLLABLE SSANGCIEUC WAE KIYEOK + 0xA68D: 0xCAF6, //HANGUL SYLLABLE SSANGCIEUC WAE SSANGKIYEOK + 0xA68E: 0xCAF7, //HANGUL SYLLABLE SSANGCIEUC WAE KIYEOKSIOS + 0xA68F: 0xCAF8, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUN + 0xA690: 0xCAF9, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUNCIEUC + 0xA691: 0xCAFA, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUNHIEUH + 0xA692: 0xCAFB, //HANGUL SYLLABLE SSANGCIEUC WAE TIKEUT + 0xA693: 0xCAFC, //HANGUL SYLLABLE SSANGCIEUC WAE RIEUL + 0xA694: 0xCAFD, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULKIYEOK + 0xA695: 0xCAFE, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULMIEUM + 0xA696: 0xCAFF, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULPIEUP + 0xA697: 0xCB00, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULSIOS + 0xA698: 0xCB01, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULTHIEUTH + 0xA699: 0xCB02, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULPHIEUPH + 0xA69A: 0xCB03, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULHIEUH + 0xA69B: 0xCB04, //HANGUL SYLLABLE SSANGCIEUC WAE MIEUM + 0xA69C: 0xCB05, //HANGUL SYLLABLE SSANGCIEUC WAE PIEUP + 0xA69D: 0xCB06, //HANGUL SYLLABLE SSANGCIEUC WAE PIEUPSIOS + 0xA69E: 0xCB07, //HANGUL SYLLABLE SSANGCIEUC WAE SIOS + 0xA69F: 0xCB09, //HANGUL SYLLABLE SSANGCIEUC WAE IEUNG + 0xA6A0: 0xCB0A, //HANGUL SYLLABLE SSANGCIEUC WAE CIEUC + 0xA6A1: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA6A2: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA6A3: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA6A4: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA6A5: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA6A6: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA6A7: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA6A8: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA6A9: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA6AA: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA6AB: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA6AC: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0xA6AD: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0xA6AE: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0xA6AF: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0xA6B0: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0xA6B1: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0xA6B2: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0xA6B3: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0xA6B4: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0xA6B5: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0xA6B6: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0xA6B7: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0xA6B8: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0xA6B9: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0xA6BA: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0xA6BB: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0xA6BC: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0xA6BD: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0xA6BE: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0xA6BF: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0xA6C0: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0xA6C1: 0x2512, //BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT + 0xA6C2: 0x2511, //BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY + 0xA6C3: 0x251A, //BOX DRAWINGS UP HEAVY AND LEFT LIGHT + 0xA6C4: 0x2519, //BOX DRAWINGS UP LIGHT AND LEFT HEAVY + 0xA6C5: 0x2516, //BOX DRAWINGS UP HEAVY AND RIGHT LIGHT + 0xA6C6: 0x2515, //BOX DRAWINGS UP LIGHT AND RIGHT HEAVY + 0xA6C7: 0x250E, //BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT + 0xA6C8: 0x250D, //BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY + 0xA6C9: 0x251E, //BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT + 0xA6CA: 0x251F, //BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT + 0xA6CB: 0x2521, //BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY + 0xA6CC: 0x2522, //BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY + 0xA6CD: 0x2526, //BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT + 0xA6CE: 0x2527, //BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT + 0xA6CF: 0x2529, //BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY + 0xA6D0: 0x252A, //BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY + 0xA6D1: 0x252D, //BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT + 0xA6D2: 0x252E, //BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT + 0xA6D3: 0x2531, //BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY + 0xA6D4: 0x2532, //BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY + 0xA6D5: 0x2535, //BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT + 0xA6D6: 0x2536, //BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT + 0xA6D7: 0x2539, //BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY + 0xA6D8: 0x253A, //BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY + 0xA6D9: 0x253D, //BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT + 0xA6DA: 0x253E, //BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT + 0xA6DB: 0x2540, //BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT + 0xA6DC: 0x2541, //BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT + 0xA6DD: 0x2543, //BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT + 0xA6DE: 0x2544, //BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT + 0xA6DF: 0x2545, //BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT + 0xA6E0: 0x2546, //BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT + 0xA6E1: 0x2547, //BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY + 0xA6E2: 0x2548, //BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY + 0xA6E3: 0x2549, //BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY + 0xA6E4: 0x254A, //BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY + 0xA741: 0xCB0B, //HANGUL SYLLABLE SSANGCIEUC WAE CHIEUCH + 0xA742: 0xCB0C, //HANGUL SYLLABLE SSANGCIEUC WAE KHIEUKH + 0xA743: 0xCB0D, //HANGUL SYLLABLE SSANGCIEUC WAE THIEUTH + 0xA744: 0xCB0E, //HANGUL SYLLABLE SSANGCIEUC WAE PHIEUPH + 0xA745: 0xCB0F, //HANGUL SYLLABLE SSANGCIEUC WAE HIEUH + 0xA746: 0xCB11, //HANGUL SYLLABLE SSANGCIEUC OE KIYEOK + 0xA747: 0xCB12, //HANGUL SYLLABLE SSANGCIEUC OE SSANGKIYEOK + 0xA748: 0xCB13, //HANGUL SYLLABLE SSANGCIEUC OE KIYEOKSIOS + 0xA749: 0xCB15, //HANGUL SYLLABLE SSANGCIEUC OE NIEUNCIEUC + 0xA74A: 0xCB16, //HANGUL SYLLABLE SSANGCIEUC OE NIEUNHIEUH + 0xA74B: 0xCB17, //HANGUL SYLLABLE SSANGCIEUC OE TIKEUT + 0xA74C: 0xCB19, //HANGUL SYLLABLE SSANGCIEUC OE RIEULKIYEOK + 0xA74D: 0xCB1A, //HANGUL SYLLABLE SSANGCIEUC OE RIEULMIEUM + 0xA74E: 0xCB1B, //HANGUL SYLLABLE SSANGCIEUC OE RIEULPIEUP + 0xA74F: 0xCB1C, //HANGUL SYLLABLE SSANGCIEUC OE RIEULSIOS + 0xA750: 0xCB1D, //HANGUL SYLLABLE SSANGCIEUC OE RIEULTHIEUTH + 0xA751: 0xCB1E, //HANGUL SYLLABLE SSANGCIEUC OE RIEULPHIEUPH + 0xA752: 0xCB1F, //HANGUL SYLLABLE SSANGCIEUC OE RIEULHIEUH + 0xA753: 0xCB22, //HANGUL SYLLABLE SSANGCIEUC OE PIEUPSIOS + 0xA754: 0xCB23, //HANGUL SYLLABLE SSANGCIEUC OE SIOS + 0xA755: 0xCB24, //HANGUL SYLLABLE SSANGCIEUC OE SSANGSIOS + 0xA756: 0xCB25, //HANGUL SYLLABLE SSANGCIEUC OE IEUNG + 0xA757: 0xCB26, //HANGUL SYLLABLE SSANGCIEUC OE CIEUC + 0xA758: 0xCB27, //HANGUL SYLLABLE SSANGCIEUC OE CHIEUCH + 0xA759: 0xCB28, //HANGUL SYLLABLE SSANGCIEUC OE KHIEUKH + 0xA75A: 0xCB29, //HANGUL SYLLABLE SSANGCIEUC OE THIEUTH + 0xA761: 0xCB2A, //HANGUL SYLLABLE SSANGCIEUC OE PHIEUPH + 0xA762: 0xCB2B, //HANGUL SYLLABLE SSANGCIEUC OE HIEUH + 0xA763: 0xCB2C, //HANGUL SYLLABLE SSANGCIEUC YO + 0xA764: 0xCB2D, //HANGUL SYLLABLE SSANGCIEUC YO KIYEOK + 0xA765: 0xCB2E, //HANGUL SYLLABLE SSANGCIEUC YO SSANGKIYEOK + 0xA766: 0xCB2F, //HANGUL SYLLABLE SSANGCIEUC YO KIYEOKSIOS + 0xA767: 0xCB30, //HANGUL SYLLABLE SSANGCIEUC YO NIEUN + 0xA768: 0xCB31, //HANGUL SYLLABLE SSANGCIEUC YO NIEUNCIEUC + 0xA769: 0xCB32, //HANGUL SYLLABLE SSANGCIEUC YO NIEUNHIEUH + 0xA76A: 0xCB33, //HANGUL SYLLABLE SSANGCIEUC YO TIKEUT + 0xA76B: 0xCB34, //HANGUL SYLLABLE SSANGCIEUC YO RIEUL + 0xA76C: 0xCB35, //HANGUL SYLLABLE SSANGCIEUC YO RIEULKIYEOK + 0xA76D: 0xCB36, //HANGUL SYLLABLE SSANGCIEUC YO RIEULMIEUM + 0xA76E: 0xCB37, //HANGUL SYLLABLE SSANGCIEUC YO RIEULPIEUP + 0xA76F: 0xCB38, //HANGUL SYLLABLE SSANGCIEUC YO RIEULSIOS + 0xA770: 0xCB39, //HANGUL SYLLABLE SSANGCIEUC YO RIEULTHIEUTH + 0xA771: 0xCB3A, //HANGUL SYLLABLE SSANGCIEUC YO RIEULPHIEUPH + 0xA772: 0xCB3B, //HANGUL SYLLABLE SSANGCIEUC YO RIEULHIEUH + 0xA773: 0xCB3C, //HANGUL SYLLABLE SSANGCIEUC YO MIEUM + 0xA774: 0xCB3D, //HANGUL SYLLABLE SSANGCIEUC YO PIEUP + 0xA775: 0xCB3E, //HANGUL SYLLABLE SSANGCIEUC YO PIEUPSIOS + 0xA776: 0xCB3F, //HANGUL SYLLABLE SSANGCIEUC YO SIOS + 0xA777: 0xCB40, //HANGUL SYLLABLE SSANGCIEUC YO SSANGSIOS + 0xA778: 0xCB42, //HANGUL SYLLABLE SSANGCIEUC YO CIEUC + 0xA779: 0xCB43, //HANGUL SYLLABLE SSANGCIEUC YO CHIEUCH + 0xA77A: 0xCB44, //HANGUL SYLLABLE SSANGCIEUC YO KHIEUKH + 0xA781: 0xCB45, //HANGUL SYLLABLE SSANGCIEUC YO THIEUTH + 0xA782: 0xCB46, //HANGUL SYLLABLE SSANGCIEUC YO PHIEUPH + 0xA783: 0xCB47, //HANGUL SYLLABLE SSANGCIEUC YO HIEUH + 0xA784: 0xCB4A, //HANGUL SYLLABLE SSANGCIEUC U SSANGKIYEOK + 0xA785: 0xCB4B, //HANGUL SYLLABLE SSANGCIEUC U KIYEOKSIOS + 0xA786: 0xCB4D, //HANGUL SYLLABLE SSANGCIEUC U NIEUNCIEUC + 0xA787: 0xCB4E, //HANGUL SYLLABLE SSANGCIEUC U NIEUNHIEUH + 0xA788: 0xCB4F, //HANGUL SYLLABLE SSANGCIEUC U TIKEUT + 0xA789: 0xCB51, //HANGUL SYLLABLE SSANGCIEUC U RIEULKIYEOK + 0xA78A: 0xCB52, //HANGUL SYLLABLE SSANGCIEUC U RIEULMIEUM + 0xA78B: 0xCB53, //HANGUL SYLLABLE SSANGCIEUC U RIEULPIEUP + 0xA78C: 0xCB54, //HANGUL SYLLABLE SSANGCIEUC U RIEULSIOS + 0xA78D: 0xCB55, //HANGUL SYLLABLE SSANGCIEUC U RIEULTHIEUTH + 0xA78E: 0xCB56, //HANGUL SYLLABLE SSANGCIEUC U RIEULPHIEUPH + 0xA78F: 0xCB57, //HANGUL SYLLABLE SSANGCIEUC U RIEULHIEUH + 0xA790: 0xCB5A, //HANGUL SYLLABLE SSANGCIEUC U PIEUPSIOS + 0xA791: 0xCB5B, //HANGUL SYLLABLE SSANGCIEUC U SIOS + 0xA792: 0xCB5C, //HANGUL SYLLABLE SSANGCIEUC U SSANGSIOS + 0xA793: 0xCB5E, //HANGUL SYLLABLE SSANGCIEUC U CIEUC + 0xA794: 0xCB5F, //HANGUL SYLLABLE SSANGCIEUC U CHIEUCH + 0xA795: 0xCB60, //HANGUL SYLLABLE SSANGCIEUC U KHIEUKH + 0xA796: 0xCB61, //HANGUL SYLLABLE SSANGCIEUC U THIEUTH + 0xA797: 0xCB62, //HANGUL SYLLABLE SSANGCIEUC U PHIEUPH + 0xA798: 0xCB63, //HANGUL SYLLABLE SSANGCIEUC U HIEUH + 0xA799: 0xCB65, //HANGUL SYLLABLE SSANGCIEUC WEO KIYEOK + 0xA79A: 0xCB66, //HANGUL SYLLABLE SSANGCIEUC WEO SSANGKIYEOK + 0xA79B: 0xCB67, //HANGUL SYLLABLE SSANGCIEUC WEO KIYEOKSIOS + 0xA79C: 0xCB68, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUN + 0xA79D: 0xCB69, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUNCIEUC + 0xA79E: 0xCB6A, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUNHIEUH + 0xA79F: 0xCB6B, //HANGUL SYLLABLE SSANGCIEUC WEO TIKEUT + 0xA7A0: 0xCB6C, //HANGUL SYLLABLE SSANGCIEUC WEO RIEUL + 0xA7A1: 0x3395, //SQUARE MU L + 0xA7A2: 0x3396, //SQUARE ML + 0xA7A3: 0x3397, //SQUARE DL + 0xA7A4: 0x2113, //SCRIPT SMALL L + 0xA7A5: 0x3398, //SQUARE KL + 0xA7A6: 0x33C4, //SQUARE CC + 0xA7A7: 0x33A3, //SQUARE MM CUBED + 0xA7A8: 0x33A4, //SQUARE CM CUBED + 0xA7A9: 0x33A5, //SQUARE M CUBED + 0xA7AA: 0x33A6, //SQUARE KM CUBED + 0xA7AB: 0x3399, //SQUARE FM + 0xA7AC: 0x339A, //SQUARE NM + 0xA7AD: 0x339B, //SQUARE MU M + 0xA7AE: 0x339C, //SQUARE MM + 0xA7AF: 0x339D, //SQUARE CM + 0xA7B0: 0x339E, //SQUARE KM + 0xA7B1: 0x339F, //SQUARE MM SQUARED + 0xA7B2: 0x33A0, //SQUARE CM SQUARED + 0xA7B3: 0x33A1, //SQUARE M SQUARED + 0xA7B4: 0x33A2, //SQUARE KM SQUARED + 0xA7B5: 0x33CA, //SQUARE HA + 0xA7B6: 0x338D, //SQUARE MU G + 0xA7B7: 0x338E, //SQUARE MG + 0xA7B8: 0x338F, //SQUARE KG + 0xA7B9: 0x33CF, //SQUARE KT + 0xA7BA: 0x3388, //SQUARE CAL + 0xA7BB: 0x3389, //SQUARE KCAL + 0xA7BC: 0x33C8, //SQUARE DB + 0xA7BD: 0x33A7, //SQUARE M OVER S + 0xA7BE: 0x33A8, //SQUARE M OVER S SQUARED + 0xA7BF: 0x33B0, //SQUARE PS + 0xA7C0: 0x33B1, //SQUARE NS + 0xA7C1: 0x33B2, //SQUARE MU S + 0xA7C2: 0x33B3, //SQUARE MS + 0xA7C3: 0x33B4, //SQUARE PV + 0xA7C4: 0x33B5, //SQUARE NV + 0xA7C5: 0x33B6, //SQUARE MU V + 0xA7C6: 0x33B7, //SQUARE MV + 0xA7C7: 0x33B8, //SQUARE KV + 0xA7C8: 0x33B9, //SQUARE MV MEGA + 0xA7C9: 0x3380, //SQUARE PA AMPS + 0xA7CA: 0x3381, //SQUARE NA + 0xA7CB: 0x3382, //SQUARE MU A + 0xA7CC: 0x3383, //SQUARE MA + 0xA7CD: 0x3384, //SQUARE KA + 0xA7CE: 0x33BA, //SQUARE PW + 0xA7CF: 0x33BB, //SQUARE NW + 0xA7D0: 0x33BC, //SQUARE MU W + 0xA7D1: 0x33BD, //SQUARE MW + 0xA7D2: 0x33BE, //SQUARE KW + 0xA7D3: 0x33BF, //SQUARE MW MEGA + 0xA7D4: 0x3390, //SQUARE HZ + 0xA7D5: 0x3391, //SQUARE KHZ + 0xA7D6: 0x3392, //SQUARE MHZ + 0xA7D7: 0x3393, //SQUARE GHZ + 0xA7D8: 0x3394, //SQUARE THZ + 0xA7D9: 0x2126, //OHM SIGN + 0xA7DA: 0x33C0, //SQUARE K OHM + 0xA7DB: 0x33C1, //SQUARE M OHM + 0xA7DC: 0x338A, //SQUARE PF + 0xA7DD: 0x338B, //SQUARE NF + 0xA7DE: 0x338C, //SQUARE MU F + 0xA7DF: 0x33D6, //SQUARE MOL + 0xA7E0: 0x33C5, //SQUARE CD + 0xA7E1: 0x33AD, //SQUARE RAD + 0xA7E2: 0x33AE, //SQUARE RAD OVER S + 0xA7E3: 0x33AF, //SQUARE RAD OVER S SQUARED + 0xA7E4: 0x33DB, //SQUARE SR + 0xA7E5: 0x33A9, //SQUARE PA + 0xA7E6: 0x33AA, //SQUARE KPA + 0xA7E7: 0x33AB, //SQUARE MPA + 0xA7E8: 0x33AC, //SQUARE GPA + 0xA7E9: 0x33DD, //SQUARE WB + 0xA7EA: 0x33D0, //SQUARE LM + 0xA7EB: 0x33D3, //SQUARE LX + 0xA7EC: 0x33C3, //SQUARE BQ + 0xA7ED: 0x33C9, //SQUARE GY + 0xA7EE: 0x33DC, //SQUARE SV + 0xA7EF: 0x33C6, //SQUARE C OVER KG + 0xA841: 0xCB6D, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULKIYEOK + 0xA842: 0xCB6E, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULMIEUM + 0xA843: 0xCB6F, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULPIEUP + 0xA844: 0xCB70, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULSIOS + 0xA845: 0xCB71, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULTHIEUTH + 0xA846: 0xCB72, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULPHIEUPH + 0xA847: 0xCB73, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULHIEUH + 0xA848: 0xCB74, //HANGUL SYLLABLE SSANGCIEUC WEO MIEUM + 0xA849: 0xCB75, //HANGUL SYLLABLE SSANGCIEUC WEO PIEUP + 0xA84A: 0xCB76, //HANGUL SYLLABLE SSANGCIEUC WEO PIEUPSIOS + 0xA84B: 0xCB77, //HANGUL SYLLABLE SSANGCIEUC WEO SIOS + 0xA84C: 0xCB7A, //HANGUL SYLLABLE SSANGCIEUC WEO CIEUC + 0xA84D: 0xCB7B, //HANGUL SYLLABLE SSANGCIEUC WEO CHIEUCH + 0xA84E: 0xCB7C, //HANGUL SYLLABLE SSANGCIEUC WEO KHIEUKH + 0xA84F: 0xCB7D, //HANGUL SYLLABLE SSANGCIEUC WEO THIEUTH + 0xA850: 0xCB7E, //HANGUL SYLLABLE SSANGCIEUC WEO PHIEUPH + 0xA851: 0xCB7F, //HANGUL SYLLABLE SSANGCIEUC WEO HIEUH + 0xA852: 0xCB80, //HANGUL SYLLABLE SSANGCIEUC WE + 0xA853: 0xCB81, //HANGUL SYLLABLE SSANGCIEUC WE KIYEOK + 0xA854: 0xCB82, //HANGUL SYLLABLE SSANGCIEUC WE SSANGKIYEOK + 0xA855: 0xCB83, //HANGUL SYLLABLE SSANGCIEUC WE KIYEOKSIOS + 0xA856: 0xCB84, //HANGUL SYLLABLE SSANGCIEUC WE NIEUN + 0xA857: 0xCB85, //HANGUL SYLLABLE SSANGCIEUC WE NIEUNCIEUC + 0xA858: 0xCB86, //HANGUL SYLLABLE SSANGCIEUC WE NIEUNHIEUH + 0xA859: 0xCB87, //HANGUL SYLLABLE SSANGCIEUC WE TIKEUT + 0xA85A: 0xCB88, //HANGUL SYLLABLE SSANGCIEUC WE RIEUL + 0xA861: 0xCB89, //HANGUL SYLLABLE SSANGCIEUC WE RIEULKIYEOK + 0xA862: 0xCB8A, //HANGUL SYLLABLE SSANGCIEUC WE RIEULMIEUM + 0xA863: 0xCB8B, //HANGUL SYLLABLE SSANGCIEUC WE RIEULPIEUP + 0xA864: 0xCB8C, //HANGUL SYLLABLE SSANGCIEUC WE RIEULSIOS + 0xA865: 0xCB8D, //HANGUL SYLLABLE SSANGCIEUC WE RIEULTHIEUTH + 0xA866: 0xCB8E, //HANGUL SYLLABLE SSANGCIEUC WE RIEULPHIEUPH + 0xA867: 0xCB8F, //HANGUL SYLLABLE SSANGCIEUC WE RIEULHIEUH + 0xA868: 0xCB90, //HANGUL SYLLABLE SSANGCIEUC WE MIEUM + 0xA869: 0xCB91, //HANGUL SYLLABLE SSANGCIEUC WE PIEUP + 0xA86A: 0xCB92, //HANGUL SYLLABLE SSANGCIEUC WE PIEUPSIOS + 0xA86B: 0xCB93, //HANGUL SYLLABLE SSANGCIEUC WE SIOS + 0xA86C: 0xCB94, //HANGUL SYLLABLE SSANGCIEUC WE SSANGSIOS + 0xA86D: 0xCB95, //HANGUL SYLLABLE SSANGCIEUC WE IEUNG + 0xA86E: 0xCB96, //HANGUL SYLLABLE SSANGCIEUC WE CIEUC + 0xA86F: 0xCB97, //HANGUL SYLLABLE SSANGCIEUC WE CHIEUCH + 0xA870: 0xCB98, //HANGUL SYLLABLE SSANGCIEUC WE KHIEUKH + 0xA871: 0xCB99, //HANGUL SYLLABLE SSANGCIEUC WE THIEUTH + 0xA872: 0xCB9A, //HANGUL SYLLABLE SSANGCIEUC WE PHIEUPH + 0xA873: 0xCB9B, //HANGUL SYLLABLE SSANGCIEUC WE HIEUH + 0xA874: 0xCB9D, //HANGUL SYLLABLE SSANGCIEUC WI KIYEOK + 0xA875: 0xCB9E, //HANGUL SYLLABLE SSANGCIEUC WI SSANGKIYEOK + 0xA876: 0xCB9F, //HANGUL SYLLABLE SSANGCIEUC WI KIYEOKSIOS + 0xA877: 0xCBA0, //HANGUL SYLLABLE SSANGCIEUC WI NIEUN + 0xA878: 0xCBA1, //HANGUL SYLLABLE SSANGCIEUC WI NIEUNCIEUC + 0xA879: 0xCBA2, //HANGUL SYLLABLE SSANGCIEUC WI NIEUNHIEUH + 0xA87A: 0xCBA3, //HANGUL SYLLABLE SSANGCIEUC WI TIKEUT + 0xA881: 0xCBA4, //HANGUL SYLLABLE SSANGCIEUC WI RIEUL + 0xA882: 0xCBA5, //HANGUL SYLLABLE SSANGCIEUC WI RIEULKIYEOK + 0xA883: 0xCBA6, //HANGUL SYLLABLE SSANGCIEUC WI RIEULMIEUM + 0xA884: 0xCBA7, //HANGUL SYLLABLE SSANGCIEUC WI RIEULPIEUP + 0xA885: 0xCBA8, //HANGUL SYLLABLE SSANGCIEUC WI RIEULSIOS + 0xA886: 0xCBA9, //HANGUL SYLLABLE SSANGCIEUC WI RIEULTHIEUTH + 0xA887: 0xCBAA, //HANGUL SYLLABLE SSANGCIEUC WI RIEULPHIEUPH + 0xA888: 0xCBAB, //HANGUL SYLLABLE SSANGCIEUC WI RIEULHIEUH + 0xA889: 0xCBAC, //HANGUL SYLLABLE SSANGCIEUC WI MIEUM + 0xA88A: 0xCBAD, //HANGUL SYLLABLE SSANGCIEUC WI PIEUP + 0xA88B: 0xCBAE, //HANGUL SYLLABLE SSANGCIEUC WI PIEUPSIOS + 0xA88C: 0xCBAF, //HANGUL SYLLABLE SSANGCIEUC WI SIOS + 0xA88D: 0xCBB0, //HANGUL SYLLABLE SSANGCIEUC WI SSANGSIOS + 0xA88E: 0xCBB1, //HANGUL SYLLABLE SSANGCIEUC WI IEUNG + 0xA88F: 0xCBB2, //HANGUL SYLLABLE SSANGCIEUC WI CIEUC + 0xA890: 0xCBB3, //HANGUL SYLLABLE SSANGCIEUC WI CHIEUCH + 0xA891: 0xCBB4, //HANGUL SYLLABLE SSANGCIEUC WI KHIEUKH + 0xA892: 0xCBB5, //HANGUL SYLLABLE SSANGCIEUC WI THIEUTH + 0xA893: 0xCBB6, //HANGUL SYLLABLE SSANGCIEUC WI PHIEUPH + 0xA894: 0xCBB7, //HANGUL SYLLABLE SSANGCIEUC WI HIEUH + 0xA895: 0xCBB9, //HANGUL SYLLABLE SSANGCIEUC YU KIYEOK + 0xA896: 0xCBBA, //HANGUL SYLLABLE SSANGCIEUC YU SSANGKIYEOK + 0xA897: 0xCBBB, //HANGUL SYLLABLE SSANGCIEUC YU KIYEOKSIOS + 0xA898: 0xCBBC, //HANGUL SYLLABLE SSANGCIEUC YU NIEUN + 0xA899: 0xCBBD, //HANGUL SYLLABLE SSANGCIEUC YU NIEUNCIEUC + 0xA89A: 0xCBBE, //HANGUL SYLLABLE SSANGCIEUC YU NIEUNHIEUH + 0xA89B: 0xCBBF, //HANGUL SYLLABLE SSANGCIEUC YU TIKEUT + 0xA89C: 0xCBC0, //HANGUL SYLLABLE SSANGCIEUC YU RIEUL + 0xA89D: 0xCBC1, //HANGUL SYLLABLE SSANGCIEUC YU RIEULKIYEOK + 0xA89E: 0xCBC2, //HANGUL SYLLABLE SSANGCIEUC YU RIEULMIEUM + 0xA89F: 0xCBC3, //HANGUL SYLLABLE SSANGCIEUC YU RIEULPIEUP + 0xA8A0: 0xCBC4, //HANGUL SYLLABLE SSANGCIEUC YU RIEULSIOS + 0xA8A1: 0x00C6, //LATIN CAPITAL LETTER AE + 0xA8A2: 0x00D0, //LATIN CAPITAL LETTER ETH + 0xA8A3: 0x00AA, //FEMININE ORDINAL INDICATOR + 0xA8A4: 0x0126, //LATIN CAPITAL LETTER H WITH STROKE + 0xA8A6: 0x0132, //LATIN CAPITAL LIGATURE IJ + 0xA8A8: 0x013F, //LATIN CAPITAL LETTER L WITH MIDDLE DOT + 0xA8A9: 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0xA8AA: 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0xA8AB: 0x0152, //LATIN CAPITAL LIGATURE OE + 0xA8AC: 0x00BA, //MASCULINE ORDINAL INDICATOR + 0xA8AD: 0x00DE, //LATIN CAPITAL LETTER THORN + 0xA8AE: 0x0166, //LATIN CAPITAL LETTER T WITH STROKE + 0xA8AF: 0x014A, //LATIN CAPITAL LETTER ENG + 0xA8B1: 0x3260, //CIRCLED HANGUL KIYEOK + 0xA8B2: 0x3261, //CIRCLED HANGUL NIEUN + 0xA8B3: 0x3262, //CIRCLED HANGUL TIKEUT + 0xA8B4: 0x3263, //CIRCLED HANGUL RIEUL + 0xA8B5: 0x3264, //CIRCLED HANGUL MIEUM + 0xA8B6: 0x3265, //CIRCLED HANGUL PIEUP + 0xA8B7: 0x3266, //CIRCLED HANGUL SIOS + 0xA8B8: 0x3267, //CIRCLED HANGUL IEUNG + 0xA8B9: 0x3268, //CIRCLED HANGUL CIEUC + 0xA8BA: 0x3269, //CIRCLED HANGUL CHIEUCH + 0xA8BB: 0x326A, //CIRCLED HANGUL KHIEUKH + 0xA8BC: 0x326B, //CIRCLED HANGUL THIEUTH + 0xA8BD: 0x326C, //CIRCLED HANGUL PHIEUPH + 0xA8BE: 0x326D, //CIRCLED HANGUL HIEUH + 0xA8BF: 0x326E, //CIRCLED HANGUL KIYEOK A + 0xA8C0: 0x326F, //CIRCLED HANGUL NIEUN A + 0xA8C1: 0x3270, //CIRCLED HANGUL TIKEUT A + 0xA8C2: 0x3271, //CIRCLED HANGUL RIEUL A + 0xA8C3: 0x3272, //CIRCLED HANGUL MIEUM A + 0xA8C4: 0x3273, //CIRCLED HANGUL PIEUP A + 0xA8C5: 0x3274, //CIRCLED HANGUL SIOS A + 0xA8C6: 0x3275, //CIRCLED HANGUL IEUNG A + 0xA8C7: 0x3276, //CIRCLED HANGUL CIEUC A + 0xA8C8: 0x3277, //CIRCLED HANGUL CHIEUCH A + 0xA8C9: 0x3278, //CIRCLED HANGUL KHIEUKH A + 0xA8CA: 0x3279, //CIRCLED HANGUL THIEUTH A + 0xA8CB: 0x327A, //CIRCLED HANGUL PHIEUPH A + 0xA8CC: 0x327B, //CIRCLED HANGUL HIEUH A + 0xA8CD: 0x24D0, //CIRCLED LATIN SMALL LETTER A + 0xA8CE: 0x24D1, //CIRCLED LATIN SMALL LETTER B + 0xA8CF: 0x24D2, //CIRCLED LATIN SMALL LETTER C + 0xA8D0: 0x24D3, //CIRCLED LATIN SMALL LETTER D + 0xA8D1: 0x24D4, //CIRCLED LATIN SMALL LETTER E + 0xA8D2: 0x24D5, //CIRCLED LATIN SMALL LETTER F + 0xA8D3: 0x24D6, //CIRCLED LATIN SMALL LETTER G + 0xA8D4: 0x24D7, //CIRCLED LATIN SMALL LETTER H + 0xA8D5: 0x24D8, //CIRCLED LATIN SMALL LETTER I + 0xA8D6: 0x24D9, //CIRCLED LATIN SMALL LETTER J + 0xA8D7: 0x24DA, //CIRCLED LATIN SMALL LETTER K + 0xA8D8: 0x24DB, //CIRCLED LATIN SMALL LETTER L + 0xA8D9: 0x24DC, //CIRCLED LATIN SMALL LETTER M + 0xA8DA: 0x24DD, //CIRCLED LATIN SMALL LETTER N + 0xA8DB: 0x24DE, //CIRCLED LATIN SMALL LETTER O + 0xA8DC: 0x24DF, //CIRCLED LATIN SMALL LETTER P + 0xA8DD: 0x24E0, //CIRCLED LATIN SMALL LETTER Q + 0xA8DE: 0x24E1, //CIRCLED LATIN SMALL LETTER R + 0xA8DF: 0x24E2, //CIRCLED LATIN SMALL LETTER S + 0xA8E0: 0x24E3, //CIRCLED LATIN SMALL LETTER T + 0xA8E1: 0x24E4, //CIRCLED LATIN SMALL LETTER U + 0xA8E2: 0x24E5, //CIRCLED LATIN SMALL LETTER V + 0xA8E3: 0x24E6, //CIRCLED LATIN SMALL LETTER W + 0xA8E4: 0x24E7, //CIRCLED LATIN SMALL LETTER X + 0xA8E5: 0x24E8, //CIRCLED LATIN SMALL LETTER Y + 0xA8E6: 0x24E9, //CIRCLED LATIN SMALL LETTER Z + 0xA8E7: 0x2460, //CIRCLED DIGIT ONE + 0xA8E8: 0x2461, //CIRCLED DIGIT TWO + 0xA8E9: 0x2462, //CIRCLED DIGIT THREE + 0xA8EA: 0x2463, //CIRCLED DIGIT FOUR + 0xA8EB: 0x2464, //CIRCLED DIGIT FIVE + 0xA8EC: 0x2465, //CIRCLED DIGIT SIX + 0xA8ED: 0x2466, //CIRCLED DIGIT SEVEN + 0xA8EE: 0x2467, //CIRCLED DIGIT EIGHT + 0xA8EF: 0x2468, //CIRCLED DIGIT NINE + 0xA8F0: 0x2469, //CIRCLED NUMBER TEN + 0xA8F1: 0x246A, //CIRCLED NUMBER ELEVEN + 0xA8F2: 0x246B, //CIRCLED NUMBER TWELVE + 0xA8F3: 0x246C, //CIRCLED NUMBER THIRTEEN + 0xA8F4: 0x246D, //CIRCLED NUMBER FOURTEEN + 0xA8F5: 0x246E, //CIRCLED NUMBER FIFTEEN + 0xA8F6: 0x00BD, //VULGAR FRACTION ONE HALF + 0xA8F7: 0x2153, //VULGAR FRACTION ONE THIRD + 0xA8F8: 0x2154, //VULGAR FRACTION TWO THIRDS + 0xA8F9: 0x00BC, //VULGAR FRACTION ONE QUARTER + 0xA8FA: 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0xA8FB: 0x215B, //VULGAR FRACTION ONE EIGHTH + 0xA8FC: 0x215C, //VULGAR FRACTION THREE EIGHTHS + 0xA8FD: 0x215D, //VULGAR FRACTION FIVE EIGHTHS + 0xA8FE: 0x215E, //VULGAR FRACTION SEVEN EIGHTHS + 0xA941: 0xCBC5, //HANGUL SYLLABLE SSANGCIEUC YU RIEULTHIEUTH + 0xA942: 0xCBC6, //HANGUL SYLLABLE SSANGCIEUC YU RIEULPHIEUPH + 0xA943: 0xCBC7, //HANGUL SYLLABLE SSANGCIEUC YU RIEULHIEUH + 0xA944: 0xCBC8, //HANGUL SYLLABLE SSANGCIEUC YU MIEUM + 0xA945: 0xCBC9, //HANGUL SYLLABLE SSANGCIEUC YU PIEUP + 0xA946: 0xCBCA, //HANGUL SYLLABLE SSANGCIEUC YU PIEUPSIOS + 0xA947: 0xCBCB, //HANGUL SYLLABLE SSANGCIEUC YU SIOS + 0xA948: 0xCBCC, //HANGUL SYLLABLE SSANGCIEUC YU SSANGSIOS + 0xA949: 0xCBCD, //HANGUL SYLLABLE SSANGCIEUC YU IEUNG + 0xA94A: 0xCBCE, //HANGUL SYLLABLE SSANGCIEUC YU CIEUC + 0xA94B: 0xCBCF, //HANGUL SYLLABLE SSANGCIEUC YU CHIEUCH + 0xA94C: 0xCBD0, //HANGUL SYLLABLE SSANGCIEUC YU KHIEUKH + 0xA94D: 0xCBD1, //HANGUL SYLLABLE SSANGCIEUC YU THIEUTH + 0xA94E: 0xCBD2, //HANGUL SYLLABLE SSANGCIEUC YU PHIEUPH + 0xA94F: 0xCBD3, //HANGUL SYLLABLE SSANGCIEUC YU HIEUH + 0xA950: 0xCBD5, //HANGUL SYLLABLE SSANGCIEUC EU KIYEOK + 0xA951: 0xCBD6, //HANGUL SYLLABLE SSANGCIEUC EU SSANGKIYEOK + 0xA952: 0xCBD7, //HANGUL SYLLABLE SSANGCIEUC EU KIYEOKSIOS + 0xA953: 0xCBD8, //HANGUL SYLLABLE SSANGCIEUC EU NIEUN + 0xA954: 0xCBD9, //HANGUL SYLLABLE SSANGCIEUC EU NIEUNCIEUC + 0xA955: 0xCBDA, //HANGUL SYLLABLE SSANGCIEUC EU NIEUNHIEUH + 0xA956: 0xCBDB, //HANGUL SYLLABLE SSANGCIEUC EU TIKEUT + 0xA957: 0xCBDC, //HANGUL SYLLABLE SSANGCIEUC EU RIEUL + 0xA958: 0xCBDD, //HANGUL SYLLABLE SSANGCIEUC EU RIEULKIYEOK + 0xA959: 0xCBDE, //HANGUL SYLLABLE SSANGCIEUC EU RIEULMIEUM + 0xA95A: 0xCBDF, //HANGUL SYLLABLE SSANGCIEUC EU RIEULPIEUP + 0xA961: 0xCBE0, //HANGUL SYLLABLE SSANGCIEUC EU RIEULSIOS + 0xA962: 0xCBE1, //HANGUL SYLLABLE SSANGCIEUC EU RIEULTHIEUTH + 0xA963: 0xCBE2, //HANGUL SYLLABLE SSANGCIEUC EU RIEULPHIEUPH + 0xA964: 0xCBE3, //HANGUL SYLLABLE SSANGCIEUC EU RIEULHIEUH + 0xA965: 0xCBE5, //HANGUL SYLLABLE SSANGCIEUC EU PIEUP + 0xA966: 0xCBE6, //HANGUL SYLLABLE SSANGCIEUC EU PIEUPSIOS + 0xA967: 0xCBE8, //HANGUL SYLLABLE SSANGCIEUC EU SSANGSIOS + 0xA968: 0xCBEA, //HANGUL SYLLABLE SSANGCIEUC EU CIEUC + 0xA969: 0xCBEB, //HANGUL SYLLABLE SSANGCIEUC EU CHIEUCH + 0xA96A: 0xCBEC, //HANGUL SYLLABLE SSANGCIEUC EU KHIEUKH + 0xA96B: 0xCBED, //HANGUL SYLLABLE SSANGCIEUC EU THIEUTH + 0xA96C: 0xCBEE, //HANGUL SYLLABLE SSANGCIEUC EU PHIEUPH + 0xA96D: 0xCBEF, //HANGUL SYLLABLE SSANGCIEUC EU HIEUH + 0xA96E: 0xCBF0, //HANGUL SYLLABLE SSANGCIEUC YI + 0xA96F: 0xCBF1, //HANGUL SYLLABLE SSANGCIEUC YI KIYEOK + 0xA970: 0xCBF2, //HANGUL SYLLABLE SSANGCIEUC YI SSANGKIYEOK + 0xA971: 0xCBF3, //HANGUL SYLLABLE SSANGCIEUC YI KIYEOKSIOS + 0xA972: 0xCBF4, //HANGUL SYLLABLE SSANGCIEUC YI NIEUN + 0xA973: 0xCBF5, //HANGUL SYLLABLE SSANGCIEUC YI NIEUNCIEUC + 0xA974: 0xCBF6, //HANGUL SYLLABLE SSANGCIEUC YI NIEUNHIEUH + 0xA975: 0xCBF7, //HANGUL SYLLABLE SSANGCIEUC YI TIKEUT + 0xA976: 0xCBF8, //HANGUL SYLLABLE SSANGCIEUC YI RIEUL + 0xA977: 0xCBF9, //HANGUL SYLLABLE SSANGCIEUC YI RIEULKIYEOK + 0xA978: 0xCBFA, //HANGUL SYLLABLE SSANGCIEUC YI RIEULMIEUM + 0xA979: 0xCBFB, //HANGUL SYLLABLE SSANGCIEUC YI RIEULPIEUP + 0xA97A: 0xCBFC, //HANGUL SYLLABLE SSANGCIEUC YI RIEULSIOS + 0xA981: 0xCBFD, //HANGUL SYLLABLE SSANGCIEUC YI RIEULTHIEUTH + 0xA982: 0xCBFE, //HANGUL SYLLABLE SSANGCIEUC YI RIEULPHIEUPH + 0xA983: 0xCBFF, //HANGUL SYLLABLE SSANGCIEUC YI RIEULHIEUH + 0xA984: 0xCC00, //HANGUL SYLLABLE SSANGCIEUC YI MIEUM + 0xA985: 0xCC01, //HANGUL SYLLABLE SSANGCIEUC YI PIEUP + 0xA986: 0xCC02, //HANGUL SYLLABLE SSANGCIEUC YI PIEUPSIOS + 0xA987: 0xCC03, //HANGUL SYLLABLE SSANGCIEUC YI SIOS + 0xA988: 0xCC04, //HANGUL SYLLABLE SSANGCIEUC YI SSANGSIOS + 0xA989: 0xCC05, //HANGUL SYLLABLE SSANGCIEUC YI IEUNG + 0xA98A: 0xCC06, //HANGUL SYLLABLE SSANGCIEUC YI CIEUC + 0xA98B: 0xCC07, //HANGUL SYLLABLE SSANGCIEUC YI CHIEUCH + 0xA98C: 0xCC08, //HANGUL SYLLABLE SSANGCIEUC YI KHIEUKH + 0xA98D: 0xCC09, //HANGUL SYLLABLE SSANGCIEUC YI THIEUTH + 0xA98E: 0xCC0A, //HANGUL SYLLABLE SSANGCIEUC YI PHIEUPH + 0xA98F: 0xCC0B, //HANGUL SYLLABLE SSANGCIEUC YI HIEUH + 0xA990: 0xCC0E, //HANGUL SYLLABLE SSANGCIEUC I SSANGKIYEOK + 0xA991: 0xCC0F, //HANGUL SYLLABLE SSANGCIEUC I KIYEOKSIOS + 0xA992: 0xCC11, //HANGUL SYLLABLE SSANGCIEUC I NIEUNCIEUC + 0xA993: 0xCC12, //HANGUL SYLLABLE SSANGCIEUC I NIEUNHIEUH + 0xA994: 0xCC13, //HANGUL SYLLABLE SSANGCIEUC I TIKEUT + 0xA995: 0xCC15, //HANGUL SYLLABLE SSANGCIEUC I RIEULKIYEOK + 0xA996: 0xCC16, //HANGUL SYLLABLE SSANGCIEUC I RIEULMIEUM + 0xA997: 0xCC17, //HANGUL SYLLABLE SSANGCIEUC I RIEULPIEUP + 0xA998: 0xCC18, //HANGUL SYLLABLE SSANGCIEUC I RIEULSIOS + 0xA999: 0xCC19, //HANGUL SYLLABLE SSANGCIEUC I RIEULTHIEUTH + 0xA99A: 0xCC1A, //HANGUL SYLLABLE SSANGCIEUC I RIEULPHIEUPH + 0xA99B: 0xCC1B, //HANGUL SYLLABLE SSANGCIEUC I RIEULHIEUH + 0xA99C: 0xCC1E, //HANGUL SYLLABLE SSANGCIEUC I PIEUPSIOS + 0xA99D: 0xCC1F, //HANGUL SYLLABLE SSANGCIEUC I SIOS + 0xA99E: 0xCC20, //HANGUL SYLLABLE SSANGCIEUC I SSANGSIOS + 0xA99F: 0xCC23, //HANGUL SYLLABLE SSANGCIEUC I CHIEUCH + 0xA9A0: 0xCC24, //HANGUL SYLLABLE SSANGCIEUC I KHIEUKH + 0xA9A1: 0x00E6, //LATIN SMALL LETTER AE + 0xA9A2: 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0xA9A3: 0x00F0, //LATIN SMALL LETTER ETH + 0xA9A4: 0x0127, //LATIN SMALL LETTER H WITH STROKE + 0xA9A5: 0x0131, //LATIN SMALL LETTER DOTLESS I + 0xA9A6: 0x0133, //LATIN SMALL LIGATURE IJ + 0xA9A7: 0x0138, //LATIN SMALL LETTER KRA + 0xA9A8: 0x0140, //LATIN SMALL LETTER L WITH MIDDLE DOT + 0xA9A9: 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0xA9AA: 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0xA9AB: 0x0153, //LATIN SMALL LIGATURE OE + 0xA9AC: 0x00DF, //LATIN SMALL LETTER SHARP S + 0xA9AD: 0x00FE, //LATIN SMALL LETTER THORN + 0xA9AE: 0x0167, //LATIN SMALL LETTER T WITH STROKE + 0xA9AF: 0x014B, //LATIN SMALL LETTER ENG + 0xA9B0: 0x0149, //LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + 0xA9B1: 0x3200, //PARENTHESIZED HANGUL KIYEOK + 0xA9B2: 0x3201, //PARENTHESIZED HANGUL NIEUN + 0xA9B3: 0x3202, //PARENTHESIZED HANGUL TIKEUT + 0xA9B4: 0x3203, //PARENTHESIZED HANGUL RIEUL + 0xA9B5: 0x3204, //PARENTHESIZED HANGUL MIEUM + 0xA9B6: 0x3205, //PARENTHESIZED HANGUL PIEUP + 0xA9B7: 0x3206, //PARENTHESIZED HANGUL SIOS + 0xA9B8: 0x3207, //PARENTHESIZED HANGUL IEUNG + 0xA9B9: 0x3208, //PARENTHESIZED HANGUL CIEUC + 0xA9BA: 0x3209, //PARENTHESIZED HANGUL CHIEUCH + 0xA9BB: 0x320A, //PARENTHESIZED HANGUL KHIEUKH + 0xA9BC: 0x320B, //PARENTHESIZED HANGUL THIEUTH + 0xA9BD: 0x320C, //PARENTHESIZED HANGUL PHIEUPH + 0xA9BE: 0x320D, //PARENTHESIZED HANGUL HIEUH + 0xA9BF: 0x320E, //PARENTHESIZED HANGUL KIYEOK A + 0xA9C0: 0x320F, //PARENTHESIZED HANGUL NIEUN A + 0xA9C1: 0x3210, //PARENTHESIZED HANGUL TIKEUT A + 0xA9C2: 0x3211, //PARENTHESIZED HANGUL RIEUL A + 0xA9C3: 0x3212, //PARENTHESIZED HANGUL MIEUM A + 0xA9C4: 0x3213, //PARENTHESIZED HANGUL PIEUP A + 0xA9C5: 0x3214, //PARENTHESIZED HANGUL SIOS A + 0xA9C6: 0x3215, //PARENTHESIZED HANGUL IEUNG A + 0xA9C7: 0x3216, //PARENTHESIZED HANGUL CIEUC A + 0xA9C8: 0x3217, //PARENTHESIZED HANGUL CHIEUCH A + 0xA9C9: 0x3218, //PARENTHESIZED HANGUL KHIEUKH A + 0xA9CA: 0x3219, //PARENTHESIZED HANGUL THIEUTH A + 0xA9CB: 0x321A, //PARENTHESIZED HANGUL PHIEUPH A + 0xA9CC: 0x321B, //PARENTHESIZED HANGUL HIEUH A + 0xA9CD: 0x249C, //PARENTHESIZED LATIN SMALL LETTER A + 0xA9CE: 0x249D, //PARENTHESIZED LATIN SMALL LETTER B + 0xA9CF: 0x249E, //PARENTHESIZED LATIN SMALL LETTER C + 0xA9D0: 0x249F, //PARENTHESIZED LATIN SMALL LETTER D + 0xA9D1: 0x24A0, //PARENTHESIZED LATIN SMALL LETTER E + 0xA9D2: 0x24A1, //PARENTHESIZED LATIN SMALL LETTER F + 0xA9D3: 0x24A2, //PARENTHESIZED LATIN SMALL LETTER G + 0xA9D4: 0x24A3, //PARENTHESIZED LATIN SMALL LETTER H + 0xA9D5: 0x24A4, //PARENTHESIZED LATIN SMALL LETTER I + 0xA9D6: 0x24A5, //PARENTHESIZED LATIN SMALL LETTER J + 0xA9D7: 0x24A6, //PARENTHESIZED LATIN SMALL LETTER K + 0xA9D8: 0x24A7, //PARENTHESIZED LATIN SMALL LETTER L + 0xA9D9: 0x24A8, //PARENTHESIZED LATIN SMALL LETTER M + 0xA9DA: 0x24A9, //PARENTHESIZED LATIN SMALL LETTER N + 0xA9DB: 0x24AA, //PARENTHESIZED LATIN SMALL LETTER O + 0xA9DC: 0x24AB, //PARENTHESIZED LATIN SMALL LETTER P + 0xA9DD: 0x24AC, //PARENTHESIZED LATIN SMALL LETTER Q + 0xA9DE: 0x24AD, //PARENTHESIZED LATIN SMALL LETTER R + 0xA9DF: 0x24AE, //PARENTHESIZED LATIN SMALL LETTER S + 0xA9E0: 0x24AF, //PARENTHESIZED LATIN SMALL LETTER T + 0xA9E1: 0x24B0, //PARENTHESIZED LATIN SMALL LETTER U + 0xA9E2: 0x24B1, //PARENTHESIZED LATIN SMALL LETTER V + 0xA9E3: 0x24B2, //PARENTHESIZED LATIN SMALL LETTER W + 0xA9E4: 0x24B3, //PARENTHESIZED LATIN SMALL LETTER X + 0xA9E5: 0x24B4, //PARENTHESIZED LATIN SMALL LETTER Y + 0xA9E6: 0x24B5, //PARENTHESIZED LATIN SMALL LETTER Z + 0xA9E7: 0x2474, //PARENTHESIZED DIGIT ONE + 0xA9E8: 0x2475, //PARENTHESIZED DIGIT TWO + 0xA9E9: 0x2476, //PARENTHESIZED DIGIT THREE + 0xA9EA: 0x2477, //PARENTHESIZED DIGIT FOUR + 0xA9EB: 0x2478, //PARENTHESIZED DIGIT FIVE + 0xA9EC: 0x2479, //PARENTHESIZED DIGIT SIX + 0xA9ED: 0x247A, //PARENTHESIZED DIGIT SEVEN + 0xA9EE: 0x247B, //PARENTHESIZED DIGIT EIGHT + 0xA9EF: 0x247C, //PARENTHESIZED DIGIT NINE + 0xA9F0: 0x247D, //PARENTHESIZED NUMBER TEN + 0xA9F1: 0x247E, //PARENTHESIZED NUMBER ELEVEN + 0xA9F2: 0x247F, //PARENTHESIZED NUMBER TWELVE + 0xA9F3: 0x2480, //PARENTHESIZED NUMBER THIRTEEN + 0xA9F4: 0x2481, //PARENTHESIZED NUMBER FOURTEEN + 0xA9F5: 0x2482, //PARENTHESIZED NUMBER FIFTEEN + 0xA9F6: 0x00B9, //SUPERSCRIPT ONE + 0xA9F7: 0x00B2, //SUPERSCRIPT TWO + 0xA9F8: 0x00B3, //SUPERSCRIPT THREE + 0xA9F9: 0x2074, //SUPERSCRIPT FOUR + 0xA9FA: 0x207F, //SUPERSCRIPT LATIN SMALL LETTER N + 0xA9FB: 0x2081, //SUBSCRIPT ONE + 0xA9FC: 0x2082, //SUBSCRIPT TWO + 0xA9FD: 0x2083, //SUBSCRIPT THREE + 0xA9FE: 0x2084, //SUBSCRIPT FOUR + 0xAA41: 0xCC25, //HANGUL SYLLABLE SSANGCIEUC I THIEUTH + 0xAA42: 0xCC26, //HANGUL SYLLABLE SSANGCIEUC I PHIEUPH + 0xAA43: 0xCC2A, //HANGUL SYLLABLE CHIEUCH A SSANGKIYEOK + 0xAA44: 0xCC2B, //HANGUL SYLLABLE CHIEUCH A KIYEOKSIOS + 0xAA45: 0xCC2D, //HANGUL SYLLABLE CHIEUCH A NIEUNCIEUC + 0xAA46: 0xCC2F, //HANGUL SYLLABLE CHIEUCH A TIKEUT + 0xAA47: 0xCC31, //HANGUL SYLLABLE CHIEUCH A RIEULKIYEOK + 0xAA48: 0xCC32, //HANGUL SYLLABLE CHIEUCH A RIEULMIEUM + 0xAA49: 0xCC33, //HANGUL SYLLABLE CHIEUCH A RIEULPIEUP + 0xAA4A: 0xCC34, //HANGUL SYLLABLE CHIEUCH A RIEULSIOS + 0xAA4B: 0xCC35, //HANGUL SYLLABLE CHIEUCH A RIEULTHIEUTH + 0xAA4C: 0xCC36, //HANGUL SYLLABLE CHIEUCH A RIEULPHIEUPH + 0xAA4D: 0xCC37, //HANGUL SYLLABLE CHIEUCH A RIEULHIEUH + 0xAA4E: 0xCC3A, //HANGUL SYLLABLE CHIEUCH A PIEUPSIOS + 0xAA4F: 0xCC3F, //HANGUL SYLLABLE CHIEUCH A CHIEUCH + 0xAA50: 0xCC40, //HANGUL SYLLABLE CHIEUCH A KHIEUKH + 0xAA51: 0xCC41, //HANGUL SYLLABLE CHIEUCH A THIEUTH + 0xAA52: 0xCC42, //HANGUL SYLLABLE CHIEUCH A PHIEUPH + 0xAA53: 0xCC43, //HANGUL SYLLABLE CHIEUCH A HIEUH + 0xAA54: 0xCC46, //HANGUL SYLLABLE CHIEUCH AE SSANGKIYEOK + 0xAA55: 0xCC47, //HANGUL SYLLABLE CHIEUCH AE KIYEOKSIOS + 0xAA56: 0xCC49, //HANGUL SYLLABLE CHIEUCH AE NIEUNCIEUC + 0xAA57: 0xCC4A, //HANGUL SYLLABLE CHIEUCH AE NIEUNHIEUH + 0xAA58: 0xCC4B, //HANGUL SYLLABLE CHIEUCH AE TIKEUT + 0xAA59: 0xCC4D, //HANGUL SYLLABLE CHIEUCH AE RIEULKIYEOK + 0xAA5A: 0xCC4E, //HANGUL SYLLABLE CHIEUCH AE RIEULMIEUM + 0xAA61: 0xCC4F, //HANGUL SYLLABLE CHIEUCH AE RIEULPIEUP + 0xAA62: 0xCC50, //HANGUL SYLLABLE CHIEUCH AE RIEULSIOS + 0xAA63: 0xCC51, //HANGUL SYLLABLE CHIEUCH AE RIEULTHIEUTH + 0xAA64: 0xCC52, //HANGUL SYLLABLE CHIEUCH AE RIEULPHIEUPH + 0xAA65: 0xCC53, //HANGUL SYLLABLE CHIEUCH AE RIEULHIEUH + 0xAA66: 0xCC56, //HANGUL SYLLABLE CHIEUCH AE PIEUPSIOS + 0xAA67: 0xCC5A, //HANGUL SYLLABLE CHIEUCH AE CIEUC + 0xAA68: 0xCC5B, //HANGUL SYLLABLE CHIEUCH AE CHIEUCH + 0xAA69: 0xCC5C, //HANGUL SYLLABLE CHIEUCH AE KHIEUKH + 0xAA6A: 0xCC5D, //HANGUL SYLLABLE CHIEUCH AE THIEUTH + 0xAA6B: 0xCC5E, //HANGUL SYLLABLE CHIEUCH AE PHIEUPH + 0xAA6C: 0xCC5F, //HANGUL SYLLABLE CHIEUCH AE HIEUH + 0xAA6D: 0xCC61, //HANGUL SYLLABLE CHIEUCH YA KIYEOK + 0xAA6E: 0xCC62, //HANGUL SYLLABLE CHIEUCH YA SSANGKIYEOK + 0xAA6F: 0xCC63, //HANGUL SYLLABLE CHIEUCH YA KIYEOKSIOS + 0xAA70: 0xCC65, //HANGUL SYLLABLE CHIEUCH YA NIEUNCIEUC + 0xAA71: 0xCC67, //HANGUL SYLLABLE CHIEUCH YA TIKEUT + 0xAA72: 0xCC69, //HANGUL SYLLABLE CHIEUCH YA RIEULKIYEOK + 0xAA73: 0xCC6A, //HANGUL SYLLABLE CHIEUCH YA RIEULMIEUM + 0xAA74: 0xCC6B, //HANGUL SYLLABLE CHIEUCH YA RIEULPIEUP + 0xAA75: 0xCC6C, //HANGUL SYLLABLE CHIEUCH YA RIEULSIOS + 0xAA76: 0xCC6D, //HANGUL SYLLABLE CHIEUCH YA RIEULTHIEUTH + 0xAA77: 0xCC6E, //HANGUL SYLLABLE CHIEUCH YA RIEULPHIEUPH + 0xAA78: 0xCC6F, //HANGUL SYLLABLE CHIEUCH YA RIEULHIEUH + 0xAA79: 0xCC71, //HANGUL SYLLABLE CHIEUCH YA PIEUP + 0xAA7A: 0xCC72, //HANGUL SYLLABLE CHIEUCH YA PIEUPSIOS + 0xAA81: 0xCC73, //HANGUL SYLLABLE CHIEUCH YA SIOS + 0xAA82: 0xCC74, //HANGUL SYLLABLE CHIEUCH YA SSANGSIOS + 0xAA83: 0xCC76, //HANGUL SYLLABLE CHIEUCH YA CIEUC + 0xAA84: 0xCC77, //HANGUL SYLLABLE CHIEUCH YA CHIEUCH + 0xAA85: 0xCC78, //HANGUL SYLLABLE CHIEUCH YA KHIEUKH + 0xAA86: 0xCC79, //HANGUL SYLLABLE CHIEUCH YA THIEUTH + 0xAA87: 0xCC7A, //HANGUL SYLLABLE CHIEUCH YA PHIEUPH + 0xAA88: 0xCC7B, //HANGUL SYLLABLE CHIEUCH YA HIEUH + 0xAA89: 0xCC7C, //HANGUL SYLLABLE CHIEUCH YAE + 0xAA8A: 0xCC7D, //HANGUL SYLLABLE CHIEUCH YAE KIYEOK + 0xAA8B: 0xCC7E, //HANGUL SYLLABLE CHIEUCH YAE SSANGKIYEOK + 0xAA8C: 0xCC7F, //HANGUL SYLLABLE CHIEUCH YAE KIYEOKSIOS + 0xAA8D: 0xCC80, //HANGUL SYLLABLE CHIEUCH YAE NIEUN + 0xAA8E: 0xCC81, //HANGUL SYLLABLE CHIEUCH YAE NIEUNCIEUC + 0xAA8F: 0xCC82, //HANGUL SYLLABLE CHIEUCH YAE NIEUNHIEUH + 0xAA90: 0xCC83, //HANGUL SYLLABLE CHIEUCH YAE TIKEUT + 0xAA91: 0xCC84, //HANGUL SYLLABLE CHIEUCH YAE RIEUL + 0xAA92: 0xCC85, //HANGUL SYLLABLE CHIEUCH YAE RIEULKIYEOK + 0xAA93: 0xCC86, //HANGUL SYLLABLE CHIEUCH YAE RIEULMIEUM + 0xAA94: 0xCC87, //HANGUL SYLLABLE CHIEUCH YAE RIEULPIEUP + 0xAA95: 0xCC88, //HANGUL SYLLABLE CHIEUCH YAE RIEULSIOS + 0xAA96: 0xCC89, //HANGUL SYLLABLE CHIEUCH YAE RIEULTHIEUTH + 0xAA97: 0xCC8A, //HANGUL SYLLABLE CHIEUCH YAE RIEULPHIEUPH + 0xAA98: 0xCC8B, //HANGUL SYLLABLE CHIEUCH YAE RIEULHIEUH + 0xAA99: 0xCC8C, //HANGUL SYLLABLE CHIEUCH YAE MIEUM + 0xAA9A: 0xCC8D, //HANGUL SYLLABLE CHIEUCH YAE PIEUP + 0xAA9B: 0xCC8E, //HANGUL SYLLABLE CHIEUCH YAE PIEUPSIOS + 0xAA9C: 0xCC8F, //HANGUL SYLLABLE CHIEUCH YAE SIOS + 0xAA9D: 0xCC90, //HANGUL SYLLABLE CHIEUCH YAE SSANGSIOS + 0xAA9E: 0xCC91, //HANGUL SYLLABLE CHIEUCH YAE IEUNG + 0xAA9F: 0xCC92, //HANGUL SYLLABLE CHIEUCH YAE CIEUC + 0xAAA0: 0xCC93, //HANGUL SYLLABLE CHIEUCH YAE CHIEUCH + 0xAAA1: 0x3041, //HIRAGANA LETTER SMALL A + 0xAAA2: 0x3042, //HIRAGANA LETTER A + 0xAAA3: 0x3043, //HIRAGANA LETTER SMALL I + 0xAAA4: 0x3044, //HIRAGANA LETTER I + 0xAAA5: 0x3045, //HIRAGANA LETTER SMALL U + 0xAAA6: 0x3046, //HIRAGANA LETTER U + 0xAAA7: 0x3047, //HIRAGANA LETTER SMALL E + 0xAAA8: 0x3048, //HIRAGANA LETTER E + 0xAAA9: 0x3049, //HIRAGANA LETTER SMALL O + 0xAAAA: 0x304A, //HIRAGANA LETTER O + 0xAAAB: 0x304B, //HIRAGANA LETTER KA + 0xAAAC: 0x304C, //HIRAGANA LETTER GA + 0xAAAD: 0x304D, //HIRAGANA LETTER KI + 0xAAAE: 0x304E, //HIRAGANA LETTER GI + 0xAAAF: 0x304F, //HIRAGANA LETTER KU + 0xAAB0: 0x3050, //HIRAGANA LETTER GU + 0xAAB1: 0x3051, //HIRAGANA LETTER KE + 0xAAB2: 0x3052, //HIRAGANA LETTER GE + 0xAAB3: 0x3053, //HIRAGANA LETTER KO + 0xAAB4: 0x3054, //HIRAGANA LETTER GO + 0xAAB5: 0x3055, //HIRAGANA LETTER SA + 0xAAB6: 0x3056, //HIRAGANA LETTER ZA + 0xAAB7: 0x3057, //HIRAGANA LETTER SI + 0xAAB8: 0x3058, //HIRAGANA LETTER ZI + 0xAAB9: 0x3059, //HIRAGANA LETTER SU + 0xAABA: 0x305A, //HIRAGANA LETTER ZU + 0xAABB: 0x305B, //HIRAGANA LETTER SE + 0xAABC: 0x305C, //HIRAGANA LETTER ZE + 0xAABD: 0x305D, //HIRAGANA LETTER SO + 0xAABE: 0x305E, //HIRAGANA LETTER ZO + 0xAABF: 0x305F, //HIRAGANA LETTER TA + 0xAAC0: 0x3060, //HIRAGANA LETTER DA + 0xAAC1: 0x3061, //HIRAGANA LETTER TI + 0xAAC2: 0x3062, //HIRAGANA LETTER DI + 0xAAC3: 0x3063, //HIRAGANA LETTER SMALL TU + 0xAAC4: 0x3064, //HIRAGANA LETTER TU + 0xAAC5: 0x3065, //HIRAGANA LETTER DU + 0xAAC6: 0x3066, //HIRAGANA LETTER TE + 0xAAC7: 0x3067, //HIRAGANA LETTER DE + 0xAAC8: 0x3068, //HIRAGANA LETTER TO + 0xAAC9: 0x3069, //HIRAGANA LETTER DO + 0xAACA: 0x306A, //HIRAGANA LETTER NA + 0xAACB: 0x306B, //HIRAGANA LETTER NI + 0xAACC: 0x306C, //HIRAGANA LETTER NU + 0xAACD: 0x306D, //HIRAGANA LETTER NE + 0xAACE: 0x306E, //HIRAGANA LETTER NO + 0xAACF: 0x306F, //HIRAGANA LETTER HA + 0xAAD0: 0x3070, //HIRAGANA LETTER BA + 0xAAD1: 0x3071, //HIRAGANA LETTER PA + 0xAAD2: 0x3072, //HIRAGANA LETTER HI + 0xAAD3: 0x3073, //HIRAGANA LETTER BI + 0xAAD4: 0x3074, //HIRAGANA LETTER PI + 0xAAD5: 0x3075, //HIRAGANA LETTER HU + 0xAAD6: 0x3076, //HIRAGANA LETTER BU + 0xAAD7: 0x3077, //HIRAGANA LETTER PU + 0xAAD8: 0x3078, //HIRAGANA LETTER HE + 0xAAD9: 0x3079, //HIRAGANA LETTER BE + 0xAADA: 0x307A, //HIRAGANA LETTER PE + 0xAADB: 0x307B, //HIRAGANA LETTER HO + 0xAADC: 0x307C, //HIRAGANA LETTER BO + 0xAADD: 0x307D, //HIRAGANA LETTER PO + 0xAADE: 0x307E, //HIRAGANA LETTER MA + 0xAADF: 0x307F, //HIRAGANA LETTER MI + 0xAAE0: 0x3080, //HIRAGANA LETTER MU + 0xAAE1: 0x3081, //HIRAGANA LETTER ME + 0xAAE2: 0x3082, //HIRAGANA LETTER MO + 0xAAE3: 0x3083, //HIRAGANA LETTER SMALL YA + 0xAAE4: 0x3084, //HIRAGANA LETTER YA + 0xAAE5: 0x3085, //HIRAGANA LETTER SMALL YU + 0xAAE6: 0x3086, //HIRAGANA LETTER YU + 0xAAE7: 0x3087, //HIRAGANA LETTER SMALL YO + 0xAAE8: 0x3088, //HIRAGANA LETTER YO + 0xAAE9: 0x3089, //HIRAGANA LETTER RA + 0xAAEA: 0x308A, //HIRAGANA LETTER RI + 0xAAEB: 0x308B, //HIRAGANA LETTER RU + 0xAAEC: 0x308C, //HIRAGANA LETTER RE + 0xAAED: 0x308D, //HIRAGANA LETTER RO + 0xAAEE: 0x308E, //HIRAGANA LETTER SMALL WA + 0xAAEF: 0x308F, //HIRAGANA LETTER WA + 0xAAF0: 0x3090, //HIRAGANA LETTER WI + 0xAAF1: 0x3091, //HIRAGANA LETTER WE + 0xAAF2: 0x3092, //HIRAGANA LETTER WO + 0xAAF3: 0x3093, //HIRAGANA LETTER N + 0xAB41: 0xCC94, //HANGUL SYLLABLE CHIEUCH YAE KHIEUKH + 0xAB42: 0xCC95, //HANGUL SYLLABLE CHIEUCH YAE THIEUTH + 0xAB43: 0xCC96, //HANGUL SYLLABLE CHIEUCH YAE PHIEUPH + 0xAB44: 0xCC97, //HANGUL SYLLABLE CHIEUCH YAE HIEUH + 0xAB45: 0xCC9A, //HANGUL SYLLABLE CHIEUCH EO SSANGKIYEOK + 0xAB46: 0xCC9B, //HANGUL SYLLABLE CHIEUCH EO KIYEOKSIOS + 0xAB47: 0xCC9D, //HANGUL SYLLABLE CHIEUCH EO NIEUNCIEUC + 0xAB48: 0xCC9E, //HANGUL SYLLABLE CHIEUCH EO NIEUNHIEUH + 0xAB49: 0xCC9F, //HANGUL SYLLABLE CHIEUCH EO TIKEUT + 0xAB4A: 0xCCA1, //HANGUL SYLLABLE CHIEUCH EO RIEULKIYEOK + 0xAB4B: 0xCCA2, //HANGUL SYLLABLE CHIEUCH EO RIEULMIEUM + 0xAB4C: 0xCCA3, //HANGUL SYLLABLE CHIEUCH EO RIEULPIEUP + 0xAB4D: 0xCCA4, //HANGUL SYLLABLE CHIEUCH EO RIEULSIOS + 0xAB4E: 0xCCA5, //HANGUL SYLLABLE CHIEUCH EO RIEULTHIEUTH + 0xAB4F: 0xCCA6, //HANGUL SYLLABLE CHIEUCH EO RIEULPHIEUPH + 0xAB50: 0xCCA7, //HANGUL SYLLABLE CHIEUCH EO RIEULHIEUH + 0xAB51: 0xCCAA, //HANGUL SYLLABLE CHIEUCH EO PIEUPSIOS + 0xAB52: 0xCCAE, //HANGUL SYLLABLE CHIEUCH EO CIEUC + 0xAB53: 0xCCAF, //HANGUL SYLLABLE CHIEUCH EO CHIEUCH + 0xAB54: 0xCCB0, //HANGUL SYLLABLE CHIEUCH EO KHIEUKH + 0xAB55: 0xCCB1, //HANGUL SYLLABLE CHIEUCH EO THIEUTH + 0xAB56: 0xCCB2, //HANGUL SYLLABLE CHIEUCH EO PHIEUPH + 0xAB57: 0xCCB3, //HANGUL SYLLABLE CHIEUCH EO HIEUH + 0xAB58: 0xCCB6, //HANGUL SYLLABLE CHIEUCH E SSANGKIYEOK + 0xAB59: 0xCCB7, //HANGUL SYLLABLE CHIEUCH E KIYEOKSIOS + 0xAB5A: 0xCCB9, //HANGUL SYLLABLE CHIEUCH E NIEUNCIEUC + 0xAB61: 0xCCBA, //HANGUL SYLLABLE CHIEUCH E NIEUNHIEUH + 0xAB62: 0xCCBB, //HANGUL SYLLABLE CHIEUCH E TIKEUT + 0xAB63: 0xCCBD, //HANGUL SYLLABLE CHIEUCH E RIEULKIYEOK + 0xAB64: 0xCCBE, //HANGUL SYLLABLE CHIEUCH E RIEULMIEUM + 0xAB65: 0xCCBF, //HANGUL SYLLABLE CHIEUCH E RIEULPIEUP + 0xAB66: 0xCCC0, //HANGUL SYLLABLE CHIEUCH E RIEULSIOS + 0xAB67: 0xCCC1, //HANGUL SYLLABLE CHIEUCH E RIEULTHIEUTH + 0xAB68: 0xCCC2, //HANGUL SYLLABLE CHIEUCH E RIEULPHIEUPH + 0xAB69: 0xCCC3, //HANGUL SYLLABLE CHIEUCH E RIEULHIEUH + 0xAB6A: 0xCCC6, //HANGUL SYLLABLE CHIEUCH E PIEUPSIOS + 0xAB6B: 0xCCC8, //HANGUL SYLLABLE CHIEUCH E SSANGSIOS + 0xAB6C: 0xCCCA, //HANGUL SYLLABLE CHIEUCH E CIEUC + 0xAB6D: 0xCCCB, //HANGUL SYLLABLE CHIEUCH E CHIEUCH + 0xAB6E: 0xCCCC, //HANGUL SYLLABLE CHIEUCH E KHIEUKH + 0xAB6F: 0xCCCD, //HANGUL SYLLABLE CHIEUCH E THIEUTH + 0xAB70: 0xCCCE, //HANGUL SYLLABLE CHIEUCH E PHIEUPH + 0xAB71: 0xCCCF, //HANGUL SYLLABLE CHIEUCH E HIEUH + 0xAB72: 0xCCD1, //HANGUL SYLLABLE CHIEUCH YEO KIYEOK + 0xAB73: 0xCCD2, //HANGUL SYLLABLE CHIEUCH YEO SSANGKIYEOK + 0xAB74: 0xCCD3, //HANGUL SYLLABLE CHIEUCH YEO KIYEOKSIOS + 0xAB75: 0xCCD5, //HANGUL SYLLABLE CHIEUCH YEO NIEUNCIEUC + 0xAB76: 0xCCD6, //HANGUL SYLLABLE CHIEUCH YEO NIEUNHIEUH + 0xAB77: 0xCCD7, //HANGUL SYLLABLE CHIEUCH YEO TIKEUT + 0xAB78: 0xCCD8, //HANGUL SYLLABLE CHIEUCH YEO RIEUL + 0xAB79: 0xCCD9, //HANGUL SYLLABLE CHIEUCH YEO RIEULKIYEOK + 0xAB7A: 0xCCDA, //HANGUL SYLLABLE CHIEUCH YEO RIEULMIEUM + 0xAB81: 0xCCDB, //HANGUL SYLLABLE CHIEUCH YEO RIEULPIEUP + 0xAB82: 0xCCDC, //HANGUL SYLLABLE CHIEUCH YEO RIEULSIOS + 0xAB83: 0xCCDD, //HANGUL SYLLABLE CHIEUCH YEO RIEULTHIEUTH + 0xAB84: 0xCCDE, //HANGUL SYLLABLE CHIEUCH YEO RIEULPHIEUPH + 0xAB85: 0xCCDF, //HANGUL SYLLABLE CHIEUCH YEO RIEULHIEUH + 0xAB86: 0xCCE0, //HANGUL SYLLABLE CHIEUCH YEO MIEUM + 0xAB87: 0xCCE1, //HANGUL SYLLABLE CHIEUCH YEO PIEUP + 0xAB88: 0xCCE2, //HANGUL SYLLABLE CHIEUCH YEO PIEUPSIOS + 0xAB89: 0xCCE3, //HANGUL SYLLABLE CHIEUCH YEO SIOS + 0xAB8A: 0xCCE5, //HANGUL SYLLABLE CHIEUCH YEO IEUNG + 0xAB8B: 0xCCE6, //HANGUL SYLLABLE CHIEUCH YEO CIEUC + 0xAB8C: 0xCCE7, //HANGUL SYLLABLE CHIEUCH YEO CHIEUCH + 0xAB8D: 0xCCE8, //HANGUL SYLLABLE CHIEUCH YEO KHIEUKH + 0xAB8E: 0xCCE9, //HANGUL SYLLABLE CHIEUCH YEO THIEUTH + 0xAB8F: 0xCCEA, //HANGUL SYLLABLE CHIEUCH YEO PHIEUPH + 0xAB90: 0xCCEB, //HANGUL SYLLABLE CHIEUCH YEO HIEUH + 0xAB91: 0xCCED, //HANGUL SYLLABLE CHIEUCH YE KIYEOK + 0xAB92: 0xCCEE, //HANGUL SYLLABLE CHIEUCH YE SSANGKIYEOK + 0xAB93: 0xCCEF, //HANGUL SYLLABLE CHIEUCH YE KIYEOKSIOS + 0xAB94: 0xCCF1, //HANGUL SYLLABLE CHIEUCH YE NIEUNCIEUC + 0xAB95: 0xCCF2, //HANGUL SYLLABLE CHIEUCH YE NIEUNHIEUH + 0xAB96: 0xCCF3, //HANGUL SYLLABLE CHIEUCH YE TIKEUT + 0xAB97: 0xCCF4, //HANGUL SYLLABLE CHIEUCH YE RIEUL + 0xAB98: 0xCCF5, //HANGUL SYLLABLE CHIEUCH YE RIEULKIYEOK + 0xAB99: 0xCCF6, //HANGUL SYLLABLE CHIEUCH YE RIEULMIEUM + 0xAB9A: 0xCCF7, //HANGUL SYLLABLE CHIEUCH YE RIEULPIEUP + 0xAB9B: 0xCCF8, //HANGUL SYLLABLE CHIEUCH YE RIEULSIOS + 0xAB9C: 0xCCF9, //HANGUL SYLLABLE CHIEUCH YE RIEULTHIEUTH + 0xAB9D: 0xCCFA, //HANGUL SYLLABLE CHIEUCH YE RIEULPHIEUPH + 0xAB9E: 0xCCFB, //HANGUL SYLLABLE CHIEUCH YE RIEULHIEUH + 0xAB9F: 0xCCFC, //HANGUL SYLLABLE CHIEUCH YE MIEUM + 0xABA0: 0xCCFD, //HANGUL SYLLABLE CHIEUCH YE PIEUP + 0xABA1: 0x30A1, //KATAKANA LETTER SMALL A + 0xABA2: 0x30A2, //KATAKANA LETTER A + 0xABA3: 0x30A3, //KATAKANA LETTER SMALL I + 0xABA4: 0x30A4, //KATAKANA LETTER I + 0xABA5: 0x30A5, //KATAKANA LETTER SMALL U + 0xABA6: 0x30A6, //KATAKANA LETTER U + 0xABA7: 0x30A7, //KATAKANA LETTER SMALL E + 0xABA8: 0x30A8, //KATAKANA LETTER E + 0xABA9: 0x30A9, //KATAKANA LETTER SMALL O + 0xABAA: 0x30AA, //KATAKANA LETTER O + 0xABAB: 0x30AB, //KATAKANA LETTER KA + 0xABAC: 0x30AC, //KATAKANA LETTER GA + 0xABAD: 0x30AD, //KATAKANA LETTER KI + 0xABAE: 0x30AE, //KATAKANA LETTER GI + 0xABAF: 0x30AF, //KATAKANA LETTER KU + 0xABB0: 0x30B0, //KATAKANA LETTER GU + 0xABB1: 0x30B1, //KATAKANA LETTER KE + 0xABB2: 0x30B2, //KATAKANA LETTER GE + 0xABB3: 0x30B3, //KATAKANA LETTER KO + 0xABB4: 0x30B4, //KATAKANA LETTER GO + 0xABB5: 0x30B5, //KATAKANA LETTER SA + 0xABB6: 0x30B6, //KATAKANA LETTER ZA + 0xABB7: 0x30B7, //KATAKANA LETTER SI + 0xABB8: 0x30B8, //KATAKANA LETTER ZI + 0xABB9: 0x30B9, //KATAKANA LETTER SU + 0xABBA: 0x30BA, //KATAKANA LETTER ZU + 0xABBB: 0x30BB, //KATAKANA LETTER SE + 0xABBC: 0x30BC, //KATAKANA LETTER ZE + 0xABBD: 0x30BD, //KATAKANA LETTER SO + 0xABBE: 0x30BE, //KATAKANA LETTER ZO + 0xABBF: 0x30BF, //KATAKANA LETTER TA + 0xABC0: 0x30C0, //KATAKANA LETTER DA + 0xABC1: 0x30C1, //KATAKANA LETTER TI + 0xABC2: 0x30C2, //KATAKANA LETTER DI + 0xABC3: 0x30C3, //KATAKANA LETTER SMALL TU + 0xABC4: 0x30C4, //KATAKANA LETTER TU + 0xABC5: 0x30C5, //KATAKANA LETTER DU + 0xABC6: 0x30C6, //KATAKANA LETTER TE + 0xABC7: 0x30C7, //KATAKANA LETTER DE + 0xABC8: 0x30C8, //KATAKANA LETTER TO + 0xABC9: 0x30C9, //KATAKANA LETTER DO + 0xABCA: 0x30CA, //KATAKANA LETTER NA + 0xABCB: 0x30CB, //KATAKANA LETTER NI + 0xABCC: 0x30CC, //KATAKANA LETTER NU + 0xABCD: 0x30CD, //KATAKANA LETTER NE + 0xABCE: 0x30CE, //KATAKANA LETTER NO + 0xABCF: 0x30CF, //KATAKANA LETTER HA + 0xABD0: 0x30D0, //KATAKANA LETTER BA + 0xABD1: 0x30D1, //KATAKANA LETTER PA + 0xABD2: 0x30D2, //KATAKANA LETTER HI + 0xABD3: 0x30D3, //KATAKANA LETTER BI + 0xABD4: 0x30D4, //KATAKANA LETTER PI + 0xABD5: 0x30D5, //KATAKANA LETTER HU + 0xABD6: 0x30D6, //KATAKANA LETTER BU + 0xABD7: 0x30D7, //KATAKANA LETTER PU + 0xABD8: 0x30D8, //KATAKANA LETTER HE + 0xABD9: 0x30D9, //KATAKANA LETTER BE + 0xABDA: 0x30DA, //KATAKANA LETTER PE + 0xABDB: 0x30DB, //KATAKANA LETTER HO + 0xABDC: 0x30DC, //KATAKANA LETTER BO + 0xABDD: 0x30DD, //KATAKANA LETTER PO + 0xABDE: 0x30DE, //KATAKANA LETTER MA + 0xABDF: 0x30DF, //KATAKANA LETTER MI + 0xABE0: 0x30E0, //KATAKANA LETTER MU + 0xABE1: 0x30E1, //KATAKANA LETTER ME + 0xABE2: 0x30E2, //KATAKANA LETTER MO + 0xABE3: 0x30E3, //KATAKANA LETTER SMALL YA + 0xABE4: 0x30E4, //KATAKANA LETTER YA + 0xABE5: 0x30E5, //KATAKANA LETTER SMALL YU + 0xABE6: 0x30E6, //KATAKANA LETTER YU + 0xABE7: 0x30E7, //KATAKANA LETTER SMALL YO + 0xABE8: 0x30E8, //KATAKANA LETTER YO + 0xABE9: 0x30E9, //KATAKANA LETTER RA + 0xABEA: 0x30EA, //KATAKANA LETTER RI + 0xABEB: 0x30EB, //KATAKANA LETTER RU + 0xABEC: 0x30EC, //KATAKANA LETTER RE + 0xABED: 0x30ED, //KATAKANA LETTER RO + 0xABEE: 0x30EE, //KATAKANA LETTER SMALL WA + 0xABEF: 0x30EF, //KATAKANA LETTER WA + 0xABF0: 0x30F0, //KATAKANA LETTER WI + 0xABF1: 0x30F1, //KATAKANA LETTER WE + 0xABF2: 0x30F2, //KATAKANA LETTER WO + 0xABF3: 0x30F3, //KATAKANA LETTER N + 0xABF4: 0x30F4, //KATAKANA LETTER VU + 0xABF5: 0x30F5, //KATAKANA LETTER SMALL KA + 0xABF6: 0x30F6, //KATAKANA LETTER SMALL KE + 0xAC41: 0xCCFE, //HANGUL SYLLABLE CHIEUCH YE PIEUPSIOS + 0xAC42: 0xCCFF, //HANGUL SYLLABLE CHIEUCH YE SIOS + 0xAC43: 0xCD00, //HANGUL SYLLABLE CHIEUCH YE SSANGSIOS + 0xAC44: 0xCD02, //HANGUL SYLLABLE CHIEUCH YE CIEUC + 0xAC45: 0xCD03, //HANGUL SYLLABLE CHIEUCH YE CHIEUCH + 0xAC46: 0xCD04, //HANGUL SYLLABLE CHIEUCH YE KHIEUKH + 0xAC47: 0xCD05, //HANGUL SYLLABLE CHIEUCH YE THIEUTH + 0xAC48: 0xCD06, //HANGUL SYLLABLE CHIEUCH YE PHIEUPH + 0xAC49: 0xCD07, //HANGUL SYLLABLE CHIEUCH YE HIEUH + 0xAC4A: 0xCD0A, //HANGUL SYLLABLE CHIEUCH O SSANGKIYEOK + 0xAC4B: 0xCD0B, //HANGUL SYLLABLE CHIEUCH O KIYEOKSIOS + 0xAC4C: 0xCD0D, //HANGUL SYLLABLE CHIEUCH O NIEUNCIEUC + 0xAC4D: 0xCD0E, //HANGUL SYLLABLE CHIEUCH O NIEUNHIEUH + 0xAC4E: 0xCD0F, //HANGUL SYLLABLE CHIEUCH O TIKEUT + 0xAC4F: 0xCD11, //HANGUL SYLLABLE CHIEUCH O RIEULKIYEOK + 0xAC50: 0xCD12, //HANGUL SYLLABLE CHIEUCH O RIEULMIEUM + 0xAC51: 0xCD13, //HANGUL SYLLABLE CHIEUCH O RIEULPIEUP + 0xAC52: 0xCD14, //HANGUL SYLLABLE CHIEUCH O RIEULSIOS + 0xAC53: 0xCD15, //HANGUL SYLLABLE CHIEUCH O RIEULTHIEUTH + 0xAC54: 0xCD16, //HANGUL SYLLABLE CHIEUCH O RIEULPHIEUPH + 0xAC55: 0xCD17, //HANGUL SYLLABLE CHIEUCH O RIEULHIEUH + 0xAC56: 0xCD1A, //HANGUL SYLLABLE CHIEUCH O PIEUPSIOS + 0xAC57: 0xCD1C, //HANGUL SYLLABLE CHIEUCH O SSANGSIOS + 0xAC58: 0xCD1E, //HANGUL SYLLABLE CHIEUCH O CIEUC + 0xAC59: 0xCD1F, //HANGUL SYLLABLE CHIEUCH O CHIEUCH + 0xAC5A: 0xCD20, //HANGUL SYLLABLE CHIEUCH O KHIEUKH + 0xAC61: 0xCD21, //HANGUL SYLLABLE CHIEUCH O THIEUTH + 0xAC62: 0xCD22, //HANGUL SYLLABLE CHIEUCH O PHIEUPH + 0xAC63: 0xCD23, //HANGUL SYLLABLE CHIEUCH O HIEUH + 0xAC64: 0xCD25, //HANGUL SYLLABLE CHIEUCH WA KIYEOK + 0xAC65: 0xCD26, //HANGUL SYLLABLE CHIEUCH WA SSANGKIYEOK + 0xAC66: 0xCD27, //HANGUL SYLLABLE CHIEUCH WA KIYEOKSIOS + 0xAC67: 0xCD29, //HANGUL SYLLABLE CHIEUCH WA NIEUNCIEUC + 0xAC68: 0xCD2A, //HANGUL SYLLABLE CHIEUCH WA NIEUNHIEUH + 0xAC69: 0xCD2B, //HANGUL SYLLABLE CHIEUCH WA TIKEUT + 0xAC6A: 0xCD2D, //HANGUL SYLLABLE CHIEUCH WA RIEULKIYEOK + 0xAC6B: 0xCD2E, //HANGUL SYLLABLE CHIEUCH WA RIEULMIEUM + 0xAC6C: 0xCD2F, //HANGUL SYLLABLE CHIEUCH WA RIEULPIEUP + 0xAC6D: 0xCD30, //HANGUL SYLLABLE CHIEUCH WA RIEULSIOS + 0xAC6E: 0xCD31, //HANGUL SYLLABLE CHIEUCH WA RIEULTHIEUTH + 0xAC6F: 0xCD32, //HANGUL SYLLABLE CHIEUCH WA RIEULPHIEUPH + 0xAC70: 0xCD33, //HANGUL SYLLABLE CHIEUCH WA RIEULHIEUH + 0xAC71: 0xCD34, //HANGUL SYLLABLE CHIEUCH WA MIEUM + 0xAC72: 0xCD35, //HANGUL SYLLABLE CHIEUCH WA PIEUP + 0xAC73: 0xCD36, //HANGUL SYLLABLE CHIEUCH WA PIEUPSIOS + 0xAC74: 0xCD37, //HANGUL SYLLABLE CHIEUCH WA SIOS + 0xAC75: 0xCD38, //HANGUL SYLLABLE CHIEUCH WA SSANGSIOS + 0xAC76: 0xCD3A, //HANGUL SYLLABLE CHIEUCH WA CIEUC + 0xAC77: 0xCD3B, //HANGUL SYLLABLE CHIEUCH WA CHIEUCH + 0xAC78: 0xCD3C, //HANGUL SYLLABLE CHIEUCH WA KHIEUKH + 0xAC79: 0xCD3D, //HANGUL SYLLABLE CHIEUCH WA THIEUTH + 0xAC7A: 0xCD3E, //HANGUL SYLLABLE CHIEUCH WA PHIEUPH + 0xAC81: 0xCD3F, //HANGUL SYLLABLE CHIEUCH WA HIEUH + 0xAC82: 0xCD40, //HANGUL SYLLABLE CHIEUCH WAE + 0xAC83: 0xCD41, //HANGUL SYLLABLE CHIEUCH WAE KIYEOK + 0xAC84: 0xCD42, //HANGUL SYLLABLE CHIEUCH WAE SSANGKIYEOK + 0xAC85: 0xCD43, //HANGUL SYLLABLE CHIEUCH WAE KIYEOKSIOS + 0xAC86: 0xCD44, //HANGUL SYLLABLE CHIEUCH WAE NIEUN + 0xAC87: 0xCD45, //HANGUL SYLLABLE CHIEUCH WAE NIEUNCIEUC + 0xAC88: 0xCD46, //HANGUL SYLLABLE CHIEUCH WAE NIEUNHIEUH + 0xAC89: 0xCD47, //HANGUL SYLLABLE CHIEUCH WAE TIKEUT + 0xAC8A: 0xCD48, //HANGUL SYLLABLE CHIEUCH WAE RIEUL + 0xAC8B: 0xCD49, //HANGUL SYLLABLE CHIEUCH WAE RIEULKIYEOK + 0xAC8C: 0xCD4A, //HANGUL SYLLABLE CHIEUCH WAE RIEULMIEUM + 0xAC8D: 0xCD4B, //HANGUL SYLLABLE CHIEUCH WAE RIEULPIEUP + 0xAC8E: 0xCD4C, //HANGUL SYLLABLE CHIEUCH WAE RIEULSIOS + 0xAC8F: 0xCD4D, //HANGUL SYLLABLE CHIEUCH WAE RIEULTHIEUTH + 0xAC90: 0xCD4E, //HANGUL SYLLABLE CHIEUCH WAE RIEULPHIEUPH + 0xAC91: 0xCD4F, //HANGUL SYLLABLE CHIEUCH WAE RIEULHIEUH + 0xAC92: 0xCD50, //HANGUL SYLLABLE CHIEUCH WAE MIEUM + 0xAC93: 0xCD51, //HANGUL SYLLABLE CHIEUCH WAE PIEUP + 0xAC94: 0xCD52, //HANGUL SYLLABLE CHIEUCH WAE PIEUPSIOS + 0xAC95: 0xCD53, //HANGUL SYLLABLE CHIEUCH WAE SIOS + 0xAC96: 0xCD54, //HANGUL SYLLABLE CHIEUCH WAE SSANGSIOS + 0xAC97: 0xCD55, //HANGUL SYLLABLE CHIEUCH WAE IEUNG + 0xAC98: 0xCD56, //HANGUL SYLLABLE CHIEUCH WAE CIEUC + 0xAC99: 0xCD57, //HANGUL SYLLABLE CHIEUCH WAE CHIEUCH + 0xAC9A: 0xCD58, //HANGUL SYLLABLE CHIEUCH WAE KHIEUKH + 0xAC9B: 0xCD59, //HANGUL SYLLABLE CHIEUCH WAE THIEUTH + 0xAC9C: 0xCD5A, //HANGUL SYLLABLE CHIEUCH WAE PHIEUPH + 0xAC9D: 0xCD5B, //HANGUL SYLLABLE CHIEUCH WAE HIEUH + 0xAC9E: 0xCD5D, //HANGUL SYLLABLE CHIEUCH OE KIYEOK + 0xAC9F: 0xCD5E, //HANGUL SYLLABLE CHIEUCH OE SSANGKIYEOK + 0xACA0: 0xCD5F, //HANGUL SYLLABLE CHIEUCH OE KIYEOKSIOS + 0xACA1: 0x0410, //CYRILLIC CAPITAL LETTER A + 0xACA2: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0xACA3: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0xACA4: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0xACA5: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0xACA6: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0xACA7: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0xACA8: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0xACA9: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0xACAA: 0x0418, //CYRILLIC CAPITAL LETTER I + 0xACAB: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0xACAC: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0xACAD: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0xACAE: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0xACAF: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0xACB0: 0x041E, //CYRILLIC CAPITAL LETTER O + 0xACB1: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0xACB2: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0xACB3: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0xACB4: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0xACB5: 0x0423, //CYRILLIC CAPITAL LETTER U + 0xACB6: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0xACB7: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0xACB8: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0xACB9: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0xACBA: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0xACBB: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0xACBC: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0xACBD: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0xACBE: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0xACBF: 0x042D, //CYRILLIC CAPITAL LETTER E + 0xACC0: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0xACC1: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0xACD1: 0x0430, //CYRILLIC SMALL LETTER A + 0xACD2: 0x0431, //CYRILLIC SMALL LETTER BE + 0xACD3: 0x0432, //CYRILLIC SMALL LETTER VE + 0xACD4: 0x0433, //CYRILLIC SMALL LETTER GHE + 0xACD5: 0x0434, //CYRILLIC SMALL LETTER DE + 0xACD6: 0x0435, //CYRILLIC SMALL LETTER IE + 0xACD7: 0x0451, //CYRILLIC SMALL LETTER IO + 0xACD8: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0xACD9: 0x0437, //CYRILLIC SMALL LETTER ZE + 0xACDA: 0x0438, //CYRILLIC SMALL LETTER I + 0xACDB: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0xACDC: 0x043A, //CYRILLIC SMALL LETTER KA + 0xACDD: 0x043B, //CYRILLIC SMALL LETTER EL + 0xACDE: 0x043C, //CYRILLIC SMALL LETTER EM + 0xACDF: 0x043D, //CYRILLIC SMALL LETTER EN + 0xACE0: 0x043E, //CYRILLIC SMALL LETTER O + 0xACE1: 0x043F, //CYRILLIC SMALL LETTER PE + 0xACE2: 0x0440, //CYRILLIC SMALL LETTER ER + 0xACE3: 0x0441, //CYRILLIC SMALL LETTER ES + 0xACE4: 0x0442, //CYRILLIC SMALL LETTER TE + 0xACE5: 0x0443, //CYRILLIC SMALL LETTER U + 0xACE6: 0x0444, //CYRILLIC SMALL LETTER EF + 0xACE7: 0x0445, //CYRILLIC SMALL LETTER HA + 0xACE8: 0x0446, //CYRILLIC SMALL LETTER TSE + 0xACE9: 0x0447, //CYRILLIC SMALL LETTER CHE + 0xACEA: 0x0448, //CYRILLIC SMALL LETTER SHA + 0xACEB: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0xACEC: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0xACED: 0x044B, //CYRILLIC SMALL LETTER YERU + 0xACEE: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0xACEF: 0x044D, //CYRILLIC SMALL LETTER E + 0xACF0: 0x044E, //CYRILLIC SMALL LETTER YU + 0xACF1: 0x044F, //CYRILLIC SMALL LETTER YA + 0xAD41: 0xCD61, //HANGUL SYLLABLE CHIEUCH OE NIEUNCIEUC + 0xAD42: 0xCD62, //HANGUL SYLLABLE CHIEUCH OE NIEUNHIEUH + 0xAD43: 0xCD63, //HANGUL SYLLABLE CHIEUCH OE TIKEUT + 0xAD44: 0xCD65, //HANGUL SYLLABLE CHIEUCH OE RIEULKIYEOK + 0xAD45: 0xCD66, //HANGUL SYLLABLE CHIEUCH OE RIEULMIEUM + 0xAD46: 0xCD67, //HANGUL SYLLABLE CHIEUCH OE RIEULPIEUP + 0xAD47: 0xCD68, //HANGUL SYLLABLE CHIEUCH OE RIEULSIOS + 0xAD48: 0xCD69, //HANGUL SYLLABLE CHIEUCH OE RIEULTHIEUTH + 0xAD49: 0xCD6A, //HANGUL SYLLABLE CHIEUCH OE RIEULPHIEUPH + 0xAD4A: 0xCD6B, //HANGUL SYLLABLE CHIEUCH OE RIEULHIEUH + 0xAD4B: 0xCD6E, //HANGUL SYLLABLE CHIEUCH OE PIEUPSIOS + 0xAD4C: 0xCD70, //HANGUL SYLLABLE CHIEUCH OE SSANGSIOS + 0xAD4D: 0xCD72, //HANGUL SYLLABLE CHIEUCH OE CIEUC + 0xAD4E: 0xCD73, //HANGUL SYLLABLE CHIEUCH OE CHIEUCH + 0xAD4F: 0xCD74, //HANGUL SYLLABLE CHIEUCH OE KHIEUKH + 0xAD50: 0xCD75, //HANGUL SYLLABLE CHIEUCH OE THIEUTH + 0xAD51: 0xCD76, //HANGUL SYLLABLE CHIEUCH OE PHIEUPH + 0xAD52: 0xCD77, //HANGUL SYLLABLE CHIEUCH OE HIEUH + 0xAD53: 0xCD79, //HANGUL SYLLABLE CHIEUCH YO KIYEOK + 0xAD54: 0xCD7A, //HANGUL SYLLABLE CHIEUCH YO SSANGKIYEOK + 0xAD55: 0xCD7B, //HANGUL SYLLABLE CHIEUCH YO KIYEOKSIOS + 0xAD56: 0xCD7C, //HANGUL SYLLABLE CHIEUCH YO NIEUN + 0xAD57: 0xCD7D, //HANGUL SYLLABLE CHIEUCH YO NIEUNCIEUC + 0xAD58: 0xCD7E, //HANGUL SYLLABLE CHIEUCH YO NIEUNHIEUH + 0xAD59: 0xCD7F, //HANGUL SYLLABLE CHIEUCH YO TIKEUT + 0xAD5A: 0xCD80, //HANGUL SYLLABLE CHIEUCH YO RIEUL + 0xAD61: 0xCD81, //HANGUL SYLLABLE CHIEUCH YO RIEULKIYEOK + 0xAD62: 0xCD82, //HANGUL SYLLABLE CHIEUCH YO RIEULMIEUM + 0xAD63: 0xCD83, //HANGUL SYLLABLE CHIEUCH YO RIEULPIEUP + 0xAD64: 0xCD84, //HANGUL SYLLABLE CHIEUCH YO RIEULSIOS + 0xAD65: 0xCD85, //HANGUL SYLLABLE CHIEUCH YO RIEULTHIEUTH + 0xAD66: 0xCD86, //HANGUL SYLLABLE CHIEUCH YO RIEULPHIEUPH + 0xAD67: 0xCD87, //HANGUL SYLLABLE CHIEUCH YO RIEULHIEUH + 0xAD68: 0xCD89, //HANGUL SYLLABLE CHIEUCH YO PIEUP + 0xAD69: 0xCD8A, //HANGUL SYLLABLE CHIEUCH YO PIEUPSIOS + 0xAD6A: 0xCD8B, //HANGUL SYLLABLE CHIEUCH YO SIOS + 0xAD6B: 0xCD8C, //HANGUL SYLLABLE CHIEUCH YO SSANGSIOS + 0xAD6C: 0xCD8D, //HANGUL SYLLABLE CHIEUCH YO IEUNG + 0xAD6D: 0xCD8E, //HANGUL SYLLABLE CHIEUCH YO CIEUC + 0xAD6E: 0xCD8F, //HANGUL SYLLABLE CHIEUCH YO CHIEUCH + 0xAD6F: 0xCD90, //HANGUL SYLLABLE CHIEUCH YO KHIEUKH + 0xAD70: 0xCD91, //HANGUL SYLLABLE CHIEUCH YO THIEUTH + 0xAD71: 0xCD92, //HANGUL SYLLABLE CHIEUCH YO PHIEUPH + 0xAD72: 0xCD93, //HANGUL SYLLABLE CHIEUCH YO HIEUH + 0xAD73: 0xCD96, //HANGUL SYLLABLE CHIEUCH U SSANGKIYEOK + 0xAD74: 0xCD97, //HANGUL SYLLABLE CHIEUCH U KIYEOKSIOS + 0xAD75: 0xCD99, //HANGUL SYLLABLE CHIEUCH U NIEUNCIEUC + 0xAD76: 0xCD9A, //HANGUL SYLLABLE CHIEUCH U NIEUNHIEUH + 0xAD77: 0xCD9B, //HANGUL SYLLABLE CHIEUCH U TIKEUT + 0xAD78: 0xCD9D, //HANGUL SYLLABLE CHIEUCH U RIEULKIYEOK + 0xAD79: 0xCD9E, //HANGUL SYLLABLE CHIEUCH U RIEULMIEUM + 0xAD7A: 0xCD9F, //HANGUL SYLLABLE CHIEUCH U RIEULPIEUP + 0xAD81: 0xCDA0, //HANGUL SYLLABLE CHIEUCH U RIEULSIOS + 0xAD82: 0xCDA1, //HANGUL SYLLABLE CHIEUCH U RIEULTHIEUTH + 0xAD83: 0xCDA2, //HANGUL SYLLABLE CHIEUCH U RIEULPHIEUPH + 0xAD84: 0xCDA3, //HANGUL SYLLABLE CHIEUCH U RIEULHIEUH + 0xAD85: 0xCDA6, //HANGUL SYLLABLE CHIEUCH U PIEUPSIOS + 0xAD86: 0xCDA8, //HANGUL SYLLABLE CHIEUCH U SSANGSIOS + 0xAD87: 0xCDAA, //HANGUL SYLLABLE CHIEUCH U CIEUC + 0xAD88: 0xCDAB, //HANGUL SYLLABLE CHIEUCH U CHIEUCH + 0xAD89: 0xCDAC, //HANGUL SYLLABLE CHIEUCH U KHIEUKH + 0xAD8A: 0xCDAD, //HANGUL SYLLABLE CHIEUCH U THIEUTH + 0xAD8B: 0xCDAE, //HANGUL SYLLABLE CHIEUCH U PHIEUPH + 0xAD8C: 0xCDAF, //HANGUL SYLLABLE CHIEUCH U HIEUH + 0xAD8D: 0xCDB1, //HANGUL SYLLABLE CHIEUCH WEO KIYEOK + 0xAD8E: 0xCDB2, //HANGUL SYLLABLE CHIEUCH WEO SSANGKIYEOK + 0xAD8F: 0xCDB3, //HANGUL SYLLABLE CHIEUCH WEO KIYEOKSIOS + 0xAD90: 0xCDB4, //HANGUL SYLLABLE CHIEUCH WEO NIEUN + 0xAD91: 0xCDB5, //HANGUL SYLLABLE CHIEUCH WEO NIEUNCIEUC + 0xAD92: 0xCDB6, //HANGUL SYLLABLE CHIEUCH WEO NIEUNHIEUH + 0xAD93: 0xCDB7, //HANGUL SYLLABLE CHIEUCH WEO TIKEUT + 0xAD94: 0xCDB8, //HANGUL SYLLABLE CHIEUCH WEO RIEUL + 0xAD95: 0xCDB9, //HANGUL SYLLABLE CHIEUCH WEO RIEULKIYEOK + 0xAD96: 0xCDBA, //HANGUL SYLLABLE CHIEUCH WEO RIEULMIEUM + 0xAD97: 0xCDBB, //HANGUL SYLLABLE CHIEUCH WEO RIEULPIEUP + 0xAD98: 0xCDBC, //HANGUL SYLLABLE CHIEUCH WEO RIEULSIOS + 0xAD99: 0xCDBD, //HANGUL SYLLABLE CHIEUCH WEO RIEULTHIEUTH + 0xAD9A: 0xCDBE, //HANGUL SYLLABLE CHIEUCH WEO RIEULPHIEUPH + 0xAD9B: 0xCDBF, //HANGUL SYLLABLE CHIEUCH WEO RIEULHIEUH + 0xAD9C: 0xCDC0, //HANGUL SYLLABLE CHIEUCH WEO MIEUM + 0xAD9D: 0xCDC1, //HANGUL SYLLABLE CHIEUCH WEO PIEUP + 0xAD9E: 0xCDC2, //HANGUL SYLLABLE CHIEUCH WEO PIEUPSIOS + 0xAD9F: 0xCDC3, //HANGUL SYLLABLE CHIEUCH WEO SIOS + 0xADA0: 0xCDC5, //HANGUL SYLLABLE CHIEUCH WEO IEUNG + 0xAE41: 0xCDC6, //HANGUL SYLLABLE CHIEUCH WEO CIEUC + 0xAE42: 0xCDC7, //HANGUL SYLLABLE CHIEUCH WEO CHIEUCH + 0xAE43: 0xCDC8, //HANGUL SYLLABLE CHIEUCH WEO KHIEUKH + 0xAE44: 0xCDC9, //HANGUL SYLLABLE CHIEUCH WEO THIEUTH + 0xAE45: 0xCDCA, //HANGUL SYLLABLE CHIEUCH WEO PHIEUPH + 0xAE46: 0xCDCB, //HANGUL SYLLABLE CHIEUCH WEO HIEUH + 0xAE47: 0xCDCD, //HANGUL SYLLABLE CHIEUCH WE KIYEOK + 0xAE48: 0xCDCE, //HANGUL SYLLABLE CHIEUCH WE SSANGKIYEOK + 0xAE49: 0xCDCF, //HANGUL SYLLABLE CHIEUCH WE KIYEOKSIOS + 0xAE4A: 0xCDD1, //HANGUL SYLLABLE CHIEUCH WE NIEUNCIEUC + 0xAE4B: 0xCDD2, //HANGUL SYLLABLE CHIEUCH WE NIEUNHIEUH + 0xAE4C: 0xCDD3, //HANGUL SYLLABLE CHIEUCH WE TIKEUT + 0xAE4D: 0xCDD4, //HANGUL SYLLABLE CHIEUCH WE RIEUL + 0xAE4E: 0xCDD5, //HANGUL SYLLABLE CHIEUCH WE RIEULKIYEOK + 0xAE4F: 0xCDD6, //HANGUL SYLLABLE CHIEUCH WE RIEULMIEUM + 0xAE50: 0xCDD7, //HANGUL SYLLABLE CHIEUCH WE RIEULPIEUP + 0xAE51: 0xCDD8, //HANGUL SYLLABLE CHIEUCH WE RIEULSIOS + 0xAE52: 0xCDD9, //HANGUL SYLLABLE CHIEUCH WE RIEULTHIEUTH + 0xAE53: 0xCDDA, //HANGUL SYLLABLE CHIEUCH WE RIEULPHIEUPH + 0xAE54: 0xCDDB, //HANGUL SYLLABLE CHIEUCH WE RIEULHIEUH + 0xAE55: 0xCDDC, //HANGUL SYLLABLE CHIEUCH WE MIEUM + 0xAE56: 0xCDDD, //HANGUL SYLLABLE CHIEUCH WE PIEUP + 0xAE57: 0xCDDE, //HANGUL SYLLABLE CHIEUCH WE PIEUPSIOS + 0xAE58: 0xCDDF, //HANGUL SYLLABLE CHIEUCH WE SIOS + 0xAE59: 0xCDE0, //HANGUL SYLLABLE CHIEUCH WE SSANGSIOS + 0xAE5A: 0xCDE1, //HANGUL SYLLABLE CHIEUCH WE IEUNG + 0xAE61: 0xCDE2, //HANGUL SYLLABLE CHIEUCH WE CIEUC + 0xAE62: 0xCDE3, //HANGUL SYLLABLE CHIEUCH WE CHIEUCH + 0xAE63: 0xCDE4, //HANGUL SYLLABLE CHIEUCH WE KHIEUKH + 0xAE64: 0xCDE5, //HANGUL SYLLABLE CHIEUCH WE THIEUTH + 0xAE65: 0xCDE6, //HANGUL SYLLABLE CHIEUCH WE PHIEUPH + 0xAE66: 0xCDE7, //HANGUL SYLLABLE CHIEUCH WE HIEUH + 0xAE67: 0xCDE9, //HANGUL SYLLABLE CHIEUCH WI KIYEOK + 0xAE68: 0xCDEA, //HANGUL SYLLABLE CHIEUCH WI SSANGKIYEOK + 0xAE69: 0xCDEB, //HANGUL SYLLABLE CHIEUCH WI KIYEOKSIOS + 0xAE6A: 0xCDED, //HANGUL SYLLABLE CHIEUCH WI NIEUNCIEUC + 0xAE6B: 0xCDEE, //HANGUL SYLLABLE CHIEUCH WI NIEUNHIEUH + 0xAE6C: 0xCDEF, //HANGUL SYLLABLE CHIEUCH WI TIKEUT + 0xAE6D: 0xCDF1, //HANGUL SYLLABLE CHIEUCH WI RIEULKIYEOK + 0xAE6E: 0xCDF2, //HANGUL SYLLABLE CHIEUCH WI RIEULMIEUM + 0xAE6F: 0xCDF3, //HANGUL SYLLABLE CHIEUCH WI RIEULPIEUP + 0xAE70: 0xCDF4, //HANGUL SYLLABLE CHIEUCH WI RIEULSIOS + 0xAE71: 0xCDF5, //HANGUL SYLLABLE CHIEUCH WI RIEULTHIEUTH + 0xAE72: 0xCDF6, //HANGUL SYLLABLE CHIEUCH WI RIEULPHIEUPH + 0xAE73: 0xCDF7, //HANGUL SYLLABLE CHIEUCH WI RIEULHIEUH + 0xAE74: 0xCDFA, //HANGUL SYLLABLE CHIEUCH WI PIEUPSIOS + 0xAE75: 0xCDFC, //HANGUL SYLLABLE CHIEUCH WI SSANGSIOS + 0xAE76: 0xCDFE, //HANGUL SYLLABLE CHIEUCH WI CIEUC + 0xAE77: 0xCDFF, //HANGUL SYLLABLE CHIEUCH WI CHIEUCH + 0xAE78: 0xCE00, //HANGUL SYLLABLE CHIEUCH WI KHIEUKH + 0xAE79: 0xCE01, //HANGUL SYLLABLE CHIEUCH WI THIEUTH + 0xAE7A: 0xCE02, //HANGUL SYLLABLE CHIEUCH WI PHIEUPH + 0xAE81: 0xCE03, //HANGUL SYLLABLE CHIEUCH WI HIEUH + 0xAE82: 0xCE05, //HANGUL SYLLABLE CHIEUCH YU KIYEOK + 0xAE83: 0xCE06, //HANGUL SYLLABLE CHIEUCH YU SSANGKIYEOK + 0xAE84: 0xCE07, //HANGUL SYLLABLE CHIEUCH YU KIYEOKSIOS + 0xAE85: 0xCE09, //HANGUL SYLLABLE CHIEUCH YU NIEUNCIEUC + 0xAE86: 0xCE0A, //HANGUL SYLLABLE CHIEUCH YU NIEUNHIEUH + 0xAE87: 0xCE0B, //HANGUL SYLLABLE CHIEUCH YU TIKEUT + 0xAE88: 0xCE0D, //HANGUL SYLLABLE CHIEUCH YU RIEULKIYEOK + 0xAE89: 0xCE0E, //HANGUL SYLLABLE CHIEUCH YU RIEULMIEUM + 0xAE8A: 0xCE0F, //HANGUL SYLLABLE CHIEUCH YU RIEULPIEUP + 0xAE8B: 0xCE10, //HANGUL SYLLABLE CHIEUCH YU RIEULSIOS + 0xAE8C: 0xCE11, //HANGUL SYLLABLE CHIEUCH YU RIEULTHIEUTH + 0xAE8D: 0xCE12, //HANGUL SYLLABLE CHIEUCH YU RIEULPHIEUPH + 0xAE8E: 0xCE13, //HANGUL SYLLABLE CHIEUCH YU RIEULHIEUH + 0xAE8F: 0xCE15, //HANGUL SYLLABLE CHIEUCH YU PIEUP + 0xAE90: 0xCE16, //HANGUL SYLLABLE CHIEUCH YU PIEUPSIOS + 0xAE91: 0xCE17, //HANGUL SYLLABLE CHIEUCH YU SIOS + 0xAE92: 0xCE18, //HANGUL SYLLABLE CHIEUCH YU SSANGSIOS + 0xAE93: 0xCE1A, //HANGUL SYLLABLE CHIEUCH YU CIEUC + 0xAE94: 0xCE1B, //HANGUL SYLLABLE CHIEUCH YU CHIEUCH + 0xAE95: 0xCE1C, //HANGUL SYLLABLE CHIEUCH YU KHIEUKH + 0xAE96: 0xCE1D, //HANGUL SYLLABLE CHIEUCH YU THIEUTH + 0xAE97: 0xCE1E, //HANGUL SYLLABLE CHIEUCH YU PHIEUPH + 0xAE98: 0xCE1F, //HANGUL SYLLABLE CHIEUCH YU HIEUH + 0xAE99: 0xCE22, //HANGUL SYLLABLE CHIEUCH EU SSANGKIYEOK + 0xAE9A: 0xCE23, //HANGUL SYLLABLE CHIEUCH EU KIYEOKSIOS + 0xAE9B: 0xCE25, //HANGUL SYLLABLE CHIEUCH EU NIEUNCIEUC + 0xAE9C: 0xCE26, //HANGUL SYLLABLE CHIEUCH EU NIEUNHIEUH + 0xAE9D: 0xCE27, //HANGUL SYLLABLE CHIEUCH EU TIKEUT + 0xAE9E: 0xCE29, //HANGUL SYLLABLE CHIEUCH EU RIEULKIYEOK + 0xAE9F: 0xCE2A, //HANGUL SYLLABLE CHIEUCH EU RIEULMIEUM + 0xAEA0: 0xCE2B, //HANGUL SYLLABLE CHIEUCH EU RIEULPIEUP + 0xAF41: 0xCE2C, //HANGUL SYLLABLE CHIEUCH EU RIEULSIOS + 0xAF42: 0xCE2D, //HANGUL SYLLABLE CHIEUCH EU RIEULTHIEUTH + 0xAF43: 0xCE2E, //HANGUL SYLLABLE CHIEUCH EU RIEULPHIEUPH + 0xAF44: 0xCE2F, //HANGUL SYLLABLE CHIEUCH EU RIEULHIEUH + 0xAF45: 0xCE32, //HANGUL SYLLABLE CHIEUCH EU PIEUPSIOS + 0xAF46: 0xCE34, //HANGUL SYLLABLE CHIEUCH EU SSANGSIOS + 0xAF47: 0xCE36, //HANGUL SYLLABLE CHIEUCH EU CIEUC + 0xAF48: 0xCE37, //HANGUL SYLLABLE CHIEUCH EU CHIEUCH + 0xAF49: 0xCE38, //HANGUL SYLLABLE CHIEUCH EU KHIEUKH + 0xAF4A: 0xCE39, //HANGUL SYLLABLE CHIEUCH EU THIEUTH + 0xAF4B: 0xCE3A, //HANGUL SYLLABLE CHIEUCH EU PHIEUPH + 0xAF4C: 0xCE3B, //HANGUL SYLLABLE CHIEUCH EU HIEUH + 0xAF4D: 0xCE3C, //HANGUL SYLLABLE CHIEUCH YI + 0xAF4E: 0xCE3D, //HANGUL SYLLABLE CHIEUCH YI KIYEOK + 0xAF4F: 0xCE3E, //HANGUL SYLLABLE CHIEUCH YI SSANGKIYEOK + 0xAF50: 0xCE3F, //HANGUL SYLLABLE CHIEUCH YI KIYEOKSIOS + 0xAF51: 0xCE40, //HANGUL SYLLABLE CHIEUCH YI NIEUN + 0xAF52: 0xCE41, //HANGUL SYLLABLE CHIEUCH YI NIEUNCIEUC + 0xAF53: 0xCE42, //HANGUL SYLLABLE CHIEUCH YI NIEUNHIEUH + 0xAF54: 0xCE43, //HANGUL SYLLABLE CHIEUCH YI TIKEUT + 0xAF55: 0xCE44, //HANGUL SYLLABLE CHIEUCH YI RIEUL + 0xAF56: 0xCE45, //HANGUL SYLLABLE CHIEUCH YI RIEULKIYEOK + 0xAF57: 0xCE46, //HANGUL SYLLABLE CHIEUCH YI RIEULMIEUM + 0xAF58: 0xCE47, //HANGUL SYLLABLE CHIEUCH YI RIEULPIEUP + 0xAF59: 0xCE48, //HANGUL SYLLABLE CHIEUCH YI RIEULSIOS + 0xAF5A: 0xCE49, //HANGUL SYLLABLE CHIEUCH YI RIEULTHIEUTH + 0xAF61: 0xCE4A, //HANGUL SYLLABLE CHIEUCH YI RIEULPHIEUPH + 0xAF62: 0xCE4B, //HANGUL SYLLABLE CHIEUCH YI RIEULHIEUH + 0xAF63: 0xCE4C, //HANGUL SYLLABLE CHIEUCH YI MIEUM + 0xAF64: 0xCE4D, //HANGUL SYLLABLE CHIEUCH YI PIEUP + 0xAF65: 0xCE4E, //HANGUL SYLLABLE CHIEUCH YI PIEUPSIOS + 0xAF66: 0xCE4F, //HANGUL SYLLABLE CHIEUCH YI SIOS + 0xAF67: 0xCE50, //HANGUL SYLLABLE CHIEUCH YI SSANGSIOS + 0xAF68: 0xCE51, //HANGUL SYLLABLE CHIEUCH YI IEUNG + 0xAF69: 0xCE52, //HANGUL SYLLABLE CHIEUCH YI CIEUC + 0xAF6A: 0xCE53, //HANGUL SYLLABLE CHIEUCH YI CHIEUCH + 0xAF6B: 0xCE54, //HANGUL SYLLABLE CHIEUCH YI KHIEUKH + 0xAF6C: 0xCE55, //HANGUL SYLLABLE CHIEUCH YI THIEUTH + 0xAF6D: 0xCE56, //HANGUL SYLLABLE CHIEUCH YI PHIEUPH + 0xAF6E: 0xCE57, //HANGUL SYLLABLE CHIEUCH YI HIEUH + 0xAF6F: 0xCE5A, //HANGUL SYLLABLE CHIEUCH I SSANGKIYEOK + 0xAF70: 0xCE5B, //HANGUL SYLLABLE CHIEUCH I KIYEOKSIOS + 0xAF71: 0xCE5D, //HANGUL SYLLABLE CHIEUCH I NIEUNCIEUC + 0xAF72: 0xCE5E, //HANGUL SYLLABLE CHIEUCH I NIEUNHIEUH + 0xAF73: 0xCE62, //HANGUL SYLLABLE CHIEUCH I RIEULMIEUM + 0xAF74: 0xCE63, //HANGUL SYLLABLE CHIEUCH I RIEULPIEUP + 0xAF75: 0xCE64, //HANGUL SYLLABLE CHIEUCH I RIEULSIOS + 0xAF76: 0xCE65, //HANGUL SYLLABLE CHIEUCH I RIEULTHIEUTH + 0xAF77: 0xCE66, //HANGUL SYLLABLE CHIEUCH I RIEULPHIEUPH + 0xAF78: 0xCE67, //HANGUL SYLLABLE CHIEUCH I RIEULHIEUH + 0xAF79: 0xCE6A, //HANGUL SYLLABLE CHIEUCH I PIEUPSIOS + 0xAF7A: 0xCE6C, //HANGUL SYLLABLE CHIEUCH I SSANGSIOS + 0xAF81: 0xCE6E, //HANGUL SYLLABLE CHIEUCH I CIEUC + 0xAF82: 0xCE6F, //HANGUL SYLLABLE CHIEUCH I CHIEUCH + 0xAF83: 0xCE70, //HANGUL SYLLABLE CHIEUCH I KHIEUKH + 0xAF84: 0xCE71, //HANGUL SYLLABLE CHIEUCH I THIEUTH + 0xAF85: 0xCE72, //HANGUL SYLLABLE CHIEUCH I PHIEUPH + 0xAF86: 0xCE73, //HANGUL SYLLABLE CHIEUCH I HIEUH + 0xAF87: 0xCE76, //HANGUL SYLLABLE KHIEUKH A SSANGKIYEOK + 0xAF88: 0xCE77, //HANGUL SYLLABLE KHIEUKH A KIYEOKSIOS + 0xAF89: 0xCE79, //HANGUL SYLLABLE KHIEUKH A NIEUNCIEUC + 0xAF8A: 0xCE7A, //HANGUL SYLLABLE KHIEUKH A NIEUNHIEUH + 0xAF8B: 0xCE7B, //HANGUL SYLLABLE KHIEUKH A TIKEUT + 0xAF8C: 0xCE7D, //HANGUL SYLLABLE KHIEUKH A RIEULKIYEOK + 0xAF8D: 0xCE7E, //HANGUL SYLLABLE KHIEUKH A RIEULMIEUM + 0xAF8E: 0xCE7F, //HANGUL SYLLABLE KHIEUKH A RIEULPIEUP + 0xAF8F: 0xCE80, //HANGUL SYLLABLE KHIEUKH A RIEULSIOS + 0xAF90: 0xCE81, //HANGUL SYLLABLE KHIEUKH A RIEULTHIEUTH + 0xAF91: 0xCE82, //HANGUL SYLLABLE KHIEUKH A RIEULPHIEUPH + 0xAF92: 0xCE83, //HANGUL SYLLABLE KHIEUKH A RIEULHIEUH + 0xAF93: 0xCE86, //HANGUL SYLLABLE KHIEUKH A PIEUPSIOS + 0xAF94: 0xCE88, //HANGUL SYLLABLE KHIEUKH A SSANGSIOS + 0xAF95: 0xCE8A, //HANGUL SYLLABLE KHIEUKH A CIEUC + 0xAF96: 0xCE8B, //HANGUL SYLLABLE KHIEUKH A CHIEUCH + 0xAF97: 0xCE8C, //HANGUL SYLLABLE KHIEUKH A KHIEUKH + 0xAF98: 0xCE8D, //HANGUL SYLLABLE KHIEUKH A THIEUTH + 0xAF99: 0xCE8E, //HANGUL SYLLABLE KHIEUKH A PHIEUPH + 0xAF9A: 0xCE8F, //HANGUL SYLLABLE KHIEUKH A HIEUH + 0xAF9B: 0xCE92, //HANGUL SYLLABLE KHIEUKH AE SSANGKIYEOK + 0xAF9C: 0xCE93, //HANGUL SYLLABLE KHIEUKH AE KIYEOKSIOS + 0xAF9D: 0xCE95, //HANGUL SYLLABLE KHIEUKH AE NIEUNCIEUC + 0xAF9E: 0xCE96, //HANGUL SYLLABLE KHIEUKH AE NIEUNHIEUH + 0xAF9F: 0xCE97, //HANGUL SYLLABLE KHIEUKH AE TIKEUT + 0xAFA0: 0xCE99, //HANGUL SYLLABLE KHIEUKH AE RIEULKIYEOK + 0xB041: 0xCE9A, //HANGUL SYLLABLE KHIEUKH AE RIEULMIEUM + 0xB042: 0xCE9B, //HANGUL SYLLABLE KHIEUKH AE RIEULPIEUP + 0xB043: 0xCE9C, //HANGUL SYLLABLE KHIEUKH AE RIEULSIOS + 0xB044: 0xCE9D, //HANGUL SYLLABLE KHIEUKH AE RIEULTHIEUTH + 0xB045: 0xCE9E, //HANGUL SYLLABLE KHIEUKH AE RIEULPHIEUPH + 0xB046: 0xCE9F, //HANGUL SYLLABLE KHIEUKH AE RIEULHIEUH + 0xB047: 0xCEA2, //HANGUL SYLLABLE KHIEUKH AE PIEUPSIOS + 0xB048: 0xCEA6, //HANGUL SYLLABLE KHIEUKH AE CIEUC + 0xB049: 0xCEA7, //HANGUL SYLLABLE KHIEUKH AE CHIEUCH + 0xB04A: 0xCEA8, //HANGUL SYLLABLE KHIEUKH AE KHIEUKH + 0xB04B: 0xCEA9, //HANGUL SYLLABLE KHIEUKH AE THIEUTH + 0xB04C: 0xCEAA, //HANGUL SYLLABLE KHIEUKH AE PHIEUPH + 0xB04D: 0xCEAB, //HANGUL SYLLABLE KHIEUKH AE HIEUH + 0xB04E: 0xCEAE, //HANGUL SYLLABLE KHIEUKH YA SSANGKIYEOK + 0xB04F: 0xCEAF, //HANGUL SYLLABLE KHIEUKH YA KIYEOKSIOS + 0xB050: 0xCEB0, //HANGUL SYLLABLE KHIEUKH YA NIEUN + 0xB051: 0xCEB1, //HANGUL SYLLABLE KHIEUKH YA NIEUNCIEUC + 0xB052: 0xCEB2, //HANGUL SYLLABLE KHIEUKH YA NIEUNHIEUH + 0xB053: 0xCEB3, //HANGUL SYLLABLE KHIEUKH YA TIKEUT + 0xB054: 0xCEB4, //HANGUL SYLLABLE KHIEUKH YA RIEUL + 0xB055: 0xCEB5, //HANGUL SYLLABLE KHIEUKH YA RIEULKIYEOK + 0xB056: 0xCEB6, //HANGUL SYLLABLE KHIEUKH YA RIEULMIEUM + 0xB057: 0xCEB7, //HANGUL SYLLABLE KHIEUKH YA RIEULPIEUP + 0xB058: 0xCEB8, //HANGUL SYLLABLE KHIEUKH YA RIEULSIOS + 0xB059: 0xCEB9, //HANGUL SYLLABLE KHIEUKH YA RIEULTHIEUTH + 0xB05A: 0xCEBA, //HANGUL SYLLABLE KHIEUKH YA RIEULPHIEUPH + 0xB061: 0xCEBB, //HANGUL SYLLABLE KHIEUKH YA RIEULHIEUH + 0xB062: 0xCEBC, //HANGUL SYLLABLE KHIEUKH YA MIEUM + 0xB063: 0xCEBD, //HANGUL SYLLABLE KHIEUKH YA PIEUP + 0xB064: 0xCEBE, //HANGUL SYLLABLE KHIEUKH YA PIEUPSIOS + 0xB065: 0xCEBF, //HANGUL SYLLABLE KHIEUKH YA SIOS + 0xB066: 0xCEC0, //HANGUL SYLLABLE KHIEUKH YA SSANGSIOS + 0xB067: 0xCEC2, //HANGUL SYLLABLE KHIEUKH YA CIEUC + 0xB068: 0xCEC3, //HANGUL SYLLABLE KHIEUKH YA CHIEUCH + 0xB069: 0xCEC4, //HANGUL SYLLABLE KHIEUKH YA KHIEUKH + 0xB06A: 0xCEC5, //HANGUL SYLLABLE KHIEUKH YA THIEUTH + 0xB06B: 0xCEC6, //HANGUL SYLLABLE KHIEUKH YA PHIEUPH + 0xB06C: 0xCEC7, //HANGUL SYLLABLE KHIEUKH YA HIEUH + 0xB06D: 0xCEC8, //HANGUL SYLLABLE KHIEUKH YAE + 0xB06E: 0xCEC9, //HANGUL SYLLABLE KHIEUKH YAE KIYEOK + 0xB06F: 0xCECA, //HANGUL SYLLABLE KHIEUKH YAE SSANGKIYEOK + 0xB070: 0xCECB, //HANGUL SYLLABLE KHIEUKH YAE KIYEOKSIOS + 0xB071: 0xCECC, //HANGUL SYLLABLE KHIEUKH YAE NIEUN + 0xB072: 0xCECD, //HANGUL SYLLABLE KHIEUKH YAE NIEUNCIEUC + 0xB073: 0xCECE, //HANGUL SYLLABLE KHIEUKH YAE NIEUNHIEUH + 0xB074: 0xCECF, //HANGUL SYLLABLE KHIEUKH YAE TIKEUT + 0xB075: 0xCED0, //HANGUL SYLLABLE KHIEUKH YAE RIEUL + 0xB076: 0xCED1, //HANGUL SYLLABLE KHIEUKH YAE RIEULKIYEOK + 0xB077: 0xCED2, //HANGUL SYLLABLE KHIEUKH YAE RIEULMIEUM + 0xB078: 0xCED3, //HANGUL SYLLABLE KHIEUKH YAE RIEULPIEUP + 0xB079: 0xCED4, //HANGUL SYLLABLE KHIEUKH YAE RIEULSIOS + 0xB07A: 0xCED5, //HANGUL SYLLABLE KHIEUKH YAE RIEULTHIEUTH + 0xB081: 0xCED6, //HANGUL SYLLABLE KHIEUKH YAE RIEULPHIEUPH + 0xB082: 0xCED7, //HANGUL SYLLABLE KHIEUKH YAE RIEULHIEUH + 0xB083: 0xCED8, //HANGUL SYLLABLE KHIEUKH YAE MIEUM + 0xB084: 0xCED9, //HANGUL SYLLABLE KHIEUKH YAE PIEUP + 0xB085: 0xCEDA, //HANGUL SYLLABLE KHIEUKH YAE PIEUPSIOS + 0xB086: 0xCEDB, //HANGUL SYLLABLE KHIEUKH YAE SIOS + 0xB087: 0xCEDC, //HANGUL SYLLABLE KHIEUKH YAE SSANGSIOS + 0xB088: 0xCEDD, //HANGUL SYLLABLE KHIEUKH YAE IEUNG + 0xB089: 0xCEDE, //HANGUL SYLLABLE KHIEUKH YAE CIEUC + 0xB08A: 0xCEDF, //HANGUL SYLLABLE KHIEUKH YAE CHIEUCH + 0xB08B: 0xCEE0, //HANGUL SYLLABLE KHIEUKH YAE KHIEUKH + 0xB08C: 0xCEE1, //HANGUL SYLLABLE KHIEUKH YAE THIEUTH + 0xB08D: 0xCEE2, //HANGUL SYLLABLE KHIEUKH YAE PHIEUPH + 0xB08E: 0xCEE3, //HANGUL SYLLABLE KHIEUKH YAE HIEUH + 0xB08F: 0xCEE6, //HANGUL SYLLABLE KHIEUKH EO SSANGKIYEOK + 0xB090: 0xCEE7, //HANGUL SYLLABLE KHIEUKH EO KIYEOKSIOS + 0xB091: 0xCEE9, //HANGUL SYLLABLE KHIEUKH EO NIEUNCIEUC + 0xB092: 0xCEEA, //HANGUL SYLLABLE KHIEUKH EO NIEUNHIEUH + 0xB093: 0xCEED, //HANGUL SYLLABLE KHIEUKH EO RIEULKIYEOK + 0xB094: 0xCEEE, //HANGUL SYLLABLE KHIEUKH EO RIEULMIEUM + 0xB095: 0xCEEF, //HANGUL SYLLABLE KHIEUKH EO RIEULPIEUP + 0xB096: 0xCEF0, //HANGUL SYLLABLE KHIEUKH EO RIEULSIOS + 0xB097: 0xCEF1, //HANGUL SYLLABLE KHIEUKH EO RIEULTHIEUTH + 0xB098: 0xCEF2, //HANGUL SYLLABLE KHIEUKH EO RIEULPHIEUPH + 0xB099: 0xCEF3, //HANGUL SYLLABLE KHIEUKH EO RIEULHIEUH + 0xB09A: 0xCEF6, //HANGUL SYLLABLE KHIEUKH EO PIEUPSIOS + 0xB09B: 0xCEFA, //HANGUL SYLLABLE KHIEUKH EO CIEUC + 0xB09C: 0xCEFB, //HANGUL SYLLABLE KHIEUKH EO CHIEUCH + 0xB09D: 0xCEFC, //HANGUL SYLLABLE KHIEUKH EO KHIEUKH + 0xB09E: 0xCEFD, //HANGUL SYLLABLE KHIEUKH EO THIEUTH + 0xB09F: 0xCEFE, //HANGUL SYLLABLE KHIEUKH EO PHIEUPH + 0xB0A0: 0xCEFF, //HANGUL SYLLABLE KHIEUKH EO HIEUH + 0xB0A1: 0xAC00, //HANGUL SYLLABLE KIYEOK A + 0xB0A2: 0xAC01, //HANGUL SYLLABLE KIYEOK A KIYEOK + 0xB0A3: 0xAC04, //HANGUL SYLLABLE KIYEOK A NIEUN + 0xB0A4: 0xAC07, //HANGUL SYLLABLE KIYEOK A TIKEUT + 0xB0A5: 0xAC08, //HANGUL SYLLABLE KIYEOK A RIEUL + 0xB0A6: 0xAC09, //HANGUL SYLLABLE KIYEOK A RIEULKIYEOK + 0xB0A7: 0xAC0A, //HANGUL SYLLABLE KIYEOK A RIEULMIEUM + 0xB0A8: 0xAC10, //HANGUL SYLLABLE KIYEOK A MIEUM + 0xB0A9: 0xAC11, //HANGUL SYLLABLE KIYEOK A PIEUP + 0xB0AA: 0xAC12, //HANGUL SYLLABLE KIYEOK A PIEUPSIOS + 0xB0AB: 0xAC13, //HANGUL SYLLABLE KIYEOK A SIOS + 0xB0AC: 0xAC14, //HANGUL SYLLABLE KIYEOK A SSANGSIOS + 0xB0AD: 0xAC15, //HANGUL SYLLABLE KIYEOK A IEUNG + 0xB0AE: 0xAC16, //HANGUL SYLLABLE KIYEOK A CIEUC + 0xB0AF: 0xAC17, //HANGUL SYLLABLE KIYEOK A CHIEUCH + 0xB0B0: 0xAC19, //HANGUL SYLLABLE KIYEOK A THIEUTH + 0xB0B1: 0xAC1A, //HANGUL SYLLABLE KIYEOK A PHIEUPH + 0xB0B2: 0xAC1B, //HANGUL SYLLABLE KIYEOK A HIEUH + 0xB0B3: 0xAC1C, //HANGUL SYLLABLE KIYEOK AE + 0xB0B4: 0xAC1D, //HANGUL SYLLABLE KIYEOK AE KIYEOK + 0xB0B5: 0xAC20, //HANGUL SYLLABLE KIYEOK AE NIEUN + 0xB0B6: 0xAC24, //HANGUL SYLLABLE KIYEOK AE RIEUL + 0xB0B7: 0xAC2C, //HANGUL SYLLABLE KIYEOK AE MIEUM + 0xB0B8: 0xAC2D, //HANGUL SYLLABLE KIYEOK AE PIEUP + 0xB0B9: 0xAC2F, //HANGUL SYLLABLE KIYEOK AE SIOS + 0xB0BA: 0xAC30, //HANGUL SYLLABLE KIYEOK AE SSANGSIOS + 0xB0BB: 0xAC31, //HANGUL SYLLABLE KIYEOK AE IEUNG + 0xB0BC: 0xAC38, //HANGUL SYLLABLE KIYEOK YA + 0xB0BD: 0xAC39, //HANGUL SYLLABLE KIYEOK YA KIYEOK + 0xB0BE: 0xAC3C, //HANGUL SYLLABLE KIYEOK YA NIEUN + 0xB0BF: 0xAC40, //HANGUL SYLLABLE KIYEOK YA RIEUL + 0xB0C0: 0xAC4B, //HANGUL SYLLABLE KIYEOK YA SIOS + 0xB0C1: 0xAC4D, //HANGUL SYLLABLE KIYEOK YA IEUNG + 0xB0C2: 0xAC54, //HANGUL SYLLABLE KIYEOK YAE + 0xB0C3: 0xAC58, //HANGUL SYLLABLE KIYEOK YAE NIEUN + 0xB0C4: 0xAC5C, //HANGUL SYLLABLE KIYEOK YAE RIEUL + 0xB0C5: 0xAC70, //HANGUL SYLLABLE KIYEOK EO + 0xB0C6: 0xAC71, //HANGUL SYLLABLE KIYEOK EO KIYEOK + 0xB0C7: 0xAC74, //HANGUL SYLLABLE KIYEOK EO NIEUN + 0xB0C8: 0xAC77, //HANGUL SYLLABLE KIYEOK EO TIKEUT + 0xB0C9: 0xAC78, //HANGUL SYLLABLE KIYEOK EO RIEUL + 0xB0CA: 0xAC7A, //HANGUL SYLLABLE KIYEOK EO RIEULMIEUM + 0xB0CB: 0xAC80, //HANGUL SYLLABLE KIYEOK EO MIEUM + 0xB0CC: 0xAC81, //HANGUL SYLLABLE KIYEOK EO PIEUP + 0xB0CD: 0xAC83, //HANGUL SYLLABLE KIYEOK EO SIOS + 0xB0CE: 0xAC84, //HANGUL SYLLABLE KIYEOK EO SSANGSIOS + 0xB0CF: 0xAC85, //HANGUL SYLLABLE KIYEOK EO IEUNG + 0xB0D0: 0xAC86, //HANGUL SYLLABLE KIYEOK EO CIEUC + 0xB0D1: 0xAC89, //HANGUL SYLLABLE KIYEOK EO THIEUTH + 0xB0D2: 0xAC8A, //HANGUL SYLLABLE KIYEOK EO PHIEUPH + 0xB0D3: 0xAC8B, //HANGUL SYLLABLE KIYEOK EO HIEUH + 0xB0D4: 0xAC8C, //HANGUL SYLLABLE KIYEOK E + 0xB0D5: 0xAC90, //HANGUL SYLLABLE KIYEOK E NIEUN + 0xB0D6: 0xAC94, //HANGUL SYLLABLE KIYEOK E RIEUL + 0xB0D7: 0xAC9C, //HANGUL SYLLABLE KIYEOK E MIEUM + 0xB0D8: 0xAC9D, //HANGUL SYLLABLE KIYEOK E PIEUP + 0xB0D9: 0xAC9F, //HANGUL SYLLABLE KIYEOK E SIOS + 0xB0DA: 0xACA0, //HANGUL SYLLABLE KIYEOK E SSANGSIOS + 0xB0DB: 0xACA1, //HANGUL SYLLABLE KIYEOK E IEUNG + 0xB0DC: 0xACA8, //HANGUL SYLLABLE KIYEOK YEO + 0xB0DD: 0xACA9, //HANGUL SYLLABLE KIYEOK YEO KIYEOK + 0xB0DE: 0xACAA, //HANGUL SYLLABLE KIYEOK YEO SSANGKIYEOK + 0xB0DF: 0xACAC, //HANGUL SYLLABLE KIYEOK YEO NIEUN + 0xB0E0: 0xACAF, //HANGUL SYLLABLE KIYEOK YEO TIKEUT + 0xB0E1: 0xACB0, //HANGUL SYLLABLE KIYEOK YEO RIEUL + 0xB0E2: 0xACB8, //HANGUL SYLLABLE KIYEOK YEO MIEUM + 0xB0E3: 0xACB9, //HANGUL SYLLABLE KIYEOK YEO PIEUP + 0xB0E4: 0xACBB, //HANGUL SYLLABLE KIYEOK YEO SIOS + 0xB0E5: 0xACBC, //HANGUL SYLLABLE KIYEOK YEO SSANGSIOS + 0xB0E6: 0xACBD, //HANGUL SYLLABLE KIYEOK YEO IEUNG + 0xB0E7: 0xACC1, //HANGUL SYLLABLE KIYEOK YEO THIEUTH + 0xB0E8: 0xACC4, //HANGUL SYLLABLE KIYEOK YE + 0xB0E9: 0xACC8, //HANGUL SYLLABLE KIYEOK YE NIEUN + 0xB0EA: 0xACCC, //HANGUL SYLLABLE KIYEOK YE RIEUL + 0xB0EB: 0xACD5, //HANGUL SYLLABLE KIYEOK YE PIEUP + 0xB0EC: 0xACD7, //HANGUL SYLLABLE KIYEOK YE SIOS + 0xB0ED: 0xACE0, //HANGUL SYLLABLE KIYEOK O + 0xB0EE: 0xACE1, //HANGUL SYLLABLE KIYEOK O KIYEOK + 0xB0EF: 0xACE4, //HANGUL SYLLABLE KIYEOK O NIEUN + 0xB0F0: 0xACE7, //HANGUL SYLLABLE KIYEOK O TIKEUT + 0xB0F1: 0xACE8, //HANGUL SYLLABLE KIYEOK O RIEUL + 0xB0F2: 0xACEA, //HANGUL SYLLABLE KIYEOK O RIEULMIEUM + 0xB0F3: 0xACEC, //HANGUL SYLLABLE KIYEOK O RIEULSIOS + 0xB0F4: 0xACEF, //HANGUL SYLLABLE KIYEOK O RIEULHIEUH + 0xB0F5: 0xACF0, //HANGUL SYLLABLE KIYEOK O MIEUM + 0xB0F6: 0xACF1, //HANGUL SYLLABLE KIYEOK O PIEUP + 0xB0F7: 0xACF3, //HANGUL SYLLABLE KIYEOK O SIOS + 0xB0F8: 0xACF5, //HANGUL SYLLABLE KIYEOK O IEUNG + 0xB0F9: 0xACF6, //HANGUL SYLLABLE KIYEOK O CIEUC + 0xB0FA: 0xACFC, //HANGUL SYLLABLE KIYEOK WA + 0xB0FB: 0xACFD, //HANGUL SYLLABLE KIYEOK WA KIYEOK + 0xB0FC: 0xAD00, //HANGUL SYLLABLE KIYEOK WA NIEUN + 0xB0FD: 0xAD04, //HANGUL SYLLABLE KIYEOK WA RIEUL + 0xB0FE: 0xAD06, //HANGUL SYLLABLE KIYEOK WA RIEULMIEUM + 0xB141: 0xCF02, //HANGUL SYLLABLE KHIEUKH E SSANGKIYEOK + 0xB142: 0xCF03, //HANGUL SYLLABLE KHIEUKH E KIYEOKSIOS + 0xB143: 0xCF05, //HANGUL SYLLABLE KHIEUKH E NIEUNCIEUC + 0xB144: 0xCF06, //HANGUL SYLLABLE KHIEUKH E NIEUNHIEUH + 0xB145: 0xCF07, //HANGUL SYLLABLE KHIEUKH E TIKEUT + 0xB146: 0xCF09, //HANGUL SYLLABLE KHIEUKH E RIEULKIYEOK + 0xB147: 0xCF0A, //HANGUL SYLLABLE KHIEUKH E RIEULMIEUM + 0xB148: 0xCF0B, //HANGUL SYLLABLE KHIEUKH E RIEULPIEUP + 0xB149: 0xCF0C, //HANGUL SYLLABLE KHIEUKH E RIEULSIOS + 0xB14A: 0xCF0D, //HANGUL SYLLABLE KHIEUKH E RIEULTHIEUTH + 0xB14B: 0xCF0E, //HANGUL SYLLABLE KHIEUKH E RIEULPHIEUPH + 0xB14C: 0xCF0F, //HANGUL SYLLABLE KHIEUKH E RIEULHIEUH + 0xB14D: 0xCF12, //HANGUL SYLLABLE KHIEUKH E PIEUPSIOS + 0xB14E: 0xCF14, //HANGUL SYLLABLE KHIEUKH E SSANGSIOS + 0xB14F: 0xCF16, //HANGUL SYLLABLE KHIEUKH E CIEUC + 0xB150: 0xCF17, //HANGUL SYLLABLE KHIEUKH E CHIEUCH + 0xB151: 0xCF18, //HANGUL SYLLABLE KHIEUKH E KHIEUKH + 0xB152: 0xCF19, //HANGUL SYLLABLE KHIEUKH E THIEUTH + 0xB153: 0xCF1A, //HANGUL SYLLABLE KHIEUKH E PHIEUPH + 0xB154: 0xCF1B, //HANGUL SYLLABLE KHIEUKH E HIEUH + 0xB155: 0xCF1D, //HANGUL SYLLABLE KHIEUKH YEO KIYEOK + 0xB156: 0xCF1E, //HANGUL SYLLABLE KHIEUKH YEO SSANGKIYEOK + 0xB157: 0xCF1F, //HANGUL SYLLABLE KHIEUKH YEO KIYEOKSIOS + 0xB158: 0xCF21, //HANGUL SYLLABLE KHIEUKH YEO NIEUNCIEUC + 0xB159: 0xCF22, //HANGUL SYLLABLE KHIEUKH YEO NIEUNHIEUH + 0xB15A: 0xCF23, //HANGUL SYLLABLE KHIEUKH YEO TIKEUT + 0xB161: 0xCF25, //HANGUL SYLLABLE KHIEUKH YEO RIEULKIYEOK + 0xB162: 0xCF26, //HANGUL SYLLABLE KHIEUKH YEO RIEULMIEUM + 0xB163: 0xCF27, //HANGUL SYLLABLE KHIEUKH YEO RIEULPIEUP + 0xB164: 0xCF28, //HANGUL SYLLABLE KHIEUKH YEO RIEULSIOS + 0xB165: 0xCF29, //HANGUL SYLLABLE KHIEUKH YEO RIEULTHIEUTH + 0xB166: 0xCF2A, //HANGUL SYLLABLE KHIEUKH YEO RIEULPHIEUPH + 0xB167: 0xCF2B, //HANGUL SYLLABLE KHIEUKH YEO RIEULHIEUH + 0xB168: 0xCF2E, //HANGUL SYLLABLE KHIEUKH YEO PIEUPSIOS + 0xB169: 0xCF32, //HANGUL SYLLABLE KHIEUKH YEO CIEUC + 0xB16A: 0xCF33, //HANGUL SYLLABLE KHIEUKH YEO CHIEUCH + 0xB16B: 0xCF34, //HANGUL SYLLABLE KHIEUKH YEO KHIEUKH + 0xB16C: 0xCF35, //HANGUL SYLLABLE KHIEUKH YEO THIEUTH + 0xB16D: 0xCF36, //HANGUL SYLLABLE KHIEUKH YEO PHIEUPH + 0xB16E: 0xCF37, //HANGUL SYLLABLE KHIEUKH YEO HIEUH + 0xB16F: 0xCF39, //HANGUL SYLLABLE KHIEUKH YE KIYEOK + 0xB170: 0xCF3A, //HANGUL SYLLABLE KHIEUKH YE SSANGKIYEOK + 0xB171: 0xCF3B, //HANGUL SYLLABLE KHIEUKH YE KIYEOKSIOS + 0xB172: 0xCF3C, //HANGUL SYLLABLE KHIEUKH YE NIEUN + 0xB173: 0xCF3D, //HANGUL SYLLABLE KHIEUKH YE NIEUNCIEUC + 0xB174: 0xCF3E, //HANGUL SYLLABLE KHIEUKH YE NIEUNHIEUH + 0xB175: 0xCF3F, //HANGUL SYLLABLE KHIEUKH YE TIKEUT + 0xB176: 0xCF40, //HANGUL SYLLABLE KHIEUKH YE RIEUL + 0xB177: 0xCF41, //HANGUL SYLLABLE KHIEUKH YE RIEULKIYEOK + 0xB178: 0xCF42, //HANGUL SYLLABLE KHIEUKH YE RIEULMIEUM + 0xB179: 0xCF43, //HANGUL SYLLABLE KHIEUKH YE RIEULPIEUP + 0xB17A: 0xCF44, //HANGUL SYLLABLE KHIEUKH YE RIEULSIOS + 0xB181: 0xCF45, //HANGUL SYLLABLE KHIEUKH YE RIEULTHIEUTH + 0xB182: 0xCF46, //HANGUL SYLLABLE KHIEUKH YE RIEULPHIEUPH + 0xB183: 0xCF47, //HANGUL SYLLABLE KHIEUKH YE RIEULHIEUH + 0xB184: 0xCF48, //HANGUL SYLLABLE KHIEUKH YE MIEUM + 0xB185: 0xCF49, //HANGUL SYLLABLE KHIEUKH YE PIEUP + 0xB186: 0xCF4A, //HANGUL SYLLABLE KHIEUKH YE PIEUPSIOS + 0xB187: 0xCF4B, //HANGUL SYLLABLE KHIEUKH YE SIOS + 0xB188: 0xCF4C, //HANGUL SYLLABLE KHIEUKH YE SSANGSIOS + 0xB189: 0xCF4D, //HANGUL SYLLABLE KHIEUKH YE IEUNG + 0xB18A: 0xCF4E, //HANGUL SYLLABLE KHIEUKH YE CIEUC + 0xB18B: 0xCF4F, //HANGUL SYLLABLE KHIEUKH YE CHIEUCH + 0xB18C: 0xCF50, //HANGUL SYLLABLE KHIEUKH YE KHIEUKH + 0xB18D: 0xCF51, //HANGUL SYLLABLE KHIEUKH YE THIEUTH + 0xB18E: 0xCF52, //HANGUL SYLLABLE KHIEUKH YE PHIEUPH + 0xB18F: 0xCF53, //HANGUL SYLLABLE KHIEUKH YE HIEUH + 0xB190: 0xCF56, //HANGUL SYLLABLE KHIEUKH O SSANGKIYEOK + 0xB191: 0xCF57, //HANGUL SYLLABLE KHIEUKH O KIYEOKSIOS + 0xB192: 0xCF59, //HANGUL SYLLABLE KHIEUKH O NIEUNCIEUC + 0xB193: 0xCF5A, //HANGUL SYLLABLE KHIEUKH O NIEUNHIEUH + 0xB194: 0xCF5B, //HANGUL SYLLABLE KHIEUKH O TIKEUT + 0xB195: 0xCF5D, //HANGUL SYLLABLE KHIEUKH O RIEULKIYEOK + 0xB196: 0xCF5E, //HANGUL SYLLABLE KHIEUKH O RIEULMIEUM + 0xB197: 0xCF5F, //HANGUL SYLLABLE KHIEUKH O RIEULPIEUP + 0xB198: 0xCF60, //HANGUL SYLLABLE KHIEUKH O RIEULSIOS + 0xB199: 0xCF61, //HANGUL SYLLABLE KHIEUKH O RIEULTHIEUTH + 0xB19A: 0xCF62, //HANGUL SYLLABLE KHIEUKH O RIEULPHIEUPH + 0xB19B: 0xCF63, //HANGUL SYLLABLE KHIEUKH O RIEULHIEUH + 0xB19C: 0xCF66, //HANGUL SYLLABLE KHIEUKH O PIEUPSIOS + 0xB19D: 0xCF68, //HANGUL SYLLABLE KHIEUKH O SSANGSIOS + 0xB19E: 0xCF6A, //HANGUL SYLLABLE KHIEUKH O CIEUC + 0xB19F: 0xCF6B, //HANGUL SYLLABLE KHIEUKH O CHIEUCH + 0xB1A0: 0xCF6C, //HANGUL SYLLABLE KHIEUKH O KHIEUKH + 0xB1A1: 0xAD0C, //HANGUL SYLLABLE KIYEOK WA MIEUM + 0xB1A2: 0xAD0D, //HANGUL SYLLABLE KIYEOK WA PIEUP + 0xB1A3: 0xAD0F, //HANGUL SYLLABLE KIYEOK WA SIOS + 0xB1A4: 0xAD11, //HANGUL SYLLABLE KIYEOK WA IEUNG + 0xB1A5: 0xAD18, //HANGUL SYLLABLE KIYEOK WAE + 0xB1A6: 0xAD1C, //HANGUL SYLLABLE KIYEOK WAE NIEUN + 0xB1A7: 0xAD20, //HANGUL SYLLABLE KIYEOK WAE RIEUL + 0xB1A8: 0xAD29, //HANGUL SYLLABLE KIYEOK WAE PIEUP + 0xB1A9: 0xAD2C, //HANGUL SYLLABLE KIYEOK WAE SSANGSIOS + 0xB1AA: 0xAD2D, //HANGUL SYLLABLE KIYEOK WAE IEUNG + 0xB1AB: 0xAD34, //HANGUL SYLLABLE KIYEOK OE + 0xB1AC: 0xAD35, //HANGUL SYLLABLE KIYEOK OE KIYEOK + 0xB1AD: 0xAD38, //HANGUL SYLLABLE KIYEOK OE NIEUN + 0xB1AE: 0xAD3C, //HANGUL SYLLABLE KIYEOK OE RIEUL + 0xB1AF: 0xAD44, //HANGUL SYLLABLE KIYEOK OE MIEUM + 0xB1B0: 0xAD45, //HANGUL SYLLABLE KIYEOK OE PIEUP + 0xB1B1: 0xAD47, //HANGUL SYLLABLE KIYEOK OE SIOS + 0xB1B2: 0xAD49, //HANGUL SYLLABLE KIYEOK OE IEUNG + 0xB1B3: 0xAD50, //HANGUL SYLLABLE KIYEOK YO + 0xB1B4: 0xAD54, //HANGUL SYLLABLE KIYEOK YO NIEUN + 0xB1B5: 0xAD58, //HANGUL SYLLABLE KIYEOK YO RIEUL + 0xB1B6: 0xAD61, //HANGUL SYLLABLE KIYEOK YO PIEUP + 0xB1B7: 0xAD63, //HANGUL SYLLABLE KIYEOK YO SIOS + 0xB1B8: 0xAD6C, //HANGUL SYLLABLE KIYEOK U + 0xB1B9: 0xAD6D, //HANGUL SYLLABLE KIYEOK U KIYEOK + 0xB1BA: 0xAD70, //HANGUL SYLLABLE KIYEOK U NIEUN + 0xB1BB: 0xAD73, //HANGUL SYLLABLE KIYEOK U TIKEUT + 0xB1BC: 0xAD74, //HANGUL SYLLABLE KIYEOK U RIEUL + 0xB1BD: 0xAD75, //HANGUL SYLLABLE KIYEOK U RIEULKIYEOK + 0xB1BE: 0xAD76, //HANGUL SYLLABLE KIYEOK U RIEULMIEUM + 0xB1BF: 0xAD7B, //HANGUL SYLLABLE KIYEOK U RIEULHIEUH + 0xB1C0: 0xAD7C, //HANGUL SYLLABLE KIYEOK U MIEUM + 0xB1C1: 0xAD7D, //HANGUL SYLLABLE KIYEOK U PIEUP + 0xB1C2: 0xAD7F, //HANGUL SYLLABLE KIYEOK U SIOS + 0xB1C3: 0xAD81, //HANGUL SYLLABLE KIYEOK U IEUNG + 0xB1C4: 0xAD82, //HANGUL SYLLABLE KIYEOK U CIEUC + 0xB1C5: 0xAD88, //HANGUL SYLLABLE KIYEOK WEO + 0xB1C6: 0xAD89, //HANGUL SYLLABLE KIYEOK WEO KIYEOK + 0xB1C7: 0xAD8C, //HANGUL SYLLABLE KIYEOK WEO NIEUN + 0xB1C8: 0xAD90, //HANGUL SYLLABLE KIYEOK WEO RIEUL + 0xB1C9: 0xAD9C, //HANGUL SYLLABLE KIYEOK WEO SSANGSIOS + 0xB1CA: 0xAD9D, //HANGUL SYLLABLE KIYEOK WEO IEUNG + 0xB1CB: 0xADA4, //HANGUL SYLLABLE KIYEOK WE + 0xB1CC: 0xADB7, //HANGUL SYLLABLE KIYEOK WE SIOS + 0xB1CD: 0xADC0, //HANGUL SYLLABLE KIYEOK WI + 0xB1CE: 0xADC1, //HANGUL SYLLABLE KIYEOK WI KIYEOK + 0xB1CF: 0xADC4, //HANGUL SYLLABLE KIYEOK WI NIEUN + 0xB1D0: 0xADC8, //HANGUL SYLLABLE KIYEOK WI RIEUL + 0xB1D1: 0xADD0, //HANGUL SYLLABLE KIYEOK WI MIEUM + 0xB1D2: 0xADD1, //HANGUL SYLLABLE KIYEOK WI PIEUP + 0xB1D3: 0xADD3, //HANGUL SYLLABLE KIYEOK WI SIOS + 0xB1D4: 0xADDC, //HANGUL SYLLABLE KIYEOK YU + 0xB1D5: 0xADE0, //HANGUL SYLLABLE KIYEOK YU NIEUN + 0xB1D6: 0xADE4, //HANGUL SYLLABLE KIYEOK YU RIEUL + 0xB1D7: 0xADF8, //HANGUL SYLLABLE KIYEOK EU + 0xB1D8: 0xADF9, //HANGUL SYLLABLE KIYEOK EU KIYEOK + 0xB1D9: 0xADFC, //HANGUL SYLLABLE KIYEOK EU NIEUN + 0xB1DA: 0xADFF, //HANGUL SYLLABLE KIYEOK EU TIKEUT + 0xB1DB: 0xAE00, //HANGUL SYLLABLE KIYEOK EU RIEUL + 0xB1DC: 0xAE01, //HANGUL SYLLABLE KIYEOK EU RIEULKIYEOK + 0xB1DD: 0xAE08, //HANGUL SYLLABLE KIYEOK EU MIEUM + 0xB1DE: 0xAE09, //HANGUL SYLLABLE KIYEOK EU PIEUP + 0xB1DF: 0xAE0B, //HANGUL SYLLABLE KIYEOK EU SIOS + 0xB1E0: 0xAE0D, //HANGUL SYLLABLE KIYEOK EU IEUNG + 0xB1E1: 0xAE14, //HANGUL SYLLABLE KIYEOK YI + 0xB1E2: 0xAE30, //HANGUL SYLLABLE KIYEOK I + 0xB1E3: 0xAE31, //HANGUL SYLLABLE KIYEOK I KIYEOK + 0xB1E4: 0xAE34, //HANGUL SYLLABLE KIYEOK I NIEUN + 0xB1E5: 0xAE37, //HANGUL SYLLABLE KIYEOK I TIKEUT + 0xB1E6: 0xAE38, //HANGUL SYLLABLE KIYEOK I RIEUL + 0xB1E7: 0xAE3A, //HANGUL SYLLABLE KIYEOK I RIEULMIEUM + 0xB1E8: 0xAE40, //HANGUL SYLLABLE KIYEOK I MIEUM + 0xB1E9: 0xAE41, //HANGUL SYLLABLE KIYEOK I PIEUP + 0xB1EA: 0xAE43, //HANGUL SYLLABLE KIYEOK I SIOS + 0xB1EB: 0xAE45, //HANGUL SYLLABLE KIYEOK I IEUNG + 0xB1EC: 0xAE46, //HANGUL SYLLABLE KIYEOK I CIEUC + 0xB1ED: 0xAE4A, //HANGUL SYLLABLE KIYEOK I PHIEUPH + 0xB1EE: 0xAE4C, //HANGUL SYLLABLE SSANGKIYEOK A + 0xB1EF: 0xAE4D, //HANGUL SYLLABLE SSANGKIYEOK A KIYEOK + 0xB1F0: 0xAE4E, //HANGUL SYLLABLE SSANGKIYEOK A SSANGKIYEOK + 0xB1F1: 0xAE50, //HANGUL SYLLABLE SSANGKIYEOK A NIEUN + 0xB1F2: 0xAE54, //HANGUL SYLLABLE SSANGKIYEOK A RIEUL + 0xB1F3: 0xAE56, //HANGUL SYLLABLE SSANGKIYEOK A RIEULMIEUM + 0xB1F4: 0xAE5C, //HANGUL SYLLABLE SSANGKIYEOK A MIEUM + 0xB1F5: 0xAE5D, //HANGUL SYLLABLE SSANGKIYEOK A PIEUP + 0xB1F6: 0xAE5F, //HANGUL SYLLABLE SSANGKIYEOK A SIOS + 0xB1F7: 0xAE60, //HANGUL SYLLABLE SSANGKIYEOK A SSANGSIOS + 0xB1F8: 0xAE61, //HANGUL SYLLABLE SSANGKIYEOK A IEUNG + 0xB1F9: 0xAE65, //HANGUL SYLLABLE SSANGKIYEOK A THIEUTH + 0xB1FA: 0xAE68, //HANGUL SYLLABLE SSANGKIYEOK AE + 0xB1FB: 0xAE69, //HANGUL SYLLABLE SSANGKIYEOK AE KIYEOK + 0xB1FC: 0xAE6C, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUN + 0xB1FD: 0xAE70, //HANGUL SYLLABLE SSANGKIYEOK AE RIEUL + 0xB1FE: 0xAE78, //HANGUL SYLLABLE SSANGKIYEOK AE MIEUM + 0xB241: 0xCF6D, //HANGUL SYLLABLE KHIEUKH O THIEUTH + 0xB242: 0xCF6E, //HANGUL SYLLABLE KHIEUKH O PHIEUPH + 0xB243: 0xCF6F, //HANGUL SYLLABLE KHIEUKH O HIEUH + 0xB244: 0xCF72, //HANGUL SYLLABLE KHIEUKH WA SSANGKIYEOK + 0xB245: 0xCF73, //HANGUL SYLLABLE KHIEUKH WA KIYEOKSIOS + 0xB246: 0xCF75, //HANGUL SYLLABLE KHIEUKH WA NIEUNCIEUC + 0xB247: 0xCF76, //HANGUL SYLLABLE KHIEUKH WA NIEUNHIEUH + 0xB248: 0xCF77, //HANGUL SYLLABLE KHIEUKH WA TIKEUT + 0xB249: 0xCF79, //HANGUL SYLLABLE KHIEUKH WA RIEULKIYEOK + 0xB24A: 0xCF7A, //HANGUL SYLLABLE KHIEUKH WA RIEULMIEUM + 0xB24B: 0xCF7B, //HANGUL SYLLABLE KHIEUKH WA RIEULPIEUP + 0xB24C: 0xCF7C, //HANGUL SYLLABLE KHIEUKH WA RIEULSIOS + 0xB24D: 0xCF7D, //HANGUL SYLLABLE KHIEUKH WA RIEULTHIEUTH + 0xB24E: 0xCF7E, //HANGUL SYLLABLE KHIEUKH WA RIEULPHIEUPH + 0xB24F: 0xCF7F, //HANGUL SYLLABLE KHIEUKH WA RIEULHIEUH + 0xB250: 0xCF81, //HANGUL SYLLABLE KHIEUKH WA PIEUP + 0xB251: 0xCF82, //HANGUL SYLLABLE KHIEUKH WA PIEUPSIOS + 0xB252: 0xCF83, //HANGUL SYLLABLE KHIEUKH WA SIOS + 0xB253: 0xCF84, //HANGUL SYLLABLE KHIEUKH WA SSANGSIOS + 0xB254: 0xCF86, //HANGUL SYLLABLE KHIEUKH WA CIEUC + 0xB255: 0xCF87, //HANGUL SYLLABLE KHIEUKH WA CHIEUCH + 0xB256: 0xCF88, //HANGUL SYLLABLE KHIEUKH WA KHIEUKH + 0xB257: 0xCF89, //HANGUL SYLLABLE KHIEUKH WA THIEUTH + 0xB258: 0xCF8A, //HANGUL SYLLABLE KHIEUKH WA PHIEUPH + 0xB259: 0xCF8B, //HANGUL SYLLABLE KHIEUKH WA HIEUH + 0xB25A: 0xCF8D, //HANGUL SYLLABLE KHIEUKH WAE KIYEOK + 0xB261: 0xCF8E, //HANGUL SYLLABLE KHIEUKH WAE SSANGKIYEOK + 0xB262: 0xCF8F, //HANGUL SYLLABLE KHIEUKH WAE KIYEOKSIOS + 0xB263: 0xCF90, //HANGUL SYLLABLE KHIEUKH WAE NIEUN + 0xB264: 0xCF91, //HANGUL SYLLABLE KHIEUKH WAE NIEUNCIEUC + 0xB265: 0xCF92, //HANGUL SYLLABLE KHIEUKH WAE NIEUNHIEUH + 0xB266: 0xCF93, //HANGUL SYLLABLE KHIEUKH WAE TIKEUT + 0xB267: 0xCF94, //HANGUL SYLLABLE KHIEUKH WAE RIEUL + 0xB268: 0xCF95, //HANGUL SYLLABLE KHIEUKH WAE RIEULKIYEOK + 0xB269: 0xCF96, //HANGUL SYLLABLE KHIEUKH WAE RIEULMIEUM + 0xB26A: 0xCF97, //HANGUL SYLLABLE KHIEUKH WAE RIEULPIEUP + 0xB26B: 0xCF98, //HANGUL SYLLABLE KHIEUKH WAE RIEULSIOS + 0xB26C: 0xCF99, //HANGUL SYLLABLE KHIEUKH WAE RIEULTHIEUTH + 0xB26D: 0xCF9A, //HANGUL SYLLABLE KHIEUKH WAE RIEULPHIEUPH + 0xB26E: 0xCF9B, //HANGUL SYLLABLE KHIEUKH WAE RIEULHIEUH + 0xB26F: 0xCF9C, //HANGUL SYLLABLE KHIEUKH WAE MIEUM + 0xB270: 0xCF9D, //HANGUL SYLLABLE KHIEUKH WAE PIEUP + 0xB271: 0xCF9E, //HANGUL SYLLABLE KHIEUKH WAE PIEUPSIOS + 0xB272: 0xCF9F, //HANGUL SYLLABLE KHIEUKH WAE SIOS + 0xB273: 0xCFA0, //HANGUL SYLLABLE KHIEUKH WAE SSANGSIOS + 0xB274: 0xCFA2, //HANGUL SYLLABLE KHIEUKH WAE CIEUC + 0xB275: 0xCFA3, //HANGUL SYLLABLE KHIEUKH WAE CHIEUCH + 0xB276: 0xCFA4, //HANGUL SYLLABLE KHIEUKH WAE KHIEUKH + 0xB277: 0xCFA5, //HANGUL SYLLABLE KHIEUKH WAE THIEUTH + 0xB278: 0xCFA6, //HANGUL SYLLABLE KHIEUKH WAE PHIEUPH + 0xB279: 0xCFA7, //HANGUL SYLLABLE KHIEUKH WAE HIEUH + 0xB27A: 0xCFA9, //HANGUL SYLLABLE KHIEUKH OE KIYEOK + 0xB281: 0xCFAA, //HANGUL SYLLABLE KHIEUKH OE SSANGKIYEOK + 0xB282: 0xCFAB, //HANGUL SYLLABLE KHIEUKH OE KIYEOKSIOS + 0xB283: 0xCFAC, //HANGUL SYLLABLE KHIEUKH OE NIEUN + 0xB284: 0xCFAD, //HANGUL SYLLABLE KHIEUKH OE NIEUNCIEUC + 0xB285: 0xCFAE, //HANGUL SYLLABLE KHIEUKH OE NIEUNHIEUH + 0xB286: 0xCFAF, //HANGUL SYLLABLE KHIEUKH OE TIKEUT + 0xB287: 0xCFB1, //HANGUL SYLLABLE KHIEUKH OE RIEULKIYEOK + 0xB288: 0xCFB2, //HANGUL SYLLABLE KHIEUKH OE RIEULMIEUM + 0xB289: 0xCFB3, //HANGUL SYLLABLE KHIEUKH OE RIEULPIEUP + 0xB28A: 0xCFB4, //HANGUL SYLLABLE KHIEUKH OE RIEULSIOS + 0xB28B: 0xCFB5, //HANGUL SYLLABLE KHIEUKH OE RIEULTHIEUTH + 0xB28C: 0xCFB6, //HANGUL SYLLABLE KHIEUKH OE RIEULPHIEUPH + 0xB28D: 0xCFB7, //HANGUL SYLLABLE KHIEUKH OE RIEULHIEUH + 0xB28E: 0xCFB8, //HANGUL SYLLABLE KHIEUKH OE MIEUM + 0xB28F: 0xCFB9, //HANGUL SYLLABLE KHIEUKH OE PIEUP + 0xB290: 0xCFBA, //HANGUL SYLLABLE KHIEUKH OE PIEUPSIOS + 0xB291: 0xCFBB, //HANGUL SYLLABLE KHIEUKH OE SIOS + 0xB292: 0xCFBC, //HANGUL SYLLABLE KHIEUKH OE SSANGSIOS + 0xB293: 0xCFBD, //HANGUL SYLLABLE KHIEUKH OE IEUNG + 0xB294: 0xCFBE, //HANGUL SYLLABLE KHIEUKH OE CIEUC + 0xB295: 0xCFBF, //HANGUL SYLLABLE KHIEUKH OE CHIEUCH + 0xB296: 0xCFC0, //HANGUL SYLLABLE KHIEUKH OE KHIEUKH + 0xB297: 0xCFC1, //HANGUL SYLLABLE KHIEUKH OE THIEUTH + 0xB298: 0xCFC2, //HANGUL SYLLABLE KHIEUKH OE PHIEUPH + 0xB299: 0xCFC3, //HANGUL SYLLABLE KHIEUKH OE HIEUH + 0xB29A: 0xCFC5, //HANGUL SYLLABLE KHIEUKH YO KIYEOK + 0xB29B: 0xCFC6, //HANGUL SYLLABLE KHIEUKH YO SSANGKIYEOK + 0xB29C: 0xCFC7, //HANGUL SYLLABLE KHIEUKH YO KIYEOKSIOS + 0xB29D: 0xCFC8, //HANGUL SYLLABLE KHIEUKH YO NIEUN + 0xB29E: 0xCFC9, //HANGUL SYLLABLE KHIEUKH YO NIEUNCIEUC + 0xB29F: 0xCFCA, //HANGUL SYLLABLE KHIEUKH YO NIEUNHIEUH + 0xB2A0: 0xCFCB, //HANGUL SYLLABLE KHIEUKH YO TIKEUT + 0xB2A1: 0xAE79, //HANGUL SYLLABLE SSANGKIYEOK AE PIEUP + 0xB2A2: 0xAE7B, //HANGUL SYLLABLE SSANGKIYEOK AE SIOS + 0xB2A3: 0xAE7C, //HANGUL SYLLABLE SSANGKIYEOK AE SSANGSIOS + 0xB2A4: 0xAE7D, //HANGUL SYLLABLE SSANGKIYEOK AE IEUNG + 0xB2A5: 0xAE84, //HANGUL SYLLABLE SSANGKIYEOK YA + 0xB2A6: 0xAE85, //HANGUL SYLLABLE SSANGKIYEOK YA KIYEOK + 0xB2A7: 0xAE8C, //HANGUL SYLLABLE SSANGKIYEOK YA RIEUL + 0xB2A8: 0xAEBC, //HANGUL SYLLABLE SSANGKIYEOK EO + 0xB2A9: 0xAEBD, //HANGUL SYLLABLE SSANGKIYEOK EO KIYEOK + 0xB2AA: 0xAEBE, //HANGUL SYLLABLE SSANGKIYEOK EO SSANGKIYEOK + 0xB2AB: 0xAEC0, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUN + 0xB2AC: 0xAEC4, //HANGUL SYLLABLE SSANGKIYEOK EO RIEUL + 0xB2AD: 0xAECC, //HANGUL SYLLABLE SSANGKIYEOK EO MIEUM + 0xB2AE: 0xAECD, //HANGUL SYLLABLE SSANGKIYEOK EO PIEUP + 0xB2AF: 0xAECF, //HANGUL SYLLABLE SSANGKIYEOK EO SIOS + 0xB2B0: 0xAED0, //HANGUL SYLLABLE SSANGKIYEOK EO SSANGSIOS + 0xB2B1: 0xAED1, //HANGUL SYLLABLE SSANGKIYEOK EO IEUNG + 0xB2B2: 0xAED8, //HANGUL SYLLABLE SSANGKIYEOK E + 0xB2B3: 0xAED9, //HANGUL SYLLABLE SSANGKIYEOK E KIYEOK + 0xB2B4: 0xAEDC, //HANGUL SYLLABLE SSANGKIYEOK E NIEUN + 0xB2B5: 0xAEE8, //HANGUL SYLLABLE SSANGKIYEOK E MIEUM + 0xB2B6: 0xAEEB, //HANGUL SYLLABLE SSANGKIYEOK E SIOS + 0xB2B7: 0xAEED, //HANGUL SYLLABLE SSANGKIYEOK E IEUNG + 0xB2B8: 0xAEF4, //HANGUL SYLLABLE SSANGKIYEOK YEO + 0xB2B9: 0xAEF8, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUN + 0xB2BA: 0xAEFC, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEUL + 0xB2BB: 0xAF07, //HANGUL SYLLABLE SSANGKIYEOK YEO SIOS + 0xB2BC: 0xAF08, //HANGUL SYLLABLE SSANGKIYEOK YEO SSANGSIOS + 0xB2BD: 0xAF0D, //HANGUL SYLLABLE SSANGKIYEOK YEO THIEUTH + 0xB2BE: 0xAF10, //HANGUL SYLLABLE SSANGKIYEOK YE + 0xB2BF: 0xAF2C, //HANGUL SYLLABLE SSANGKIYEOK O + 0xB2C0: 0xAF2D, //HANGUL SYLLABLE SSANGKIYEOK O KIYEOK + 0xB2C1: 0xAF30, //HANGUL SYLLABLE SSANGKIYEOK O NIEUN + 0xB2C2: 0xAF32, //HANGUL SYLLABLE SSANGKIYEOK O NIEUNHIEUH + 0xB2C3: 0xAF34, //HANGUL SYLLABLE SSANGKIYEOK O RIEUL + 0xB2C4: 0xAF3C, //HANGUL SYLLABLE SSANGKIYEOK O MIEUM + 0xB2C5: 0xAF3D, //HANGUL SYLLABLE SSANGKIYEOK O PIEUP + 0xB2C6: 0xAF3F, //HANGUL SYLLABLE SSANGKIYEOK O SIOS + 0xB2C7: 0xAF41, //HANGUL SYLLABLE SSANGKIYEOK O IEUNG + 0xB2C8: 0xAF42, //HANGUL SYLLABLE SSANGKIYEOK O CIEUC + 0xB2C9: 0xAF43, //HANGUL SYLLABLE SSANGKIYEOK O CHIEUCH + 0xB2CA: 0xAF48, //HANGUL SYLLABLE SSANGKIYEOK WA + 0xB2CB: 0xAF49, //HANGUL SYLLABLE SSANGKIYEOK WA KIYEOK + 0xB2CC: 0xAF50, //HANGUL SYLLABLE SSANGKIYEOK WA RIEUL + 0xB2CD: 0xAF5C, //HANGUL SYLLABLE SSANGKIYEOK WA SSANGSIOS + 0xB2CE: 0xAF5D, //HANGUL SYLLABLE SSANGKIYEOK WA IEUNG + 0xB2CF: 0xAF64, //HANGUL SYLLABLE SSANGKIYEOK WAE + 0xB2D0: 0xAF65, //HANGUL SYLLABLE SSANGKIYEOK WAE KIYEOK + 0xB2D1: 0xAF79, //HANGUL SYLLABLE SSANGKIYEOK WAE IEUNG + 0xB2D2: 0xAF80, //HANGUL SYLLABLE SSANGKIYEOK OE + 0xB2D3: 0xAF84, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUN + 0xB2D4: 0xAF88, //HANGUL SYLLABLE SSANGKIYEOK OE RIEUL + 0xB2D5: 0xAF90, //HANGUL SYLLABLE SSANGKIYEOK OE MIEUM + 0xB2D6: 0xAF91, //HANGUL SYLLABLE SSANGKIYEOK OE PIEUP + 0xB2D7: 0xAF95, //HANGUL SYLLABLE SSANGKIYEOK OE IEUNG + 0xB2D8: 0xAF9C, //HANGUL SYLLABLE SSANGKIYEOK YO + 0xB2D9: 0xAFB8, //HANGUL SYLLABLE SSANGKIYEOK U + 0xB2DA: 0xAFB9, //HANGUL SYLLABLE SSANGKIYEOK U KIYEOK + 0xB2DB: 0xAFBC, //HANGUL SYLLABLE SSANGKIYEOK U NIEUN + 0xB2DC: 0xAFC0, //HANGUL SYLLABLE SSANGKIYEOK U RIEUL + 0xB2DD: 0xAFC7, //HANGUL SYLLABLE SSANGKIYEOK U RIEULHIEUH + 0xB2DE: 0xAFC8, //HANGUL SYLLABLE SSANGKIYEOK U MIEUM + 0xB2DF: 0xAFC9, //HANGUL SYLLABLE SSANGKIYEOK U PIEUP + 0xB2E0: 0xAFCB, //HANGUL SYLLABLE SSANGKIYEOK U SIOS + 0xB2E1: 0xAFCD, //HANGUL SYLLABLE SSANGKIYEOK U IEUNG + 0xB2E2: 0xAFCE, //HANGUL SYLLABLE SSANGKIYEOK U CIEUC + 0xB2E3: 0xAFD4, //HANGUL SYLLABLE SSANGKIYEOK WEO + 0xB2E4: 0xAFDC, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEUL + 0xB2E5: 0xAFE8, //HANGUL SYLLABLE SSANGKIYEOK WEO SSANGSIOS + 0xB2E6: 0xAFE9, //HANGUL SYLLABLE SSANGKIYEOK WEO IEUNG + 0xB2E7: 0xAFF0, //HANGUL SYLLABLE SSANGKIYEOK WE + 0xB2E8: 0xAFF1, //HANGUL SYLLABLE SSANGKIYEOK WE KIYEOK + 0xB2E9: 0xAFF4, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUN + 0xB2EA: 0xAFF8, //HANGUL SYLLABLE SSANGKIYEOK WE RIEUL + 0xB2EB: 0xB000, //HANGUL SYLLABLE SSANGKIYEOK WE MIEUM + 0xB2EC: 0xB001, //HANGUL SYLLABLE SSANGKIYEOK WE PIEUP + 0xB2ED: 0xB004, //HANGUL SYLLABLE SSANGKIYEOK WE SSANGSIOS + 0xB2EE: 0xB00C, //HANGUL SYLLABLE SSANGKIYEOK WI + 0xB2EF: 0xB010, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUN + 0xB2F0: 0xB014, //HANGUL SYLLABLE SSANGKIYEOK WI RIEUL + 0xB2F1: 0xB01C, //HANGUL SYLLABLE SSANGKIYEOK WI MIEUM + 0xB2F2: 0xB01D, //HANGUL SYLLABLE SSANGKIYEOK WI PIEUP + 0xB2F3: 0xB028, //HANGUL SYLLABLE SSANGKIYEOK YU + 0xB2F4: 0xB044, //HANGUL SYLLABLE SSANGKIYEOK EU + 0xB2F5: 0xB045, //HANGUL SYLLABLE SSANGKIYEOK EU KIYEOK + 0xB2F6: 0xB048, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUN + 0xB2F7: 0xB04A, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUNHIEUH + 0xB2F8: 0xB04C, //HANGUL SYLLABLE SSANGKIYEOK EU RIEUL + 0xB2F9: 0xB04E, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULMIEUM + 0xB2FA: 0xB053, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULHIEUH + 0xB2FB: 0xB054, //HANGUL SYLLABLE SSANGKIYEOK EU MIEUM + 0xB2FC: 0xB055, //HANGUL SYLLABLE SSANGKIYEOK EU PIEUP + 0xB2FD: 0xB057, //HANGUL SYLLABLE SSANGKIYEOK EU SIOS + 0xB2FE: 0xB059, //HANGUL SYLLABLE SSANGKIYEOK EU IEUNG + 0xB341: 0xCFCC, //HANGUL SYLLABLE KHIEUKH YO RIEUL + 0xB342: 0xCFCD, //HANGUL SYLLABLE KHIEUKH YO RIEULKIYEOK + 0xB343: 0xCFCE, //HANGUL SYLLABLE KHIEUKH YO RIEULMIEUM + 0xB344: 0xCFCF, //HANGUL SYLLABLE KHIEUKH YO RIEULPIEUP + 0xB345: 0xCFD0, //HANGUL SYLLABLE KHIEUKH YO RIEULSIOS + 0xB346: 0xCFD1, //HANGUL SYLLABLE KHIEUKH YO RIEULTHIEUTH + 0xB347: 0xCFD2, //HANGUL SYLLABLE KHIEUKH YO RIEULPHIEUPH + 0xB348: 0xCFD3, //HANGUL SYLLABLE KHIEUKH YO RIEULHIEUH + 0xB349: 0xCFD4, //HANGUL SYLLABLE KHIEUKH YO MIEUM + 0xB34A: 0xCFD5, //HANGUL SYLLABLE KHIEUKH YO PIEUP + 0xB34B: 0xCFD6, //HANGUL SYLLABLE KHIEUKH YO PIEUPSIOS + 0xB34C: 0xCFD7, //HANGUL SYLLABLE KHIEUKH YO SIOS + 0xB34D: 0xCFD8, //HANGUL SYLLABLE KHIEUKH YO SSANGSIOS + 0xB34E: 0xCFD9, //HANGUL SYLLABLE KHIEUKH YO IEUNG + 0xB34F: 0xCFDA, //HANGUL SYLLABLE KHIEUKH YO CIEUC + 0xB350: 0xCFDB, //HANGUL SYLLABLE KHIEUKH YO CHIEUCH + 0xB351: 0xCFDC, //HANGUL SYLLABLE KHIEUKH YO KHIEUKH + 0xB352: 0xCFDD, //HANGUL SYLLABLE KHIEUKH YO THIEUTH + 0xB353: 0xCFDE, //HANGUL SYLLABLE KHIEUKH YO PHIEUPH + 0xB354: 0xCFDF, //HANGUL SYLLABLE KHIEUKH YO HIEUH + 0xB355: 0xCFE2, //HANGUL SYLLABLE KHIEUKH U SSANGKIYEOK + 0xB356: 0xCFE3, //HANGUL SYLLABLE KHIEUKH U KIYEOKSIOS + 0xB357: 0xCFE5, //HANGUL SYLLABLE KHIEUKH U NIEUNCIEUC + 0xB358: 0xCFE6, //HANGUL SYLLABLE KHIEUKH U NIEUNHIEUH + 0xB359: 0xCFE7, //HANGUL SYLLABLE KHIEUKH U TIKEUT + 0xB35A: 0xCFE9, //HANGUL SYLLABLE KHIEUKH U RIEULKIYEOK + 0xB361: 0xCFEA, //HANGUL SYLLABLE KHIEUKH U RIEULMIEUM + 0xB362: 0xCFEB, //HANGUL SYLLABLE KHIEUKH U RIEULPIEUP + 0xB363: 0xCFEC, //HANGUL SYLLABLE KHIEUKH U RIEULSIOS + 0xB364: 0xCFED, //HANGUL SYLLABLE KHIEUKH U RIEULTHIEUTH + 0xB365: 0xCFEE, //HANGUL SYLLABLE KHIEUKH U RIEULPHIEUPH + 0xB366: 0xCFEF, //HANGUL SYLLABLE KHIEUKH U RIEULHIEUH + 0xB367: 0xCFF2, //HANGUL SYLLABLE KHIEUKH U PIEUPSIOS + 0xB368: 0xCFF4, //HANGUL SYLLABLE KHIEUKH U SSANGSIOS + 0xB369: 0xCFF6, //HANGUL SYLLABLE KHIEUKH U CIEUC + 0xB36A: 0xCFF7, //HANGUL SYLLABLE KHIEUKH U CHIEUCH + 0xB36B: 0xCFF8, //HANGUL SYLLABLE KHIEUKH U KHIEUKH + 0xB36C: 0xCFF9, //HANGUL SYLLABLE KHIEUKH U THIEUTH + 0xB36D: 0xCFFA, //HANGUL SYLLABLE KHIEUKH U PHIEUPH + 0xB36E: 0xCFFB, //HANGUL SYLLABLE KHIEUKH U HIEUH + 0xB36F: 0xCFFD, //HANGUL SYLLABLE KHIEUKH WEO KIYEOK + 0xB370: 0xCFFE, //HANGUL SYLLABLE KHIEUKH WEO SSANGKIYEOK + 0xB371: 0xCFFF, //HANGUL SYLLABLE KHIEUKH WEO KIYEOKSIOS + 0xB372: 0xD001, //HANGUL SYLLABLE KHIEUKH WEO NIEUNCIEUC + 0xB373: 0xD002, //HANGUL SYLLABLE KHIEUKH WEO NIEUNHIEUH + 0xB374: 0xD003, //HANGUL SYLLABLE KHIEUKH WEO TIKEUT + 0xB375: 0xD005, //HANGUL SYLLABLE KHIEUKH WEO RIEULKIYEOK + 0xB376: 0xD006, //HANGUL SYLLABLE KHIEUKH WEO RIEULMIEUM + 0xB377: 0xD007, //HANGUL SYLLABLE KHIEUKH WEO RIEULPIEUP + 0xB378: 0xD008, //HANGUL SYLLABLE KHIEUKH WEO RIEULSIOS + 0xB379: 0xD009, //HANGUL SYLLABLE KHIEUKH WEO RIEULTHIEUTH + 0xB37A: 0xD00A, //HANGUL SYLLABLE KHIEUKH WEO RIEULPHIEUPH + 0xB381: 0xD00B, //HANGUL SYLLABLE KHIEUKH WEO RIEULHIEUH + 0xB382: 0xD00C, //HANGUL SYLLABLE KHIEUKH WEO MIEUM + 0xB383: 0xD00D, //HANGUL SYLLABLE KHIEUKH WEO PIEUP + 0xB384: 0xD00E, //HANGUL SYLLABLE KHIEUKH WEO PIEUPSIOS + 0xB385: 0xD00F, //HANGUL SYLLABLE KHIEUKH WEO SIOS + 0xB386: 0xD010, //HANGUL SYLLABLE KHIEUKH WEO SSANGSIOS + 0xB387: 0xD012, //HANGUL SYLLABLE KHIEUKH WEO CIEUC + 0xB388: 0xD013, //HANGUL SYLLABLE KHIEUKH WEO CHIEUCH + 0xB389: 0xD014, //HANGUL SYLLABLE KHIEUKH WEO KHIEUKH + 0xB38A: 0xD015, //HANGUL SYLLABLE KHIEUKH WEO THIEUTH + 0xB38B: 0xD016, //HANGUL SYLLABLE KHIEUKH WEO PHIEUPH + 0xB38C: 0xD017, //HANGUL SYLLABLE KHIEUKH WEO HIEUH + 0xB38D: 0xD019, //HANGUL SYLLABLE KHIEUKH WE KIYEOK + 0xB38E: 0xD01A, //HANGUL SYLLABLE KHIEUKH WE SSANGKIYEOK + 0xB38F: 0xD01B, //HANGUL SYLLABLE KHIEUKH WE KIYEOKSIOS + 0xB390: 0xD01C, //HANGUL SYLLABLE KHIEUKH WE NIEUN + 0xB391: 0xD01D, //HANGUL SYLLABLE KHIEUKH WE NIEUNCIEUC + 0xB392: 0xD01E, //HANGUL SYLLABLE KHIEUKH WE NIEUNHIEUH + 0xB393: 0xD01F, //HANGUL SYLLABLE KHIEUKH WE TIKEUT + 0xB394: 0xD020, //HANGUL SYLLABLE KHIEUKH WE RIEUL + 0xB395: 0xD021, //HANGUL SYLLABLE KHIEUKH WE RIEULKIYEOK + 0xB396: 0xD022, //HANGUL SYLLABLE KHIEUKH WE RIEULMIEUM + 0xB397: 0xD023, //HANGUL SYLLABLE KHIEUKH WE RIEULPIEUP + 0xB398: 0xD024, //HANGUL SYLLABLE KHIEUKH WE RIEULSIOS + 0xB399: 0xD025, //HANGUL SYLLABLE KHIEUKH WE RIEULTHIEUTH + 0xB39A: 0xD026, //HANGUL SYLLABLE KHIEUKH WE RIEULPHIEUPH + 0xB39B: 0xD027, //HANGUL SYLLABLE KHIEUKH WE RIEULHIEUH + 0xB39C: 0xD028, //HANGUL SYLLABLE KHIEUKH WE MIEUM + 0xB39D: 0xD029, //HANGUL SYLLABLE KHIEUKH WE PIEUP + 0xB39E: 0xD02A, //HANGUL SYLLABLE KHIEUKH WE PIEUPSIOS + 0xB39F: 0xD02B, //HANGUL SYLLABLE KHIEUKH WE SIOS + 0xB3A0: 0xD02C, //HANGUL SYLLABLE KHIEUKH WE SSANGSIOS + 0xB3A1: 0xB05D, //HANGUL SYLLABLE SSANGKIYEOK EU THIEUTH + 0xB3A2: 0xB07C, //HANGUL SYLLABLE SSANGKIYEOK I + 0xB3A3: 0xB07D, //HANGUL SYLLABLE SSANGKIYEOK I KIYEOK + 0xB3A4: 0xB080, //HANGUL SYLLABLE SSANGKIYEOK I NIEUN + 0xB3A5: 0xB084, //HANGUL SYLLABLE SSANGKIYEOK I RIEUL + 0xB3A6: 0xB08C, //HANGUL SYLLABLE SSANGKIYEOK I MIEUM + 0xB3A7: 0xB08D, //HANGUL SYLLABLE SSANGKIYEOK I PIEUP + 0xB3A8: 0xB08F, //HANGUL SYLLABLE SSANGKIYEOK I SIOS + 0xB3A9: 0xB091, //HANGUL SYLLABLE SSANGKIYEOK I IEUNG + 0xB3AA: 0xB098, //HANGUL SYLLABLE NIEUN A + 0xB3AB: 0xB099, //HANGUL SYLLABLE NIEUN A KIYEOK + 0xB3AC: 0xB09A, //HANGUL SYLLABLE NIEUN A SSANGKIYEOK + 0xB3AD: 0xB09C, //HANGUL SYLLABLE NIEUN A NIEUN + 0xB3AE: 0xB09F, //HANGUL SYLLABLE NIEUN A TIKEUT + 0xB3AF: 0xB0A0, //HANGUL SYLLABLE NIEUN A RIEUL + 0xB3B0: 0xB0A1, //HANGUL SYLLABLE NIEUN A RIEULKIYEOK + 0xB3B1: 0xB0A2, //HANGUL SYLLABLE NIEUN A RIEULMIEUM + 0xB3B2: 0xB0A8, //HANGUL SYLLABLE NIEUN A MIEUM + 0xB3B3: 0xB0A9, //HANGUL SYLLABLE NIEUN A PIEUP + 0xB3B4: 0xB0AB, //HANGUL SYLLABLE NIEUN A SIOS + 0xB3B5: 0xB0AC, //HANGUL SYLLABLE NIEUN A SSANGSIOS + 0xB3B6: 0xB0AD, //HANGUL SYLLABLE NIEUN A IEUNG + 0xB3B7: 0xB0AE, //HANGUL SYLLABLE NIEUN A CIEUC + 0xB3B8: 0xB0AF, //HANGUL SYLLABLE NIEUN A CHIEUCH + 0xB3B9: 0xB0B1, //HANGUL SYLLABLE NIEUN A THIEUTH + 0xB3BA: 0xB0B3, //HANGUL SYLLABLE NIEUN A HIEUH + 0xB3BB: 0xB0B4, //HANGUL SYLLABLE NIEUN AE + 0xB3BC: 0xB0B5, //HANGUL SYLLABLE NIEUN AE KIYEOK + 0xB3BD: 0xB0B8, //HANGUL SYLLABLE NIEUN AE NIEUN + 0xB3BE: 0xB0BC, //HANGUL SYLLABLE NIEUN AE RIEUL + 0xB3BF: 0xB0C4, //HANGUL SYLLABLE NIEUN AE MIEUM + 0xB3C0: 0xB0C5, //HANGUL SYLLABLE NIEUN AE PIEUP + 0xB3C1: 0xB0C7, //HANGUL SYLLABLE NIEUN AE SIOS + 0xB3C2: 0xB0C8, //HANGUL SYLLABLE NIEUN AE SSANGSIOS + 0xB3C3: 0xB0C9, //HANGUL SYLLABLE NIEUN AE IEUNG + 0xB3C4: 0xB0D0, //HANGUL SYLLABLE NIEUN YA + 0xB3C5: 0xB0D1, //HANGUL SYLLABLE NIEUN YA KIYEOK + 0xB3C6: 0xB0D4, //HANGUL SYLLABLE NIEUN YA NIEUN + 0xB3C7: 0xB0D8, //HANGUL SYLLABLE NIEUN YA RIEUL + 0xB3C8: 0xB0E0, //HANGUL SYLLABLE NIEUN YA MIEUM + 0xB3C9: 0xB0E5, //HANGUL SYLLABLE NIEUN YA IEUNG + 0xB3CA: 0xB108, //HANGUL SYLLABLE NIEUN EO + 0xB3CB: 0xB109, //HANGUL SYLLABLE NIEUN EO KIYEOK + 0xB3CC: 0xB10B, //HANGUL SYLLABLE NIEUN EO KIYEOKSIOS + 0xB3CD: 0xB10C, //HANGUL SYLLABLE NIEUN EO NIEUN + 0xB3CE: 0xB110, //HANGUL SYLLABLE NIEUN EO RIEUL + 0xB3CF: 0xB112, //HANGUL SYLLABLE NIEUN EO RIEULMIEUM + 0xB3D0: 0xB113, //HANGUL SYLLABLE NIEUN EO RIEULPIEUP + 0xB3D1: 0xB118, //HANGUL SYLLABLE NIEUN EO MIEUM + 0xB3D2: 0xB119, //HANGUL SYLLABLE NIEUN EO PIEUP + 0xB3D3: 0xB11B, //HANGUL SYLLABLE NIEUN EO SIOS + 0xB3D4: 0xB11C, //HANGUL SYLLABLE NIEUN EO SSANGSIOS + 0xB3D5: 0xB11D, //HANGUL SYLLABLE NIEUN EO IEUNG + 0xB3D6: 0xB123, //HANGUL SYLLABLE NIEUN EO HIEUH + 0xB3D7: 0xB124, //HANGUL SYLLABLE NIEUN E + 0xB3D8: 0xB125, //HANGUL SYLLABLE NIEUN E KIYEOK + 0xB3D9: 0xB128, //HANGUL SYLLABLE NIEUN E NIEUN + 0xB3DA: 0xB12C, //HANGUL SYLLABLE NIEUN E RIEUL + 0xB3DB: 0xB134, //HANGUL SYLLABLE NIEUN E MIEUM + 0xB3DC: 0xB135, //HANGUL SYLLABLE NIEUN E PIEUP + 0xB3DD: 0xB137, //HANGUL SYLLABLE NIEUN E SIOS + 0xB3DE: 0xB138, //HANGUL SYLLABLE NIEUN E SSANGSIOS + 0xB3DF: 0xB139, //HANGUL SYLLABLE NIEUN E IEUNG + 0xB3E0: 0xB140, //HANGUL SYLLABLE NIEUN YEO + 0xB3E1: 0xB141, //HANGUL SYLLABLE NIEUN YEO KIYEOK + 0xB3E2: 0xB144, //HANGUL SYLLABLE NIEUN YEO NIEUN + 0xB3E3: 0xB148, //HANGUL SYLLABLE NIEUN YEO RIEUL + 0xB3E4: 0xB150, //HANGUL SYLLABLE NIEUN YEO MIEUM + 0xB3E5: 0xB151, //HANGUL SYLLABLE NIEUN YEO PIEUP + 0xB3E6: 0xB154, //HANGUL SYLLABLE NIEUN YEO SSANGSIOS + 0xB3E7: 0xB155, //HANGUL SYLLABLE NIEUN YEO IEUNG + 0xB3E8: 0xB158, //HANGUL SYLLABLE NIEUN YEO KHIEUKH + 0xB3E9: 0xB15C, //HANGUL SYLLABLE NIEUN YE + 0xB3EA: 0xB160, //HANGUL SYLLABLE NIEUN YE NIEUN + 0xB3EB: 0xB178, //HANGUL SYLLABLE NIEUN O + 0xB3EC: 0xB179, //HANGUL SYLLABLE NIEUN O KIYEOK + 0xB3ED: 0xB17C, //HANGUL SYLLABLE NIEUN O NIEUN + 0xB3EE: 0xB180, //HANGUL SYLLABLE NIEUN O RIEUL + 0xB3EF: 0xB182, //HANGUL SYLLABLE NIEUN O RIEULMIEUM + 0xB3F0: 0xB188, //HANGUL SYLLABLE NIEUN O MIEUM + 0xB3F1: 0xB189, //HANGUL SYLLABLE NIEUN O PIEUP + 0xB3F2: 0xB18B, //HANGUL SYLLABLE NIEUN O SIOS + 0xB3F3: 0xB18D, //HANGUL SYLLABLE NIEUN O IEUNG + 0xB3F4: 0xB192, //HANGUL SYLLABLE NIEUN O PHIEUPH + 0xB3F5: 0xB193, //HANGUL SYLLABLE NIEUN O HIEUH + 0xB3F6: 0xB194, //HANGUL SYLLABLE NIEUN WA + 0xB3F7: 0xB198, //HANGUL SYLLABLE NIEUN WA NIEUN + 0xB3F8: 0xB19C, //HANGUL SYLLABLE NIEUN WA RIEUL + 0xB3F9: 0xB1A8, //HANGUL SYLLABLE NIEUN WA SSANGSIOS + 0xB3FA: 0xB1CC, //HANGUL SYLLABLE NIEUN OE + 0xB3FB: 0xB1D0, //HANGUL SYLLABLE NIEUN OE NIEUN + 0xB3FC: 0xB1D4, //HANGUL SYLLABLE NIEUN OE RIEUL + 0xB3FD: 0xB1DC, //HANGUL SYLLABLE NIEUN OE MIEUM + 0xB3FE: 0xB1DD, //HANGUL SYLLABLE NIEUN OE PIEUP + 0xB441: 0xD02E, //HANGUL SYLLABLE KHIEUKH WE CIEUC + 0xB442: 0xD02F, //HANGUL SYLLABLE KHIEUKH WE CHIEUCH + 0xB443: 0xD030, //HANGUL SYLLABLE KHIEUKH WE KHIEUKH + 0xB444: 0xD031, //HANGUL SYLLABLE KHIEUKH WE THIEUTH + 0xB445: 0xD032, //HANGUL SYLLABLE KHIEUKH WE PHIEUPH + 0xB446: 0xD033, //HANGUL SYLLABLE KHIEUKH WE HIEUH + 0xB447: 0xD036, //HANGUL SYLLABLE KHIEUKH WI SSANGKIYEOK + 0xB448: 0xD037, //HANGUL SYLLABLE KHIEUKH WI KIYEOKSIOS + 0xB449: 0xD039, //HANGUL SYLLABLE KHIEUKH WI NIEUNCIEUC + 0xB44A: 0xD03A, //HANGUL SYLLABLE KHIEUKH WI NIEUNHIEUH + 0xB44B: 0xD03B, //HANGUL SYLLABLE KHIEUKH WI TIKEUT + 0xB44C: 0xD03D, //HANGUL SYLLABLE KHIEUKH WI RIEULKIYEOK + 0xB44D: 0xD03E, //HANGUL SYLLABLE KHIEUKH WI RIEULMIEUM + 0xB44E: 0xD03F, //HANGUL SYLLABLE KHIEUKH WI RIEULPIEUP + 0xB44F: 0xD040, //HANGUL SYLLABLE KHIEUKH WI RIEULSIOS + 0xB450: 0xD041, //HANGUL SYLLABLE KHIEUKH WI RIEULTHIEUTH + 0xB451: 0xD042, //HANGUL SYLLABLE KHIEUKH WI RIEULPHIEUPH + 0xB452: 0xD043, //HANGUL SYLLABLE KHIEUKH WI RIEULHIEUH + 0xB453: 0xD046, //HANGUL SYLLABLE KHIEUKH WI PIEUPSIOS + 0xB454: 0xD048, //HANGUL SYLLABLE KHIEUKH WI SSANGSIOS + 0xB455: 0xD04A, //HANGUL SYLLABLE KHIEUKH WI CIEUC + 0xB456: 0xD04B, //HANGUL SYLLABLE KHIEUKH WI CHIEUCH + 0xB457: 0xD04C, //HANGUL SYLLABLE KHIEUKH WI KHIEUKH + 0xB458: 0xD04D, //HANGUL SYLLABLE KHIEUKH WI THIEUTH + 0xB459: 0xD04E, //HANGUL SYLLABLE KHIEUKH WI PHIEUPH + 0xB45A: 0xD04F, //HANGUL SYLLABLE KHIEUKH WI HIEUH + 0xB461: 0xD051, //HANGUL SYLLABLE KHIEUKH YU KIYEOK + 0xB462: 0xD052, //HANGUL SYLLABLE KHIEUKH YU SSANGKIYEOK + 0xB463: 0xD053, //HANGUL SYLLABLE KHIEUKH YU KIYEOKSIOS + 0xB464: 0xD055, //HANGUL SYLLABLE KHIEUKH YU NIEUNCIEUC + 0xB465: 0xD056, //HANGUL SYLLABLE KHIEUKH YU NIEUNHIEUH + 0xB466: 0xD057, //HANGUL SYLLABLE KHIEUKH YU TIKEUT + 0xB467: 0xD059, //HANGUL SYLLABLE KHIEUKH YU RIEULKIYEOK + 0xB468: 0xD05A, //HANGUL SYLLABLE KHIEUKH YU RIEULMIEUM + 0xB469: 0xD05B, //HANGUL SYLLABLE KHIEUKH YU RIEULPIEUP + 0xB46A: 0xD05C, //HANGUL SYLLABLE KHIEUKH YU RIEULSIOS + 0xB46B: 0xD05D, //HANGUL SYLLABLE KHIEUKH YU RIEULTHIEUTH + 0xB46C: 0xD05E, //HANGUL SYLLABLE KHIEUKH YU RIEULPHIEUPH + 0xB46D: 0xD05F, //HANGUL SYLLABLE KHIEUKH YU RIEULHIEUH + 0xB46E: 0xD061, //HANGUL SYLLABLE KHIEUKH YU PIEUP + 0xB46F: 0xD062, //HANGUL SYLLABLE KHIEUKH YU PIEUPSIOS + 0xB470: 0xD063, //HANGUL SYLLABLE KHIEUKH YU SIOS + 0xB471: 0xD064, //HANGUL SYLLABLE KHIEUKH YU SSANGSIOS + 0xB472: 0xD065, //HANGUL SYLLABLE KHIEUKH YU IEUNG + 0xB473: 0xD066, //HANGUL SYLLABLE KHIEUKH YU CIEUC + 0xB474: 0xD067, //HANGUL SYLLABLE KHIEUKH YU CHIEUCH + 0xB475: 0xD068, //HANGUL SYLLABLE KHIEUKH YU KHIEUKH + 0xB476: 0xD069, //HANGUL SYLLABLE KHIEUKH YU THIEUTH + 0xB477: 0xD06A, //HANGUL SYLLABLE KHIEUKH YU PHIEUPH + 0xB478: 0xD06B, //HANGUL SYLLABLE KHIEUKH YU HIEUH + 0xB479: 0xD06E, //HANGUL SYLLABLE KHIEUKH EU SSANGKIYEOK + 0xB47A: 0xD06F, //HANGUL SYLLABLE KHIEUKH EU KIYEOKSIOS + 0xB481: 0xD071, //HANGUL SYLLABLE KHIEUKH EU NIEUNCIEUC + 0xB482: 0xD072, //HANGUL SYLLABLE KHIEUKH EU NIEUNHIEUH + 0xB483: 0xD073, //HANGUL SYLLABLE KHIEUKH EU TIKEUT + 0xB484: 0xD075, //HANGUL SYLLABLE KHIEUKH EU RIEULKIYEOK + 0xB485: 0xD076, //HANGUL SYLLABLE KHIEUKH EU RIEULMIEUM + 0xB486: 0xD077, //HANGUL SYLLABLE KHIEUKH EU RIEULPIEUP + 0xB487: 0xD078, //HANGUL SYLLABLE KHIEUKH EU RIEULSIOS + 0xB488: 0xD079, //HANGUL SYLLABLE KHIEUKH EU RIEULTHIEUTH + 0xB489: 0xD07A, //HANGUL SYLLABLE KHIEUKH EU RIEULPHIEUPH + 0xB48A: 0xD07B, //HANGUL SYLLABLE KHIEUKH EU RIEULHIEUH + 0xB48B: 0xD07E, //HANGUL SYLLABLE KHIEUKH EU PIEUPSIOS + 0xB48C: 0xD07F, //HANGUL SYLLABLE KHIEUKH EU SIOS + 0xB48D: 0xD080, //HANGUL SYLLABLE KHIEUKH EU SSANGSIOS + 0xB48E: 0xD082, //HANGUL SYLLABLE KHIEUKH EU CIEUC + 0xB48F: 0xD083, //HANGUL SYLLABLE KHIEUKH EU CHIEUCH + 0xB490: 0xD084, //HANGUL SYLLABLE KHIEUKH EU KHIEUKH + 0xB491: 0xD085, //HANGUL SYLLABLE KHIEUKH EU THIEUTH + 0xB492: 0xD086, //HANGUL SYLLABLE KHIEUKH EU PHIEUPH + 0xB493: 0xD087, //HANGUL SYLLABLE KHIEUKH EU HIEUH + 0xB494: 0xD088, //HANGUL SYLLABLE KHIEUKH YI + 0xB495: 0xD089, //HANGUL SYLLABLE KHIEUKH YI KIYEOK + 0xB496: 0xD08A, //HANGUL SYLLABLE KHIEUKH YI SSANGKIYEOK + 0xB497: 0xD08B, //HANGUL SYLLABLE KHIEUKH YI KIYEOKSIOS + 0xB498: 0xD08C, //HANGUL SYLLABLE KHIEUKH YI NIEUN + 0xB499: 0xD08D, //HANGUL SYLLABLE KHIEUKH YI NIEUNCIEUC + 0xB49A: 0xD08E, //HANGUL SYLLABLE KHIEUKH YI NIEUNHIEUH + 0xB49B: 0xD08F, //HANGUL SYLLABLE KHIEUKH YI TIKEUT + 0xB49C: 0xD090, //HANGUL SYLLABLE KHIEUKH YI RIEUL + 0xB49D: 0xD091, //HANGUL SYLLABLE KHIEUKH YI RIEULKIYEOK + 0xB49E: 0xD092, //HANGUL SYLLABLE KHIEUKH YI RIEULMIEUM + 0xB49F: 0xD093, //HANGUL SYLLABLE KHIEUKH YI RIEULPIEUP + 0xB4A0: 0xD094, //HANGUL SYLLABLE KHIEUKH YI RIEULSIOS + 0xB4A1: 0xB1DF, //HANGUL SYLLABLE NIEUN OE SIOS + 0xB4A2: 0xB1E8, //HANGUL SYLLABLE NIEUN YO + 0xB4A3: 0xB1E9, //HANGUL SYLLABLE NIEUN YO KIYEOK + 0xB4A4: 0xB1EC, //HANGUL SYLLABLE NIEUN YO NIEUN + 0xB4A5: 0xB1F0, //HANGUL SYLLABLE NIEUN YO RIEUL + 0xB4A6: 0xB1F9, //HANGUL SYLLABLE NIEUN YO PIEUP + 0xB4A7: 0xB1FB, //HANGUL SYLLABLE NIEUN YO SIOS + 0xB4A8: 0xB1FD, //HANGUL SYLLABLE NIEUN YO IEUNG + 0xB4A9: 0xB204, //HANGUL SYLLABLE NIEUN U + 0xB4AA: 0xB205, //HANGUL SYLLABLE NIEUN U KIYEOK + 0xB4AB: 0xB208, //HANGUL SYLLABLE NIEUN U NIEUN + 0xB4AC: 0xB20B, //HANGUL SYLLABLE NIEUN U TIKEUT + 0xB4AD: 0xB20C, //HANGUL SYLLABLE NIEUN U RIEUL + 0xB4AE: 0xB214, //HANGUL SYLLABLE NIEUN U MIEUM + 0xB4AF: 0xB215, //HANGUL SYLLABLE NIEUN U PIEUP + 0xB4B0: 0xB217, //HANGUL SYLLABLE NIEUN U SIOS + 0xB4B1: 0xB219, //HANGUL SYLLABLE NIEUN U IEUNG + 0xB4B2: 0xB220, //HANGUL SYLLABLE NIEUN WEO + 0xB4B3: 0xB234, //HANGUL SYLLABLE NIEUN WEO SSANGSIOS + 0xB4B4: 0xB23C, //HANGUL SYLLABLE NIEUN WE + 0xB4B5: 0xB258, //HANGUL SYLLABLE NIEUN WI + 0xB4B6: 0xB25C, //HANGUL SYLLABLE NIEUN WI NIEUN + 0xB4B7: 0xB260, //HANGUL SYLLABLE NIEUN WI RIEUL + 0xB4B8: 0xB268, //HANGUL SYLLABLE NIEUN WI MIEUM + 0xB4B9: 0xB269, //HANGUL SYLLABLE NIEUN WI PIEUP + 0xB4BA: 0xB274, //HANGUL SYLLABLE NIEUN YU + 0xB4BB: 0xB275, //HANGUL SYLLABLE NIEUN YU KIYEOK + 0xB4BC: 0xB27C, //HANGUL SYLLABLE NIEUN YU RIEUL + 0xB4BD: 0xB284, //HANGUL SYLLABLE NIEUN YU MIEUM + 0xB4BE: 0xB285, //HANGUL SYLLABLE NIEUN YU PIEUP + 0xB4BF: 0xB289, //HANGUL SYLLABLE NIEUN YU IEUNG + 0xB4C0: 0xB290, //HANGUL SYLLABLE NIEUN EU + 0xB4C1: 0xB291, //HANGUL SYLLABLE NIEUN EU KIYEOK + 0xB4C2: 0xB294, //HANGUL SYLLABLE NIEUN EU NIEUN + 0xB4C3: 0xB298, //HANGUL SYLLABLE NIEUN EU RIEUL + 0xB4C4: 0xB299, //HANGUL SYLLABLE NIEUN EU RIEULKIYEOK + 0xB4C5: 0xB29A, //HANGUL SYLLABLE NIEUN EU RIEULMIEUM + 0xB4C6: 0xB2A0, //HANGUL SYLLABLE NIEUN EU MIEUM + 0xB4C7: 0xB2A1, //HANGUL SYLLABLE NIEUN EU PIEUP + 0xB4C8: 0xB2A3, //HANGUL SYLLABLE NIEUN EU SIOS + 0xB4C9: 0xB2A5, //HANGUL SYLLABLE NIEUN EU IEUNG + 0xB4CA: 0xB2A6, //HANGUL SYLLABLE NIEUN EU CIEUC + 0xB4CB: 0xB2AA, //HANGUL SYLLABLE NIEUN EU PHIEUPH + 0xB4CC: 0xB2AC, //HANGUL SYLLABLE NIEUN YI + 0xB4CD: 0xB2B0, //HANGUL SYLLABLE NIEUN YI NIEUN + 0xB4CE: 0xB2B4, //HANGUL SYLLABLE NIEUN YI RIEUL + 0xB4CF: 0xB2C8, //HANGUL SYLLABLE NIEUN I + 0xB4D0: 0xB2C9, //HANGUL SYLLABLE NIEUN I KIYEOK + 0xB4D1: 0xB2CC, //HANGUL SYLLABLE NIEUN I NIEUN + 0xB4D2: 0xB2D0, //HANGUL SYLLABLE NIEUN I RIEUL + 0xB4D3: 0xB2D2, //HANGUL SYLLABLE NIEUN I RIEULMIEUM + 0xB4D4: 0xB2D8, //HANGUL SYLLABLE NIEUN I MIEUM + 0xB4D5: 0xB2D9, //HANGUL SYLLABLE NIEUN I PIEUP + 0xB4D6: 0xB2DB, //HANGUL SYLLABLE NIEUN I SIOS + 0xB4D7: 0xB2DD, //HANGUL SYLLABLE NIEUN I IEUNG + 0xB4D8: 0xB2E2, //HANGUL SYLLABLE NIEUN I PHIEUPH + 0xB4D9: 0xB2E4, //HANGUL SYLLABLE TIKEUT A + 0xB4DA: 0xB2E5, //HANGUL SYLLABLE TIKEUT A KIYEOK + 0xB4DB: 0xB2E6, //HANGUL SYLLABLE TIKEUT A SSANGKIYEOK + 0xB4DC: 0xB2E8, //HANGUL SYLLABLE TIKEUT A NIEUN + 0xB4DD: 0xB2EB, //HANGUL SYLLABLE TIKEUT A TIKEUT + 0xB4DE: 0xB2EC, //HANGUL SYLLABLE TIKEUT A RIEUL + 0xB4DF: 0xB2ED, //HANGUL SYLLABLE TIKEUT A RIEULKIYEOK + 0xB4E0: 0xB2EE, //HANGUL SYLLABLE TIKEUT A RIEULMIEUM + 0xB4E1: 0xB2EF, //HANGUL SYLLABLE TIKEUT A RIEULPIEUP + 0xB4E2: 0xB2F3, //HANGUL SYLLABLE TIKEUT A RIEULHIEUH + 0xB4E3: 0xB2F4, //HANGUL SYLLABLE TIKEUT A MIEUM + 0xB4E4: 0xB2F5, //HANGUL SYLLABLE TIKEUT A PIEUP + 0xB4E5: 0xB2F7, //HANGUL SYLLABLE TIKEUT A SIOS + 0xB4E6: 0xB2F8, //HANGUL SYLLABLE TIKEUT A SSANGSIOS + 0xB4E7: 0xB2F9, //HANGUL SYLLABLE TIKEUT A IEUNG + 0xB4E8: 0xB2FA, //HANGUL SYLLABLE TIKEUT A CIEUC + 0xB4E9: 0xB2FB, //HANGUL SYLLABLE TIKEUT A CHIEUCH + 0xB4EA: 0xB2FF, //HANGUL SYLLABLE TIKEUT A HIEUH + 0xB4EB: 0xB300, //HANGUL SYLLABLE TIKEUT AE + 0xB4EC: 0xB301, //HANGUL SYLLABLE TIKEUT AE KIYEOK + 0xB4ED: 0xB304, //HANGUL SYLLABLE TIKEUT AE NIEUN + 0xB4EE: 0xB308, //HANGUL SYLLABLE TIKEUT AE RIEUL + 0xB4EF: 0xB310, //HANGUL SYLLABLE TIKEUT AE MIEUM + 0xB4F0: 0xB311, //HANGUL SYLLABLE TIKEUT AE PIEUP + 0xB4F1: 0xB313, //HANGUL SYLLABLE TIKEUT AE SIOS + 0xB4F2: 0xB314, //HANGUL SYLLABLE TIKEUT AE SSANGSIOS + 0xB4F3: 0xB315, //HANGUL SYLLABLE TIKEUT AE IEUNG + 0xB4F4: 0xB31C, //HANGUL SYLLABLE TIKEUT YA + 0xB4F5: 0xB354, //HANGUL SYLLABLE TIKEUT EO + 0xB4F6: 0xB355, //HANGUL SYLLABLE TIKEUT EO KIYEOK + 0xB4F7: 0xB356, //HANGUL SYLLABLE TIKEUT EO SSANGKIYEOK + 0xB4F8: 0xB358, //HANGUL SYLLABLE TIKEUT EO NIEUN + 0xB4F9: 0xB35B, //HANGUL SYLLABLE TIKEUT EO TIKEUT + 0xB4FA: 0xB35C, //HANGUL SYLLABLE TIKEUT EO RIEUL + 0xB4FB: 0xB35E, //HANGUL SYLLABLE TIKEUT EO RIEULMIEUM + 0xB4FC: 0xB35F, //HANGUL SYLLABLE TIKEUT EO RIEULPIEUP + 0xB4FD: 0xB364, //HANGUL SYLLABLE TIKEUT EO MIEUM + 0xB4FE: 0xB365, //HANGUL SYLLABLE TIKEUT EO PIEUP + 0xB541: 0xD095, //HANGUL SYLLABLE KHIEUKH YI RIEULTHIEUTH + 0xB542: 0xD096, //HANGUL SYLLABLE KHIEUKH YI RIEULPHIEUPH + 0xB543: 0xD097, //HANGUL SYLLABLE KHIEUKH YI RIEULHIEUH + 0xB544: 0xD098, //HANGUL SYLLABLE KHIEUKH YI MIEUM + 0xB545: 0xD099, //HANGUL SYLLABLE KHIEUKH YI PIEUP + 0xB546: 0xD09A, //HANGUL SYLLABLE KHIEUKH YI PIEUPSIOS + 0xB547: 0xD09B, //HANGUL SYLLABLE KHIEUKH YI SIOS + 0xB548: 0xD09C, //HANGUL SYLLABLE KHIEUKH YI SSANGSIOS + 0xB549: 0xD09D, //HANGUL SYLLABLE KHIEUKH YI IEUNG + 0xB54A: 0xD09E, //HANGUL SYLLABLE KHIEUKH YI CIEUC + 0xB54B: 0xD09F, //HANGUL SYLLABLE KHIEUKH YI CHIEUCH + 0xB54C: 0xD0A0, //HANGUL SYLLABLE KHIEUKH YI KHIEUKH + 0xB54D: 0xD0A1, //HANGUL SYLLABLE KHIEUKH YI THIEUTH + 0xB54E: 0xD0A2, //HANGUL SYLLABLE KHIEUKH YI PHIEUPH + 0xB54F: 0xD0A3, //HANGUL SYLLABLE KHIEUKH YI HIEUH + 0xB550: 0xD0A6, //HANGUL SYLLABLE KHIEUKH I SSANGKIYEOK + 0xB551: 0xD0A7, //HANGUL SYLLABLE KHIEUKH I KIYEOKSIOS + 0xB552: 0xD0A9, //HANGUL SYLLABLE KHIEUKH I NIEUNCIEUC + 0xB553: 0xD0AA, //HANGUL SYLLABLE KHIEUKH I NIEUNHIEUH + 0xB554: 0xD0AB, //HANGUL SYLLABLE KHIEUKH I TIKEUT + 0xB555: 0xD0AD, //HANGUL SYLLABLE KHIEUKH I RIEULKIYEOK + 0xB556: 0xD0AE, //HANGUL SYLLABLE KHIEUKH I RIEULMIEUM + 0xB557: 0xD0AF, //HANGUL SYLLABLE KHIEUKH I RIEULPIEUP + 0xB558: 0xD0B0, //HANGUL SYLLABLE KHIEUKH I RIEULSIOS + 0xB559: 0xD0B1, //HANGUL SYLLABLE KHIEUKH I RIEULTHIEUTH + 0xB55A: 0xD0B2, //HANGUL SYLLABLE KHIEUKH I RIEULPHIEUPH + 0xB561: 0xD0B3, //HANGUL SYLLABLE KHIEUKH I RIEULHIEUH + 0xB562: 0xD0B6, //HANGUL SYLLABLE KHIEUKH I PIEUPSIOS + 0xB563: 0xD0B8, //HANGUL SYLLABLE KHIEUKH I SSANGSIOS + 0xB564: 0xD0BA, //HANGUL SYLLABLE KHIEUKH I CIEUC + 0xB565: 0xD0BB, //HANGUL SYLLABLE KHIEUKH I CHIEUCH + 0xB566: 0xD0BC, //HANGUL SYLLABLE KHIEUKH I KHIEUKH + 0xB567: 0xD0BD, //HANGUL SYLLABLE KHIEUKH I THIEUTH + 0xB568: 0xD0BE, //HANGUL SYLLABLE KHIEUKH I PHIEUPH + 0xB569: 0xD0BF, //HANGUL SYLLABLE KHIEUKH I HIEUH + 0xB56A: 0xD0C2, //HANGUL SYLLABLE THIEUTH A SSANGKIYEOK + 0xB56B: 0xD0C3, //HANGUL SYLLABLE THIEUTH A KIYEOKSIOS + 0xB56C: 0xD0C5, //HANGUL SYLLABLE THIEUTH A NIEUNCIEUC + 0xB56D: 0xD0C6, //HANGUL SYLLABLE THIEUTH A NIEUNHIEUH + 0xB56E: 0xD0C7, //HANGUL SYLLABLE THIEUTH A TIKEUT + 0xB56F: 0xD0CA, //HANGUL SYLLABLE THIEUTH A RIEULMIEUM + 0xB570: 0xD0CB, //HANGUL SYLLABLE THIEUTH A RIEULPIEUP + 0xB571: 0xD0CC, //HANGUL SYLLABLE THIEUTH A RIEULSIOS + 0xB572: 0xD0CD, //HANGUL SYLLABLE THIEUTH A RIEULTHIEUTH + 0xB573: 0xD0CE, //HANGUL SYLLABLE THIEUTH A RIEULPHIEUPH + 0xB574: 0xD0CF, //HANGUL SYLLABLE THIEUTH A RIEULHIEUH + 0xB575: 0xD0D2, //HANGUL SYLLABLE THIEUTH A PIEUPSIOS + 0xB576: 0xD0D6, //HANGUL SYLLABLE THIEUTH A CIEUC + 0xB577: 0xD0D7, //HANGUL SYLLABLE THIEUTH A CHIEUCH + 0xB578: 0xD0D8, //HANGUL SYLLABLE THIEUTH A KHIEUKH + 0xB579: 0xD0D9, //HANGUL SYLLABLE THIEUTH A THIEUTH + 0xB57A: 0xD0DA, //HANGUL SYLLABLE THIEUTH A PHIEUPH + 0xB581: 0xD0DB, //HANGUL SYLLABLE THIEUTH A HIEUH + 0xB582: 0xD0DE, //HANGUL SYLLABLE THIEUTH AE SSANGKIYEOK + 0xB583: 0xD0DF, //HANGUL SYLLABLE THIEUTH AE KIYEOKSIOS + 0xB584: 0xD0E1, //HANGUL SYLLABLE THIEUTH AE NIEUNCIEUC + 0xB585: 0xD0E2, //HANGUL SYLLABLE THIEUTH AE NIEUNHIEUH + 0xB586: 0xD0E3, //HANGUL SYLLABLE THIEUTH AE TIKEUT + 0xB587: 0xD0E5, //HANGUL SYLLABLE THIEUTH AE RIEULKIYEOK + 0xB588: 0xD0E6, //HANGUL SYLLABLE THIEUTH AE RIEULMIEUM + 0xB589: 0xD0E7, //HANGUL SYLLABLE THIEUTH AE RIEULPIEUP + 0xB58A: 0xD0E8, //HANGUL SYLLABLE THIEUTH AE RIEULSIOS + 0xB58B: 0xD0E9, //HANGUL SYLLABLE THIEUTH AE RIEULTHIEUTH + 0xB58C: 0xD0EA, //HANGUL SYLLABLE THIEUTH AE RIEULPHIEUPH + 0xB58D: 0xD0EB, //HANGUL SYLLABLE THIEUTH AE RIEULHIEUH + 0xB58E: 0xD0EE, //HANGUL SYLLABLE THIEUTH AE PIEUPSIOS + 0xB58F: 0xD0F2, //HANGUL SYLLABLE THIEUTH AE CIEUC + 0xB590: 0xD0F3, //HANGUL SYLLABLE THIEUTH AE CHIEUCH + 0xB591: 0xD0F4, //HANGUL SYLLABLE THIEUTH AE KHIEUKH + 0xB592: 0xD0F5, //HANGUL SYLLABLE THIEUTH AE THIEUTH + 0xB593: 0xD0F6, //HANGUL SYLLABLE THIEUTH AE PHIEUPH + 0xB594: 0xD0F7, //HANGUL SYLLABLE THIEUTH AE HIEUH + 0xB595: 0xD0F9, //HANGUL SYLLABLE THIEUTH YA KIYEOK + 0xB596: 0xD0FA, //HANGUL SYLLABLE THIEUTH YA SSANGKIYEOK + 0xB597: 0xD0FB, //HANGUL SYLLABLE THIEUTH YA KIYEOKSIOS + 0xB598: 0xD0FC, //HANGUL SYLLABLE THIEUTH YA NIEUN + 0xB599: 0xD0FD, //HANGUL SYLLABLE THIEUTH YA NIEUNCIEUC + 0xB59A: 0xD0FE, //HANGUL SYLLABLE THIEUTH YA NIEUNHIEUH + 0xB59B: 0xD0FF, //HANGUL SYLLABLE THIEUTH YA TIKEUT + 0xB59C: 0xD100, //HANGUL SYLLABLE THIEUTH YA RIEUL + 0xB59D: 0xD101, //HANGUL SYLLABLE THIEUTH YA RIEULKIYEOK + 0xB59E: 0xD102, //HANGUL SYLLABLE THIEUTH YA RIEULMIEUM + 0xB59F: 0xD103, //HANGUL SYLLABLE THIEUTH YA RIEULPIEUP + 0xB5A0: 0xD104, //HANGUL SYLLABLE THIEUTH YA RIEULSIOS + 0xB5A1: 0xB367, //HANGUL SYLLABLE TIKEUT EO SIOS + 0xB5A2: 0xB369, //HANGUL SYLLABLE TIKEUT EO IEUNG + 0xB5A3: 0xB36B, //HANGUL SYLLABLE TIKEUT EO CHIEUCH + 0xB5A4: 0xB36E, //HANGUL SYLLABLE TIKEUT EO PHIEUPH + 0xB5A5: 0xB370, //HANGUL SYLLABLE TIKEUT E + 0xB5A6: 0xB371, //HANGUL SYLLABLE TIKEUT E KIYEOK + 0xB5A7: 0xB374, //HANGUL SYLLABLE TIKEUT E NIEUN + 0xB5A8: 0xB378, //HANGUL SYLLABLE TIKEUT E RIEUL + 0xB5A9: 0xB380, //HANGUL SYLLABLE TIKEUT E MIEUM + 0xB5AA: 0xB381, //HANGUL SYLLABLE TIKEUT E PIEUP + 0xB5AB: 0xB383, //HANGUL SYLLABLE TIKEUT E SIOS + 0xB5AC: 0xB384, //HANGUL SYLLABLE TIKEUT E SSANGSIOS + 0xB5AD: 0xB385, //HANGUL SYLLABLE TIKEUT E IEUNG + 0xB5AE: 0xB38C, //HANGUL SYLLABLE TIKEUT YEO + 0xB5AF: 0xB390, //HANGUL SYLLABLE TIKEUT YEO NIEUN + 0xB5B0: 0xB394, //HANGUL SYLLABLE TIKEUT YEO RIEUL + 0xB5B1: 0xB3A0, //HANGUL SYLLABLE TIKEUT YEO SSANGSIOS + 0xB5B2: 0xB3A1, //HANGUL SYLLABLE TIKEUT YEO IEUNG + 0xB5B3: 0xB3A8, //HANGUL SYLLABLE TIKEUT YE + 0xB5B4: 0xB3AC, //HANGUL SYLLABLE TIKEUT YE NIEUN + 0xB5B5: 0xB3C4, //HANGUL SYLLABLE TIKEUT O + 0xB5B6: 0xB3C5, //HANGUL SYLLABLE TIKEUT O KIYEOK + 0xB5B7: 0xB3C8, //HANGUL SYLLABLE TIKEUT O NIEUN + 0xB5B8: 0xB3CB, //HANGUL SYLLABLE TIKEUT O TIKEUT + 0xB5B9: 0xB3CC, //HANGUL SYLLABLE TIKEUT O RIEUL + 0xB5BA: 0xB3CE, //HANGUL SYLLABLE TIKEUT O RIEULMIEUM + 0xB5BB: 0xB3D0, //HANGUL SYLLABLE TIKEUT O RIEULSIOS + 0xB5BC: 0xB3D4, //HANGUL SYLLABLE TIKEUT O MIEUM + 0xB5BD: 0xB3D5, //HANGUL SYLLABLE TIKEUT O PIEUP + 0xB5BE: 0xB3D7, //HANGUL SYLLABLE TIKEUT O SIOS + 0xB5BF: 0xB3D9, //HANGUL SYLLABLE TIKEUT O IEUNG + 0xB5C0: 0xB3DB, //HANGUL SYLLABLE TIKEUT O CHIEUCH + 0xB5C1: 0xB3DD, //HANGUL SYLLABLE TIKEUT O THIEUTH + 0xB5C2: 0xB3E0, //HANGUL SYLLABLE TIKEUT WA + 0xB5C3: 0xB3E4, //HANGUL SYLLABLE TIKEUT WA NIEUN + 0xB5C4: 0xB3E8, //HANGUL SYLLABLE TIKEUT WA RIEUL + 0xB5C5: 0xB3FC, //HANGUL SYLLABLE TIKEUT WAE + 0xB5C6: 0xB410, //HANGUL SYLLABLE TIKEUT WAE SSANGSIOS + 0xB5C7: 0xB418, //HANGUL SYLLABLE TIKEUT OE + 0xB5C8: 0xB41C, //HANGUL SYLLABLE TIKEUT OE NIEUN + 0xB5C9: 0xB420, //HANGUL SYLLABLE TIKEUT OE RIEUL + 0xB5CA: 0xB428, //HANGUL SYLLABLE TIKEUT OE MIEUM + 0xB5CB: 0xB429, //HANGUL SYLLABLE TIKEUT OE PIEUP + 0xB5CC: 0xB42B, //HANGUL SYLLABLE TIKEUT OE SIOS + 0xB5CD: 0xB434, //HANGUL SYLLABLE TIKEUT YO + 0xB5CE: 0xB450, //HANGUL SYLLABLE TIKEUT U + 0xB5CF: 0xB451, //HANGUL SYLLABLE TIKEUT U KIYEOK + 0xB5D0: 0xB454, //HANGUL SYLLABLE TIKEUT U NIEUN + 0xB5D1: 0xB458, //HANGUL SYLLABLE TIKEUT U RIEUL + 0xB5D2: 0xB460, //HANGUL SYLLABLE TIKEUT U MIEUM + 0xB5D3: 0xB461, //HANGUL SYLLABLE TIKEUT U PIEUP + 0xB5D4: 0xB463, //HANGUL SYLLABLE TIKEUT U SIOS + 0xB5D5: 0xB465, //HANGUL SYLLABLE TIKEUT U IEUNG + 0xB5D6: 0xB46C, //HANGUL SYLLABLE TIKEUT WEO + 0xB5D7: 0xB480, //HANGUL SYLLABLE TIKEUT WEO SSANGSIOS + 0xB5D8: 0xB488, //HANGUL SYLLABLE TIKEUT WE + 0xB5D9: 0xB49D, //HANGUL SYLLABLE TIKEUT WE IEUNG + 0xB5DA: 0xB4A4, //HANGUL SYLLABLE TIKEUT WI + 0xB5DB: 0xB4A8, //HANGUL SYLLABLE TIKEUT WI NIEUN + 0xB5DC: 0xB4AC, //HANGUL SYLLABLE TIKEUT WI RIEUL + 0xB5DD: 0xB4B5, //HANGUL SYLLABLE TIKEUT WI PIEUP + 0xB5DE: 0xB4B7, //HANGUL SYLLABLE TIKEUT WI SIOS + 0xB5DF: 0xB4B9, //HANGUL SYLLABLE TIKEUT WI IEUNG + 0xB5E0: 0xB4C0, //HANGUL SYLLABLE TIKEUT YU + 0xB5E1: 0xB4C4, //HANGUL SYLLABLE TIKEUT YU NIEUN + 0xB5E2: 0xB4C8, //HANGUL SYLLABLE TIKEUT YU RIEUL + 0xB5E3: 0xB4D0, //HANGUL SYLLABLE TIKEUT YU MIEUM + 0xB5E4: 0xB4D5, //HANGUL SYLLABLE TIKEUT YU IEUNG + 0xB5E5: 0xB4DC, //HANGUL SYLLABLE TIKEUT EU + 0xB5E6: 0xB4DD, //HANGUL SYLLABLE TIKEUT EU KIYEOK + 0xB5E7: 0xB4E0, //HANGUL SYLLABLE TIKEUT EU NIEUN + 0xB5E8: 0xB4E3, //HANGUL SYLLABLE TIKEUT EU TIKEUT + 0xB5E9: 0xB4E4, //HANGUL SYLLABLE TIKEUT EU RIEUL + 0xB5EA: 0xB4E6, //HANGUL SYLLABLE TIKEUT EU RIEULMIEUM + 0xB5EB: 0xB4EC, //HANGUL SYLLABLE TIKEUT EU MIEUM + 0xB5EC: 0xB4ED, //HANGUL SYLLABLE TIKEUT EU PIEUP + 0xB5ED: 0xB4EF, //HANGUL SYLLABLE TIKEUT EU SIOS + 0xB5EE: 0xB4F1, //HANGUL SYLLABLE TIKEUT EU IEUNG + 0xB5EF: 0xB4F8, //HANGUL SYLLABLE TIKEUT YI + 0xB5F0: 0xB514, //HANGUL SYLLABLE TIKEUT I + 0xB5F1: 0xB515, //HANGUL SYLLABLE TIKEUT I KIYEOK + 0xB5F2: 0xB518, //HANGUL SYLLABLE TIKEUT I NIEUN + 0xB5F3: 0xB51B, //HANGUL SYLLABLE TIKEUT I TIKEUT + 0xB5F4: 0xB51C, //HANGUL SYLLABLE TIKEUT I RIEUL + 0xB5F5: 0xB524, //HANGUL SYLLABLE TIKEUT I MIEUM + 0xB5F6: 0xB525, //HANGUL SYLLABLE TIKEUT I PIEUP + 0xB5F7: 0xB527, //HANGUL SYLLABLE TIKEUT I SIOS + 0xB5F8: 0xB528, //HANGUL SYLLABLE TIKEUT I SSANGSIOS + 0xB5F9: 0xB529, //HANGUL SYLLABLE TIKEUT I IEUNG + 0xB5FA: 0xB52A, //HANGUL SYLLABLE TIKEUT I CIEUC + 0xB5FB: 0xB530, //HANGUL SYLLABLE SSANGTIKEUT A + 0xB5FC: 0xB531, //HANGUL SYLLABLE SSANGTIKEUT A KIYEOK + 0xB5FD: 0xB534, //HANGUL SYLLABLE SSANGTIKEUT A NIEUN + 0xB5FE: 0xB538, //HANGUL SYLLABLE SSANGTIKEUT A RIEUL + 0xB641: 0xD105, //HANGUL SYLLABLE THIEUTH YA RIEULTHIEUTH + 0xB642: 0xD106, //HANGUL SYLLABLE THIEUTH YA RIEULPHIEUPH + 0xB643: 0xD107, //HANGUL SYLLABLE THIEUTH YA RIEULHIEUH + 0xB644: 0xD108, //HANGUL SYLLABLE THIEUTH YA MIEUM + 0xB645: 0xD109, //HANGUL SYLLABLE THIEUTH YA PIEUP + 0xB646: 0xD10A, //HANGUL SYLLABLE THIEUTH YA PIEUPSIOS + 0xB647: 0xD10B, //HANGUL SYLLABLE THIEUTH YA SIOS + 0xB648: 0xD10C, //HANGUL SYLLABLE THIEUTH YA SSANGSIOS + 0xB649: 0xD10E, //HANGUL SYLLABLE THIEUTH YA CIEUC + 0xB64A: 0xD10F, //HANGUL SYLLABLE THIEUTH YA CHIEUCH + 0xB64B: 0xD110, //HANGUL SYLLABLE THIEUTH YA KHIEUKH + 0xB64C: 0xD111, //HANGUL SYLLABLE THIEUTH YA THIEUTH + 0xB64D: 0xD112, //HANGUL SYLLABLE THIEUTH YA PHIEUPH + 0xB64E: 0xD113, //HANGUL SYLLABLE THIEUTH YA HIEUH + 0xB64F: 0xD114, //HANGUL SYLLABLE THIEUTH YAE + 0xB650: 0xD115, //HANGUL SYLLABLE THIEUTH YAE KIYEOK + 0xB651: 0xD116, //HANGUL SYLLABLE THIEUTH YAE SSANGKIYEOK + 0xB652: 0xD117, //HANGUL SYLLABLE THIEUTH YAE KIYEOKSIOS + 0xB653: 0xD118, //HANGUL SYLLABLE THIEUTH YAE NIEUN + 0xB654: 0xD119, //HANGUL SYLLABLE THIEUTH YAE NIEUNCIEUC + 0xB655: 0xD11A, //HANGUL SYLLABLE THIEUTH YAE NIEUNHIEUH + 0xB656: 0xD11B, //HANGUL SYLLABLE THIEUTH YAE TIKEUT + 0xB657: 0xD11C, //HANGUL SYLLABLE THIEUTH YAE RIEUL + 0xB658: 0xD11D, //HANGUL SYLLABLE THIEUTH YAE RIEULKIYEOK + 0xB659: 0xD11E, //HANGUL SYLLABLE THIEUTH YAE RIEULMIEUM + 0xB65A: 0xD11F, //HANGUL SYLLABLE THIEUTH YAE RIEULPIEUP + 0xB661: 0xD120, //HANGUL SYLLABLE THIEUTH YAE RIEULSIOS + 0xB662: 0xD121, //HANGUL SYLLABLE THIEUTH YAE RIEULTHIEUTH + 0xB663: 0xD122, //HANGUL SYLLABLE THIEUTH YAE RIEULPHIEUPH + 0xB664: 0xD123, //HANGUL SYLLABLE THIEUTH YAE RIEULHIEUH + 0xB665: 0xD124, //HANGUL SYLLABLE THIEUTH YAE MIEUM + 0xB666: 0xD125, //HANGUL SYLLABLE THIEUTH YAE PIEUP + 0xB667: 0xD126, //HANGUL SYLLABLE THIEUTH YAE PIEUPSIOS + 0xB668: 0xD127, //HANGUL SYLLABLE THIEUTH YAE SIOS + 0xB669: 0xD128, //HANGUL SYLLABLE THIEUTH YAE SSANGSIOS + 0xB66A: 0xD129, //HANGUL SYLLABLE THIEUTH YAE IEUNG + 0xB66B: 0xD12A, //HANGUL SYLLABLE THIEUTH YAE CIEUC + 0xB66C: 0xD12B, //HANGUL SYLLABLE THIEUTH YAE CHIEUCH + 0xB66D: 0xD12C, //HANGUL SYLLABLE THIEUTH YAE KHIEUKH + 0xB66E: 0xD12D, //HANGUL SYLLABLE THIEUTH YAE THIEUTH + 0xB66F: 0xD12E, //HANGUL SYLLABLE THIEUTH YAE PHIEUPH + 0xB670: 0xD12F, //HANGUL SYLLABLE THIEUTH YAE HIEUH + 0xB671: 0xD132, //HANGUL SYLLABLE THIEUTH EO SSANGKIYEOK + 0xB672: 0xD133, //HANGUL SYLLABLE THIEUTH EO KIYEOKSIOS + 0xB673: 0xD135, //HANGUL SYLLABLE THIEUTH EO NIEUNCIEUC + 0xB674: 0xD136, //HANGUL SYLLABLE THIEUTH EO NIEUNHIEUH + 0xB675: 0xD137, //HANGUL SYLLABLE THIEUTH EO TIKEUT + 0xB676: 0xD139, //HANGUL SYLLABLE THIEUTH EO RIEULKIYEOK + 0xB677: 0xD13B, //HANGUL SYLLABLE THIEUTH EO RIEULPIEUP + 0xB678: 0xD13C, //HANGUL SYLLABLE THIEUTH EO RIEULSIOS + 0xB679: 0xD13D, //HANGUL SYLLABLE THIEUTH EO RIEULTHIEUTH + 0xB67A: 0xD13E, //HANGUL SYLLABLE THIEUTH EO RIEULPHIEUPH + 0xB681: 0xD13F, //HANGUL SYLLABLE THIEUTH EO RIEULHIEUH + 0xB682: 0xD142, //HANGUL SYLLABLE THIEUTH EO PIEUPSIOS + 0xB683: 0xD146, //HANGUL SYLLABLE THIEUTH EO CIEUC + 0xB684: 0xD147, //HANGUL SYLLABLE THIEUTH EO CHIEUCH + 0xB685: 0xD148, //HANGUL SYLLABLE THIEUTH EO KHIEUKH + 0xB686: 0xD149, //HANGUL SYLLABLE THIEUTH EO THIEUTH + 0xB687: 0xD14A, //HANGUL SYLLABLE THIEUTH EO PHIEUPH + 0xB688: 0xD14B, //HANGUL SYLLABLE THIEUTH EO HIEUH + 0xB689: 0xD14E, //HANGUL SYLLABLE THIEUTH E SSANGKIYEOK + 0xB68A: 0xD14F, //HANGUL SYLLABLE THIEUTH E KIYEOKSIOS + 0xB68B: 0xD151, //HANGUL SYLLABLE THIEUTH E NIEUNCIEUC + 0xB68C: 0xD152, //HANGUL SYLLABLE THIEUTH E NIEUNHIEUH + 0xB68D: 0xD153, //HANGUL SYLLABLE THIEUTH E TIKEUT + 0xB68E: 0xD155, //HANGUL SYLLABLE THIEUTH E RIEULKIYEOK + 0xB68F: 0xD156, //HANGUL SYLLABLE THIEUTH E RIEULMIEUM + 0xB690: 0xD157, //HANGUL SYLLABLE THIEUTH E RIEULPIEUP + 0xB691: 0xD158, //HANGUL SYLLABLE THIEUTH E RIEULSIOS + 0xB692: 0xD159, //HANGUL SYLLABLE THIEUTH E RIEULTHIEUTH + 0xB693: 0xD15A, //HANGUL SYLLABLE THIEUTH E RIEULPHIEUPH + 0xB694: 0xD15B, //HANGUL SYLLABLE THIEUTH E RIEULHIEUH + 0xB695: 0xD15E, //HANGUL SYLLABLE THIEUTH E PIEUPSIOS + 0xB696: 0xD160, //HANGUL SYLLABLE THIEUTH E SSANGSIOS + 0xB697: 0xD162, //HANGUL SYLLABLE THIEUTH E CIEUC + 0xB698: 0xD163, //HANGUL SYLLABLE THIEUTH E CHIEUCH + 0xB699: 0xD164, //HANGUL SYLLABLE THIEUTH E KHIEUKH + 0xB69A: 0xD165, //HANGUL SYLLABLE THIEUTH E THIEUTH + 0xB69B: 0xD166, //HANGUL SYLLABLE THIEUTH E PHIEUPH + 0xB69C: 0xD167, //HANGUL SYLLABLE THIEUTH E HIEUH + 0xB69D: 0xD169, //HANGUL SYLLABLE THIEUTH YEO KIYEOK + 0xB69E: 0xD16A, //HANGUL SYLLABLE THIEUTH YEO SSANGKIYEOK + 0xB69F: 0xD16B, //HANGUL SYLLABLE THIEUTH YEO KIYEOKSIOS + 0xB6A0: 0xD16D, //HANGUL SYLLABLE THIEUTH YEO NIEUNCIEUC + 0xB6A1: 0xB540, //HANGUL SYLLABLE SSANGTIKEUT A MIEUM + 0xB6A2: 0xB541, //HANGUL SYLLABLE SSANGTIKEUT A PIEUP + 0xB6A3: 0xB543, //HANGUL SYLLABLE SSANGTIKEUT A SIOS + 0xB6A4: 0xB544, //HANGUL SYLLABLE SSANGTIKEUT A SSANGSIOS + 0xB6A5: 0xB545, //HANGUL SYLLABLE SSANGTIKEUT A IEUNG + 0xB6A6: 0xB54B, //HANGUL SYLLABLE SSANGTIKEUT A HIEUH + 0xB6A7: 0xB54C, //HANGUL SYLLABLE SSANGTIKEUT AE + 0xB6A8: 0xB54D, //HANGUL SYLLABLE SSANGTIKEUT AE KIYEOK + 0xB6A9: 0xB550, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUN + 0xB6AA: 0xB554, //HANGUL SYLLABLE SSANGTIKEUT AE RIEUL + 0xB6AB: 0xB55C, //HANGUL SYLLABLE SSANGTIKEUT AE MIEUM + 0xB6AC: 0xB55D, //HANGUL SYLLABLE SSANGTIKEUT AE PIEUP + 0xB6AD: 0xB55F, //HANGUL SYLLABLE SSANGTIKEUT AE SIOS + 0xB6AE: 0xB560, //HANGUL SYLLABLE SSANGTIKEUT AE SSANGSIOS + 0xB6AF: 0xB561, //HANGUL SYLLABLE SSANGTIKEUT AE IEUNG + 0xB6B0: 0xB5A0, //HANGUL SYLLABLE SSANGTIKEUT EO + 0xB6B1: 0xB5A1, //HANGUL SYLLABLE SSANGTIKEUT EO KIYEOK + 0xB6B2: 0xB5A4, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUN + 0xB6B3: 0xB5A8, //HANGUL SYLLABLE SSANGTIKEUT EO RIEUL + 0xB6B4: 0xB5AA, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULMIEUM + 0xB6B5: 0xB5AB, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULPIEUP + 0xB6B6: 0xB5B0, //HANGUL SYLLABLE SSANGTIKEUT EO MIEUM + 0xB6B7: 0xB5B1, //HANGUL SYLLABLE SSANGTIKEUT EO PIEUP + 0xB6B8: 0xB5B3, //HANGUL SYLLABLE SSANGTIKEUT EO SIOS + 0xB6B9: 0xB5B4, //HANGUL SYLLABLE SSANGTIKEUT EO SSANGSIOS + 0xB6BA: 0xB5B5, //HANGUL SYLLABLE SSANGTIKEUT EO IEUNG + 0xB6BB: 0xB5BB, //HANGUL SYLLABLE SSANGTIKEUT EO HIEUH + 0xB6BC: 0xB5BC, //HANGUL SYLLABLE SSANGTIKEUT E + 0xB6BD: 0xB5BD, //HANGUL SYLLABLE SSANGTIKEUT E KIYEOK + 0xB6BE: 0xB5C0, //HANGUL SYLLABLE SSANGTIKEUT E NIEUN + 0xB6BF: 0xB5C4, //HANGUL SYLLABLE SSANGTIKEUT E RIEUL + 0xB6C0: 0xB5CC, //HANGUL SYLLABLE SSANGTIKEUT E MIEUM + 0xB6C1: 0xB5CD, //HANGUL SYLLABLE SSANGTIKEUT E PIEUP + 0xB6C2: 0xB5CF, //HANGUL SYLLABLE SSANGTIKEUT E SIOS + 0xB6C3: 0xB5D0, //HANGUL SYLLABLE SSANGTIKEUT E SSANGSIOS + 0xB6C4: 0xB5D1, //HANGUL SYLLABLE SSANGTIKEUT E IEUNG + 0xB6C5: 0xB5D8, //HANGUL SYLLABLE SSANGTIKEUT YEO + 0xB6C6: 0xB5EC, //HANGUL SYLLABLE SSANGTIKEUT YEO SSANGSIOS + 0xB6C7: 0xB610, //HANGUL SYLLABLE SSANGTIKEUT O + 0xB6C8: 0xB611, //HANGUL SYLLABLE SSANGTIKEUT O KIYEOK + 0xB6C9: 0xB614, //HANGUL SYLLABLE SSANGTIKEUT O NIEUN + 0xB6CA: 0xB618, //HANGUL SYLLABLE SSANGTIKEUT O RIEUL + 0xB6CB: 0xB625, //HANGUL SYLLABLE SSANGTIKEUT O IEUNG + 0xB6CC: 0xB62C, //HANGUL SYLLABLE SSANGTIKEUT WA + 0xB6CD: 0xB634, //HANGUL SYLLABLE SSANGTIKEUT WA RIEUL + 0xB6CE: 0xB648, //HANGUL SYLLABLE SSANGTIKEUT WAE + 0xB6CF: 0xB664, //HANGUL SYLLABLE SSANGTIKEUT OE + 0xB6D0: 0xB668, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUN + 0xB6D1: 0xB69C, //HANGUL SYLLABLE SSANGTIKEUT U + 0xB6D2: 0xB69D, //HANGUL SYLLABLE SSANGTIKEUT U KIYEOK + 0xB6D3: 0xB6A0, //HANGUL SYLLABLE SSANGTIKEUT U NIEUN + 0xB6D4: 0xB6A4, //HANGUL SYLLABLE SSANGTIKEUT U RIEUL + 0xB6D5: 0xB6AB, //HANGUL SYLLABLE SSANGTIKEUT U RIEULHIEUH + 0xB6D6: 0xB6AC, //HANGUL SYLLABLE SSANGTIKEUT U MIEUM + 0xB6D7: 0xB6B1, //HANGUL SYLLABLE SSANGTIKEUT U IEUNG + 0xB6D8: 0xB6D4, //HANGUL SYLLABLE SSANGTIKEUT WE + 0xB6D9: 0xB6F0, //HANGUL SYLLABLE SSANGTIKEUT WI + 0xB6DA: 0xB6F4, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUN + 0xB6DB: 0xB6F8, //HANGUL SYLLABLE SSANGTIKEUT WI RIEUL + 0xB6DC: 0xB700, //HANGUL SYLLABLE SSANGTIKEUT WI MIEUM + 0xB6DD: 0xB701, //HANGUL SYLLABLE SSANGTIKEUT WI PIEUP + 0xB6DE: 0xB705, //HANGUL SYLLABLE SSANGTIKEUT WI IEUNG + 0xB6DF: 0xB728, //HANGUL SYLLABLE SSANGTIKEUT EU + 0xB6E0: 0xB729, //HANGUL SYLLABLE SSANGTIKEUT EU KIYEOK + 0xB6E1: 0xB72C, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUN + 0xB6E2: 0xB72F, //HANGUL SYLLABLE SSANGTIKEUT EU TIKEUT + 0xB6E3: 0xB730, //HANGUL SYLLABLE SSANGTIKEUT EU RIEUL + 0xB6E4: 0xB738, //HANGUL SYLLABLE SSANGTIKEUT EU MIEUM + 0xB6E5: 0xB739, //HANGUL SYLLABLE SSANGTIKEUT EU PIEUP + 0xB6E6: 0xB73B, //HANGUL SYLLABLE SSANGTIKEUT EU SIOS + 0xB6E7: 0xB744, //HANGUL SYLLABLE SSANGTIKEUT YI + 0xB6E8: 0xB748, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUN + 0xB6E9: 0xB74C, //HANGUL SYLLABLE SSANGTIKEUT YI RIEUL + 0xB6EA: 0xB754, //HANGUL SYLLABLE SSANGTIKEUT YI MIEUM + 0xB6EB: 0xB755, //HANGUL SYLLABLE SSANGTIKEUT YI PIEUP + 0xB6EC: 0xB760, //HANGUL SYLLABLE SSANGTIKEUT I + 0xB6ED: 0xB764, //HANGUL SYLLABLE SSANGTIKEUT I NIEUN + 0xB6EE: 0xB768, //HANGUL SYLLABLE SSANGTIKEUT I RIEUL + 0xB6EF: 0xB770, //HANGUL SYLLABLE SSANGTIKEUT I MIEUM + 0xB6F0: 0xB771, //HANGUL SYLLABLE SSANGTIKEUT I PIEUP + 0xB6F1: 0xB773, //HANGUL SYLLABLE SSANGTIKEUT I SIOS + 0xB6F2: 0xB775, //HANGUL SYLLABLE SSANGTIKEUT I IEUNG + 0xB6F3: 0xB77C, //HANGUL SYLLABLE RIEUL A + 0xB6F4: 0xB77D, //HANGUL SYLLABLE RIEUL A KIYEOK + 0xB6F5: 0xB780, //HANGUL SYLLABLE RIEUL A NIEUN + 0xB6F6: 0xB784, //HANGUL SYLLABLE RIEUL A RIEUL + 0xB6F7: 0xB78C, //HANGUL SYLLABLE RIEUL A MIEUM + 0xB6F8: 0xB78D, //HANGUL SYLLABLE RIEUL A PIEUP + 0xB6F9: 0xB78F, //HANGUL SYLLABLE RIEUL A SIOS + 0xB6FA: 0xB790, //HANGUL SYLLABLE RIEUL A SSANGSIOS + 0xB6FB: 0xB791, //HANGUL SYLLABLE RIEUL A IEUNG + 0xB6FC: 0xB792, //HANGUL SYLLABLE RIEUL A CIEUC + 0xB6FD: 0xB796, //HANGUL SYLLABLE RIEUL A PHIEUPH + 0xB6FE: 0xB797, //HANGUL SYLLABLE RIEUL A HIEUH + 0xB741: 0xD16E, //HANGUL SYLLABLE THIEUTH YEO NIEUNHIEUH + 0xB742: 0xD16F, //HANGUL SYLLABLE THIEUTH YEO TIKEUT + 0xB743: 0xD170, //HANGUL SYLLABLE THIEUTH YEO RIEUL + 0xB744: 0xD171, //HANGUL SYLLABLE THIEUTH YEO RIEULKIYEOK + 0xB745: 0xD172, //HANGUL SYLLABLE THIEUTH YEO RIEULMIEUM + 0xB746: 0xD173, //HANGUL SYLLABLE THIEUTH YEO RIEULPIEUP + 0xB747: 0xD174, //HANGUL SYLLABLE THIEUTH YEO RIEULSIOS + 0xB748: 0xD175, //HANGUL SYLLABLE THIEUTH YEO RIEULTHIEUTH + 0xB749: 0xD176, //HANGUL SYLLABLE THIEUTH YEO RIEULPHIEUPH + 0xB74A: 0xD177, //HANGUL SYLLABLE THIEUTH YEO RIEULHIEUH + 0xB74B: 0xD178, //HANGUL SYLLABLE THIEUTH YEO MIEUM + 0xB74C: 0xD179, //HANGUL SYLLABLE THIEUTH YEO PIEUP + 0xB74D: 0xD17A, //HANGUL SYLLABLE THIEUTH YEO PIEUPSIOS + 0xB74E: 0xD17B, //HANGUL SYLLABLE THIEUTH YEO SIOS + 0xB74F: 0xD17D, //HANGUL SYLLABLE THIEUTH YEO IEUNG + 0xB750: 0xD17E, //HANGUL SYLLABLE THIEUTH YEO CIEUC + 0xB751: 0xD17F, //HANGUL SYLLABLE THIEUTH YEO CHIEUCH + 0xB752: 0xD180, //HANGUL SYLLABLE THIEUTH YEO KHIEUKH + 0xB753: 0xD181, //HANGUL SYLLABLE THIEUTH YEO THIEUTH + 0xB754: 0xD182, //HANGUL SYLLABLE THIEUTH YEO PHIEUPH + 0xB755: 0xD183, //HANGUL SYLLABLE THIEUTH YEO HIEUH + 0xB756: 0xD185, //HANGUL SYLLABLE THIEUTH YE KIYEOK + 0xB757: 0xD186, //HANGUL SYLLABLE THIEUTH YE SSANGKIYEOK + 0xB758: 0xD187, //HANGUL SYLLABLE THIEUTH YE KIYEOKSIOS + 0xB759: 0xD189, //HANGUL SYLLABLE THIEUTH YE NIEUNCIEUC + 0xB75A: 0xD18A, //HANGUL SYLLABLE THIEUTH YE NIEUNHIEUH + 0xB761: 0xD18B, //HANGUL SYLLABLE THIEUTH YE TIKEUT + 0xB762: 0xD18C, //HANGUL SYLLABLE THIEUTH YE RIEUL + 0xB763: 0xD18D, //HANGUL SYLLABLE THIEUTH YE RIEULKIYEOK + 0xB764: 0xD18E, //HANGUL SYLLABLE THIEUTH YE RIEULMIEUM + 0xB765: 0xD18F, //HANGUL SYLLABLE THIEUTH YE RIEULPIEUP + 0xB766: 0xD190, //HANGUL SYLLABLE THIEUTH YE RIEULSIOS + 0xB767: 0xD191, //HANGUL SYLLABLE THIEUTH YE RIEULTHIEUTH + 0xB768: 0xD192, //HANGUL SYLLABLE THIEUTH YE RIEULPHIEUPH + 0xB769: 0xD193, //HANGUL SYLLABLE THIEUTH YE RIEULHIEUH + 0xB76A: 0xD194, //HANGUL SYLLABLE THIEUTH YE MIEUM + 0xB76B: 0xD195, //HANGUL SYLLABLE THIEUTH YE PIEUP + 0xB76C: 0xD196, //HANGUL SYLLABLE THIEUTH YE PIEUPSIOS + 0xB76D: 0xD197, //HANGUL SYLLABLE THIEUTH YE SIOS + 0xB76E: 0xD198, //HANGUL SYLLABLE THIEUTH YE SSANGSIOS + 0xB76F: 0xD199, //HANGUL SYLLABLE THIEUTH YE IEUNG + 0xB770: 0xD19A, //HANGUL SYLLABLE THIEUTH YE CIEUC + 0xB771: 0xD19B, //HANGUL SYLLABLE THIEUTH YE CHIEUCH + 0xB772: 0xD19C, //HANGUL SYLLABLE THIEUTH YE KHIEUKH + 0xB773: 0xD19D, //HANGUL SYLLABLE THIEUTH YE THIEUTH + 0xB774: 0xD19E, //HANGUL SYLLABLE THIEUTH YE PHIEUPH + 0xB775: 0xD19F, //HANGUL SYLLABLE THIEUTH YE HIEUH + 0xB776: 0xD1A2, //HANGUL SYLLABLE THIEUTH O SSANGKIYEOK + 0xB777: 0xD1A3, //HANGUL SYLLABLE THIEUTH O KIYEOKSIOS + 0xB778: 0xD1A5, //HANGUL SYLLABLE THIEUTH O NIEUNCIEUC + 0xB779: 0xD1A6, //HANGUL SYLLABLE THIEUTH O NIEUNHIEUH + 0xB77A: 0xD1A7, //HANGUL SYLLABLE THIEUTH O TIKEUT + 0xB781: 0xD1A9, //HANGUL SYLLABLE THIEUTH O RIEULKIYEOK + 0xB782: 0xD1AA, //HANGUL SYLLABLE THIEUTH O RIEULMIEUM + 0xB783: 0xD1AB, //HANGUL SYLLABLE THIEUTH O RIEULPIEUP + 0xB784: 0xD1AC, //HANGUL SYLLABLE THIEUTH O RIEULSIOS + 0xB785: 0xD1AD, //HANGUL SYLLABLE THIEUTH O RIEULTHIEUTH + 0xB786: 0xD1AE, //HANGUL SYLLABLE THIEUTH O RIEULPHIEUPH + 0xB787: 0xD1AF, //HANGUL SYLLABLE THIEUTH O RIEULHIEUH + 0xB788: 0xD1B2, //HANGUL SYLLABLE THIEUTH O PIEUPSIOS + 0xB789: 0xD1B4, //HANGUL SYLLABLE THIEUTH O SSANGSIOS + 0xB78A: 0xD1B6, //HANGUL SYLLABLE THIEUTH O CIEUC + 0xB78B: 0xD1B7, //HANGUL SYLLABLE THIEUTH O CHIEUCH + 0xB78C: 0xD1B8, //HANGUL SYLLABLE THIEUTH O KHIEUKH + 0xB78D: 0xD1B9, //HANGUL SYLLABLE THIEUTH O THIEUTH + 0xB78E: 0xD1BB, //HANGUL SYLLABLE THIEUTH O HIEUH + 0xB78F: 0xD1BD, //HANGUL SYLLABLE THIEUTH WA KIYEOK + 0xB790: 0xD1BE, //HANGUL SYLLABLE THIEUTH WA SSANGKIYEOK + 0xB791: 0xD1BF, //HANGUL SYLLABLE THIEUTH WA KIYEOKSIOS + 0xB792: 0xD1C1, //HANGUL SYLLABLE THIEUTH WA NIEUNCIEUC + 0xB793: 0xD1C2, //HANGUL SYLLABLE THIEUTH WA NIEUNHIEUH + 0xB794: 0xD1C3, //HANGUL SYLLABLE THIEUTH WA TIKEUT + 0xB795: 0xD1C4, //HANGUL SYLLABLE THIEUTH WA RIEUL + 0xB796: 0xD1C5, //HANGUL SYLLABLE THIEUTH WA RIEULKIYEOK + 0xB797: 0xD1C6, //HANGUL SYLLABLE THIEUTH WA RIEULMIEUM + 0xB798: 0xD1C7, //HANGUL SYLLABLE THIEUTH WA RIEULPIEUP + 0xB799: 0xD1C8, //HANGUL SYLLABLE THIEUTH WA RIEULSIOS + 0xB79A: 0xD1C9, //HANGUL SYLLABLE THIEUTH WA RIEULTHIEUTH + 0xB79B: 0xD1CA, //HANGUL SYLLABLE THIEUTH WA RIEULPHIEUPH + 0xB79C: 0xD1CB, //HANGUL SYLLABLE THIEUTH WA RIEULHIEUH + 0xB79D: 0xD1CC, //HANGUL SYLLABLE THIEUTH WA MIEUM + 0xB79E: 0xD1CD, //HANGUL SYLLABLE THIEUTH WA PIEUP + 0xB79F: 0xD1CE, //HANGUL SYLLABLE THIEUTH WA PIEUPSIOS + 0xB7A0: 0xD1CF, //HANGUL SYLLABLE THIEUTH WA SIOS + 0xB7A1: 0xB798, //HANGUL SYLLABLE RIEUL AE + 0xB7A2: 0xB799, //HANGUL SYLLABLE RIEUL AE KIYEOK + 0xB7A3: 0xB79C, //HANGUL SYLLABLE RIEUL AE NIEUN + 0xB7A4: 0xB7A0, //HANGUL SYLLABLE RIEUL AE RIEUL + 0xB7A5: 0xB7A8, //HANGUL SYLLABLE RIEUL AE MIEUM + 0xB7A6: 0xB7A9, //HANGUL SYLLABLE RIEUL AE PIEUP + 0xB7A7: 0xB7AB, //HANGUL SYLLABLE RIEUL AE SIOS + 0xB7A8: 0xB7AC, //HANGUL SYLLABLE RIEUL AE SSANGSIOS + 0xB7A9: 0xB7AD, //HANGUL SYLLABLE RIEUL AE IEUNG + 0xB7AA: 0xB7B4, //HANGUL SYLLABLE RIEUL YA + 0xB7AB: 0xB7B5, //HANGUL SYLLABLE RIEUL YA KIYEOK + 0xB7AC: 0xB7B8, //HANGUL SYLLABLE RIEUL YA NIEUN + 0xB7AD: 0xB7C7, //HANGUL SYLLABLE RIEUL YA SIOS + 0xB7AE: 0xB7C9, //HANGUL SYLLABLE RIEUL YA IEUNG + 0xB7AF: 0xB7EC, //HANGUL SYLLABLE RIEUL EO + 0xB7B0: 0xB7ED, //HANGUL SYLLABLE RIEUL EO KIYEOK + 0xB7B1: 0xB7F0, //HANGUL SYLLABLE RIEUL EO NIEUN + 0xB7B2: 0xB7F4, //HANGUL SYLLABLE RIEUL EO RIEUL + 0xB7B3: 0xB7FC, //HANGUL SYLLABLE RIEUL EO MIEUM + 0xB7B4: 0xB7FD, //HANGUL SYLLABLE RIEUL EO PIEUP + 0xB7B5: 0xB7FF, //HANGUL SYLLABLE RIEUL EO SIOS + 0xB7B6: 0xB800, //HANGUL SYLLABLE RIEUL EO SSANGSIOS + 0xB7B7: 0xB801, //HANGUL SYLLABLE RIEUL EO IEUNG + 0xB7B8: 0xB807, //HANGUL SYLLABLE RIEUL EO HIEUH + 0xB7B9: 0xB808, //HANGUL SYLLABLE RIEUL E + 0xB7BA: 0xB809, //HANGUL SYLLABLE RIEUL E KIYEOK + 0xB7BB: 0xB80C, //HANGUL SYLLABLE RIEUL E NIEUN + 0xB7BC: 0xB810, //HANGUL SYLLABLE RIEUL E RIEUL + 0xB7BD: 0xB818, //HANGUL SYLLABLE RIEUL E MIEUM + 0xB7BE: 0xB819, //HANGUL SYLLABLE RIEUL E PIEUP + 0xB7BF: 0xB81B, //HANGUL SYLLABLE RIEUL E SIOS + 0xB7C0: 0xB81D, //HANGUL SYLLABLE RIEUL E IEUNG + 0xB7C1: 0xB824, //HANGUL SYLLABLE RIEUL YEO + 0xB7C2: 0xB825, //HANGUL SYLLABLE RIEUL YEO KIYEOK + 0xB7C3: 0xB828, //HANGUL SYLLABLE RIEUL YEO NIEUN + 0xB7C4: 0xB82C, //HANGUL SYLLABLE RIEUL YEO RIEUL + 0xB7C5: 0xB834, //HANGUL SYLLABLE RIEUL YEO MIEUM + 0xB7C6: 0xB835, //HANGUL SYLLABLE RIEUL YEO PIEUP + 0xB7C7: 0xB837, //HANGUL SYLLABLE RIEUL YEO SIOS + 0xB7C8: 0xB838, //HANGUL SYLLABLE RIEUL YEO SSANGSIOS + 0xB7C9: 0xB839, //HANGUL SYLLABLE RIEUL YEO IEUNG + 0xB7CA: 0xB840, //HANGUL SYLLABLE RIEUL YE + 0xB7CB: 0xB844, //HANGUL SYLLABLE RIEUL YE NIEUN + 0xB7CC: 0xB851, //HANGUL SYLLABLE RIEUL YE PIEUP + 0xB7CD: 0xB853, //HANGUL SYLLABLE RIEUL YE SIOS + 0xB7CE: 0xB85C, //HANGUL SYLLABLE RIEUL O + 0xB7CF: 0xB85D, //HANGUL SYLLABLE RIEUL O KIYEOK + 0xB7D0: 0xB860, //HANGUL SYLLABLE RIEUL O NIEUN + 0xB7D1: 0xB864, //HANGUL SYLLABLE RIEUL O RIEUL + 0xB7D2: 0xB86C, //HANGUL SYLLABLE RIEUL O MIEUM + 0xB7D3: 0xB86D, //HANGUL SYLLABLE RIEUL O PIEUP + 0xB7D4: 0xB86F, //HANGUL SYLLABLE RIEUL O SIOS + 0xB7D5: 0xB871, //HANGUL SYLLABLE RIEUL O IEUNG + 0xB7D6: 0xB878, //HANGUL SYLLABLE RIEUL WA + 0xB7D7: 0xB87C, //HANGUL SYLLABLE RIEUL WA NIEUN + 0xB7D8: 0xB88D, //HANGUL SYLLABLE RIEUL WA IEUNG + 0xB7D9: 0xB8A8, //HANGUL SYLLABLE RIEUL WAE SSANGSIOS + 0xB7DA: 0xB8B0, //HANGUL SYLLABLE RIEUL OE + 0xB7DB: 0xB8B4, //HANGUL SYLLABLE RIEUL OE NIEUN + 0xB7DC: 0xB8B8, //HANGUL SYLLABLE RIEUL OE RIEUL + 0xB7DD: 0xB8C0, //HANGUL SYLLABLE RIEUL OE MIEUM + 0xB7DE: 0xB8C1, //HANGUL SYLLABLE RIEUL OE PIEUP + 0xB7DF: 0xB8C3, //HANGUL SYLLABLE RIEUL OE SIOS + 0xB7E0: 0xB8C5, //HANGUL SYLLABLE RIEUL OE IEUNG + 0xB7E1: 0xB8CC, //HANGUL SYLLABLE RIEUL YO + 0xB7E2: 0xB8D0, //HANGUL SYLLABLE RIEUL YO NIEUN + 0xB7E3: 0xB8D4, //HANGUL SYLLABLE RIEUL YO RIEUL + 0xB7E4: 0xB8DD, //HANGUL SYLLABLE RIEUL YO PIEUP + 0xB7E5: 0xB8DF, //HANGUL SYLLABLE RIEUL YO SIOS + 0xB7E6: 0xB8E1, //HANGUL SYLLABLE RIEUL YO IEUNG + 0xB7E7: 0xB8E8, //HANGUL SYLLABLE RIEUL U + 0xB7E8: 0xB8E9, //HANGUL SYLLABLE RIEUL U KIYEOK + 0xB7E9: 0xB8EC, //HANGUL SYLLABLE RIEUL U NIEUN + 0xB7EA: 0xB8F0, //HANGUL SYLLABLE RIEUL U RIEUL + 0xB7EB: 0xB8F8, //HANGUL SYLLABLE RIEUL U MIEUM + 0xB7EC: 0xB8F9, //HANGUL SYLLABLE RIEUL U PIEUP + 0xB7ED: 0xB8FB, //HANGUL SYLLABLE RIEUL U SIOS + 0xB7EE: 0xB8FD, //HANGUL SYLLABLE RIEUL U IEUNG + 0xB7EF: 0xB904, //HANGUL SYLLABLE RIEUL WEO + 0xB7F0: 0xB918, //HANGUL SYLLABLE RIEUL WEO SSANGSIOS + 0xB7F1: 0xB920, //HANGUL SYLLABLE RIEUL WE + 0xB7F2: 0xB93C, //HANGUL SYLLABLE RIEUL WI + 0xB7F3: 0xB93D, //HANGUL SYLLABLE RIEUL WI KIYEOK + 0xB7F4: 0xB940, //HANGUL SYLLABLE RIEUL WI NIEUN + 0xB7F5: 0xB944, //HANGUL SYLLABLE RIEUL WI RIEUL + 0xB7F6: 0xB94C, //HANGUL SYLLABLE RIEUL WI MIEUM + 0xB7F7: 0xB94F, //HANGUL SYLLABLE RIEUL WI SIOS + 0xB7F8: 0xB951, //HANGUL SYLLABLE RIEUL WI IEUNG + 0xB7F9: 0xB958, //HANGUL SYLLABLE RIEUL YU + 0xB7FA: 0xB959, //HANGUL SYLLABLE RIEUL YU KIYEOK + 0xB7FB: 0xB95C, //HANGUL SYLLABLE RIEUL YU NIEUN + 0xB7FC: 0xB960, //HANGUL SYLLABLE RIEUL YU RIEUL + 0xB7FD: 0xB968, //HANGUL SYLLABLE RIEUL YU MIEUM + 0xB7FE: 0xB969, //HANGUL SYLLABLE RIEUL YU PIEUP + 0xB841: 0xD1D0, //HANGUL SYLLABLE THIEUTH WA SSANGSIOS + 0xB842: 0xD1D1, //HANGUL SYLLABLE THIEUTH WA IEUNG + 0xB843: 0xD1D2, //HANGUL SYLLABLE THIEUTH WA CIEUC + 0xB844: 0xD1D3, //HANGUL SYLLABLE THIEUTH WA CHIEUCH + 0xB845: 0xD1D4, //HANGUL SYLLABLE THIEUTH WA KHIEUKH + 0xB846: 0xD1D5, //HANGUL SYLLABLE THIEUTH WA THIEUTH + 0xB847: 0xD1D6, //HANGUL SYLLABLE THIEUTH WA PHIEUPH + 0xB848: 0xD1D7, //HANGUL SYLLABLE THIEUTH WA HIEUH + 0xB849: 0xD1D9, //HANGUL SYLLABLE THIEUTH WAE KIYEOK + 0xB84A: 0xD1DA, //HANGUL SYLLABLE THIEUTH WAE SSANGKIYEOK + 0xB84B: 0xD1DB, //HANGUL SYLLABLE THIEUTH WAE KIYEOKSIOS + 0xB84C: 0xD1DC, //HANGUL SYLLABLE THIEUTH WAE NIEUN + 0xB84D: 0xD1DD, //HANGUL SYLLABLE THIEUTH WAE NIEUNCIEUC + 0xB84E: 0xD1DE, //HANGUL SYLLABLE THIEUTH WAE NIEUNHIEUH + 0xB84F: 0xD1DF, //HANGUL SYLLABLE THIEUTH WAE TIKEUT + 0xB850: 0xD1E0, //HANGUL SYLLABLE THIEUTH WAE RIEUL + 0xB851: 0xD1E1, //HANGUL SYLLABLE THIEUTH WAE RIEULKIYEOK + 0xB852: 0xD1E2, //HANGUL SYLLABLE THIEUTH WAE RIEULMIEUM + 0xB853: 0xD1E3, //HANGUL SYLLABLE THIEUTH WAE RIEULPIEUP + 0xB854: 0xD1E4, //HANGUL SYLLABLE THIEUTH WAE RIEULSIOS + 0xB855: 0xD1E5, //HANGUL SYLLABLE THIEUTH WAE RIEULTHIEUTH + 0xB856: 0xD1E6, //HANGUL SYLLABLE THIEUTH WAE RIEULPHIEUPH + 0xB857: 0xD1E7, //HANGUL SYLLABLE THIEUTH WAE RIEULHIEUH + 0xB858: 0xD1E8, //HANGUL SYLLABLE THIEUTH WAE MIEUM + 0xB859: 0xD1E9, //HANGUL SYLLABLE THIEUTH WAE PIEUP + 0xB85A: 0xD1EA, //HANGUL SYLLABLE THIEUTH WAE PIEUPSIOS + 0xB861: 0xD1EB, //HANGUL SYLLABLE THIEUTH WAE SIOS + 0xB862: 0xD1EC, //HANGUL SYLLABLE THIEUTH WAE SSANGSIOS + 0xB863: 0xD1ED, //HANGUL SYLLABLE THIEUTH WAE IEUNG + 0xB864: 0xD1EE, //HANGUL SYLLABLE THIEUTH WAE CIEUC + 0xB865: 0xD1EF, //HANGUL SYLLABLE THIEUTH WAE CHIEUCH + 0xB866: 0xD1F0, //HANGUL SYLLABLE THIEUTH WAE KHIEUKH + 0xB867: 0xD1F1, //HANGUL SYLLABLE THIEUTH WAE THIEUTH + 0xB868: 0xD1F2, //HANGUL SYLLABLE THIEUTH WAE PHIEUPH + 0xB869: 0xD1F3, //HANGUL SYLLABLE THIEUTH WAE HIEUH + 0xB86A: 0xD1F5, //HANGUL SYLLABLE THIEUTH OE KIYEOK + 0xB86B: 0xD1F6, //HANGUL SYLLABLE THIEUTH OE SSANGKIYEOK + 0xB86C: 0xD1F7, //HANGUL SYLLABLE THIEUTH OE KIYEOKSIOS + 0xB86D: 0xD1F9, //HANGUL SYLLABLE THIEUTH OE NIEUNCIEUC + 0xB86E: 0xD1FA, //HANGUL SYLLABLE THIEUTH OE NIEUNHIEUH + 0xB86F: 0xD1FB, //HANGUL SYLLABLE THIEUTH OE TIKEUT + 0xB870: 0xD1FC, //HANGUL SYLLABLE THIEUTH OE RIEUL + 0xB871: 0xD1FD, //HANGUL SYLLABLE THIEUTH OE RIEULKIYEOK + 0xB872: 0xD1FE, //HANGUL SYLLABLE THIEUTH OE RIEULMIEUM + 0xB873: 0xD1FF, //HANGUL SYLLABLE THIEUTH OE RIEULPIEUP + 0xB874: 0xD200, //HANGUL SYLLABLE THIEUTH OE RIEULSIOS + 0xB875: 0xD201, //HANGUL SYLLABLE THIEUTH OE RIEULTHIEUTH + 0xB876: 0xD202, //HANGUL SYLLABLE THIEUTH OE RIEULPHIEUPH + 0xB877: 0xD203, //HANGUL SYLLABLE THIEUTH OE RIEULHIEUH + 0xB878: 0xD204, //HANGUL SYLLABLE THIEUTH OE MIEUM + 0xB879: 0xD205, //HANGUL SYLLABLE THIEUTH OE PIEUP + 0xB87A: 0xD206, //HANGUL SYLLABLE THIEUTH OE PIEUPSIOS + 0xB881: 0xD208, //HANGUL SYLLABLE THIEUTH OE SSANGSIOS + 0xB882: 0xD20A, //HANGUL SYLLABLE THIEUTH OE CIEUC + 0xB883: 0xD20B, //HANGUL SYLLABLE THIEUTH OE CHIEUCH + 0xB884: 0xD20C, //HANGUL SYLLABLE THIEUTH OE KHIEUKH + 0xB885: 0xD20D, //HANGUL SYLLABLE THIEUTH OE THIEUTH + 0xB886: 0xD20E, //HANGUL SYLLABLE THIEUTH OE PHIEUPH + 0xB887: 0xD20F, //HANGUL SYLLABLE THIEUTH OE HIEUH + 0xB888: 0xD211, //HANGUL SYLLABLE THIEUTH YO KIYEOK + 0xB889: 0xD212, //HANGUL SYLLABLE THIEUTH YO SSANGKIYEOK + 0xB88A: 0xD213, //HANGUL SYLLABLE THIEUTH YO KIYEOKSIOS + 0xB88B: 0xD214, //HANGUL SYLLABLE THIEUTH YO NIEUN + 0xB88C: 0xD215, //HANGUL SYLLABLE THIEUTH YO NIEUNCIEUC + 0xB88D: 0xD216, //HANGUL SYLLABLE THIEUTH YO NIEUNHIEUH + 0xB88E: 0xD217, //HANGUL SYLLABLE THIEUTH YO TIKEUT + 0xB88F: 0xD218, //HANGUL SYLLABLE THIEUTH YO RIEUL + 0xB890: 0xD219, //HANGUL SYLLABLE THIEUTH YO RIEULKIYEOK + 0xB891: 0xD21A, //HANGUL SYLLABLE THIEUTH YO RIEULMIEUM + 0xB892: 0xD21B, //HANGUL SYLLABLE THIEUTH YO RIEULPIEUP + 0xB893: 0xD21C, //HANGUL SYLLABLE THIEUTH YO RIEULSIOS + 0xB894: 0xD21D, //HANGUL SYLLABLE THIEUTH YO RIEULTHIEUTH + 0xB895: 0xD21E, //HANGUL SYLLABLE THIEUTH YO RIEULPHIEUPH + 0xB896: 0xD21F, //HANGUL SYLLABLE THIEUTH YO RIEULHIEUH + 0xB897: 0xD220, //HANGUL SYLLABLE THIEUTH YO MIEUM + 0xB898: 0xD221, //HANGUL SYLLABLE THIEUTH YO PIEUP + 0xB899: 0xD222, //HANGUL SYLLABLE THIEUTH YO PIEUPSIOS + 0xB89A: 0xD223, //HANGUL SYLLABLE THIEUTH YO SIOS + 0xB89B: 0xD224, //HANGUL SYLLABLE THIEUTH YO SSANGSIOS + 0xB89C: 0xD225, //HANGUL SYLLABLE THIEUTH YO IEUNG + 0xB89D: 0xD226, //HANGUL SYLLABLE THIEUTH YO CIEUC + 0xB89E: 0xD227, //HANGUL SYLLABLE THIEUTH YO CHIEUCH + 0xB89F: 0xD228, //HANGUL SYLLABLE THIEUTH YO KHIEUKH + 0xB8A0: 0xD229, //HANGUL SYLLABLE THIEUTH YO THIEUTH + 0xB8A1: 0xB96B, //HANGUL SYLLABLE RIEUL YU SIOS + 0xB8A2: 0xB96D, //HANGUL SYLLABLE RIEUL YU IEUNG + 0xB8A3: 0xB974, //HANGUL SYLLABLE RIEUL EU + 0xB8A4: 0xB975, //HANGUL SYLLABLE RIEUL EU KIYEOK + 0xB8A5: 0xB978, //HANGUL SYLLABLE RIEUL EU NIEUN + 0xB8A6: 0xB97C, //HANGUL SYLLABLE RIEUL EU RIEUL + 0xB8A7: 0xB984, //HANGUL SYLLABLE RIEUL EU MIEUM + 0xB8A8: 0xB985, //HANGUL SYLLABLE RIEUL EU PIEUP + 0xB8A9: 0xB987, //HANGUL SYLLABLE RIEUL EU SIOS + 0xB8AA: 0xB989, //HANGUL SYLLABLE RIEUL EU IEUNG + 0xB8AB: 0xB98A, //HANGUL SYLLABLE RIEUL EU CIEUC + 0xB8AC: 0xB98D, //HANGUL SYLLABLE RIEUL EU THIEUTH + 0xB8AD: 0xB98E, //HANGUL SYLLABLE RIEUL EU PHIEUPH + 0xB8AE: 0xB9AC, //HANGUL SYLLABLE RIEUL I + 0xB8AF: 0xB9AD, //HANGUL SYLLABLE RIEUL I KIYEOK + 0xB8B0: 0xB9B0, //HANGUL SYLLABLE RIEUL I NIEUN + 0xB8B1: 0xB9B4, //HANGUL SYLLABLE RIEUL I RIEUL + 0xB8B2: 0xB9BC, //HANGUL SYLLABLE RIEUL I MIEUM + 0xB8B3: 0xB9BD, //HANGUL SYLLABLE RIEUL I PIEUP + 0xB8B4: 0xB9BF, //HANGUL SYLLABLE RIEUL I SIOS + 0xB8B5: 0xB9C1, //HANGUL SYLLABLE RIEUL I IEUNG + 0xB8B6: 0xB9C8, //HANGUL SYLLABLE MIEUM A + 0xB8B7: 0xB9C9, //HANGUL SYLLABLE MIEUM A KIYEOK + 0xB8B8: 0xB9CC, //HANGUL SYLLABLE MIEUM A NIEUN + 0xB8B9: 0xB9CE, //HANGUL SYLLABLE MIEUM A NIEUNHIEUH + 0xB8BA: 0xB9CF, //HANGUL SYLLABLE MIEUM A TIKEUT + 0xB8BB: 0xB9D0, //HANGUL SYLLABLE MIEUM A RIEUL + 0xB8BC: 0xB9D1, //HANGUL SYLLABLE MIEUM A RIEULKIYEOK + 0xB8BD: 0xB9D2, //HANGUL SYLLABLE MIEUM A RIEULMIEUM + 0xB8BE: 0xB9D8, //HANGUL SYLLABLE MIEUM A MIEUM + 0xB8BF: 0xB9D9, //HANGUL SYLLABLE MIEUM A PIEUP + 0xB8C0: 0xB9DB, //HANGUL SYLLABLE MIEUM A SIOS + 0xB8C1: 0xB9DD, //HANGUL SYLLABLE MIEUM A IEUNG + 0xB8C2: 0xB9DE, //HANGUL SYLLABLE MIEUM A CIEUC + 0xB8C3: 0xB9E1, //HANGUL SYLLABLE MIEUM A THIEUTH + 0xB8C4: 0xB9E3, //HANGUL SYLLABLE MIEUM A HIEUH + 0xB8C5: 0xB9E4, //HANGUL SYLLABLE MIEUM AE + 0xB8C6: 0xB9E5, //HANGUL SYLLABLE MIEUM AE KIYEOK + 0xB8C7: 0xB9E8, //HANGUL SYLLABLE MIEUM AE NIEUN + 0xB8C8: 0xB9EC, //HANGUL SYLLABLE MIEUM AE RIEUL + 0xB8C9: 0xB9F4, //HANGUL SYLLABLE MIEUM AE MIEUM + 0xB8CA: 0xB9F5, //HANGUL SYLLABLE MIEUM AE PIEUP + 0xB8CB: 0xB9F7, //HANGUL SYLLABLE MIEUM AE SIOS + 0xB8CC: 0xB9F8, //HANGUL SYLLABLE MIEUM AE SSANGSIOS + 0xB8CD: 0xB9F9, //HANGUL SYLLABLE MIEUM AE IEUNG + 0xB8CE: 0xB9FA, //HANGUL SYLLABLE MIEUM AE CIEUC + 0xB8CF: 0xBA00, //HANGUL SYLLABLE MIEUM YA + 0xB8D0: 0xBA01, //HANGUL SYLLABLE MIEUM YA KIYEOK + 0xB8D1: 0xBA08, //HANGUL SYLLABLE MIEUM YA RIEUL + 0xB8D2: 0xBA15, //HANGUL SYLLABLE MIEUM YA IEUNG + 0xB8D3: 0xBA38, //HANGUL SYLLABLE MIEUM EO + 0xB8D4: 0xBA39, //HANGUL SYLLABLE MIEUM EO KIYEOK + 0xB8D5: 0xBA3C, //HANGUL SYLLABLE MIEUM EO NIEUN + 0xB8D6: 0xBA40, //HANGUL SYLLABLE MIEUM EO RIEUL + 0xB8D7: 0xBA42, //HANGUL SYLLABLE MIEUM EO RIEULMIEUM + 0xB8D8: 0xBA48, //HANGUL SYLLABLE MIEUM EO MIEUM + 0xB8D9: 0xBA49, //HANGUL SYLLABLE MIEUM EO PIEUP + 0xB8DA: 0xBA4B, //HANGUL SYLLABLE MIEUM EO SIOS + 0xB8DB: 0xBA4D, //HANGUL SYLLABLE MIEUM EO IEUNG + 0xB8DC: 0xBA4E, //HANGUL SYLLABLE MIEUM EO CIEUC + 0xB8DD: 0xBA53, //HANGUL SYLLABLE MIEUM EO HIEUH + 0xB8DE: 0xBA54, //HANGUL SYLLABLE MIEUM E + 0xB8DF: 0xBA55, //HANGUL SYLLABLE MIEUM E KIYEOK + 0xB8E0: 0xBA58, //HANGUL SYLLABLE MIEUM E NIEUN + 0xB8E1: 0xBA5C, //HANGUL SYLLABLE MIEUM E RIEUL + 0xB8E2: 0xBA64, //HANGUL SYLLABLE MIEUM E MIEUM + 0xB8E3: 0xBA65, //HANGUL SYLLABLE MIEUM E PIEUP + 0xB8E4: 0xBA67, //HANGUL SYLLABLE MIEUM E SIOS + 0xB8E5: 0xBA68, //HANGUL SYLLABLE MIEUM E SSANGSIOS + 0xB8E6: 0xBA69, //HANGUL SYLLABLE MIEUM E IEUNG + 0xB8E7: 0xBA70, //HANGUL SYLLABLE MIEUM YEO + 0xB8E8: 0xBA71, //HANGUL SYLLABLE MIEUM YEO KIYEOK + 0xB8E9: 0xBA74, //HANGUL SYLLABLE MIEUM YEO NIEUN + 0xB8EA: 0xBA78, //HANGUL SYLLABLE MIEUM YEO RIEUL + 0xB8EB: 0xBA83, //HANGUL SYLLABLE MIEUM YEO SIOS + 0xB8EC: 0xBA84, //HANGUL SYLLABLE MIEUM YEO SSANGSIOS + 0xB8ED: 0xBA85, //HANGUL SYLLABLE MIEUM YEO IEUNG + 0xB8EE: 0xBA87, //HANGUL SYLLABLE MIEUM YEO CHIEUCH + 0xB8EF: 0xBA8C, //HANGUL SYLLABLE MIEUM YE + 0xB8F0: 0xBAA8, //HANGUL SYLLABLE MIEUM O + 0xB8F1: 0xBAA9, //HANGUL SYLLABLE MIEUM O KIYEOK + 0xB8F2: 0xBAAB, //HANGUL SYLLABLE MIEUM O KIYEOKSIOS + 0xB8F3: 0xBAAC, //HANGUL SYLLABLE MIEUM O NIEUN + 0xB8F4: 0xBAB0, //HANGUL SYLLABLE MIEUM O RIEUL + 0xB8F5: 0xBAB2, //HANGUL SYLLABLE MIEUM O RIEULMIEUM + 0xB8F6: 0xBAB8, //HANGUL SYLLABLE MIEUM O MIEUM + 0xB8F7: 0xBAB9, //HANGUL SYLLABLE MIEUM O PIEUP + 0xB8F8: 0xBABB, //HANGUL SYLLABLE MIEUM O SIOS + 0xB8F9: 0xBABD, //HANGUL SYLLABLE MIEUM O IEUNG + 0xB8FA: 0xBAC4, //HANGUL SYLLABLE MIEUM WA + 0xB8FB: 0xBAC8, //HANGUL SYLLABLE MIEUM WA NIEUN + 0xB8FC: 0xBAD8, //HANGUL SYLLABLE MIEUM WA SSANGSIOS + 0xB8FD: 0xBAD9, //HANGUL SYLLABLE MIEUM WA IEUNG + 0xB8FE: 0xBAFC, //HANGUL SYLLABLE MIEUM OE + 0xB941: 0xD22A, //HANGUL SYLLABLE THIEUTH YO PHIEUPH + 0xB942: 0xD22B, //HANGUL SYLLABLE THIEUTH YO HIEUH + 0xB943: 0xD22E, //HANGUL SYLLABLE THIEUTH U SSANGKIYEOK + 0xB944: 0xD22F, //HANGUL SYLLABLE THIEUTH U KIYEOKSIOS + 0xB945: 0xD231, //HANGUL SYLLABLE THIEUTH U NIEUNCIEUC + 0xB946: 0xD232, //HANGUL SYLLABLE THIEUTH U NIEUNHIEUH + 0xB947: 0xD233, //HANGUL SYLLABLE THIEUTH U TIKEUT + 0xB948: 0xD235, //HANGUL SYLLABLE THIEUTH U RIEULKIYEOK + 0xB949: 0xD236, //HANGUL SYLLABLE THIEUTH U RIEULMIEUM + 0xB94A: 0xD237, //HANGUL SYLLABLE THIEUTH U RIEULPIEUP + 0xB94B: 0xD238, //HANGUL SYLLABLE THIEUTH U RIEULSIOS + 0xB94C: 0xD239, //HANGUL SYLLABLE THIEUTH U RIEULTHIEUTH + 0xB94D: 0xD23A, //HANGUL SYLLABLE THIEUTH U RIEULPHIEUPH + 0xB94E: 0xD23B, //HANGUL SYLLABLE THIEUTH U RIEULHIEUH + 0xB94F: 0xD23E, //HANGUL SYLLABLE THIEUTH U PIEUPSIOS + 0xB950: 0xD240, //HANGUL SYLLABLE THIEUTH U SSANGSIOS + 0xB951: 0xD242, //HANGUL SYLLABLE THIEUTH U CIEUC + 0xB952: 0xD243, //HANGUL SYLLABLE THIEUTH U CHIEUCH + 0xB953: 0xD244, //HANGUL SYLLABLE THIEUTH U KHIEUKH + 0xB954: 0xD245, //HANGUL SYLLABLE THIEUTH U THIEUTH + 0xB955: 0xD246, //HANGUL SYLLABLE THIEUTH U PHIEUPH + 0xB956: 0xD247, //HANGUL SYLLABLE THIEUTH U HIEUH + 0xB957: 0xD249, //HANGUL SYLLABLE THIEUTH WEO KIYEOK + 0xB958: 0xD24A, //HANGUL SYLLABLE THIEUTH WEO SSANGKIYEOK + 0xB959: 0xD24B, //HANGUL SYLLABLE THIEUTH WEO KIYEOKSIOS + 0xB95A: 0xD24C, //HANGUL SYLLABLE THIEUTH WEO NIEUN + 0xB961: 0xD24D, //HANGUL SYLLABLE THIEUTH WEO NIEUNCIEUC + 0xB962: 0xD24E, //HANGUL SYLLABLE THIEUTH WEO NIEUNHIEUH + 0xB963: 0xD24F, //HANGUL SYLLABLE THIEUTH WEO TIKEUT + 0xB964: 0xD250, //HANGUL SYLLABLE THIEUTH WEO RIEUL + 0xB965: 0xD251, //HANGUL SYLLABLE THIEUTH WEO RIEULKIYEOK + 0xB966: 0xD252, //HANGUL SYLLABLE THIEUTH WEO RIEULMIEUM + 0xB967: 0xD253, //HANGUL SYLLABLE THIEUTH WEO RIEULPIEUP + 0xB968: 0xD254, //HANGUL SYLLABLE THIEUTH WEO RIEULSIOS + 0xB969: 0xD255, //HANGUL SYLLABLE THIEUTH WEO RIEULTHIEUTH + 0xB96A: 0xD256, //HANGUL SYLLABLE THIEUTH WEO RIEULPHIEUPH + 0xB96B: 0xD257, //HANGUL SYLLABLE THIEUTH WEO RIEULHIEUH + 0xB96C: 0xD258, //HANGUL SYLLABLE THIEUTH WEO MIEUM + 0xB96D: 0xD259, //HANGUL SYLLABLE THIEUTH WEO PIEUP + 0xB96E: 0xD25A, //HANGUL SYLLABLE THIEUTH WEO PIEUPSIOS + 0xB96F: 0xD25B, //HANGUL SYLLABLE THIEUTH WEO SIOS + 0xB970: 0xD25D, //HANGUL SYLLABLE THIEUTH WEO IEUNG + 0xB971: 0xD25E, //HANGUL SYLLABLE THIEUTH WEO CIEUC + 0xB972: 0xD25F, //HANGUL SYLLABLE THIEUTH WEO CHIEUCH + 0xB973: 0xD260, //HANGUL SYLLABLE THIEUTH WEO KHIEUKH + 0xB974: 0xD261, //HANGUL SYLLABLE THIEUTH WEO THIEUTH + 0xB975: 0xD262, //HANGUL SYLLABLE THIEUTH WEO PHIEUPH + 0xB976: 0xD263, //HANGUL SYLLABLE THIEUTH WEO HIEUH + 0xB977: 0xD265, //HANGUL SYLLABLE THIEUTH WE KIYEOK + 0xB978: 0xD266, //HANGUL SYLLABLE THIEUTH WE SSANGKIYEOK + 0xB979: 0xD267, //HANGUL SYLLABLE THIEUTH WE KIYEOKSIOS + 0xB97A: 0xD268, //HANGUL SYLLABLE THIEUTH WE NIEUN + 0xB981: 0xD269, //HANGUL SYLLABLE THIEUTH WE NIEUNCIEUC + 0xB982: 0xD26A, //HANGUL SYLLABLE THIEUTH WE NIEUNHIEUH + 0xB983: 0xD26B, //HANGUL SYLLABLE THIEUTH WE TIKEUT + 0xB984: 0xD26C, //HANGUL SYLLABLE THIEUTH WE RIEUL + 0xB985: 0xD26D, //HANGUL SYLLABLE THIEUTH WE RIEULKIYEOK + 0xB986: 0xD26E, //HANGUL SYLLABLE THIEUTH WE RIEULMIEUM + 0xB987: 0xD26F, //HANGUL SYLLABLE THIEUTH WE RIEULPIEUP + 0xB988: 0xD270, //HANGUL SYLLABLE THIEUTH WE RIEULSIOS + 0xB989: 0xD271, //HANGUL SYLLABLE THIEUTH WE RIEULTHIEUTH + 0xB98A: 0xD272, //HANGUL SYLLABLE THIEUTH WE RIEULPHIEUPH + 0xB98B: 0xD273, //HANGUL SYLLABLE THIEUTH WE RIEULHIEUH + 0xB98C: 0xD274, //HANGUL SYLLABLE THIEUTH WE MIEUM + 0xB98D: 0xD275, //HANGUL SYLLABLE THIEUTH WE PIEUP + 0xB98E: 0xD276, //HANGUL SYLLABLE THIEUTH WE PIEUPSIOS + 0xB98F: 0xD277, //HANGUL SYLLABLE THIEUTH WE SIOS + 0xB990: 0xD278, //HANGUL SYLLABLE THIEUTH WE SSANGSIOS + 0xB991: 0xD279, //HANGUL SYLLABLE THIEUTH WE IEUNG + 0xB992: 0xD27A, //HANGUL SYLLABLE THIEUTH WE CIEUC + 0xB993: 0xD27B, //HANGUL SYLLABLE THIEUTH WE CHIEUCH + 0xB994: 0xD27C, //HANGUL SYLLABLE THIEUTH WE KHIEUKH + 0xB995: 0xD27D, //HANGUL SYLLABLE THIEUTH WE THIEUTH + 0xB996: 0xD27E, //HANGUL SYLLABLE THIEUTH WE PHIEUPH + 0xB997: 0xD27F, //HANGUL SYLLABLE THIEUTH WE HIEUH + 0xB998: 0xD282, //HANGUL SYLLABLE THIEUTH WI SSANGKIYEOK + 0xB999: 0xD283, //HANGUL SYLLABLE THIEUTH WI KIYEOKSIOS + 0xB99A: 0xD285, //HANGUL SYLLABLE THIEUTH WI NIEUNCIEUC + 0xB99B: 0xD286, //HANGUL SYLLABLE THIEUTH WI NIEUNHIEUH + 0xB99C: 0xD287, //HANGUL SYLLABLE THIEUTH WI TIKEUT + 0xB99D: 0xD289, //HANGUL SYLLABLE THIEUTH WI RIEULKIYEOK + 0xB99E: 0xD28A, //HANGUL SYLLABLE THIEUTH WI RIEULMIEUM + 0xB99F: 0xD28B, //HANGUL SYLLABLE THIEUTH WI RIEULPIEUP + 0xB9A0: 0xD28C, //HANGUL SYLLABLE THIEUTH WI RIEULSIOS + 0xB9A1: 0xBB00, //HANGUL SYLLABLE MIEUM OE NIEUN + 0xB9A2: 0xBB04, //HANGUL SYLLABLE MIEUM OE RIEUL + 0xB9A3: 0xBB0D, //HANGUL SYLLABLE MIEUM OE PIEUP + 0xB9A4: 0xBB0F, //HANGUL SYLLABLE MIEUM OE SIOS + 0xB9A5: 0xBB11, //HANGUL SYLLABLE MIEUM OE IEUNG + 0xB9A6: 0xBB18, //HANGUL SYLLABLE MIEUM YO + 0xB9A7: 0xBB1C, //HANGUL SYLLABLE MIEUM YO NIEUN + 0xB9A8: 0xBB20, //HANGUL SYLLABLE MIEUM YO RIEUL + 0xB9A9: 0xBB29, //HANGUL SYLLABLE MIEUM YO PIEUP + 0xB9AA: 0xBB2B, //HANGUL SYLLABLE MIEUM YO SIOS + 0xB9AB: 0xBB34, //HANGUL SYLLABLE MIEUM U + 0xB9AC: 0xBB35, //HANGUL SYLLABLE MIEUM U KIYEOK + 0xB9AD: 0xBB36, //HANGUL SYLLABLE MIEUM U SSANGKIYEOK + 0xB9AE: 0xBB38, //HANGUL SYLLABLE MIEUM U NIEUN + 0xB9AF: 0xBB3B, //HANGUL SYLLABLE MIEUM U TIKEUT + 0xB9B0: 0xBB3C, //HANGUL SYLLABLE MIEUM U RIEUL + 0xB9B1: 0xBB3D, //HANGUL SYLLABLE MIEUM U RIEULKIYEOK + 0xB9B2: 0xBB3E, //HANGUL SYLLABLE MIEUM U RIEULMIEUM + 0xB9B3: 0xBB44, //HANGUL SYLLABLE MIEUM U MIEUM + 0xB9B4: 0xBB45, //HANGUL SYLLABLE MIEUM U PIEUP + 0xB9B5: 0xBB47, //HANGUL SYLLABLE MIEUM U SIOS + 0xB9B6: 0xBB49, //HANGUL SYLLABLE MIEUM U IEUNG + 0xB9B7: 0xBB4D, //HANGUL SYLLABLE MIEUM U THIEUTH + 0xB9B8: 0xBB4F, //HANGUL SYLLABLE MIEUM U HIEUH + 0xB9B9: 0xBB50, //HANGUL SYLLABLE MIEUM WEO + 0xB9BA: 0xBB54, //HANGUL SYLLABLE MIEUM WEO NIEUN + 0xB9BB: 0xBB58, //HANGUL SYLLABLE MIEUM WEO RIEUL + 0xB9BC: 0xBB61, //HANGUL SYLLABLE MIEUM WEO PIEUP + 0xB9BD: 0xBB63, //HANGUL SYLLABLE MIEUM WEO SIOS + 0xB9BE: 0xBB6C, //HANGUL SYLLABLE MIEUM WE + 0xB9BF: 0xBB88, //HANGUL SYLLABLE MIEUM WI + 0xB9C0: 0xBB8C, //HANGUL SYLLABLE MIEUM WI NIEUN + 0xB9C1: 0xBB90, //HANGUL SYLLABLE MIEUM WI RIEUL + 0xB9C2: 0xBBA4, //HANGUL SYLLABLE MIEUM YU + 0xB9C3: 0xBBA8, //HANGUL SYLLABLE MIEUM YU NIEUN + 0xB9C4: 0xBBAC, //HANGUL SYLLABLE MIEUM YU RIEUL + 0xB9C5: 0xBBB4, //HANGUL SYLLABLE MIEUM YU MIEUM + 0xB9C6: 0xBBB7, //HANGUL SYLLABLE MIEUM YU SIOS + 0xB9C7: 0xBBC0, //HANGUL SYLLABLE MIEUM EU + 0xB9C8: 0xBBC4, //HANGUL SYLLABLE MIEUM EU NIEUN + 0xB9C9: 0xBBC8, //HANGUL SYLLABLE MIEUM EU RIEUL + 0xB9CA: 0xBBD0, //HANGUL SYLLABLE MIEUM EU MIEUM + 0xB9CB: 0xBBD3, //HANGUL SYLLABLE MIEUM EU SIOS + 0xB9CC: 0xBBF8, //HANGUL SYLLABLE MIEUM I + 0xB9CD: 0xBBF9, //HANGUL SYLLABLE MIEUM I KIYEOK + 0xB9CE: 0xBBFC, //HANGUL SYLLABLE MIEUM I NIEUN + 0xB9CF: 0xBBFF, //HANGUL SYLLABLE MIEUM I TIKEUT + 0xB9D0: 0xBC00, //HANGUL SYLLABLE MIEUM I RIEUL + 0xB9D1: 0xBC02, //HANGUL SYLLABLE MIEUM I RIEULMIEUM + 0xB9D2: 0xBC08, //HANGUL SYLLABLE MIEUM I MIEUM + 0xB9D3: 0xBC09, //HANGUL SYLLABLE MIEUM I PIEUP + 0xB9D4: 0xBC0B, //HANGUL SYLLABLE MIEUM I SIOS + 0xB9D5: 0xBC0C, //HANGUL SYLLABLE MIEUM I SSANGSIOS + 0xB9D6: 0xBC0D, //HANGUL SYLLABLE MIEUM I IEUNG + 0xB9D7: 0xBC0F, //HANGUL SYLLABLE MIEUM I CHIEUCH + 0xB9D8: 0xBC11, //HANGUL SYLLABLE MIEUM I THIEUTH + 0xB9D9: 0xBC14, //HANGUL SYLLABLE PIEUP A + 0xB9DA: 0xBC15, //HANGUL SYLLABLE PIEUP A KIYEOK + 0xB9DB: 0xBC16, //HANGUL SYLLABLE PIEUP A SSANGKIYEOK + 0xB9DC: 0xBC17, //HANGUL SYLLABLE PIEUP A KIYEOKSIOS + 0xB9DD: 0xBC18, //HANGUL SYLLABLE PIEUP A NIEUN + 0xB9DE: 0xBC1B, //HANGUL SYLLABLE PIEUP A TIKEUT + 0xB9DF: 0xBC1C, //HANGUL SYLLABLE PIEUP A RIEUL + 0xB9E0: 0xBC1D, //HANGUL SYLLABLE PIEUP A RIEULKIYEOK + 0xB9E1: 0xBC1E, //HANGUL SYLLABLE PIEUP A RIEULMIEUM + 0xB9E2: 0xBC1F, //HANGUL SYLLABLE PIEUP A RIEULPIEUP + 0xB9E3: 0xBC24, //HANGUL SYLLABLE PIEUP A MIEUM + 0xB9E4: 0xBC25, //HANGUL SYLLABLE PIEUP A PIEUP + 0xB9E5: 0xBC27, //HANGUL SYLLABLE PIEUP A SIOS + 0xB9E6: 0xBC29, //HANGUL SYLLABLE PIEUP A IEUNG + 0xB9E7: 0xBC2D, //HANGUL SYLLABLE PIEUP A THIEUTH + 0xB9E8: 0xBC30, //HANGUL SYLLABLE PIEUP AE + 0xB9E9: 0xBC31, //HANGUL SYLLABLE PIEUP AE KIYEOK + 0xB9EA: 0xBC34, //HANGUL SYLLABLE PIEUP AE NIEUN + 0xB9EB: 0xBC38, //HANGUL SYLLABLE PIEUP AE RIEUL + 0xB9EC: 0xBC40, //HANGUL SYLLABLE PIEUP AE MIEUM + 0xB9ED: 0xBC41, //HANGUL SYLLABLE PIEUP AE PIEUP + 0xB9EE: 0xBC43, //HANGUL SYLLABLE PIEUP AE SIOS + 0xB9EF: 0xBC44, //HANGUL SYLLABLE PIEUP AE SSANGSIOS + 0xB9F0: 0xBC45, //HANGUL SYLLABLE PIEUP AE IEUNG + 0xB9F1: 0xBC49, //HANGUL SYLLABLE PIEUP AE THIEUTH + 0xB9F2: 0xBC4C, //HANGUL SYLLABLE PIEUP YA + 0xB9F3: 0xBC4D, //HANGUL SYLLABLE PIEUP YA KIYEOK + 0xB9F4: 0xBC50, //HANGUL SYLLABLE PIEUP YA NIEUN + 0xB9F5: 0xBC5D, //HANGUL SYLLABLE PIEUP YA PIEUP + 0xB9F6: 0xBC84, //HANGUL SYLLABLE PIEUP EO + 0xB9F7: 0xBC85, //HANGUL SYLLABLE PIEUP EO KIYEOK + 0xB9F8: 0xBC88, //HANGUL SYLLABLE PIEUP EO NIEUN + 0xB9F9: 0xBC8B, //HANGUL SYLLABLE PIEUP EO TIKEUT + 0xB9FA: 0xBC8C, //HANGUL SYLLABLE PIEUP EO RIEUL + 0xB9FB: 0xBC8E, //HANGUL SYLLABLE PIEUP EO RIEULMIEUM + 0xB9FC: 0xBC94, //HANGUL SYLLABLE PIEUP EO MIEUM + 0xB9FD: 0xBC95, //HANGUL SYLLABLE PIEUP EO PIEUP + 0xB9FE: 0xBC97, //HANGUL SYLLABLE PIEUP EO SIOS + 0xBA41: 0xD28D, //HANGUL SYLLABLE THIEUTH WI RIEULTHIEUTH + 0xBA42: 0xD28E, //HANGUL SYLLABLE THIEUTH WI RIEULPHIEUPH + 0xBA43: 0xD28F, //HANGUL SYLLABLE THIEUTH WI RIEULHIEUH + 0xBA44: 0xD292, //HANGUL SYLLABLE THIEUTH WI PIEUPSIOS + 0xBA45: 0xD293, //HANGUL SYLLABLE THIEUTH WI SIOS + 0xBA46: 0xD294, //HANGUL SYLLABLE THIEUTH WI SSANGSIOS + 0xBA47: 0xD296, //HANGUL SYLLABLE THIEUTH WI CIEUC + 0xBA48: 0xD297, //HANGUL SYLLABLE THIEUTH WI CHIEUCH + 0xBA49: 0xD298, //HANGUL SYLLABLE THIEUTH WI KHIEUKH + 0xBA4A: 0xD299, //HANGUL SYLLABLE THIEUTH WI THIEUTH + 0xBA4B: 0xD29A, //HANGUL SYLLABLE THIEUTH WI PHIEUPH + 0xBA4C: 0xD29B, //HANGUL SYLLABLE THIEUTH WI HIEUH + 0xBA4D: 0xD29D, //HANGUL SYLLABLE THIEUTH YU KIYEOK + 0xBA4E: 0xD29E, //HANGUL SYLLABLE THIEUTH YU SSANGKIYEOK + 0xBA4F: 0xD29F, //HANGUL SYLLABLE THIEUTH YU KIYEOKSIOS + 0xBA50: 0xD2A1, //HANGUL SYLLABLE THIEUTH YU NIEUNCIEUC + 0xBA51: 0xD2A2, //HANGUL SYLLABLE THIEUTH YU NIEUNHIEUH + 0xBA52: 0xD2A3, //HANGUL SYLLABLE THIEUTH YU TIKEUT + 0xBA53: 0xD2A5, //HANGUL SYLLABLE THIEUTH YU RIEULKIYEOK + 0xBA54: 0xD2A6, //HANGUL SYLLABLE THIEUTH YU RIEULMIEUM + 0xBA55: 0xD2A7, //HANGUL SYLLABLE THIEUTH YU RIEULPIEUP + 0xBA56: 0xD2A8, //HANGUL SYLLABLE THIEUTH YU RIEULSIOS + 0xBA57: 0xD2A9, //HANGUL SYLLABLE THIEUTH YU RIEULTHIEUTH + 0xBA58: 0xD2AA, //HANGUL SYLLABLE THIEUTH YU RIEULPHIEUPH + 0xBA59: 0xD2AB, //HANGUL SYLLABLE THIEUTH YU RIEULHIEUH + 0xBA5A: 0xD2AD, //HANGUL SYLLABLE THIEUTH YU PIEUP + 0xBA61: 0xD2AE, //HANGUL SYLLABLE THIEUTH YU PIEUPSIOS + 0xBA62: 0xD2AF, //HANGUL SYLLABLE THIEUTH YU SIOS + 0xBA63: 0xD2B0, //HANGUL SYLLABLE THIEUTH YU SSANGSIOS + 0xBA64: 0xD2B2, //HANGUL SYLLABLE THIEUTH YU CIEUC + 0xBA65: 0xD2B3, //HANGUL SYLLABLE THIEUTH YU CHIEUCH + 0xBA66: 0xD2B4, //HANGUL SYLLABLE THIEUTH YU KHIEUKH + 0xBA67: 0xD2B5, //HANGUL SYLLABLE THIEUTH YU THIEUTH + 0xBA68: 0xD2B6, //HANGUL SYLLABLE THIEUTH YU PHIEUPH + 0xBA69: 0xD2B7, //HANGUL SYLLABLE THIEUTH YU HIEUH + 0xBA6A: 0xD2BA, //HANGUL SYLLABLE THIEUTH EU SSANGKIYEOK + 0xBA6B: 0xD2BB, //HANGUL SYLLABLE THIEUTH EU KIYEOKSIOS + 0xBA6C: 0xD2BD, //HANGUL SYLLABLE THIEUTH EU NIEUNCIEUC + 0xBA6D: 0xD2BE, //HANGUL SYLLABLE THIEUTH EU NIEUNHIEUH + 0xBA6E: 0xD2C1, //HANGUL SYLLABLE THIEUTH EU RIEULKIYEOK + 0xBA6F: 0xD2C3, //HANGUL SYLLABLE THIEUTH EU RIEULPIEUP + 0xBA70: 0xD2C4, //HANGUL SYLLABLE THIEUTH EU RIEULSIOS + 0xBA71: 0xD2C5, //HANGUL SYLLABLE THIEUTH EU RIEULTHIEUTH + 0xBA72: 0xD2C6, //HANGUL SYLLABLE THIEUTH EU RIEULPHIEUPH + 0xBA73: 0xD2C7, //HANGUL SYLLABLE THIEUTH EU RIEULHIEUH + 0xBA74: 0xD2CA, //HANGUL SYLLABLE THIEUTH EU PIEUPSIOS + 0xBA75: 0xD2CC, //HANGUL SYLLABLE THIEUTH EU SSANGSIOS + 0xBA76: 0xD2CD, //HANGUL SYLLABLE THIEUTH EU IEUNG + 0xBA77: 0xD2CE, //HANGUL SYLLABLE THIEUTH EU CIEUC + 0xBA78: 0xD2CF, //HANGUL SYLLABLE THIEUTH EU CHIEUCH + 0xBA79: 0xD2D0, //HANGUL SYLLABLE THIEUTH EU KHIEUKH + 0xBA7A: 0xD2D1, //HANGUL SYLLABLE THIEUTH EU THIEUTH + 0xBA81: 0xD2D2, //HANGUL SYLLABLE THIEUTH EU PHIEUPH + 0xBA82: 0xD2D3, //HANGUL SYLLABLE THIEUTH EU HIEUH + 0xBA83: 0xD2D5, //HANGUL SYLLABLE THIEUTH YI KIYEOK + 0xBA84: 0xD2D6, //HANGUL SYLLABLE THIEUTH YI SSANGKIYEOK + 0xBA85: 0xD2D7, //HANGUL SYLLABLE THIEUTH YI KIYEOKSIOS + 0xBA86: 0xD2D9, //HANGUL SYLLABLE THIEUTH YI NIEUNCIEUC + 0xBA87: 0xD2DA, //HANGUL SYLLABLE THIEUTH YI NIEUNHIEUH + 0xBA88: 0xD2DB, //HANGUL SYLLABLE THIEUTH YI TIKEUT + 0xBA89: 0xD2DD, //HANGUL SYLLABLE THIEUTH YI RIEULKIYEOK + 0xBA8A: 0xD2DE, //HANGUL SYLLABLE THIEUTH YI RIEULMIEUM + 0xBA8B: 0xD2DF, //HANGUL SYLLABLE THIEUTH YI RIEULPIEUP + 0xBA8C: 0xD2E0, //HANGUL SYLLABLE THIEUTH YI RIEULSIOS + 0xBA8D: 0xD2E1, //HANGUL SYLLABLE THIEUTH YI RIEULTHIEUTH + 0xBA8E: 0xD2E2, //HANGUL SYLLABLE THIEUTH YI RIEULPHIEUPH + 0xBA8F: 0xD2E3, //HANGUL SYLLABLE THIEUTH YI RIEULHIEUH + 0xBA90: 0xD2E6, //HANGUL SYLLABLE THIEUTH YI PIEUPSIOS + 0xBA91: 0xD2E7, //HANGUL SYLLABLE THIEUTH YI SIOS + 0xBA92: 0xD2E8, //HANGUL SYLLABLE THIEUTH YI SSANGSIOS + 0xBA93: 0xD2E9, //HANGUL SYLLABLE THIEUTH YI IEUNG + 0xBA94: 0xD2EA, //HANGUL SYLLABLE THIEUTH YI CIEUC + 0xBA95: 0xD2EB, //HANGUL SYLLABLE THIEUTH YI CHIEUCH + 0xBA96: 0xD2EC, //HANGUL SYLLABLE THIEUTH YI KHIEUKH + 0xBA97: 0xD2ED, //HANGUL SYLLABLE THIEUTH YI THIEUTH + 0xBA98: 0xD2EE, //HANGUL SYLLABLE THIEUTH YI PHIEUPH + 0xBA99: 0xD2EF, //HANGUL SYLLABLE THIEUTH YI HIEUH + 0xBA9A: 0xD2F2, //HANGUL SYLLABLE THIEUTH I SSANGKIYEOK + 0xBA9B: 0xD2F3, //HANGUL SYLLABLE THIEUTH I KIYEOKSIOS + 0xBA9C: 0xD2F5, //HANGUL SYLLABLE THIEUTH I NIEUNCIEUC + 0xBA9D: 0xD2F6, //HANGUL SYLLABLE THIEUTH I NIEUNHIEUH + 0xBA9E: 0xD2F7, //HANGUL SYLLABLE THIEUTH I TIKEUT + 0xBA9F: 0xD2F9, //HANGUL SYLLABLE THIEUTH I RIEULKIYEOK + 0xBAA0: 0xD2FA, //HANGUL SYLLABLE THIEUTH I RIEULMIEUM + 0xBAA1: 0xBC99, //HANGUL SYLLABLE PIEUP EO IEUNG + 0xBAA2: 0xBC9A, //HANGUL SYLLABLE PIEUP EO CIEUC + 0xBAA3: 0xBCA0, //HANGUL SYLLABLE PIEUP E + 0xBAA4: 0xBCA1, //HANGUL SYLLABLE PIEUP E KIYEOK + 0xBAA5: 0xBCA4, //HANGUL SYLLABLE PIEUP E NIEUN + 0xBAA6: 0xBCA7, //HANGUL SYLLABLE PIEUP E TIKEUT + 0xBAA7: 0xBCA8, //HANGUL SYLLABLE PIEUP E RIEUL + 0xBAA8: 0xBCB0, //HANGUL SYLLABLE PIEUP E MIEUM + 0xBAA9: 0xBCB1, //HANGUL SYLLABLE PIEUP E PIEUP + 0xBAAA: 0xBCB3, //HANGUL SYLLABLE PIEUP E SIOS + 0xBAAB: 0xBCB4, //HANGUL SYLLABLE PIEUP E SSANGSIOS + 0xBAAC: 0xBCB5, //HANGUL SYLLABLE PIEUP E IEUNG + 0xBAAD: 0xBCBC, //HANGUL SYLLABLE PIEUP YEO + 0xBAAE: 0xBCBD, //HANGUL SYLLABLE PIEUP YEO KIYEOK + 0xBAAF: 0xBCC0, //HANGUL SYLLABLE PIEUP YEO NIEUN + 0xBAB0: 0xBCC4, //HANGUL SYLLABLE PIEUP YEO RIEUL + 0xBAB1: 0xBCCD, //HANGUL SYLLABLE PIEUP YEO PIEUP + 0xBAB2: 0xBCCF, //HANGUL SYLLABLE PIEUP YEO SIOS + 0xBAB3: 0xBCD0, //HANGUL SYLLABLE PIEUP YEO SSANGSIOS + 0xBAB4: 0xBCD1, //HANGUL SYLLABLE PIEUP YEO IEUNG + 0xBAB5: 0xBCD5, //HANGUL SYLLABLE PIEUP YEO THIEUTH + 0xBAB6: 0xBCD8, //HANGUL SYLLABLE PIEUP YE + 0xBAB7: 0xBCDC, //HANGUL SYLLABLE PIEUP YE NIEUN + 0xBAB8: 0xBCF4, //HANGUL SYLLABLE PIEUP O + 0xBAB9: 0xBCF5, //HANGUL SYLLABLE PIEUP O KIYEOK + 0xBABA: 0xBCF6, //HANGUL SYLLABLE PIEUP O SSANGKIYEOK + 0xBABB: 0xBCF8, //HANGUL SYLLABLE PIEUP O NIEUN + 0xBABC: 0xBCFC, //HANGUL SYLLABLE PIEUP O RIEUL + 0xBABD: 0xBD04, //HANGUL SYLLABLE PIEUP O MIEUM + 0xBABE: 0xBD05, //HANGUL SYLLABLE PIEUP O PIEUP + 0xBABF: 0xBD07, //HANGUL SYLLABLE PIEUP O SIOS + 0xBAC0: 0xBD09, //HANGUL SYLLABLE PIEUP O IEUNG + 0xBAC1: 0xBD10, //HANGUL SYLLABLE PIEUP WA + 0xBAC2: 0xBD14, //HANGUL SYLLABLE PIEUP WA NIEUN + 0xBAC3: 0xBD24, //HANGUL SYLLABLE PIEUP WA SSANGSIOS + 0xBAC4: 0xBD2C, //HANGUL SYLLABLE PIEUP WAE + 0xBAC5: 0xBD40, //HANGUL SYLLABLE PIEUP WAE SSANGSIOS + 0xBAC6: 0xBD48, //HANGUL SYLLABLE PIEUP OE + 0xBAC7: 0xBD49, //HANGUL SYLLABLE PIEUP OE KIYEOK + 0xBAC8: 0xBD4C, //HANGUL SYLLABLE PIEUP OE NIEUN + 0xBAC9: 0xBD50, //HANGUL SYLLABLE PIEUP OE RIEUL + 0xBACA: 0xBD58, //HANGUL SYLLABLE PIEUP OE MIEUM + 0xBACB: 0xBD59, //HANGUL SYLLABLE PIEUP OE PIEUP + 0xBACC: 0xBD64, //HANGUL SYLLABLE PIEUP YO + 0xBACD: 0xBD68, //HANGUL SYLLABLE PIEUP YO NIEUN + 0xBACE: 0xBD80, //HANGUL SYLLABLE PIEUP U + 0xBACF: 0xBD81, //HANGUL SYLLABLE PIEUP U KIYEOK + 0xBAD0: 0xBD84, //HANGUL SYLLABLE PIEUP U NIEUN + 0xBAD1: 0xBD87, //HANGUL SYLLABLE PIEUP U TIKEUT + 0xBAD2: 0xBD88, //HANGUL SYLLABLE PIEUP U RIEUL + 0xBAD3: 0xBD89, //HANGUL SYLLABLE PIEUP U RIEULKIYEOK + 0xBAD4: 0xBD8A, //HANGUL SYLLABLE PIEUP U RIEULMIEUM + 0xBAD5: 0xBD90, //HANGUL SYLLABLE PIEUP U MIEUM + 0xBAD6: 0xBD91, //HANGUL SYLLABLE PIEUP U PIEUP + 0xBAD7: 0xBD93, //HANGUL SYLLABLE PIEUP U SIOS + 0xBAD8: 0xBD95, //HANGUL SYLLABLE PIEUP U IEUNG + 0xBAD9: 0xBD99, //HANGUL SYLLABLE PIEUP U THIEUTH + 0xBADA: 0xBD9A, //HANGUL SYLLABLE PIEUP U PHIEUPH + 0xBADB: 0xBD9C, //HANGUL SYLLABLE PIEUP WEO + 0xBADC: 0xBDA4, //HANGUL SYLLABLE PIEUP WEO RIEUL + 0xBADD: 0xBDB0, //HANGUL SYLLABLE PIEUP WEO SSANGSIOS + 0xBADE: 0xBDB8, //HANGUL SYLLABLE PIEUP WE + 0xBADF: 0xBDD4, //HANGUL SYLLABLE PIEUP WI + 0xBAE0: 0xBDD5, //HANGUL SYLLABLE PIEUP WI KIYEOK + 0xBAE1: 0xBDD8, //HANGUL SYLLABLE PIEUP WI NIEUN + 0xBAE2: 0xBDDC, //HANGUL SYLLABLE PIEUP WI RIEUL + 0xBAE3: 0xBDE9, //HANGUL SYLLABLE PIEUP WI IEUNG + 0xBAE4: 0xBDF0, //HANGUL SYLLABLE PIEUP YU + 0xBAE5: 0xBDF4, //HANGUL SYLLABLE PIEUP YU NIEUN + 0xBAE6: 0xBDF8, //HANGUL SYLLABLE PIEUP YU RIEUL + 0xBAE7: 0xBE00, //HANGUL SYLLABLE PIEUP YU MIEUM + 0xBAE8: 0xBE03, //HANGUL SYLLABLE PIEUP YU SIOS + 0xBAE9: 0xBE05, //HANGUL SYLLABLE PIEUP YU IEUNG + 0xBAEA: 0xBE0C, //HANGUL SYLLABLE PIEUP EU + 0xBAEB: 0xBE0D, //HANGUL SYLLABLE PIEUP EU KIYEOK + 0xBAEC: 0xBE10, //HANGUL SYLLABLE PIEUP EU NIEUN + 0xBAED: 0xBE14, //HANGUL SYLLABLE PIEUP EU RIEUL + 0xBAEE: 0xBE1C, //HANGUL SYLLABLE PIEUP EU MIEUM + 0xBAEF: 0xBE1D, //HANGUL SYLLABLE PIEUP EU PIEUP + 0xBAF0: 0xBE1F, //HANGUL SYLLABLE PIEUP EU SIOS + 0xBAF1: 0xBE44, //HANGUL SYLLABLE PIEUP I + 0xBAF2: 0xBE45, //HANGUL SYLLABLE PIEUP I KIYEOK + 0xBAF3: 0xBE48, //HANGUL SYLLABLE PIEUP I NIEUN + 0xBAF4: 0xBE4C, //HANGUL SYLLABLE PIEUP I RIEUL + 0xBAF5: 0xBE4E, //HANGUL SYLLABLE PIEUP I RIEULMIEUM + 0xBAF6: 0xBE54, //HANGUL SYLLABLE PIEUP I MIEUM + 0xBAF7: 0xBE55, //HANGUL SYLLABLE PIEUP I PIEUP + 0xBAF8: 0xBE57, //HANGUL SYLLABLE PIEUP I SIOS + 0xBAF9: 0xBE59, //HANGUL SYLLABLE PIEUP I IEUNG + 0xBAFA: 0xBE5A, //HANGUL SYLLABLE PIEUP I CIEUC + 0xBAFB: 0xBE5B, //HANGUL SYLLABLE PIEUP I CHIEUCH + 0xBAFC: 0xBE60, //HANGUL SYLLABLE SSANGPIEUP A + 0xBAFD: 0xBE61, //HANGUL SYLLABLE SSANGPIEUP A KIYEOK + 0xBAFE: 0xBE64, //HANGUL SYLLABLE SSANGPIEUP A NIEUN + 0xBB41: 0xD2FB, //HANGUL SYLLABLE THIEUTH I RIEULPIEUP + 0xBB42: 0xD2FC, //HANGUL SYLLABLE THIEUTH I RIEULSIOS + 0xBB43: 0xD2FD, //HANGUL SYLLABLE THIEUTH I RIEULTHIEUTH + 0xBB44: 0xD2FE, //HANGUL SYLLABLE THIEUTH I RIEULPHIEUPH + 0xBB45: 0xD2FF, //HANGUL SYLLABLE THIEUTH I RIEULHIEUH + 0xBB46: 0xD302, //HANGUL SYLLABLE THIEUTH I PIEUPSIOS + 0xBB47: 0xD304, //HANGUL SYLLABLE THIEUTH I SSANGSIOS + 0xBB48: 0xD306, //HANGUL SYLLABLE THIEUTH I CIEUC + 0xBB49: 0xD307, //HANGUL SYLLABLE THIEUTH I CHIEUCH + 0xBB4A: 0xD308, //HANGUL SYLLABLE THIEUTH I KHIEUKH + 0xBB4B: 0xD309, //HANGUL SYLLABLE THIEUTH I THIEUTH + 0xBB4C: 0xD30A, //HANGUL SYLLABLE THIEUTH I PHIEUPH + 0xBB4D: 0xD30B, //HANGUL SYLLABLE THIEUTH I HIEUH + 0xBB4E: 0xD30F, //HANGUL SYLLABLE PHIEUPH A KIYEOKSIOS + 0xBB4F: 0xD311, //HANGUL SYLLABLE PHIEUPH A NIEUNCIEUC + 0xBB50: 0xD312, //HANGUL SYLLABLE PHIEUPH A NIEUNHIEUH + 0xBB51: 0xD313, //HANGUL SYLLABLE PHIEUPH A TIKEUT + 0xBB52: 0xD315, //HANGUL SYLLABLE PHIEUPH A RIEULKIYEOK + 0xBB53: 0xD317, //HANGUL SYLLABLE PHIEUPH A RIEULPIEUP + 0xBB54: 0xD318, //HANGUL SYLLABLE PHIEUPH A RIEULSIOS + 0xBB55: 0xD319, //HANGUL SYLLABLE PHIEUPH A RIEULTHIEUTH + 0xBB56: 0xD31A, //HANGUL SYLLABLE PHIEUPH A RIEULPHIEUPH + 0xBB57: 0xD31B, //HANGUL SYLLABLE PHIEUPH A RIEULHIEUH + 0xBB58: 0xD31E, //HANGUL SYLLABLE PHIEUPH A PIEUPSIOS + 0xBB59: 0xD322, //HANGUL SYLLABLE PHIEUPH A CIEUC + 0xBB5A: 0xD323, //HANGUL SYLLABLE PHIEUPH A CHIEUCH + 0xBB61: 0xD324, //HANGUL SYLLABLE PHIEUPH A KHIEUKH + 0xBB62: 0xD326, //HANGUL SYLLABLE PHIEUPH A PHIEUPH + 0xBB63: 0xD327, //HANGUL SYLLABLE PHIEUPH A HIEUH + 0xBB64: 0xD32A, //HANGUL SYLLABLE PHIEUPH AE SSANGKIYEOK + 0xBB65: 0xD32B, //HANGUL SYLLABLE PHIEUPH AE KIYEOKSIOS + 0xBB66: 0xD32D, //HANGUL SYLLABLE PHIEUPH AE NIEUNCIEUC + 0xBB67: 0xD32E, //HANGUL SYLLABLE PHIEUPH AE NIEUNHIEUH + 0xBB68: 0xD32F, //HANGUL SYLLABLE PHIEUPH AE TIKEUT + 0xBB69: 0xD331, //HANGUL SYLLABLE PHIEUPH AE RIEULKIYEOK + 0xBB6A: 0xD332, //HANGUL SYLLABLE PHIEUPH AE RIEULMIEUM + 0xBB6B: 0xD333, //HANGUL SYLLABLE PHIEUPH AE RIEULPIEUP + 0xBB6C: 0xD334, //HANGUL SYLLABLE PHIEUPH AE RIEULSIOS + 0xBB6D: 0xD335, //HANGUL SYLLABLE PHIEUPH AE RIEULTHIEUTH + 0xBB6E: 0xD336, //HANGUL SYLLABLE PHIEUPH AE RIEULPHIEUPH + 0xBB6F: 0xD337, //HANGUL SYLLABLE PHIEUPH AE RIEULHIEUH + 0xBB70: 0xD33A, //HANGUL SYLLABLE PHIEUPH AE PIEUPSIOS + 0xBB71: 0xD33E, //HANGUL SYLLABLE PHIEUPH AE CIEUC + 0xBB72: 0xD33F, //HANGUL SYLLABLE PHIEUPH AE CHIEUCH + 0xBB73: 0xD340, //HANGUL SYLLABLE PHIEUPH AE KHIEUKH + 0xBB74: 0xD341, //HANGUL SYLLABLE PHIEUPH AE THIEUTH + 0xBB75: 0xD342, //HANGUL SYLLABLE PHIEUPH AE PHIEUPH + 0xBB76: 0xD343, //HANGUL SYLLABLE PHIEUPH AE HIEUH + 0xBB77: 0xD346, //HANGUL SYLLABLE PHIEUPH YA SSANGKIYEOK + 0xBB78: 0xD347, //HANGUL SYLLABLE PHIEUPH YA KIYEOKSIOS + 0xBB79: 0xD348, //HANGUL SYLLABLE PHIEUPH YA NIEUN + 0xBB7A: 0xD349, //HANGUL SYLLABLE PHIEUPH YA NIEUNCIEUC + 0xBB81: 0xD34A, //HANGUL SYLLABLE PHIEUPH YA NIEUNHIEUH + 0xBB82: 0xD34B, //HANGUL SYLLABLE PHIEUPH YA TIKEUT + 0xBB83: 0xD34C, //HANGUL SYLLABLE PHIEUPH YA RIEUL + 0xBB84: 0xD34D, //HANGUL SYLLABLE PHIEUPH YA RIEULKIYEOK + 0xBB85: 0xD34E, //HANGUL SYLLABLE PHIEUPH YA RIEULMIEUM + 0xBB86: 0xD34F, //HANGUL SYLLABLE PHIEUPH YA RIEULPIEUP + 0xBB87: 0xD350, //HANGUL SYLLABLE PHIEUPH YA RIEULSIOS + 0xBB88: 0xD351, //HANGUL SYLLABLE PHIEUPH YA RIEULTHIEUTH + 0xBB89: 0xD352, //HANGUL SYLLABLE PHIEUPH YA RIEULPHIEUPH + 0xBB8A: 0xD353, //HANGUL SYLLABLE PHIEUPH YA RIEULHIEUH + 0xBB8B: 0xD354, //HANGUL SYLLABLE PHIEUPH YA MIEUM + 0xBB8C: 0xD355, //HANGUL SYLLABLE PHIEUPH YA PIEUP + 0xBB8D: 0xD356, //HANGUL SYLLABLE PHIEUPH YA PIEUPSIOS + 0xBB8E: 0xD357, //HANGUL SYLLABLE PHIEUPH YA SIOS + 0xBB8F: 0xD358, //HANGUL SYLLABLE PHIEUPH YA SSANGSIOS + 0xBB90: 0xD359, //HANGUL SYLLABLE PHIEUPH YA IEUNG + 0xBB91: 0xD35A, //HANGUL SYLLABLE PHIEUPH YA CIEUC + 0xBB92: 0xD35B, //HANGUL SYLLABLE PHIEUPH YA CHIEUCH + 0xBB93: 0xD35C, //HANGUL SYLLABLE PHIEUPH YA KHIEUKH + 0xBB94: 0xD35D, //HANGUL SYLLABLE PHIEUPH YA THIEUTH + 0xBB95: 0xD35E, //HANGUL SYLLABLE PHIEUPH YA PHIEUPH + 0xBB96: 0xD35F, //HANGUL SYLLABLE PHIEUPH YA HIEUH + 0xBB97: 0xD360, //HANGUL SYLLABLE PHIEUPH YAE + 0xBB98: 0xD361, //HANGUL SYLLABLE PHIEUPH YAE KIYEOK + 0xBB99: 0xD362, //HANGUL SYLLABLE PHIEUPH YAE SSANGKIYEOK + 0xBB9A: 0xD363, //HANGUL SYLLABLE PHIEUPH YAE KIYEOKSIOS + 0xBB9B: 0xD364, //HANGUL SYLLABLE PHIEUPH YAE NIEUN + 0xBB9C: 0xD365, //HANGUL SYLLABLE PHIEUPH YAE NIEUNCIEUC + 0xBB9D: 0xD366, //HANGUL SYLLABLE PHIEUPH YAE NIEUNHIEUH + 0xBB9E: 0xD367, //HANGUL SYLLABLE PHIEUPH YAE TIKEUT + 0xBB9F: 0xD368, //HANGUL SYLLABLE PHIEUPH YAE RIEUL + 0xBBA0: 0xD369, //HANGUL SYLLABLE PHIEUPH YAE RIEULKIYEOK + 0xBBA1: 0xBE68, //HANGUL SYLLABLE SSANGPIEUP A RIEUL + 0xBBA2: 0xBE6A, //HANGUL SYLLABLE SSANGPIEUP A RIEULMIEUM + 0xBBA3: 0xBE70, //HANGUL SYLLABLE SSANGPIEUP A MIEUM + 0xBBA4: 0xBE71, //HANGUL SYLLABLE SSANGPIEUP A PIEUP + 0xBBA5: 0xBE73, //HANGUL SYLLABLE SSANGPIEUP A SIOS + 0xBBA6: 0xBE74, //HANGUL SYLLABLE SSANGPIEUP A SSANGSIOS + 0xBBA7: 0xBE75, //HANGUL SYLLABLE SSANGPIEUP A IEUNG + 0xBBA8: 0xBE7B, //HANGUL SYLLABLE SSANGPIEUP A HIEUH + 0xBBA9: 0xBE7C, //HANGUL SYLLABLE SSANGPIEUP AE + 0xBBAA: 0xBE7D, //HANGUL SYLLABLE SSANGPIEUP AE KIYEOK + 0xBBAB: 0xBE80, //HANGUL SYLLABLE SSANGPIEUP AE NIEUN + 0xBBAC: 0xBE84, //HANGUL SYLLABLE SSANGPIEUP AE RIEUL + 0xBBAD: 0xBE8C, //HANGUL SYLLABLE SSANGPIEUP AE MIEUM + 0xBBAE: 0xBE8D, //HANGUL SYLLABLE SSANGPIEUP AE PIEUP + 0xBBAF: 0xBE8F, //HANGUL SYLLABLE SSANGPIEUP AE SIOS + 0xBBB0: 0xBE90, //HANGUL SYLLABLE SSANGPIEUP AE SSANGSIOS + 0xBBB1: 0xBE91, //HANGUL SYLLABLE SSANGPIEUP AE IEUNG + 0xBBB2: 0xBE98, //HANGUL SYLLABLE SSANGPIEUP YA + 0xBBB3: 0xBE99, //HANGUL SYLLABLE SSANGPIEUP YA KIYEOK + 0xBBB4: 0xBEA8, //HANGUL SYLLABLE SSANGPIEUP YA MIEUM + 0xBBB5: 0xBED0, //HANGUL SYLLABLE SSANGPIEUP EO + 0xBBB6: 0xBED1, //HANGUL SYLLABLE SSANGPIEUP EO KIYEOK + 0xBBB7: 0xBED4, //HANGUL SYLLABLE SSANGPIEUP EO NIEUN + 0xBBB8: 0xBED7, //HANGUL SYLLABLE SSANGPIEUP EO TIKEUT + 0xBBB9: 0xBED8, //HANGUL SYLLABLE SSANGPIEUP EO RIEUL + 0xBBBA: 0xBEE0, //HANGUL SYLLABLE SSANGPIEUP EO MIEUM + 0xBBBB: 0xBEE3, //HANGUL SYLLABLE SSANGPIEUP EO SIOS + 0xBBBC: 0xBEE4, //HANGUL SYLLABLE SSANGPIEUP EO SSANGSIOS + 0xBBBD: 0xBEE5, //HANGUL SYLLABLE SSANGPIEUP EO IEUNG + 0xBBBE: 0xBEEC, //HANGUL SYLLABLE SSANGPIEUP E + 0xBBBF: 0xBF01, //HANGUL SYLLABLE SSANGPIEUP E IEUNG + 0xBBC0: 0xBF08, //HANGUL SYLLABLE SSANGPIEUP YEO + 0xBBC1: 0xBF09, //HANGUL SYLLABLE SSANGPIEUP YEO KIYEOK + 0xBBC2: 0xBF18, //HANGUL SYLLABLE SSANGPIEUP YEO MIEUM + 0xBBC3: 0xBF19, //HANGUL SYLLABLE SSANGPIEUP YEO PIEUP + 0xBBC4: 0xBF1B, //HANGUL SYLLABLE SSANGPIEUP YEO SIOS + 0xBBC5: 0xBF1C, //HANGUL SYLLABLE SSANGPIEUP YEO SSANGSIOS + 0xBBC6: 0xBF1D, //HANGUL SYLLABLE SSANGPIEUP YEO IEUNG + 0xBBC7: 0xBF40, //HANGUL SYLLABLE SSANGPIEUP O + 0xBBC8: 0xBF41, //HANGUL SYLLABLE SSANGPIEUP O KIYEOK + 0xBBC9: 0xBF44, //HANGUL SYLLABLE SSANGPIEUP O NIEUN + 0xBBCA: 0xBF48, //HANGUL SYLLABLE SSANGPIEUP O RIEUL + 0xBBCB: 0xBF50, //HANGUL SYLLABLE SSANGPIEUP O MIEUM + 0xBBCC: 0xBF51, //HANGUL SYLLABLE SSANGPIEUP O PIEUP + 0xBBCD: 0xBF55, //HANGUL SYLLABLE SSANGPIEUP O IEUNG + 0xBBCE: 0xBF94, //HANGUL SYLLABLE SSANGPIEUP OE + 0xBBCF: 0xBFB0, //HANGUL SYLLABLE SSANGPIEUP YO + 0xBBD0: 0xBFC5, //HANGUL SYLLABLE SSANGPIEUP YO IEUNG + 0xBBD1: 0xBFCC, //HANGUL SYLLABLE SSANGPIEUP U + 0xBBD2: 0xBFCD, //HANGUL SYLLABLE SSANGPIEUP U KIYEOK + 0xBBD3: 0xBFD0, //HANGUL SYLLABLE SSANGPIEUP U NIEUN + 0xBBD4: 0xBFD4, //HANGUL SYLLABLE SSANGPIEUP U RIEUL + 0xBBD5: 0xBFDC, //HANGUL SYLLABLE SSANGPIEUP U MIEUM + 0xBBD6: 0xBFDF, //HANGUL SYLLABLE SSANGPIEUP U SIOS + 0xBBD7: 0xBFE1, //HANGUL SYLLABLE SSANGPIEUP U IEUNG + 0xBBD8: 0xC03C, //HANGUL SYLLABLE SSANGPIEUP YU + 0xBBD9: 0xC051, //HANGUL SYLLABLE SSANGPIEUP YU IEUNG + 0xBBDA: 0xC058, //HANGUL SYLLABLE SSANGPIEUP EU + 0xBBDB: 0xC05C, //HANGUL SYLLABLE SSANGPIEUP EU NIEUN + 0xBBDC: 0xC060, //HANGUL SYLLABLE SSANGPIEUP EU RIEUL + 0xBBDD: 0xC068, //HANGUL SYLLABLE SSANGPIEUP EU MIEUM + 0xBBDE: 0xC069, //HANGUL SYLLABLE SSANGPIEUP EU PIEUP + 0xBBDF: 0xC090, //HANGUL SYLLABLE SSANGPIEUP I + 0xBBE0: 0xC091, //HANGUL SYLLABLE SSANGPIEUP I KIYEOK + 0xBBE1: 0xC094, //HANGUL SYLLABLE SSANGPIEUP I NIEUN + 0xBBE2: 0xC098, //HANGUL SYLLABLE SSANGPIEUP I RIEUL + 0xBBE3: 0xC0A0, //HANGUL SYLLABLE SSANGPIEUP I MIEUM + 0xBBE4: 0xC0A1, //HANGUL SYLLABLE SSANGPIEUP I PIEUP + 0xBBE5: 0xC0A3, //HANGUL SYLLABLE SSANGPIEUP I SIOS + 0xBBE6: 0xC0A5, //HANGUL SYLLABLE SSANGPIEUP I IEUNG + 0xBBE7: 0xC0AC, //HANGUL SYLLABLE SIOS A + 0xBBE8: 0xC0AD, //HANGUL SYLLABLE SIOS A KIYEOK + 0xBBE9: 0xC0AF, //HANGUL SYLLABLE SIOS A KIYEOKSIOS + 0xBBEA: 0xC0B0, //HANGUL SYLLABLE SIOS A NIEUN + 0xBBEB: 0xC0B3, //HANGUL SYLLABLE SIOS A TIKEUT + 0xBBEC: 0xC0B4, //HANGUL SYLLABLE SIOS A RIEUL + 0xBBED: 0xC0B5, //HANGUL SYLLABLE SIOS A RIEULKIYEOK + 0xBBEE: 0xC0B6, //HANGUL SYLLABLE SIOS A RIEULMIEUM + 0xBBEF: 0xC0BC, //HANGUL SYLLABLE SIOS A MIEUM + 0xBBF0: 0xC0BD, //HANGUL SYLLABLE SIOS A PIEUP + 0xBBF1: 0xC0BF, //HANGUL SYLLABLE SIOS A SIOS + 0xBBF2: 0xC0C0, //HANGUL SYLLABLE SIOS A SSANGSIOS + 0xBBF3: 0xC0C1, //HANGUL SYLLABLE SIOS A IEUNG + 0xBBF4: 0xC0C5, //HANGUL SYLLABLE SIOS A THIEUTH + 0xBBF5: 0xC0C8, //HANGUL SYLLABLE SIOS AE + 0xBBF6: 0xC0C9, //HANGUL SYLLABLE SIOS AE KIYEOK + 0xBBF7: 0xC0CC, //HANGUL SYLLABLE SIOS AE NIEUN + 0xBBF8: 0xC0D0, //HANGUL SYLLABLE SIOS AE RIEUL + 0xBBF9: 0xC0D8, //HANGUL SYLLABLE SIOS AE MIEUM + 0xBBFA: 0xC0D9, //HANGUL SYLLABLE SIOS AE PIEUP + 0xBBFB: 0xC0DB, //HANGUL SYLLABLE SIOS AE SIOS + 0xBBFC: 0xC0DC, //HANGUL SYLLABLE SIOS AE SSANGSIOS + 0xBBFD: 0xC0DD, //HANGUL SYLLABLE SIOS AE IEUNG + 0xBBFE: 0xC0E4, //HANGUL SYLLABLE SIOS YA + 0xBC41: 0xD36A, //HANGUL SYLLABLE PHIEUPH YAE RIEULMIEUM + 0xBC42: 0xD36B, //HANGUL SYLLABLE PHIEUPH YAE RIEULPIEUP + 0xBC43: 0xD36C, //HANGUL SYLLABLE PHIEUPH YAE RIEULSIOS + 0xBC44: 0xD36D, //HANGUL SYLLABLE PHIEUPH YAE RIEULTHIEUTH + 0xBC45: 0xD36E, //HANGUL SYLLABLE PHIEUPH YAE RIEULPHIEUPH + 0xBC46: 0xD36F, //HANGUL SYLLABLE PHIEUPH YAE RIEULHIEUH + 0xBC47: 0xD370, //HANGUL SYLLABLE PHIEUPH YAE MIEUM + 0xBC48: 0xD371, //HANGUL SYLLABLE PHIEUPH YAE PIEUP + 0xBC49: 0xD372, //HANGUL SYLLABLE PHIEUPH YAE PIEUPSIOS + 0xBC4A: 0xD373, //HANGUL SYLLABLE PHIEUPH YAE SIOS + 0xBC4B: 0xD374, //HANGUL SYLLABLE PHIEUPH YAE SSANGSIOS + 0xBC4C: 0xD375, //HANGUL SYLLABLE PHIEUPH YAE IEUNG + 0xBC4D: 0xD376, //HANGUL SYLLABLE PHIEUPH YAE CIEUC + 0xBC4E: 0xD377, //HANGUL SYLLABLE PHIEUPH YAE CHIEUCH + 0xBC4F: 0xD378, //HANGUL SYLLABLE PHIEUPH YAE KHIEUKH + 0xBC50: 0xD379, //HANGUL SYLLABLE PHIEUPH YAE THIEUTH + 0xBC51: 0xD37A, //HANGUL SYLLABLE PHIEUPH YAE PHIEUPH + 0xBC52: 0xD37B, //HANGUL SYLLABLE PHIEUPH YAE HIEUH + 0xBC53: 0xD37E, //HANGUL SYLLABLE PHIEUPH EO SSANGKIYEOK + 0xBC54: 0xD37F, //HANGUL SYLLABLE PHIEUPH EO KIYEOKSIOS + 0xBC55: 0xD381, //HANGUL SYLLABLE PHIEUPH EO NIEUNCIEUC + 0xBC56: 0xD382, //HANGUL SYLLABLE PHIEUPH EO NIEUNHIEUH + 0xBC57: 0xD383, //HANGUL SYLLABLE PHIEUPH EO TIKEUT + 0xBC58: 0xD385, //HANGUL SYLLABLE PHIEUPH EO RIEULKIYEOK + 0xBC59: 0xD386, //HANGUL SYLLABLE PHIEUPH EO RIEULMIEUM + 0xBC5A: 0xD387, //HANGUL SYLLABLE PHIEUPH EO RIEULPIEUP + 0xBC61: 0xD388, //HANGUL SYLLABLE PHIEUPH EO RIEULSIOS + 0xBC62: 0xD389, //HANGUL SYLLABLE PHIEUPH EO RIEULTHIEUTH + 0xBC63: 0xD38A, //HANGUL SYLLABLE PHIEUPH EO RIEULPHIEUPH + 0xBC64: 0xD38B, //HANGUL SYLLABLE PHIEUPH EO RIEULHIEUH + 0xBC65: 0xD38E, //HANGUL SYLLABLE PHIEUPH EO PIEUPSIOS + 0xBC66: 0xD392, //HANGUL SYLLABLE PHIEUPH EO CIEUC + 0xBC67: 0xD393, //HANGUL SYLLABLE PHIEUPH EO CHIEUCH + 0xBC68: 0xD394, //HANGUL SYLLABLE PHIEUPH EO KHIEUKH + 0xBC69: 0xD395, //HANGUL SYLLABLE PHIEUPH EO THIEUTH + 0xBC6A: 0xD396, //HANGUL SYLLABLE PHIEUPH EO PHIEUPH + 0xBC6B: 0xD397, //HANGUL SYLLABLE PHIEUPH EO HIEUH + 0xBC6C: 0xD39A, //HANGUL SYLLABLE PHIEUPH E SSANGKIYEOK + 0xBC6D: 0xD39B, //HANGUL SYLLABLE PHIEUPH E KIYEOKSIOS + 0xBC6E: 0xD39D, //HANGUL SYLLABLE PHIEUPH E NIEUNCIEUC + 0xBC6F: 0xD39E, //HANGUL SYLLABLE PHIEUPH E NIEUNHIEUH + 0xBC70: 0xD39F, //HANGUL SYLLABLE PHIEUPH E TIKEUT + 0xBC71: 0xD3A1, //HANGUL SYLLABLE PHIEUPH E RIEULKIYEOK + 0xBC72: 0xD3A2, //HANGUL SYLLABLE PHIEUPH E RIEULMIEUM + 0xBC73: 0xD3A3, //HANGUL SYLLABLE PHIEUPH E RIEULPIEUP + 0xBC74: 0xD3A4, //HANGUL SYLLABLE PHIEUPH E RIEULSIOS + 0xBC75: 0xD3A5, //HANGUL SYLLABLE PHIEUPH E RIEULTHIEUTH + 0xBC76: 0xD3A6, //HANGUL SYLLABLE PHIEUPH E RIEULPHIEUPH + 0xBC77: 0xD3A7, //HANGUL SYLLABLE PHIEUPH E RIEULHIEUH + 0xBC78: 0xD3AA, //HANGUL SYLLABLE PHIEUPH E PIEUPSIOS + 0xBC79: 0xD3AC, //HANGUL SYLLABLE PHIEUPH E SSANGSIOS + 0xBC7A: 0xD3AE, //HANGUL SYLLABLE PHIEUPH E CIEUC + 0xBC81: 0xD3AF, //HANGUL SYLLABLE PHIEUPH E CHIEUCH + 0xBC82: 0xD3B0, //HANGUL SYLLABLE PHIEUPH E KHIEUKH + 0xBC83: 0xD3B1, //HANGUL SYLLABLE PHIEUPH E THIEUTH + 0xBC84: 0xD3B2, //HANGUL SYLLABLE PHIEUPH E PHIEUPH + 0xBC85: 0xD3B3, //HANGUL SYLLABLE PHIEUPH E HIEUH + 0xBC86: 0xD3B5, //HANGUL SYLLABLE PHIEUPH YEO KIYEOK + 0xBC87: 0xD3B6, //HANGUL SYLLABLE PHIEUPH YEO SSANGKIYEOK + 0xBC88: 0xD3B7, //HANGUL SYLLABLE PHIEUPH YEO KIYEOKSIOS + 0xBC89: 0xD3B9, //HANGUL SYLLABLE PHIEUPH YEO NIEUNCIEUC + 0xBC8A: 0xD3BA, //HANGUL SYLLABLE PHIEUPH YEO NIEUNHIEUH + 0xBC8B: 0xD3BB, //HANGUL SYLLABLE PHIEUPH YEO TIKEUT + 0xBC8C: 0xD3BD, //HANGUL SYLLABLE PHIEUPH YEO RIEULKIYEOK + 0xBC8D: 0xD3BE, //HANGUL SYLLABLE PHIEUPH YEO RIEULMIEUM + 0xBC8E: 0xD3BF, //HANGUL SYLLABLE PHIEUPH YEO RIEULPIEUP + 0xBC8F: 0xD3C0, //HANGUL SYLLABLE PHIEUPH YEO RIEULSIOS + 0xBC90: 0xD3C1, //HANGUL SYLLABLE PHIEUPH YEO RIEULTHIEUTH + 0xBC91: 0xD3C2, //HANGUL SYLLABLE PHIEUPH YEO RIEULPHIEUPH + 0xBC92: 0xD3C3, //HANGUL SYLLABLE PHIEUPH YEO RIEULHIEUH + 0xBC93: 0xD3C6, //HANGUL SYLLABLE PHIEUPH YEO PIEUPSIOS + 0xBC94: 0xD3C7, //HANGUL SYLLABLE PHIEUPH YEO SIOS + 0xBC95: 0xD3CA, //HANGUL SYLLABLE PHIEUPH YEO CIEUC + 0xBC96: 0xD3CB, //HANGUL SYLLABLE PHIEUPH YEO CHIEUCH + 0xBC97: 0xD3CC, //HANGUL SYLLABLE PHIEUPH YEO KHIEUKH + 0xBC98: 0xD3CD, //HANGUL SYLLABLE PHIEUPH YEO THIEUTH + 0xBC99: 0xD3CE, //HANGUL SYLLABLE PHIEUPH YEO PHIEUPH + 0xBC9A: 0xD3CF, //HANGUL SYLLABLE PHIEUPH YEO HIEUH + 0xBC9B: 0xD3D1, //HANGUL SYLLABLE PHIEUPH YE KIYEOK + 0xBC9C: 0xD3D2, //HANGUL SYLLABLE PHIEUPH YE SSANGKIYEOK + 0xBC9D: 0xD3D3, //HANGUL SYLLABLE PHIEUPH YE KIYEOKSIOS + 0xBC9E: 0xD3D4, //HANGUL SYLLABLE PHIEUPH YE NIEUN + 0xBC9F: 0xD3D5, //HANGUL SYLLABLE PHIEUPH YE NIEUNCIEUC + 0xBCA0: 0xD3D6, //HANGUL SYLLABLE PHIEUPH YE NIEUNHIEUH + 0xBCA1: 0xC0E5, //HANGUL SYLLABLE SIOS YA KIYEOK + 0xBCA2: 0xC0E8, //HANGUL SYLLABLE SIOS YA NIEUN + 0xBCA3: 0xC0EC, //HANGUL SYLLABLE SIOS YA RIEUL + 0xBCA4: 0xC0F4, //HANGUL SYLLABLE SIOS YA MIEUM + 0xBCA5: 0xC0F5, //HANGUL SYLLABLE SIOS YA PIEUP + 0xBCA6: 0xC0F7, //HANGUL SYLLABLE SIOS YA SIOS + 0xBCA7: 0xC0F9, //HANGUL SYLLABLE SIOS YA IEUNG + 0xBCA8: 0xC100, //HANGUL SYLLABLE SIOS YAE + 0xBCA9: 0xC104, //HANGUL SYLLABLE SIOS YAE NIEUN + 0xBCAA: 0xC108, //HANGUL SYLLABLE SIOS YAE RIEUL + 0xBCAB: 0xC110, //HANGUL SYLLABLE SIOS YAE MIEUM + 0xBCAC: 0xC115, //HANGUL SYLLABLE SIOS YAE IEUNG + 0xBCAD: 0xC11C, //HANGUL SYLLABLE SIOS EO + 0xBCAE: 0xC11D, //HANGUL SYLLABLE SIOS EO KIYEOK + 0xBCAF: 0xC11E, //HANGUL SYLLABLE SIOS EO SSANGKIYEOK + 0xBCB0: 0xC11F, //HANGUL SYLLABLE SIOS EO KIYEOKSIOS + 0xBCB1: 0xC120, //HANGUL SYLLABLE SIOS EO NIEUN + 0xBCB2: 0xC123, //HANGUL SYLLABLE SIOS EO TIKEUT + 0xBCB3: 0xC124, //HANGUL SYLLABLE SIOS EO RIEUL + 0xBCB4: 0xC126, //HANGUL SYLLABLE SIOS EO RIEULMIEUM + 0xBCB5: 0xC127, //HANGUL SYLLABLE SIOS EO RIEULPIEUP + 0xBCB6: 0xC12C, //HANGUL SYLLABLE SIOS EO MIEUM + 0xBCB7: 0xC12D, //HANGUL SYLLABLE SIOS EO PIEUP + 0xBCB8: 0xC12F, //HANGUL SYLLABLE SIOS EO SIOS + 0xBCB9: 0xC130, //HANGUL SYLLABLE SIOS EO SSANGSIOS + 0xBCBA: 0xC131, //HANGUL SYLLABLE SIOS EO IEUNG + 0xBCBB: 0xC136, //HANGUL SYLLABLE SIOS EO PHIEUPH + 0xBCBC: 0xC138, //HANGUL SYLLABLE SIOS E + 0xBCBD: 0xC139, //HANGUL SYLLABLE SIOS E KIYEOK + 0xBCBE: 0xC13C, //HANGUL SYLLABLE SIOS E NIEUN + 0xBCBF: 0xC140, //HANGUL SYLLABLE SIOS E RIEUL + 0xBCC0: 0xC148, //HANGUL SYLLABLE SIOS E MIEUM + 0xBCC1: 0xC149, //HANGUL SYLLABLE SIOS E PIEUP + 0xBCC2: 0xC14B, //HANGUL SYLLABLE SIOS E SIOS + 0xBCC3: 0xC14C, //HANGUL SYLLABLE SIOS E SSANGSIOS + 0xBCC4: 0xC14D, //HANGUL SYLLABLE SIOS E IEUNG + 0xBCC5: 0xC154, //HANGUL SYLLABLE SIOS YEO + 0xBCC6: 0xC155, //HANGUL SYLLABLE SIOS YEO KIYEOK + 0xBCC7: 0xC158, //HANGUL SYLLABLE SIOS YEO NIEUN + 0xBCC8: 0xC15C, //HANGUL SYLLABLE SIOS YEO RIEUL + 0xBCC9: 0xC164, //HANGUL SYLLABLE SIOS YEO MIEUM + 0xBCCA: 0xC165, //HANGUL SYLLABLE SIOS YEO PIEUP + 0xBCCB: 0xC167, //HANGUL SYLLABLE SIOS YEO SIOS + 0xBCCC: 0xC168, //HANGUL SYLLABLE SIOS YEO SSANGSIOS + 0xBCCD: 0xC169, //HANGUL SYLLABLE SIOS YEO IEUNG + 0xBCCE: 0xC170, //HANGUL SYLLABLE SIOS YE + 0xBCCF: 0xC174, //HANGUL SYLLABLE SIOS YE NIEUN + 0xBCD0: 0xC178, //HANGUL SYLLABLE SIOS YE RIEUL + 0xBCD1: 0xC185, //HANGUL SYLLABLE SIOS YE IEUNG + 0xBCD2: 0xC18C, //HANGUL SYLLABLE SIOS O + 0xBCD3: 0xC18D, //HANGUL SYLLABLE SIOS O KIYEOK + 0xBCD4: 0xC18E, //HANGUL SYLLABLE SIOS O SSANGKIYEOK + 0xBCD5: 0xC190, //HANGUL SYLLABLE SIOS O NIEUN + 0xBCD6: 0xC194, //HANGUL SYLLABLE SIOS O RIEUL + 0xBCD7: 0xC196, //HANGUL SYLLABLE SIOS O RIEULMIEUM + 0xBCD8: 0xC19C, //HANGUL SYLLABLE SIOS O MIEUM + 0xBCD9: 0xC19D, //HANGUL SYLLABLE SIOS O PIEUP + 0xBCDA: 0xC19F, //HANGUL SYLLABLE SIOS O SIOS + 0xBCDB: 0xC1A1, //HANGUL SYLLABLE SIOS O IEUNG + 0xBCDC: 0xC1A5, //HANGUL SYLLABLE SIOS O THIEUTH + 0xBCDD: 0xC1A8, //HANGUL SYLLABLE SIOS WA + 0xBCDE: 0xC1A9, //HANGUL SYLLABLE SIOS WA KIYEOK + 0xBCDF: 0xC1AC, //HANGUL SYLLABLE SIOS WA NIEUN + 0xBCE0: 0xC1B0, //HANGUL SYLLABLE SIOS WA RIEUL + 0xBCE1: 0xC1BD, //HANGUL SYLLABLE SIOS WA IEUNG + 0xBCE2: 0xC1C4, //HANGUL SYLLABLE SIOS WAE + 0xBCE3: 0xC1C8, //HANGUL SYLLABLE SIOS WAE NIEUN + 0xBCE4: 0xC1CC, //HANGUL SYLLABLE SIOS WAE RIEUL + 0xBCE5: 0xC1D4, //HANGUL SYLLABLE SIOS WAE MIEUM + 0xBCE6: 0xC1D7, //HANGUL SYLLABLE SIOS WAE SIOS + 0xBCE7: 0xC1D8, //HANGUL SYLLABLE SIOS WAE SSANGSIOS + 0xBCE8: 0xC1E0, //HANGUL SYLLABLE SIOS OE + 0xBCE9: 0xC1E4, //HANGUL SYLLABLE SIOS OE NIEUN + 0xBCEA: 0xC1E8, //HANGUL SYLLABLE SIOS OE RIEUL + 0xBCEB: 0xC1F0, //HANGUL SYLLABLE SIOS OE MIEUM + 0xBCEC: 0xC1F1, //HANGUL SYLLABLE SIOS OE PIEUP + 0xBCED: 0xC1F3, //HANGUL SYLLABLE SIOS OE SIOS + 0xBCEE: 0xC1FC, //HANGUL SYLLABLE SIOS YO + 0xBCEF: 0xC1FD, //HANGUL SYLLABLE SIOS YO KIYEOK + 0xBCF0: 0xC200, //HANGUL SYLLABLE SIOS YO NIEUN + 0xBCF1: 0xC204, //HANGUL SYLLABLE SIOS YO RIEUL + 0xBCF2: 0xC20C, //HANGUL SYLLABLE SIOS YO MIEUM + 0xBCF3: 0xC20D, //HANGUL SYLLABLE SIOS YO PIEUP + 0xBCF4: 0xC20F, //HANGUL SYLLABLE SIOS YO SIOS + 0xBCF5: 0xC211, //HANGUL SYLLABLE SIOS YO IEUNG + 0xBCF6: 0xC218, //HANGUL SYLLABLE SIOS U + 0xBCF7: 0xC219, //HANGUL SYLLABLE SIOS U KIYEOK + 0xBCF8: 0xC21C, //HANGUL SYLLABLE SIOS U NIEUN + 0xBCF9: 0xC21F, //HANGUL SYLLABLE SIOS U TIKEUT + 0xBCFA: 0xC220, //HANGUL SYLLABLE SIOS U RIEUL + 0xBCFB: 0xC228, //HANGUL SYLLABLE SIOS U MIEUM + 0xBCFC: 0xC229, //HANGUL SYLLABLE SIOS U PIEUP + 0xBCFD: 0xC22B, //HANGUL SYLLABLE SIOS U SIOS + 0xBCFE: 0xC22D, //HANGUL SYLLABLE SIOS U IEUNG + 0xBD41: 0xD3D7, //HANGUL SYLLABLE PHIEUPH YE TIKEUT + 0xBD42: 0xD3D9, //HANGUL SYLLABLE PHIEUPH YE RIEULKIYEOK + 0xBD43: 0xD3DA, //HANGUL SYLLABLE PHIEUPH YE RIEULMIEUM + 0xBD44: 0xD3DB, //HANGUL SYLLABLE PHIEUPH YE RIEULPIEUP + 0xBD45: 0xD3DC, //HANGUL SYLLABLE PHIEUPH YE RIEULSIOS + 0xBD46: 0xD3DD, //HANGUL SYLLABLE PHIEUPH YE RIEULTHIEUTH + 0xBD47: 0xD3DE, //HANGUL SYLLABLE PHIEUPH YE RIEULPHIEUPH + 0xBD48: 0xD3DF, //HANGUL SYLLABLE PHIEUPH YE RIEULHIEUH + 0xBD49: 0xD3E0, //HANGUL SYLLABLE PHIEUPH YE MIEUM + 0xBD4A: 0xD3E2, //HANGUL SYLLABLE PHIEUPH YE PIEUPSIOS + 0xBD4B: 0xD3E4, //HANGUL SYLLABLE PHIEUPH YE SSANGSIOS + 0xBD4C: 0xD3E5, //HANGUL SYLLABLE PHIEUPH YE IEUNG + 0xBD4D: 0xD3E6, //HANGUL SYLLABLE PHIEUPH YE CIEUC + 0xBD4E: 0xD3E7, //HANGUL SYLLABLE PHIEUPH YE CHIEUCH + 0xBD4F: 0xD3E8, //HANGUL SYLLABLE PHIEUPH YE KHIEUKH + 0xBD50: 0xD3E9, //HANGUL SYLLABLE PHIEUPH YE THIEUTH + 0xBD51: 0xD3EA, //HANGUL SYLLABLE PHIEUPH YE PHIEUPH + 0xBD52: 0xD3EB, //HANGUL SYLLABLE PHIEUPH YE HIEUH + 0xBD53: 0xD3EE, //HANGUL SYLLABLE PHIEUPH O SSANGKIYEOK + 0xBD54: 0xD3EF, //HANGUL SYLLABLE PHIEUPH O KIYEOKSIOS + 0xBD55: 0xD3F1, //HANGUL SYLLABLE PHIEUPH O NIEUNCIEUC + 0xBD56: 0xD3F2, //HANGUL SYLLABLE PHIEUPH O NIEUNHIEUH + 0xBD57: 0xD3F3, //HANGUL SYLLABLE PHIEUPH O TIKEUT + 0xBD58: 0xD3F5, //HANGUL SYLLABLE PHIEUPH O RIEULKIYEOK + 0xBD59: 0xD3F6, //HANGUL SYLLABLE PHIEUPH O RIEULMIEUM + 0xBD5A: 0xD3F7, //HANGUL SYLLABLE PHIEUPH O RIEULPIEUP + 0xBD61: 0xD3F8, //HANGUL SYLLABLE PHIEUPH O RIEULSIOS + 0xBD62: 0xD3F9, //HANGUL SYLLABLE PHIEUPH O RIEULTHIEUTH + 0xBD63: 0xD3FA, //HANGUL SYLLABLE PHIEUPH O RIEULPHIEUPH + 0xBD64: 0xD3FB, //HANGUL SYLLABLE PHIEUPH O RIEULHIEUH + 0xBD65: 0xD3FE, //HANGUL SYLLABLE PHIEUPH O PIEUPSIOS + 0xBD66: 0xD400, //HANGUL SYLLABLE PHIEUPH O SSANGSIOS + 0xBD67: 0xD402, //HANGUL SYLLABLE PHIEUPH O CIEUC + 0xBD68: 0xD403, //HANGUL SYLLABLE PHIEUPH O CHIEUCH + 0xBD69: 0xD404, //HANGUL SYLLABLE PHIEUPH O KHIEUKH + 0xBD6A: 0xD405, //HANGUL SYLLABLE PHIEUPH O THIEUTH + 0xBD6B: 0xD406, //HANGUL SYLLABLE PHIEUPH O PHIEUPH + 0xBD6C: 0xD407, //HANGUL SYLLABLE PHIEUPH O HIEUH + 0xBD6D: 0xD409, //HANGUL SYLLABLE PHIEUPH WA KIYEOK + 0xBD6E: 0xD40A, //HANGUL SYLLABLE PHIEUPH WA SSANGKIYEOK + 0xBD6F: 0xD40B, //HANGUL SYLLABLE PHIEUPH WA KIYEOKSIOS + 0xBD70: 0xD40C, //HANGUL SYLLABLE PHIEUPH WA NIEUN + 0xBD71: 0xD40D, //HANGUL SYLLABLE PHIEUPH WA NIEUNCIEUC + 0xBD72: 0xD40E, //HANGUL SYLLABLE PHIEUPH WA NIEUNHIEUH + 0xBD73: 0xD40F, //HANGUL SYLLABLE PHIEUPH WA TIKEUT + 0xBD74: 0xD410, //HANGUL SYLLABLE PHIEUPH WA RIEUL + 0xBD75: 0xD411, //HANGUL SYLLABLE PHIEUPH WA RIEULKIYEOK + 0xBD76: 0xD412, //HANGUL SYLLABLE PHIEUPH WA RIEULMIEUM + 0xBD77: 0xD413, //HANGUL SYLLABLE PHIEUPH WA RIEULPIEUP + 0xBD78: 0xD414, //HANGUL SYLLABLE PHIEUPH WA RIEULSIOS + 0xBD79: 0xD415, //HANGUL SYLLABLE PHIEUPH WA RIEULTHIEUTH + 0xBD7A: 0xD416, //HANGUL SYLLABLE PHIEUPH WA RIEULPHIEUPH + 0xBD81: 0xD417, //HANGUL SYLLABLE PHIEUPH WA RIEULHIEUH + 0xBD82: 0xD418, //HANGUL SYLLABLE PHIEUPH WA MIEUM + 0xBD83: 0xD419, //HANGUL SYLLABLE PHIEUPH WA PIEUP + 0xBD84: 0xD41A, //HANGUL SYLLABLE PHIEUPH WA PIEUPSIOS + 0xBD85: 0xD41B, //HANGUL SYLLABLE PHIEUPH WA SIOS + 0xBD86: 0xD41C, //HANGUL SYLLABLE PHIEUPH WA SSANGSIOS + 0xBD87: 0xD41E, //HANGUL SYLLABLE PHIEUPH WA CIEUC + 0xBD88: 0xD41F, //HANGUL SYLLABLE PHIEUPH WA CHIEUCH + 0xBD89: 0xD420, //HANGUL SYLLABLE PHIEUPH WA KHIEUKH + 0xBD8A: 0xD421, //HANGUL SYLLABLE PHIEUPH WA THIEUTH + 0xBD8B: 0xD422, //HANGUL SYLLABLE PHIEUPH WA PHIEUPH + 0xBD8C: 0xD423, //HANGUL SYLLABLE PHIEUPH WA HIEUH + 0xBD8D: 0xD424, //HANGUL SYLLABLE PHIEUPH WAE + 0xBD8E: 0xD425, //HANGUL SYLLABLE PHIEUPH WAE KIYEOK + 0xBD8F: 0xD426, //HANGUL SYLLABLE PHIEUPH WAE SSANGKIYEOK + 0xBD90: 0xD427, //HANGUL SYLLABLE PHIEUPH WAE KIYEOKSIOS + 0xBD91: 0xD428, //HANGUL SYLLABLE PHIEUPH WAE NIEUN + 0xBD92: 0xD429, //HANGUL SYLLABLE PHIEUPH WAE NIEUNCIEUC + 0xBD93: 0xD42A, //HANGUL SYLLABLE PHIEUPH WAE NIEUNHIEUH + 0xBD94: 0xD42B, //HANGUL SYLLABLE PHIEUPH WAE TIKEUT + 0xBD95: 0xD42C, //HANGUL SYLLABLE PHIEUPH WAE RIEUL + 0xBD96: 0xD42D, //HANGUL SYLLABLE PHIEUPH WAE RIEULKIYEOK + 0xBD97: 0xD42E, //HANGUL SYLLABLE PHIEUPH WAE RIEULMIEUM + 0xBD98: 0xD42F, //HANGUL SYLLABLE PHIEUPH WAE RIEULPIEUP + 0xBD99: 0xD430, //HANGUL SYLLABLE PHIEUPH WAE RIEULSIOS + 0xBD9A: 0xD431, //HANGUL SYLLABLE PHIEUPH WAE RIEULTHIEUTH + 0xBD9B: 0xD432, //HANGUL SYLLABLE PHIEUPH WAE RIEULPHIEUPH + 0xBD9C: 0xD433, //HANGUL SYLLABLE PHIEUPH WAE RIEULHIEUH + 0xBD9D: 0xD434, //HANGUL SYLLABLE PHIEUPH WAE MIEUM + 0xBD9E: 0xD435, //HANGUL SYLLABLE PHIEUPH WAE PIEUP + 0xBD9F: 0xD436, //HANGUL SYLLABLE PHIEUPH WAE PIEUPSIOS + 0xBDA0: 0xD437, //HANGUL SYLLABLE PHIEUPH WAE SIOS + 0xBDA1: 0xC22F, //HANGUL SYLLABLE SIOS U CHIEUCH + 0xBDA2: 0xC231, //HANGUL SYLLABLE SIOS U THIEUTH + 0xBDA3: 0xC232, //HANGUL SYLLABLE SIOS U PHIEUPH + 0xBDA4: 0xC234, //HANGUL SYLLABLE SIOS WEO + 0xBDA5: 0xC248, //HANGUL SYLLABLE SIOS WEO SSANGSIOS + 0xBDA6: 0xC250, //HANGUL SYLLABLE SIOS WE + 0xBDA7: 0xC251, //HANGUL SYLLABLE SIOS WE KIYEOK + 0xBDA8: 0xC254, //HANGUL SYLLABLE SIOS WE NIEUN + 0xBDA9: 0xC258, //HANGUL SYLLABLE SIOS WE RIEUL + 0xBDAA: 0xC260, //HANGUL SYLLABLE SIOS WE MIEUM + 0xBDAB: 0xC265, //HANGUL SYLLABLE SIOS WE IEUNG + 0xBDAC: 0xC26C, //HANGUL SYLLABLE SIOS WI + 0xBDAD: 0xC26D, //HANGUL SYLLABLE SIOS WI KIYEOK + 0xBDAE: 0xC270, //HANGUL SYLLABLE SIOS WI NIEUN + 0xBDAF: 0xC274, //HANGUL SYLLABLE SIOS WI RIEUL + 0xBDB0: 0xC27C, //HANGUL SYLLABLE SIOS WI MIEUM + 0xBDB1: 0xC27D, //HANGUL SYLLABLE SIOS WI PIEUP + 0xBDB2: 0xC27F, //HANGUL SYLLABLE SIOS WI SIOS + 0xBDB3: 0xC281, //HANGUL SYLLABLE SIOS WI IEUNG + 0xBDB4: 0xC288, //HANGUL SYLLABLE SIOS YU + 0xBDB5: 0xC289, //HANGUL SYLLABLE SIOS YU KIYEOK + 0xBDB6: 0xC290, //HANGUL SYLLABLE SIOS YU RIEUL + 0xBDB7: 0xC298, //HANGUL SYLLABLE SIOS YU MIEUM + 0xBDB8: 0xC29B, //HANGUL SYLLABLE SIOS YU SIOS + 0xBDB9: 0xC29D, //HANGUL SYLLABLE SIOS YU IEUNG + 0xBDBA: 0xC2A4, //HANGUL SYLLABLE SIOS EU + 0xBDBB: 0xC2A5, //HANGUL SYLLABLE SIOS EU KIYEOK + 0xBDBC: 0xC2A8, //HANGUL SYLLABLE SIOS EU NIEUN + 0xBDBD: 0xC2AC, //HANGUL SYLLABLE SIOS EU RIEUL + 0xBDBE: 0xC2AD, //HANGUL SYLLABLE SIOS EU RIEULKIYEOK + 0xBDBF: 0xC2B4, //HANGUL SYLLABLE SIOS EU MIEUM + 0xBDC0: 0xC2B5, //HANGUL SYLLABLE SIOS EU PIEUP + 0xBDC1: 0xC2B7, //HANGUL SYLLABLE SIOS EU SIOS + 0xBDC2: 0xC2B9, //HANGUL SYLLABLE SIOS EU IEUNG + 0xBDC3: 0xC2DC, //HANGUL SYLLABLE SIOS I + 0xBDC4: 0xC2DD, //HANGUL SYLLABLE SIOS I KIYEOK + 0xBDC5: 0xC2E0, //HANGUL SYLLABLE SIOS I NIEUN + 0xBDC6: 0xC2E3, //HANGUL SYLLABLE SIOS I TIKEUT + 0xBDC7: 0xC2E4, //HANGUL SYLLABLE SIOS I RIEUL + 0xBDC8: 0xC2EB, //HANGUL SYLLABLE SIOS I RIEULHIEUH + 0xBDC9: 0xC2EC, //HANGUL SYLLABLE SIOS I MIEUM + 0xBDCA: 0xC2ED, //HANGUL SYLLABLE SIOS I PIEUP + 0xBDCB: 0xC2EF, //HANGUL SYLLABLE SIOS I SIOS + 0xBDCC: 0xC2F1, //HANGUL SYLLABLE SIOS I IEUNG + 0xBDCD: 0xC2F6, //HANGUL SYLLABLE SIOS I PHIEUPH + 0xBDCE: 0xC2F8, //HANGUL SYLLABLE SSANGSIOS A + 0xBDCF: 0xC2F9, //HANGUL SYLLABLE SSANGSIOS A KIYEOK + 0xBDD0: 0xC2FB, //HANGUL SYLLABLE SSANGSIOS A KIYEOKSIOS + 0xBDD1: 0xC2FC, //HANGUL SYLLABLE SSANGSIOS A NIEUN + 0xBDD2: 0xC300, //HANGUL SYLLABLE SSANGSIOS A RIEUL + 0xBDD3: 0xC308, //HANGUL SYLLABLE SSANGSIOS A MIEUM + 0xBDD4: 0xC309, //HANGUL SYLLABLE SSANGSIOS A PIEUP + 0xBDD5: 0xC30C, //HANGUL SYLLABLE SSANGSIOS A SSANGSIOS + 0xBDD6: 0xC30D, //HANGUL SYLLABLE SSANGSIOS A IEUNG + 0xBDD7: 0xC313, //HANGUL SYLLABLE SSANGSIOS A HIEUH + 0xBDD8: 0xC314, //HANGUL SYLLABLE SSANGSIOS AE + 0xBDD9: 0xC315, //HANGUL SYLLABLE SSANGSIOS AE KIYEOK + 0xBDDA: 0xC318, //HANGUL SYLLABLE SSANGSIOS AE NIEUN + 0xBDDB: 0xC31C, //HANGUL SYLLABLE SSANGSIOS AE RIEUL + 0xBDDC: 0xC324, //HANGUL SYLLABLE SSANGSIOS AE MIEUM + 0xBDDD: 0xC325, //HANGUL SYLLABLE SSANGSIOS AE PIEUP + 0xBDDE: 0xC328, //HANGUL SYLLABLE SSANGSIOS AE SSANGSIOS + 0xBDDF: 0xC329, //HANGUL SYLLABLE SSANGSIOS AE IEUNG + 0xBDE0: 0xC345, //HANGUL SYLLABLE SSANGSIOS YA IEUNG + 0xBDE1: 0xC368, //HANGUL SYLLABLE SSANGSIOS EO + 0xBDE2: 0xC369, //HANGUL SYLLABLE SSANGSIOS EO KIYEOK + 0xBDE3: 0xC36C, //HANGUL SYLLABLE SSANGSIOS EO NIEUN + 0xBDE4: 0xC370, //HANGUL SYLLABLE SSANGSIOS EO RIEUL + 0xBDE5: 0xC372, //HANGUL SYLLABLE SSANGSIOS EO RIEULMIEUM + 0xBDE6: 0xC378, //HANGUL SYLLABLE SSANGSIOS EO MIEUM + 0xBDE7: 0xC379, //HANGUL SYLLABLE SSANGSIOS EO PIEUP + 0xBDE8: 0xC37C, //HANGUL SYLLABLE SSANGSIOS EO SSANGSIOS + 0xBDE9: 0xC37D, //HANGUL SYLLABLE SSANGSIOS EO IEUNG + 0xBDEA: 0xC384, //HANGUL SYLLABLE SSANGSIOS E + 0xBDEB: 0xC388, //HANGUL SYLLABLE SSANGSIOS E NIEUN + 0xBDEC: 0xC38C, //HANGUL SYLLABLE SSANGSIOS E RIEUL + 0xBDED: 0xC3C0, //HANGUL SYLLABLE SSANGSIOS YE NIEUN + 0xBDEE: 0xC3D8, //HANGUL SYLLABLE SSANGSIOS O + 0xBDEF: 0xC3D9, //HANGUL SYLLABLE SSANGSIOS O KIYEOK + 0xBDF0: 0xC3DC, //HANGUL SYLLABLE SSANGSIOS O NIEUN + 0xBDF1: 0xC3DF, //HANGUL SYLLABLE SSANGSIOS O TIKEUT + 0xBDF2: 0xC3E0, //HANGUL SYLLABLE SSANGSIOS O RIEUL + 0xBDF3: 0xC3E2, //HANGUL SYLLABLE SSANGSIOS O RIEULMIEUM + 0xBDF4: 0xC3E8, //HANGUL SYLLABLE SSANGSIOS O MIEUM + 0xBDF5: 0xC3E9, //HANGUL SYLLABLE SSANGSIOS O PIEUP + 0xBDF6: 0xC3ED, //HANGUL SYLLABLE SSANGSIOS O IEUNG + 0xBDF7: 0xC3F4, //HANGUL SYLLABLE SSANGSIOS WA + 0xBDF8: 0xC3F5, //HANGUL SYLLABLE SSANGSIOS WA KIYEOK + 0xBDF9: 0xC3F8, //HANGUL SYLLABLE SSANGSIOS WA NIEUN + 0xBDFA: 0xC408, //HANGUL SYLLABLE SSANGSIOS WA SSANGSIOS + 0xBDFB: 0xC410, //HANGUL SYLLABLE SSANGSIOS WAE + 0xBDFC: 0xC424, //HANGUL SYLLABLE SSANGSIOS WAE SSANGSIOS + 0xBDFD: 0xC42C, //HANGUL SYLLABLE SSANGSIOS OE + 0xBDFE: 0xC430, //HANGUL SYLLABLE SSANGSIOS OE NIEUN + 0xBE41: 0xD438, //HANGUL SYLLABLE PHIEUPH WAE SSANGSIOS + 0xBE42: 0xD439, //HANGUL SYLLABLE PHIEUPH WAE IEUNG + 0xBE43: 0xD43A, //HANGUL SYLLABLE PHIEUPH WAE CIEUC + 0xBE44: 0xD43B, //HANGUL SYLLABLE PHIEUPH WAE CHIEUCH + 0xBE45: 0xD43C, //HANGUL SYLLABLE PHIEUPH WAE KHIEUKH + 0xBE46: 0xD43D, //HANGUL SYLLABLE PHIEUPH WAE THIEUTH + 0xBE47: 0xD43E, //HANGUL SYLLABLE PHIEUPH WAE PHIEUPH + 0xBE48: 0xD43F, //HANGUL SYLLABLE PHIEUPH WAE HIEUH + 0xBE49: 0xD441, //HANGUL SYLLABLE PHIEUPH OE KIYEOK + 0xBE4A: 0xD442, //HANGUL SYLLABLE PHIEUPH OE SSANGKIYEOK + 0xBE4B: 0xD443, //HANGUL SYLLABLE PHIEUPH OE KIYEOKSIOS + 0xBE4C: 0xD445, //HANGUL SYLLABLE PHIEUPH OE NIEUNCIEUC + 0xBE4D: 0xD446, //HANGUL SYLLABLE PHIEUPH OE NIEUNHIEUH + 0xBE4E: 0xD447, //HANGUL SYLLABLE PHIEUPH OE TIKEUT + 0xBE4F: 0xD448, //HANGUL SYLLABLE PHIEUPH OE RIEUL + 0xBE50: 0xD449, //HANGUL SYLLABLE PHIEUPH OE RIEULKIYEOK + 0xBE51: 0xD44A, //HANGUL SYLLABLE PHIEUPH OE RIEULMIEUM + 0xBE52: 0xD44B, //HANGUL SYLLABLE PHIEUPH OE RIEULPIEUP + 0xBE53: 0xD44C, //HANGUL SYLLABLE PHIEUPH OE RIEULSIOS + 0xBE54: 0xD44D, //HANGUL SYLLABLE PHIEUPH OE RIEULTHIEUTH + 0xBE55: 0xD44E, //HANGUL SYLLABLE PHIEUPH OE RIEULPHIEUPH + 0xBE56: 0xD44F, //HANGUL SYLLABLE PHIEUPH OE RIEULHIEUH + 0xBE57: 0xD450, //HANGUL SYLLABLE PHIEUPH OE MIEUM + 0xBE58: 0xD451, //HANGUL SYLLABLE PHIEUPH OE PIEUP + 0xBE59: 0xD452, //HANGUL SYLLABLE PHIEUPH OE PIEUPSIOS + 0xBE5A: 0xD453, //HANGUL SYLLABLE PHIEUPH OE SIOS + 0xBE61: 0xD454, //HANGUL SYLLABLE PHIEUPH OE SSANGSIOS + 0xBE62: 0xD455, //HANGUL SYLLABLE PHIEUPH OE IEUNG + 0xBE63: 0xD456, //HANGUL SYLLABLE PHIEUPH OE CIEUC + 0xBE64: 0xD457, //HANGUL SYLLABLE PHIEUPH OE CHIEUCH + 0xBE65: 0xD458, //HANGUL SYLLABLE PHIEUPH OE KHIEUKH + 0xBE66: 0xD459, //HANGUL SYLLABLE PHIEUPH OE THIEUTH + 0xBE67: 0xD45A, //HANGUL SYLLABLE PHIEUPH OE PHIEUPH + 0xBE68: 0xD45B, //HANGUL SYLLABLE PHIEUPH OE HIEUH + 0xBE69: 0xD45D, //HANGUL SYLLABLE PHIEUPH YO KIYEOK + 0xBE6A: 0xD45E, //HANGUL SYLLABLE PHIEUPH YO SSANGKIYEOK + 0xBE6B: 0xD45F, //HANGUL SYLLABLE PHIEUPH YO KIYEOKSIOS + 0xBE6C: 0xD461, //HANGUL SYLLABLE PHIEUPH YO NIEUNCIEUC + 0xBE6D: 0xD462, //HANGUL SYLLABLE PHIEUPH YO NIEUNHIEUH + 0xBE6E: 0xD463, //HANGUL SYLLABLE PHIEUPH YO TIKEUT + 0xBE6F: 0xD465, //HANGUL SYLLABLE PHIEUPH YO RIEULKIYEOK + 0xBE70: 0xD466, //HANGUL SYLLABLE PHIEUPH YO RIEULMIEUM + 0xBE71: 0xD467, //HANGUL SYLLABLE PHIEUPH YO RIEULPIEUP + 0xBE72: 0xD468, //HANGUL SYLLABLE PHIEUPH YO RIEULSIOS + 0xBE73: 0xD469, //HANGUL SYLLABLE PHIEUPH YO RIEULTHIEUTH + 0xBE74: 0xD46A, //HANGUL SYLLABLE PHIEUPH YO RIEULPHIEUPH + 0xBE75: 0xD46B, //HANGUL SYLLABLE PHIEUPH YO RIEULHIEUH + 0xBE76: 0xD46C, //HANGUL SYLLABLE PHIEUPH YO MIEUM + 0xBE77: 0xD46E, //HANGUL SYLLABLE PHIEUPH YO PIEUPSIOS + 0xBE78: 0xD470, //HANGUL SYLLABLE PHIEUPH YO SSANGSIOS + 0xBE79: 0xD471, //HANGUL SYLLABLE PHIEUPH YO IEUNG + 0xBE7A: 0xD472, //HANGUL SYLLABLE PHIEUPH YO CIEUC + 0xBE81: 0xD473, //HANGUL SYLLABLE PHIEUPH YO CHIEUCH + 0xBE82: 0xD474, //HANGUL SYLLABLE PHIEUPH YO KHIEUKH + 0xBE83: 0xD475, //HANGUL SYLLABLE PHIEUPH YO THIEUTH + 0xBE84: 0xD476, //HANGUL SYLLABLE PHIEUPH YO PHIEUPH + 0xBE85: 0xD477, //HANGUL SYLLABLE PHIEUPH YO HIEUH + 0xBE86: 0xD47A, //HANGUL SYLLABLE PHIEUPH U SSANGKIYEOK + 0xBE87: 0xD47B, //HANGUL SYLLABLE PHIEUPH U KIYEOKSIOS + 0xBE88: 0xD47D, //HANGUL SYLLABLE PHIEUPH U NIEUNCIEUC + 0xBE89: 0xD47E, //HANGUL SYLLABLE PHIEUPH U NIEUNHIEUH + 0xBE8A: 0xD481, //HANGUL SYLLABLE PHIEUPH U RIEULKIYEOK + 0xBE8B: 0xD483, //HANGUL SYLLABLE PHIEUPH U RIEULPIEUP + 0xBE8C: 0xD484, //HANGUL SYLLABLE PHIEUPH U RIEULSIOS + 0xBE8D: 0xD485, //HANGUL SYLLABLE PHIEUPH U RIEULTHIEUTH + 0xBE8E: 0xD486, //HANGUL SYLLABLE PHIEUPH U RIEULPHIEUPH + 0xBE8F: 0xD487, //HANGUL SYLLABLE PHIEUPH U RIEULHIEUH + 0xBE90: 0xD48A, //HANGUL SYLLABLE PHIEUPH U PIEUPSIOS + 0xBE91: 0xD48C, //HANGUL SYLLABLE PHIEUPH U SSANGSIOS + 0xBE92: 0xD48E, //HANGUL SYLLABLE PHIEUPH U CIEUC + 0xBE93: 0xD48F, //HANGUL SYLLABLE PHIEUPH U CHIEUCH + 0xBE94: 0xD490, //HANGUL SYLLABLE PHIEUPH U KHIEUKH + 0xBE95: 0xD491, //HANGUL SYLLABLE PHIEUPH U THIEUTH + 0xBE96: 0xD492, //HANGUL SYLLABLE PHIEUPH U PHIEUPH + 0xBE97: 0xD493, //HANGUL SYLLABLE PHIEUPH U HIEUH + 0xBE98: 0xD495, //HANGUL SYLLABLE PHIEUPH WEO KIYEOK + 0xBE99: 0xD496, //HANGUL SYLLABLE PHIEUPH WEO SSANGKIYEOK + 0xBE9A: 0xD497, //HANGUL SYLLABLE PHIEUPH WEO KIYEOKSIOS + 0xBE9B: 0xD498, //HANGUL SYLLABLE PHIEUPH WEO NIEUN + 0xBE9C: 0xD499, //HANGUL SYLLABLE PHIEUPH WEO NIEUNCIEUC + 0xBE9D: 0xD49A, //HANGUL SYLLABLE PHIEUPH WEO NIEUNHIEUH + 0xBE9E: 0xD49B, //HANGUL SYLLABLE PHIEUPH WEO TIKEUT + 0xBE9F: 0xD49C, //HANGUL SYLLABLE PHIEUPH WEO RIEUL + 0xBEA0: 0xD49D, //HANGUL SYLLABLE PHIEUPH WEO RIEULKIYEOK + 0xBEA1: 0xC434, //HANGUL SYLLABLE SSANGSIOS OE RIEUL + 0xBEA2: 0xC43C, //HANGUL SYLLABLE SSANGSIOS OE MIEUM + 0xBEA3: 0xC43D, //HANGUL SYLLABLE SSANGSIOS OE PIEUP + 0xBEA4: 0xC448, //HANGUL SYLLABLE SSANGSIOS YO + 0xBEA5: 0xC464, //HANGUL SYLLABLE SSANGSIOS U + 0xBEA6: 0xC465, //HANGUL SYLLABLE SSANGSIOS U KIYEOK + 0xBEA7: 0xC468, //HANGUL SYLLABLE SSANGSIOS U NIEUN + 0xBEA8: 0xC46C, //HANGUL SYLLABLE SSANGSIOS U RIEUL + 0xBEA9: 0xC474, //HANGUL SYLLABLE SSANGSIOS U MIEUM + 0xBEAA: 0xC475, //HANGUL SYLLABLE SSANGSIOS U PIEUP + 0xBEAB: 0xC479, //HANGUL SYLLABLE SSANGSIOS U IEUNG + 0xBEAC: 0xC480, //HANGUL SYLLABLE SSANGSIOS WEO + 0xBEAD: 0xC494, //HANGUL SYLLABLE SSANGSIOS WEO SSANGSIOS + 0xBEAE: 0xC49C, //HANGUL SYLLABLE SSANGSIOS WE + 0xBEAF: 0xC4B8, //HANGUL SYLLABLE SSANGSIOS WI + 0xBEB0: 0xC4BC, //HANGUL SYLLABLE SSANGSIOS WI NIEUN + 0xBEB1: 0xC4E9, //HANGUL SYLLABLE SSANGSIOS YU IEUNG + 0xBEB2: 0xC4F0, //HANGUL SYLLABLE SSANGSIOS EU + 0xBEB3: 0xC4F1, //HANGUL SYLLABLE SSANGSIOS EU KIYEOK + 0xBEB4: 0xC4F4, //HANGUL SYLLABLE SSANGSIOS EU NIEUN + 0xBEB5: 0xC4F8, //HANGUL SYLLABLE SSANGSIOS EU RIEUL + 0xBEB6: 0xC4FA, //HANGUL SYLLABLE SSANGSIOS EU RIEULMIEUM + 0xBEB7: 0xC4FF, //HANGUL SYLLABLE SSANGSIOS EU RIEULHIEUH + 0xBEB8: 0xC500, //HANGUL SYLLABLE SSANGSIOS EU MIEUM + 0xBEB9: 0xC501, //HANGUL SYLLABLE SSANGSIOS EU PIEUP + 0xBEBA: 0xC50C, //HANGUL SYLLABLE SSANGSIOS YI + 0xBEBB: 0xC510, //HANGUL SYLLABLE SSANGSIOS YI NIEUN + 0xBEBC: 0xC514, //HANGUL SYLLABLE SSANGSIOS YI RIEUL + 0xBEBD: 0xC51C, //HANGUL SYLLABLE SSANGSIOS YI MIEUM + 0xBEBE: 0xC528, //HANGUL SYLLABLE SSANGSIOS I + 0xBEBF: 0xC529, //HANGUL SYLLABLE SSANGSIOS I KIYEOK + 0xBEC0: 0xC52C, //HANGUL SYLLABLE SSANGSIOS I NIEUN + 0xBEC1: 0xC530, //HANGUL SYLLABLE SSANGSIOS I RIEUL + 0xBEC2: 0xC538, //HANGUL SYLLABLE SSANGSIOS I MIEUM + 0xBEC3: 0xC539, //HANGUL SYLLABLE SSANGSIOS I PIEUP + 0xBEC4: 0xC53B, //HANGUL SYLLABLE SSANGSIOS I SIOS + 0xBEC5: 0xC53D, //HANGUL SYLLABLE SSANGSIOS I IEUNG + 0xBEC6: 0xC544, //HANGUL SYLLABLE IEUNG A + 0xBEC7: 0xC545, //HANGUL SYLLABLE IEUNG A KIYEOK + 0xBEC8: 0xC548, //HANGUL SYLLABLE IEUNG A NIEUN + 0xBEC9: 0xC549, //HANGUL SYLLABLE IEUNG A NIEUNCIEUC + 0xBECA: 0xC54A, //HANGUL SYLLABLE IEUNG A NIEUNHIEUH + 0xBECB: 0xC54C, //HANGUL SYLLABLE IEUNG A RIEUL + 0xBECC: 0xC54D, //HANGUL SYLLABLE IEUNG A RIEULKIYEOK + 0xBECD: 0xC54E, //HANGUL SYLLABLE IEUNG A RIEULMIEUM + 0xBECE: 0xC553, //HANGUL SYLLABLE IEUNG A RIEULHIEUH + 0xBECF: 0xC554, //HANGUL SYLLABLE IEUNG A MIEUM + 0xBED0: 0xC555, //HANGUL SYLLABLE IEUNG A PIEUP + 0xBED1: 0xC557, //HANGUL SYLLABLE IEUNG A SIOS + 0xBED2: 0xC558, //HANGUL SYLLABLE IEUNG A SSANGSIOS + 0xBED3: 0xC559, //HANGUL SYLLABLE IEUNG A IEUNG + 0xBED4: 0xC55D, //HANGUL SYLLABLE IEUNG A THIEUTH + 0xBED5: 0xC55E, //HANGUL SYLLABLE IEUNG A PHIEUPH + 0xBED6: 0xC560, //HANGUL SYLLABLE IEUNG AE + 0xBED7: 0xC561, //HANGUL SYLLABLE IEUNG AE KIYEOK + 0xBED8: 0xC564, //HANGUL SYLLABLE IEUNG AE NIEUN + 0xBED9: 0xC568, //HANGUL SYLLABLE IEUNG AE RIEUL + 0xBEDA: 0xC570, //HANGUL SYLLABLE IEUNG AE MIEUM + 0xBEDB: 0xC571, //HANGUL SYLLABLE IEUNG AE PIEUP + 0xBEDC: 0xC573, //HANGUL SYLLABLE IEUNG AE SIOS + 0xBEDD: 0xC574, //HANGUL SYLLABLE IEUNG AE SSANGSIOS + 0xBEDE: 0xC575, //HANGUL SYLLABLE IEUNG AE IEUNG + 0xBEDF: 0xC57C, //HANGUL SYLLABLE IEUNG YA + 0xBEE0: 0xC57D, //HANGUL SYLLABLE IEUNG YA KIYEOK + 0xBEE1: 0xC580, //HANGUL SYLLABLE IEUNG YA NIEUN + 0xBEE2: 0xC584, //HANGUL SYLLABLE IEUNG YA RIEUL + 0xBEE3: 0xC587, //HANGUL SYLLABLE IEUNG YA RIEULPIEUP + 0xBEE4: 0xC58C, //HANGUL SYLLABLE IEUNG YA MIEUM + 0xBEE5: 0xC58D, //HANGUL SYLLABLE IEUNG YA PIEUP + 0xBEE6: 0xC58F, //HANGUL SYLLABLE IEUNG YA SIOS + 0xBEE7: 0xC591, //HANGUL SYLLABLE IEUNG YA IEUNG + 0xBEE8: 0xC595, //HANGUL SYLLABLE IEUNG YA THIEUTH + 0xBEE9: 0xC597, //HANGUL SYLLABLE IEUNG YA HIEUH + 0xBEEA: 0xC598, //HANGUL SYLLABLE IEUNG YAE + 0xBEEB: 0xC59C, //HANGUL SYLLABLE IEUNG YAE NIEUN + 0xBEEC: 0xC5A0, //HANGUL SYLLABLE IEUNG YAE RIEUL + 0xBEED: 0xC5A9, //HANGUL SYLLABLE IEUNG YAE PIEUP + 0xBEEE: 0xC5B4, //HANGUL SYLLABLE IEUNG EO + 0xBEEF: 0xC5B5, //HANGUL SYLLABLE IEUNG EO KIYEOK + 0xBEF0: 0xC5B8, //HANGUL SYLLABLE IEUNG EO NIEUN + 0xBEF1: 0xC5B9, //HANGUL SYLLABLE IEUNG EO NIEUNCIEUC + 0xBEF2: 0xC5BB, //HANGUL SYLLABLE IEUNG EO TIKEUT + 0xBEF3: 0xC5BC, //HANGUL SYLLABLE IEUNG EO RIEUL + 0xBEF4: 0xC5BD, //HANGUL SYLLABLE IEUNG EO RIEULKIYEOK + 0xBEF5: 0xC5BE, //HANGUL SYLLABLE IEUNG EO RIEULMIEUM + 0xBEF6: 0xC5C4, //HANGUL SYLLABLE IEUNG EO MIEUM + 0xBEF7: 0xC5C5, //HANGUL SYLLABLE IEUNG EO PIEUP + 0xBEF8: 0xC5C6, //HANGUL SYLLABLE IEUNG EO PIEUPSIOS + 0xBEF9: 0xC5C7, //HANGUL SYLLABLE IEUNG EO SIOS + 0xBEFA: 0xC5C8, //HANGUL SYLLABLE IEUNG EO SSANGSIOS + 0xBEFB: 0xC5C9, //HANGUL SYLLABLE IEUNG EO IEUNG + 0xBEFC: 0xC5CA, //HANGUL SYLLABLE IEUNG EO CIEUC + 0xBEFD: 0xC5CC, //HANGUL SYLLABLE IEUNG EO KHIEUKH + 0xBEFE: 0xC5CE, //HANGUL SYLLABLE IEUNG EO PHIEUPH + 0xBF41: 0xD49E, //HANGUL SYLLABLE PHIEUPH WEO RIEULMIEUM + 0xBF42: 0xD49F, //HANGUL SYLLABLE PHIEUPH WEO RIEULPIEUP + 0xBF43: 0xD4A0, //HANGUL SYLLABLE PHIEUPH WEO RIEULSIOS + 0xBF44: 0xD4A1, //HANGUL SYLLABLE PHIEUPH WEO RIEULTHIEUTH + 0xBF45: 0xD4A2, //HANGUL SYLLABLE PHIEUPH WEO RIEULPHIEUPH + 0xBF46: 0xD4A3, //HANGUL SYLLABLE PHIEUPH WEO RIEULHIEUH + 0xBF47: 0xD4A4, //HANGUL SYLLABLE PHIEUPH WEO MIEUM + 0xBF48: 0xD4A5, //HANGUL SYLLABLE PHIEUPH WEO PIEUP + 0xBF49: 0xD4A6, //HANGUL SYLLABLE PHIEUPH WEO PIEUPSIOS + 0xBF4A: 0xD4A7, //HANGUL SYLLABLE PHIEUPH WEO SIOS + 0xBF4B: 0xD4A8, //HANGUL SYLLABLE PHIEUPH WEO SSANGSIOS + 0xBF4C: 0xD4AA, //HANGUL SYLLABLE PHIEUPH WEO CIEUC + 0xBF4D: 0xD4AB, //HANGUL SYLLABLE PHIEUPH WEO CHIEUCH + 0xBF4E: 0xD4AC, //HANGUL SYLLABLE PHIEUPH WEO KHIEUKH + 0xBF4F: 0xD4AD, //HANGUL SYLLABLE PHIEUPH WEO THIEUTH + 0xBF50: 0xD4AE, //HANGUL SYLLABLE PHIEUPH WEO PHIEUPH + 0xBF51: 0xD4AF, //HANGUL SYLLABLE PHIEUPH WEO HIEUH + 0xBF52: 0xD4B0, //HANGUL SYLLABLE PHIEUPH WE + 0xBF53: 0xD4B1, //HANGUL SYLLABLE PHIEUPH WE KIYEOK + 0xBF54: 0xD4B2, //HANGUL SYLLABLE PHIEUPH WE SSANGKIYEOK + 0xBF55: 0xD4B3, //HANGUL SYLLABLE PHIEUPH WE KIYEOKSIOS + 0xBF56: 0xD4B4, //HANGUL SYLLABLE PHIEUPH WE NIEUN + 0xBF57: 0xD4B5, //HANGUL SYLLABLE PHIEUPH WE NIEUNCIEUC + 0xBF58: 0xD4B6, //HANGUL SYLLABLE PHIEUPH WE NIEUNHIEUH + 0xBF59: 0xD4B7, //HANGUL SYLLABLE PHIEUPH WE TIKEUT + 0xBF5A: 0xD4B8, //HANGUL SYLLABLE PHIEUPH WE RIEUL + 0xBF61: 0xD4B9, //HANGUL SYLLABLE PHIEUPH WE RIEULKIYEOK + 0xBF62: 0xD4BA, //HANGUL SYLLABLE PHIEUPH WE RIEULMIEUM + 0xBF63: 0xD4BB, //HANGUL SYLLABLE PHIEUPH WE RIEULPIEUP + 0xBF64: 0xD4BC, //HANGUL SYLLABLE PHIEUPH WE RIEULSIOS + 0xBF65: 0xD4BD, //HANGUL SYLLABLE PHIEUPH WE RIEULTHIEUTH + 0xBF66: 0xD4BE, //HANGUL SYLLABLE PHIEUPH WE RIEULPHIEUPH + 0xBF67: 0xD4BF, //HANGUL SYLLABLE PHIEUPH WE RIEULHIEUH + 0xBF68: 0xD4C0, //HANGUL SYLLABLE PHIEUPH WE MIEUM + 0xBF69: 0xD4C1, //HANGUL SYLLABLE PHIEUPH WE PIEUP + 0xBF6A: 0xD4C2, //HANGUL SYLLABLE PHIEUPH WE PIEUPSIOS + 0xBF6B: 0xD4C3, //HANGUL SYLLABLE PHIEUPH WE SIOS + 0xBF6C: 0xD4C4, //HANGUL SYLLABLE PHIEUPH WE SSANGSIOS + 0xBF6D: 0xD4C5, //HANGUL SYLLABLE PHIEUPH WE IEUNG + 0xBF6E: 0xD4C6, //HANGUL SYLLABLE PHIEUPH WE CIEUC + 0xBF6F: 0xD4C7, //HANGUL SYLLABLE PHIEUPH WE CHIEUCH + 0xBF70: 0xD4C8, //HANGUL SYLLABLE PHIEUPH WE KHIEUKH + 0xBF71: 0xD4C9, //HANGUL SYLLABLE PHIEUPH WE THIEUTH + 0xBF72: 0xD4CA, //HANGUL SYLLABLE PHIEUPH WE PHIEUPH + 0xBF73: 0xD4CB, //HANGUL SYLLABLE PHIEUPH WE HIEUH + 0xBF74: 0xD4CD, //HANGUL SYLLABLE PHIEUPH WI KIYEOK + 0xBF75: 0xD4CE, //HANGUL SYLLABLE PHIEUPH WI SSANGKIYEOK + 0xBF76: 0xD4CF, //HANGUL SYLLABLE PHIEUPH WI KIYEOKSIOS + 0xBF77: 0xD4D1, //HANGUL SYLLABLE PHIEUPH WI NIEUNCIEUC + 0xBF78: 0xD4D2, //HANGUL SYLLABLE PHIEUPH WI NIEUNHIEUH + 0xBF79: 0xD4D3, //HANGUL SYLLABLE PHIEUPH WI TIKEUT + 0xBF7A: 0xD4D5, //HANGUL SYLLABLE PHIEUPH WI RIEULKIYEOK + 0xBF81: 0xD4D6, //HANGUL SYLLABLE PHIEUPH WI RIEULMIEUM + 0xBF82: 0xD4D7, //HANGUL SYLLABLE PHIEUPH WI RIEULPIEUP + 0xBF83: 0xD4D8, //HANGUL SYLLABLE PHIEUPH WI RIEULSIOS + 0xBF84: 0xD4D9, //HANGUL SYLLABLE PHIEUPH WI RIEULTHIEUTH + 0xBF85: 0xD4DA, //HANGUL SYLLABLE PHIEUPH WI RIEULPHIEUPH + 0xBF86: 0xD4DB, //HANGUL SYLLABLE PHIEUPH WI RIEULHIEUH + 0xBF87: 0xD4DD, //HANGUL SYLLABLE PHIEUPH WI PIEUP + 0xBF88: 0xD4DE, //HANGUL SYLLABLE PHIEUPH WI PIEUPSIOS + 0xBF89: 0xD4E0, //HANGUL SYLLABLE PHIEUPH WI SSANGSIOS + 0xBF8A: 0xD4E1, //HANGUL SYLLABLE PHIEUPH WI IEUNG + 0xBF8B: 0xD4E2, //HANGUL SYLLABLE PHIEUPH WI CIEUC + 0xBF8C: 0xD4E3, //HANGUL SYLLABLE PHIEUPH WI CHIEUCH + 0xBF8D: 0xD4E4, //HANGUL SYLLABLE PHIEUPH WI KHIEUKH + 0xBF8E: 0xD4E5, //HANGUL SYLLABLE PHIEUPH WI THIEUTH + 0xBF8F: 0xD4E6, //HANGUL SYLLABLE PHIEUPH WI PHIEUPH + 0xBF90: 0xD4E7, //HANGUL SYLLABLE PHIEUPH WI HIEUH + 0xBF91: 0xD4E9, //HANGUL SYLLABLE PHIEUPH YU KIYEOK + 0xBF92: 0xD4EA, //HANGUL SYLLABLE PHIEUPH YU SSANGKIYEOK + 0xBF93: 0xD4EB, //HANGUL SYLLABLE PHIEUPH YU KIYEOKSIOS + 0xBF94: 0xD4ED, //HANGUL SYLLABLE PHIEUPH YU NIEUNCIEUC + 0xBF95: 0xD4EE, //HANGUL SYLLABLE PHIEUPH YU NIEUNHIEUH + 0xBF96: 0xD4EF, //HANGUL SYLLABLE PHIEUPH YU TIKEUT + 0xBF97: 0xD4F1, //HANGUL SYLLABLE PHIEUPH YU RIEULKIYEOK + 0xBF98: 0xD4F2, //HANGUL SYLLABLE PHIEUPH YU RIEULMIEUM + 0xBF99: 0xD4F3, //HANGUL SYLLABLE PHIEUPH YU RIEULPIEUP + 0xBF9A: 0xD4F4, //HANGUL SYLLABLE PHIEUPH YU RIEULSIOS + 0xBF9B: 0xD4F5, //HANGUL SYLLABLE PHIEUPH YU RIEULTHIEUTH + 0xBF9C: 0xD4F6, //HANGUL SYLLABLE PHIEUPH YU RIEULPHIEUPH + 0xBF9D: 0xD4F7, //HANGUL SYLLABLE PHIEUPH YU RIEULHIEUH + 0xBF9E: 0xD4F9, //HANGUL SYLLABLE PHIEUPH YU PIEUP + 0xBF9F: 0xD4FA, //HANGUL SYLLABLE PHIEUPH YU PIEUPSIOS + 0xBFA0: 0xD4FC, //HANGUL SYLLABLE PHIEUPH YU SSANGSIOS + 0xBFA1: 0xC5D0, //HANGUL SYLLABLE IEUNG E + 0xBFA2: 0xC5D1, //HANGUL SYLLABLE IEUNG E KIYEOK + 0xBFA3: 0xC5D4, //HANGUL SYLLABLE IEUNG E NIEUN + 0xBFA4: 0xC5D8, //HANGUL SYLLABLE IEUNG E RIEUL + 0xBFA5: 0xC5E0, //HANGUL SYLLABLE IEUNG E MIEUM + 0xBFA6: 0xC5E1, //HANGUL SYLLABLE IEUNG E PIEUP + 0xBFA7: 0xC5E3, //HANGUL SYLLABLE IEUNG E SIOS + 0xBFA8: 0xC5E5, //HANGUL SYLLABLE IEUNG E IEUNG + 0xBFA9: 0xC5EC, //HANGUL SYLLABLE IEUNG YEO + 0xBFAA: 0xC5ED, //HANGUL SYLLABLE IEUNG YEO KIYEOK + 0xBFAB: 0xC5EE, //HANGUL SYLLABLE IEUNG YEO SSANGKIYEOK + 0xBFAC: 0xC5F0, //HANGUL SYLLABLE IEUNG YEO NIEUN + 0xBFAD: 0xC5F4, //HANGUL SYLLABLE IEUNG YEO RIEUL + 0xBFAE: 0xC5F6, //HANGUL SYLLABLE IEUNG YEO RIEULMIEUM + 0xBFAF: 0xC5F7, //HANGUL SYLLABLE IEUNG YEO RIEULPIEUP + 0xBFB0: 0xC5FC, //HANGUL SYLLABLE IEUNG YEO MIEUM + 0xBFB1: 0xC5FD, //HANGUL SYLLABLE IEUNG YEO PIEUP + 0xBFB2: 0xC5FE, //HANGUL SYLLABLE IEUNG YEO PIEUPSIOS + 0xBFB3: 0xC5FF, //HANGUL SYLLABLE IEUNG YEO SIOS + 0xBFB4: 0xC600, //HANGUL SYLLABLE IEUNG YEO SSANGSIOS + 0xBFB5: 0xC601, //HANGUL SYLLABLE IEUNG YEO IEUNG + 0xBFB6: 0xC605, //HANGUL SYLLABLE IEUNG YEO THIEUTH + 0xBFB7: 0xC606, //HANGUL SYLLABLE IEUNG YEO PHIEUPH + 0xBFB8: 0xC607, //HANGUL SYLLABLE IEUNG YEO HIEUH + 0xBFB9: 0xC608, //HANGUL SYLLABLE IEUNG YE + 0xBFBA: 0xC60C, //HANGUL SYLLABLE IEUNG YE NIEUN + 0xBFBB: 0xC610, //HANGUL SYLLABLE IEUNG YE RIEUL + 0xBFBC: 0xC618, //HANGUL SYLLABLE IEUNG YE MIEUM + 0xBFBD: 0xC619, //HANGUL SYLLABLE IEUNG YE PIEUP + 0xBFBE: 0xC61B, //HANGUL SYLLABLE IEUNG YE SIOS + 0xBFBF: 0xC61C, //HANGUL SYLLABLE IEUNG YE SSANGSIOS + 0xBFC0: 0xC624, //HANGUL SYLLABLE IEUNG O + 0xBFC1: 0xC625, //HANGUL SYLLABLE IEUNG O KIYEOK + 0xBFC2: 0xC628, //HANGUL SYLLABLE IEUNG O NIEUN + 0xBFC3: 0xC62C, //HANGUL SYLLABLE IEUNG O RIEUL + 0xBFC4: 0xC62D, //HANGUL SYLLABLE IEUNG O RIEULKIYEOK + 0xBFC5: 0xC62E, //HANGUL SYLLABLE IEUNG O RIEULMIEUM + 0xBFC6: 0xC630, //HANGUL SYLLABLE IEUNG O RIEULSIOS + 0xBFC7: 0xC633, //HANGUL SYLLABLE IEUNG O RIEULHIEUH + 0xBFC8: 0xC634, //HANGUL SYLLABLE IEUNG O MIEUM + 0xBFC9: 0xC635, //HANGUL SYLLABLE IEUNG O PIEUP + 0xBFCA: 0xC637, //HANGUL SYLLABLE IEUNG O SIOS + 0xBFCB: 0xC639, //HANGUL SYLLABLE IEUNG O IEUNG + 0xBFCC: 0xC63B, //HANGUL SYLLABLE IEUNG O CHIEUCH + 0xBFCD: 0xC640, //HANGUL SYLLABLE IEUNG WA + 0xBFCE: 0xC641, //HANGUL SYLLABLE IEUNG WA KIYEOK + 0xBFCF: 0xC644, //HANGUL SYLLABLE IEUNG WA NIEUN + 0xBFD0: 0xC648, //HANGUL SYLLABLE IEUNG WA RIEUL + 0xBFD1: 0xC650, //HANGUL SYLLABLE IEUNG WA MIEUM + 0xBFD2: 0xC651, //HANGUL SYLLABLE IEUNG WA PIEUP + 0xBFD3: 0xC653, //HANGUL SYLLABLE IEUNG WA SIOS + 0xBFD4: 0xC654, //HANGUL SYLLABLE IEUNG WA SSANGSIOS + 0xBFD5: 0xC655, //HANGUL SYLLABLE IEUNG WA IEUNG + 0xBFD6: 0xC65C, //HANGUL SYLLABLE IEUNG WAE + 0xBFD7: 0xC65D, //HANGUL SYLLABLE IEUNG WAE KIYEOK + 0xBFD8: 0xC660, //HANGUL SYLLABLE IEUNG WAE NIEUN + 0xBFD9: 0xC66C, //HANGUL SYLLABLE IEUNG WAE MIEUM + 0xBFDA: 0xC66F, //HANGUL SYLLABLE IEUNG WAE SIOS + 0xBFDB: 0xC671, //HANGUL SYLLABLE IEUNG WAE IEUNG + 0xBFDC: 0xC678, //HANGUL SYLLABLE IEUNG OE + 0xBFDD: 0xC679, //HANGUL SYLLABLE IEUNG OE KIYEOK + 0xBFDE: 0xC67C, //HANGUL SYLLABLE IEUNG OE NIEUN + 0xBFDF: 0xC680, //HANGUL SYLLABLE IEUNG OE RIEUL + 0xBFE0: 0xC688, //HANGUL SYLLABLE IEUNG OE MIEUM + 0xBFE1: 0xC689, //HANGUL SYLLABLE IEUNG OE PIEUP + 0xBFE2: 0xC68B, //HANGUL SYLLABLE IEUNG OE SIOS + 0xBFE3: 0xC68D, //HANGUL SYLLABLE IEUNG OE IEUNG + 0xBFE4: 0xC694, //HANGUL SYLLABLE IEUNG YO + 0xBFE5: 0xC695, //HANGUL SYLLABLE IEUNG YO KIYEOK + 0xBFE6: 0xC698, //HANGUL SYLLABLE IEUNG YO NIEUN + 0xBFE7: 0xC69C, //HANGUL SYLLABLE IEUNG YO RIEUL + 0xBFE8: 0xC6A4, //HANGUL SYLLABLE IEUNG YO MIEUM + 0xBFE9: 0xC6A5, //HANGUL SYLLABLE IEUNG YO PIEUP + 0xBFEA: 0xC6A7, //HANGUL SYLLABLE IEUNG YO SIOS + 0xBFEB: 0xC6A9, //HANGUL SYLLABLE IEUNG YO IEUNG + 0xBFEC: 0xC6B0, //HANGUL SYLLABLE IEUNG U + 0xBFED: 0xC6B1, //HANGUL SYLLABLE IEUNG U KIYEOK + 0xBFEE: 0xC6B4, //HANGUL SYLLABLE IEUNG U NIEUN + 0xBFEF: 0xC6B8, //HANGUL SYLLABLE IEUNG U RIEUL + 0xBFF0: 0xC6B9, //HANGUL SYLLABLE IEUNG U RIEULKIYEOK + 0xBFF1: 0xC6BA, //HANGUL SYLLABLE IEUNG U RIEULMIEUM + 0xBFF2: 0xC6C0, //HANGUL SYLLABLE IEUNG U MIEUM + 0xBFF3: 0xC6C1, //HANGUL SYLLABLE IEUNG U PIEUP + 0xBFF4: 0xC6C3, //HANGUL SYLLABLE IEUNG U SIOS + 0xBFF5: 0xC6C5, //HANGUL SYLLABLE IEUNG U IEUNG + 0xBFF6: 0xC6CC, //HANGUL SYLLABLE IEUNG WEO + 0xBFF7: 0xC6CD, //HANGUL SYLLABLE IEUNG WEO KIYEOK + 0xBFF8: 0xC6D0, //HANGUL SYLLABLE IEUNG WEO NIEUN + 0xBFF9: 0xC6D4, //HANGUL SYLLABLE IEUNG WEO RIEUL + 0xBFFA: 0xC6DC, //HANGUL SYLLABLE IEUNG WEO MIEUM + 0xBFFB: 0xC6DD, //HANGUL SYLLABLE IEUNG WEO PIEUP + 0xBFFC: 0xC6E0, //HANGUL SYLLABLE IEUNG WEO SSANGSIOS + 0xBFFD: 0xC6E1, //HANGUL SYLLABLE IEUNG WEO IEUNG + 0xBFFE: 0xC6E8, //HANGUL SYLLABLE IEUNG WE + 0xC041: 0xD4FE, //HANGUL SYLLABLE PHIEUPH YU CIEUC + 0xC042: 0xD4FF, //HANGUL SYLLABLE PHIEUPH YU CHIEUCH + 0xC043: 0xD500, //HANGUL SYLLABLE PHIEUPH YU KHIEUKH + 0xC044: 0xD501, //HANGUL SYLLABLE PHIEUPH YU THIEUTH + 0xC045: 0xD502, //HANGUL SYLLABLE PHIEUPH YU PHIEUPH + 0xC046: 0xD503, //HANGUL SYLLABLE PHIEUPH YU HIEUH + 0xC047: 0xD505, //HANGUL SYLLABLE PHIEUPH EU KIYEOK + 0xC048: 0xD506, //HANGUL SYLLABLE PHIEUPH EU SSANGKIYEOK + 0xC049: 0xD507, //HANGUL SYLLABLE PHIEUPH EU KIYEOKSIOS + 0xC04A: 0xD509, //HANGUL SYLLABLE PHIEUPH EU NIEUNCIEUC + 0xC04B: 0xD50A, //HANGUL SYLLABLE PHIEUPH EU NIEUNHIEUH + 0xC04C: 0xD50B, //HANGUL SYLLABLE PHIEUPH EU TIKEUT + 0xC04D: 0xD50D, //HANGUL SYLLABLE PHIEUPH EU RIEULKIYEOK + 0xC04E: 0xD50E, //HANGUL SYLLABLE PHIEUPH EU RIEULMIEUM + 0xC04F: 0xD50F, //HANGUL SYLLABLE PHIEUPH EU RIEULPIEUP + 0xC050: 0xD510, //HANGUL SYLLABLE PHIEUPH EU RIEULSIOS + 0xC051: 0xD511, //HANGUL SYLLABLE PHIEUPH EU RIEULTHIEUTH + 0xC052: 0xD512, //HANGUL SYLLABLE PHIEUPH EU RIEULPHIEUPH + 0xC053: 0xD513, //HANGUL SYLLABLE PHIEUPH EU RIEULHIEUH + 0xC054: 0xD516, //HANGUL SYLLABLE PHIEUPH EU PIEUPSIOS + 0xC055: 0xD518, //HANGUL SYLLABLE PHIEUPH EU SSANGSIOS + 0xC056: 0xD519, //HANGUL SYLLABLE PHIEUPH EU IEUNG + 0xC057: 0xD51A, //HANGUL SYLLABLE PHIEUPH EU CIEUC + 0xC058: 0xD51B, //HANGUL SYLLABLE PHIEUPH EU CHIEUCH + 0xC059: 0xD51C, //HANGUL SYLLABLE PHIEUPH EU KHIEUKH + 0xC05A: 0xD51D, //HANGUL SYLLABLE PHIEUPH EU THIEUTH + 0xC061: 0xD51E, //HANGUL SYLLABLE PHIEUPH EU PHIEUPH + 0xC062: 0xD51F, //HANGUL SYLLABLE PHIEUPH EU HIEUH + 0xC063: 0xD520, //HANGUL SYLLABLE PHIEUPH YI + 0xC064: 0xD521, //HANGUL SYLLABLE PHIEUPH YI KIYEOK + 0xC065: 0xD522, //HANGUL SYLLABLE PHIEUPH YI SSANGKIYEOK + 0xC066: 0xD523, //HANGUL SYLLABLE PHIEUPH YI KIYEOKSIOS + 0xC067: 0xD524, //HANGUL SYLLABLE PHIEUPH YI NIEUN + 0xC068: 0xD525, //HANGUL SYLLABLE PHIEUPH YI NIEUNCIEUC + 0xC069: 0xD526, //HANGUL SYLLABLE PHIEUPH YI NIEUNHIEUH + 0xC06A: 0xD527, //HANGUL SYLLABLE PHIEUPH YI TIKEUT + 0xC06B: 0xD528, //HANGUL SYLLABLE PHIEUPH YI RIEUL + 0xC06C: 0xD529, //HANGUL SYLLABLE PHIEUPH YI RIEULKIYEOK + 0xC06D: 0xD52A, //HANGUL SYLLABLE PHIEUPH YI RIEULMIEUM + 0xC06E: 0xD52B, //HANGUL SYLLABLE PHIEUPH YI RIEULPIEUP + 0xC06F: 0xD52C, //HANGUL SYLLABLE PHIEUPH YI RIEULSIOS + 0xC070: 0xD52D, //HANGUL SYLLABLE PHIEUPH YI RIEULTHIEUTH + 0xC071: 0xD52E, //HANGUL SYLLABLE PHIEUPH YI RIEULPHIEUPH + 0xC072: 0xD52F, //HANGUL SYLLABLE PHIEUPH YI RIEULHIEUH + 0xC073: 0xD530, //HANGUL SYLLABLE PHIEUPH YI MIEUM + 0xC074: 0xD531, //HANGUL SYLLABLE PHIEUPH YI PIEUP + 0xC075: 0xD532, //HANGUL SYLLABLE PHIEUPH YI PIEUPSIOS + 0xC076: 0xD533, //HANGUL SYLLABLE PHIEUPH YI SIOS + 0xC077: 0xD534, //HANGUL SYLLABLE PHIEUPH YI SSANGSIOS + 0xC078: 0xD535, //HANGUL SYLLABLE PHIEUPH YI IEUNG + 0xC079: 0xD536, //HANGUL SYLLABLE PHIEUPH YI CIEUC + 0xC07A: 0xD537, //HANGUL SYLLABLE PHIEUPH YI CHIEUCH + 0xC081: 0xD538, //HANGUL SYLLABLE PHIEUPH YI KHIEUKH + 0xC082: 0xD539, //HANGUL SYLLABLE PHIEUPH YI THIEUTH + 0xC083: 0xD53A, //HANGUL SYLLABLE PHIEUPH YI PHIEUPH + 0xC084: 0xD53B, //HANGUL SYLLABLE PHIEUPH YI HIEUH + 0xC085: 0xD53E, //HANGUL SYLLABLE PHIEUPH I SSANGKIYEOK + 0xC086: 0xD53F, //HANGUL SYLLABLE PHIEUPH I KIYEOKSIOS + 0xC087: 0xD541, //HANGUL SYLLABLE PHIEUPH I NIEUNCIEUC + 0xC088: 0xD542, //HANGUL SYLLABLE PHIEUPH I NIEUNHIEUH + 0xC089: 0xD543, //HANGUL SYLLABLE PHIEUPH I TIKEUT + 0xC08A: 0xD545, //HANGUL SYLLABLE PHIEUPH I RIEULKIYEOK + 0xC08B: 0xD546, //HANGUL SYLLABLE PHIEUPH I RIEULMIEUM + 0xC08C: 0xD547, //HANGUL SYLLABLE PHIEUPH I RIEULPIEUP + 0xC08D: 0xD548, //HANGUL SYLLABLE PHIEUPH I RIEULSIOS + 0xC08E: 0xD549, //HANGUL SYLLABLE PHIEUPH I RIEULTHIEUTH + 0xC08F: 0xD54A, //HANGUL SYLLABLE PHIEUPH I RIEULPHIEUPH + 0xC090: 0xD54B, //HANGUL SYLLABLE PHIEUPH I RIEULHIEUH + 0xC091: 0xD54E, //HANGUL SYLLABLE PHIEUPH I PIEUPSIOS + 0xC092: 0xD550, //HANGUL SYLLABLE PHIEUPH I SSANGSIOS + 0xC093: 0xD552, //HANGUL SYLLABLE PHIEUPH I CIEUC + 0xC094: 0xD553, //HANGUL SYLLABLE PHIEUPH I CHIEUCH + 0xC095: 0xD554, //HANGUL SYLLABLE PHIEUPH I KHIEUKH + 0xC096: 0xD555, //HANGUL SYLLABLE PHIEUPH I THIEUTH + 0xC097: 0xD556, //HANGUL SYLLABLE PHIEUPH I PHIEUPH + 0xC098: 0xD557, //HANGUL SYLLABLE PHIEUPH I HIEUH + 0xC099: 0xD55A, //HANGUL SYLLABLE HIEUH A SSANGKIYEOK + 0xC09A: 0xD55B, //HANGUL SYLLABLE HIEUH A KIYEOKSIOS + 0xC09B: 0xD55D, //HANGUL SYLLABLE HIEUH A NIEUNCIEUC + 0xC09C: 0xD55E, //HANGUL SYLLABLE HIEUH A NIEUNHIEUH + 0xC09D: 0xD55F, //HANGUL SYLLABLE HIEUH A TIKEUT + 0xC09E: 0xD561, //HANGUL SYLLABLE HIEUH A RIEULKIYEOK + 0xC09F: 0xD562, //HANGUL SYLLABLE HIEUH A RIEULMIEUM + 0xC0A0: 0xD563, //HANGUL SYLLABLE HIEUH A RIEULPIEUP + 0xC0A1: 0xC6E9, //HANGUL SYLLABLE IEUNG WE KIYEOK + 0xC0A2: 0xC6EC, //HANGUL SYLLABLE IEUNG WE NIEUN + 0xC0A3: 0xC6F0, //HANGUL SYLLABLE IEUNG WE RIEUL + 0xC0A4: 0xC6F8, //HANGUL SYLLABLE IEUNG WE MIEUM + 0xC0A5: 0xC6F9, //HANGUL SYLLABLE IEUNG WE PIEUP + 0xC0A6: 0xC6FD, //HANGUL SYLLABLE IEUNG WE IEUNG + 0xC0A7: 0xC704, //HANGUL SYLLABLE IEUNG WI + 0xC0A8: 0xC705, //HANGUL SYLLABLE IEUNG WI KIYEOK + 0xC0A9: 0xC708, //HANGUL SYLLABLE IEUNG WI NIEUN + 0xC0AA: 0xC70C, //HANGUL SYLLABLE IEUNG WI RIEUL + 0xC0AB: 0xC714, //HANGUL SYLLABLE IEUNG WI MIEUM + 0xC0AC: 0xC715, //HANGUL SYLLABLE IEUNG WI PIEUP + 0xC0AD: 0xC717, //HANGUL SYLLABLE IEUNG WI SIOS + 0xC0AE: 0xC719, //HANGUL SYLLABLE IEUNG WI IEUNG + 0xC0AF: 0xC720, //HANGUL SYLLABLE IEUNG YU + 0xC0B0: 0xC721, //HANGUL SYLLABLE IEUNG YU KIYEOK + 0xC0B1: 0xC724, //HANGUL SYLLABLE IEUNG YU NIEUN + 0xC0B2: 0xC728, //HANGUL SYLLABLE IEUNG YU RIEUL + 0xC0B3: 0xC730, //HANGUL SYLLABLE IEUNG YU MIEUM + 0xC0B4: 0xC731, //HANGUL SYLLABLE IEUNG YU PIEUP + 0xC0B5: 0xC733, //HANGUL SYLLABLE IEUNG YU SIOS + 0xC0B6: 0xC735, //HANGUL SYLLABLE IEUNG YU IEUNG + 0xC0B7: 0xC737, //HANGUL SYLLABLE IEUNG YU CHIEUCH + 0xC0B8: 0xC73C, //HANGUL SYLLABLE IEUNG EU + 0xC0B9: 0xC73D, //HANGUL SYLLABLE IEUNG EU KIYEOK + 0xC0BA: 0xC740, //HANGUL SYLLABLE IEUNG EU NIEUN + 0xC0BB: 0xC744, //HANGUL SYLLABLE IEUNG EU RIEUL + 0xC0BC: 0xC74A, //HANGUL SYLLABLE IEUNG EU RIEULPHIEUPH + 0xC0BD: 0xC74C, //HANGUL SYLLABLE IEUNG EU MIEUM + 0xC0BE: 0xC74D, //HANGUL SYLLABLE IEUNG EU PIEUP + 0xC0BF: 0xC74F, //HANGUL SYLLABLE IEUNG EU SIOS + 0xC0C0: 0xC751, //HANGUL SYLLABLE IEUNG EU IEUNG + 0xC0C1: 0xC752, //HANGUL SYLLABLE IEUNG EU CIEUC + 0xC0C2: 0xC753, //HANGUL SYLLABLE IEUNG EU CHIEUCH + 0xC0C3: 0xC754, //HANGUL SYLLABLE IEUNG EU KHIEUKH + 0xC0C4: 0xC755, //HANGUL SYLLABLE IEUNG EU THIEUTH + 0xC0C5: 0xC756, //HANGUL SYLLABLE IEUNG EU PHIEUPH + 0xC0C6: 0xC757, //HANGUL SYLLABLE IEUNG EU HIEUH + 0xC0C7: 0xC758, //HANGUL SYLLABLE IEUNG YI + 0xC0C8: 0xC75C, //HANGUL SYLLABLE IEUNG YI NIEUN + 0xC0C9: 0xC760, //HANGUL SYLLABLE IEUNG YI RIEUL + 0xC0CA: 0xC768, //HANGUL SYLLABLE IEUNG YI MIEUM + 0xC0CB: 0xC76B, //HANGUL SYLLABLE IEUNG YI SIOS + 0xC0CC: 0xC774, //HANGUL SYLLABLE IEUNG I + 0xC0CD: 0xC775, //HANGUL SYLLABLE IEUNG I KIYEOK + 0xC0CE: 0xC778, //HANGUL SYLLABLE IEUNG I NIEUN + 0xC0CF: 0xC77C, //HANGUL SYLLABLE IEUNG I RIEUL + 0xC0D0: 0xC77D, //HANGUL SYLLABLE IEUNG I RIEULKIYEOK + 0xC0D1: 0xC77E, //HANGUL SYLLABLE IEUNG I RIEULMIEUM + 0xC0D2: 0xC783, //HANGUL SYLLABLE IEUNG I RIEULHIEUH + 0xC0D3: 0xC784, //HANGUL SYLLABLE IEUNG I MIEUM + 0xC0D4: 0xC785, //HANGUL SYLLABLE IEUNG I PIEUP + 0xC0D5: 0xC787, //HANGUL SYLLABLE IEUNG I SIOS + 0xC0D6: 0xC788, //HANGUL SYLLABLE IEUNG I SSANGSIOS + 0xC0D7: 0xC789, //HANGUL SYLLABLE IEUNG I IEUNG + 0xC0D8: 0xC78A, //HANGUL SYLLABLE IEUNG I CIEUC + 0xC0D9: 0xC78E, //HANGUL SYLLABLE IEUNG I PHIEUPH + 0xC0DA: 0xC790, //HANGUL SYLLABLE CIEUC A + 0xC0DB: 0xC791, //HANGUL SYLLABLE CIEUC A KIYEOK + 0xC0DC: 0xC794, //HANGUL SYLLABLE CIEUC A NIEUN + 0xC0DD: 0xC796, //HANGUL SYLLABLE CIEUC A NIEUNHIEUH + 0xC0DE: 0xC797, //HANGUL SYLLABLE CIEUC A TIKEUT + 0xC0DF: 0xC798, //HANGUL SYLLABLE CIEUC A RIEUL + 0xC0E0: 0xC79A, //HANGUL SYLLABLE CIEUC A RIEULMIEUM + 0xC0E1: 0xC7A0, //HANGUL SYLLABLE CIEUC A MIEUM + 0xC0E2: 0xC7A1, //HANGUL SYLLABLE CIEUC A PIEUP + 0xC0E3: 0xC7A3, //HANGUL SYLLABLE CIEUC A SIOS + 0xC0E4: 0xC7A4, //HANGUL SYLLABLE CIEUC A SSANGSIOS + 0xC0E5: 0xC7A5, //HANGUL SYLLABLE CIEUC A IEUNG + 0xC0E6: 0xC7A6, //HANGUL SYLLABLE CIEUC A CIEUC + 0xC0E7: 0xC7AC, //HANGUL SYLLABLE CIEUC AE + 0xC0E8: 0xC7AD, //HANGUL SYLLABLE CIEUC AE KIYEOK + 0xC0E9: 0xC7B0, //HANGUL SYLLABLE CIEUC AE NIEUN + 0xC0EA: 0xC7B4, //HANGUL SYLLABLE CIEUC AE RIEUL + 0xC0EB: 0xC7BC, //HANGUL SYLLABLE CIEUC AE MIEUM + 0xC0EC: 0xC7BD, //HANGUL SYLLABLE CIEUC AE PIEUP + 0xC0ED: 0xC7BF, //HANGUL SYLLABLE CIEUC AE SIOS + 0xC0EE: 0xC7C0, //HANGUL SYLLABLE CIEUC AE SSANGSIOS + 0xC0EF: 0xC7C1, //HANGUL SYLLABLE CIEUC AE IEUNG + 0xC0F0: 0xC7C8, //HANGUL SYLLABLE CIEUC YA + 0xC0F1: 0xC7C9, //HANGUL SYLLABLE CIEUC YA KIYEOK + 0xC0F2: 0xC7CC, //HANGUL SYLLABLE CIEUC YA NIEUN + 0xC0F3: 0xC7CE, //HANGUL SYLLABLE CIEUC YA NIEUNHIEUH + 0xC0F4: 0xC7D0, //HANGUL SYLLABLE CIEUC YA RIEUL + 0xC0F5: 0xC7D8, //HANGUL SYLLABLE CIEUC YA MIEUM + 0xC0F6: 0xC7DD, //HANGUL SYLLABLE CIEUC YA IEUNG + 0xC0F7: 0xC7E4, //HANGUL SYLLABLE CIEUC YAE + 0xC0F8: 0xC7E8, //HANGUL SYLLABLE CIEUC YAE NIEUN + 0xC0F9: 0xC7EC, //HANGUL SYLLABLE CIEUC YAE RIEUL + 0xC0FA: 0xC800, //HANGUL SYLLABLE CIEUC EO + 0xC0FB: 0xC801, //HANGUL SYLLABLE CIEUC EO KIYEOK + 0xC0FC: 0xC804, //HANGUL SYLLABLE CIEUC EO NIEUN + 0xC0FD: 0xC808, //HANGUL SYLLABLE CIEUC EO RIEUL + 0xC0FE: 0xC80A, //HANGUL SYLLABLE CIEUC EO RIEULMIEUM + 0xC141: 0xD564, //HANGUL SYLLABLE HIEUH A RIEULSIOS + 0xC142: 0xD566, //HANGUL SYLLABLE HIEUH A RIEULPHIEUPH + 0xC143: 0xD567, //HANGUL SYLLABLE HIEUH A RIEULHIEUH + 0xC144: 0xD56A, //HANGUL SYLLABLE HIEUH A PIEUPSIOS + 0xC145: 0xD56C, //HANGUL SYLLABLE HIEUH A SSANGSIOS + 0xC146: 0xD56E, //HANGUL SYLLABLE HIEUH A CIEUC + 0xC147: 0xD56F, //HANGUL SYLLABLE HIEUH A CHIEUCH + 0xC148: 0xD570, //HANGUL SYLLABLE HIEUH A KHIEUKH + 0xC149: 0xD571, //HANGUL SYLLABLE HIEUH A THIEUTH + 0xC14A: 0xD572, //HANGUL SYLLABLE HIEUH A PHIEUPH + 0xC14B: 0xD573, //HANGUL SYLLABLE HIEUH A HIEUH + 0xC14C: 0xD576, //HANGUL SYLLABLE HIEUH AE SSANGKIYEOK + 0xC14D: 0xD577, //HANGUL SYLLABLE HIEUH AE KIYEOKSIOS + 0xC14E: 0xD579, //HANGUL SYLLABLE HIEUH AE NIEUNCIEUC + 0xC14F: 0xD57A, //HANGUL SYLLABLE HIEUH AE NIEUNHIEUH + 0xC150: 0xD57B, //HANGUL SYLLABLE HIEUH AE TIKEUT + 0xC151: 0xD57D, //HANGUL SYLLABLE HIEUH AE RIEULKIYEOK + 0xC152: 0xD57E, //HANGUL SYLLABLE HIEUH AE RIEULMIEUM + 0xC153: 0xD57F, //HANGUL SYLLABLE HIEUH AE RIEULPIEUP + 0xC154: 0xD580, //HANGUL SYLLABLE HIEUH AE RIEULSIOS + 0xC155: 0xD581, //HANGUL SYLLABLE HIEUH AE RIEULTHIEUTH + 0xC156: 0xD582, //HANGUL SYLLABLE HIEUH AE RIEULPHIEUPH + 0xC157: 0xD583, //HANGUL SYLLABLE HIEUH AE RIEULHIEUH + 0xC158: 0xD586, //HANGUL SYLLABLE HIEUH AE PIEUPSIOS + 0xC159: 0xD58A, //HANGUL SYLLABLE HIEUH AE CIEUC + 0xC15A: 0xD58B, //HANGUL SYLLABLE HIEUH AE CHIEUCH + 0xC161: 0xD58C, //HANGUL SYLLABLE HIEUH AE KHIEUKH + 0xC162: 0xD58D, //HANGUL SYLLABLE HIEUH AE THIEUTH + 0xC163: 0xD58E, //HANGUL SYLLABLE HIEUH AE PHIEUPH + 0xC164: 0xD58F, //HANGUL SYLLABLE HIEUH AE HIEUH + 0xC165: 0xD591, //HANGUL SYLLABLE HIEUH YA KIYEOK + 0xC166: 0xD592, //HANGUL SYLLABLE HIEUH YA SSANGKIYEOK + 0xC167: 0xD593, //HANGUL SYLLABLE HIEUH YA KIYEOKSIOS + 0xC168: 0xD594, //HANGUL SYLLABLE HIEUH YA NIEUN + 0xC169: 0xD595, //HANGUL SYLLABLE HIEUH YA NIEUNCIEUC + 0xC16A: 0xD596, //HANGUL SYLLABLE HIEUH YA NIEUNHIEUH + 0xC16B: 0xD597, //HANGUL SYLLABLE HIEUH YA TIKEUT + 0xC16C: 0xD598, //HANGUL SYLLABLE HIEUH YA RIEUL + 0xC16D: 0xD599, //HANGUL SYLLABLE HIEUH YA RIEULKIYEOK + 0xC16E: 0xD59A, //HANGUL SYLLABLE HIEUH YA RIEULMIEUM + 0xC16F: 0xD59B, //HANGUL SYLLABLE HIEUH YA RIEULPIEUP + 0xC170: 0xD59C, //HANGUL SYLLABLE HIEUH YA RIEULSIOS + 0xC171: 0xD59D, //HANGUL SYLLABLE HIEUH YA RIEULTHIEUTH + 0xC172: 0xD59E, //HANGUL SYLLABLE HIEUH YA RIEULPHIEUPH + 0xC173: 0xD59F, //HANGUL SYLLABLE HIEUH YA RIEULHIEUH + 0xC174: 0xD5A0, //HANGUL SYLLABLE HIEUH YA MIEUM + 0xC175: 0xD5A1, //HANGUL SYLLABLE HIEUH YA PIEUP + 0xC176: 0xD5A2, //HANGUL SYLLABLE HIEUH YA PIEUPSIOS + 0xC177: 0xD5A3, //HANGUL SYLLABLE HIEUH YA SIOS + 0xC178: 0xD5A4, //HANGUL SYLLABLE HIEUH YA SSANGSIOS + 0xC179: 0xD5A6, //HANGUL SYLLABLE HIEUH YA CIEUC + 0xC17A: 0xD5A7, //HANGUL SYLLABLE HIEUH YA CHIEUCH + 0xC181: 0xD5A8, //HANGUL SYLLABLE HIEUH YA KHIEUKH + 0xC182: 0xD5A9, //HANGUL SYLLABLE HIEUH YA THIEUTH + 0xC183: 0xD5AA, //HANGUL SYLLABLE HIEUH YA PHIEUPH + 0xC184: 0xD5AB, //HANGUL SYLLABLE HIEUH YA HIEUH + 0xC185: 0xD5AC, //HANGUL SYLLABLE HIEUH YAE + 0xC186: 0xD5AD, //HANGUL SYLLABLE HIEUH YAE KIYEOK + 0xC187: 0xD5AE, //HANGUL SYLLABLE HIEUH YAE SSANGKIYEOK + 0xC188: 0xD5AF, //HANGUL SYLLABLE HIEUH YAE KIYEOKSIOS + 0xC189: 0xD5B0, //HANGUL SYLLABLE HIEUH YAE NIEUN + 0xC18A: 0xD5B1, //HANGUL SYLLABLE HIEUH YAE NIEUNCIEUC + 0xC18B: 0xD5B2, //HANGUL SYLLABLE HIEUH YAE NIEUNHIEUH + 0xC18C: 0xD5B3, //HANGUL SYLLABLE HIEUH YAE TIKEUT + 0xC18D: 0xD5B4, //HANGUL SYLLABLE HIEUH YAE RIEUL + 0xC18E: 0xD5B5, //HANGUL SYLLABLE HIEUH YAE RIEULKIYEOK + 0xC18F: 0xD5B6, //HANGUL SYLLABLE HIEUH YAE RIEULMIEUM + 0xC190: 0xD5B7, //HANGUL SYLLABLE HIEUH YAE RIEULPIEUP + 0xC191: 0xD5B8, //HANGUL SYLLABLE HIEUH YAE RIEULSIOS + 0xC192: 0xD5B9, //HANGUL SYLLABLE HIEUH YAE RIEULTHIEUTH + 0xC193: 0xD5BA, //HANGUL SYLLABLE HIEUH YAE RIEULPHIEUPH + 0xC194: 0xD5BB, //HANGUL SYLLABLE HIEUH YAE RIEULHIEUH + 0xC195: 0xD5BC, //HANGUL SYLLABLE HIEUH YAE MIEUM + 0xC196: 0xD5BD, //HANGUL SYLLABLE HIEUH YAE PIEUP + 0xC197: 0xD5BE, //HANGUL SYLLABLE HIEUH YAE PIEUPSIOS + 0xC198: 0xD5BF, //HANGUL SYLLABLE HIEUH YAE SIOS + 0xC199: 0xD5C0, //HANGUL SYLLABLE HIEUH YAE SSANGSIOS + 0xC19A: 0xD5C1, //HANGUL SYLLABLE HIEUH YAE IEUNG + 0xC19B: 0xD5C2, //HANGUL SYLLABLE HIEUH YAE CIEUC + 0xC19C: 0xD5C3, //HANGUL SYLLABLE HIEUH YAE CHIEUCH + 0xC19D: 0xD5C4, //HANGUL SYLLABLE HIEUH YAE KHIEUKH + 0xC19E: 0xD5C5, //HANGUL SYLLABLE HIEUH YAE THIEUTH + 0xC19F: 0xD5C6, //HANGUL SYLLABLE HIEUH YAE PHIEUPH + 0xC1A0: 0xD5C7, //HANGUL SYLLABLE HIEUH YAE HIEUH + 0xC1A1: 0xC810, //HANGUL SYLLABLE CIEUC EO MIEUM + 0xC1A2: 0xC811, //HANGUL SYLLABLE CIEUC EO PIEUP + 0xC1A3: 0xC813, //HANGUL SYLLABLE CIEUC EO SIOS + 0xC1A4: 0xC815, //HANGUL SYLLABLE CIEUC EO IEUNG + 0xC1A5: 0xC816, //HANGUL SYLLABLE CIEUC EO CIEUC + 0xC1A6: 0xC81C, //HANGUL SYLLABLE CIEUC E + 0xC1A7: 0xC81D, //HANGUL SYLLABLE CIEUC E KIYEOK + 0xC1A8: 0xC820, //HANGUL SYLLABLE CIEUC E NIEUN + 0xC1A9: 0xC824, //HANGUL SYLLABLE CIEUC E RIEUL + 0xC1AA: 0xC82C, //HANGUL SYLLABLE CIEUC E MIEUM + 0xC1AB: 0xC82D, //HANGUL SYLLABLE CIEUC E PIEUP + 0xC1AC: 0xC82F, //HANGUL SYLLABLE CIEUC E SIOS + 0xC1AD: 0xC831, //HANGUL SYLLABLE CIEUC E IEUNG + 0xC1AE: 0xC838, //HANGUL SYLLABLE CIEUC YEO + 0xC1AF: 0xC83C, //HANGUL SYLLABLE CIEUC YEO NIEUN + 0xC1B0: 0xC840, //HANGUL SYLLABLE CIEUC YEO RIEUL + 0xC1B1: 0xC848, //HANGUL SYLLABLE CIEUC YEO MIEUM + 0xC1B2: 0xC849, //HANGUL SYLLABLE CIEUC YEO PIEUP + 0xC1B3: 0xC84C, //HANGUL SYLLABLE CIEUC YEO SSANGSIOS + 0xC1B4: 0xC84D, //HANGUL SYLLABLE CIEUC YEO IEUNG + 0xC1B5: 0xC854, //HANGUL SYLLABLE CIEUC YE + 0xC1B6: 0xC870, //HANGUL SYLLABLE CIEUC O + 0xC1B7: 0xC871, //HANGUL SYLLABLE CIEUC O KIYEOK + 0xC1B8: 0xC874, //HANGUL SYLLABLE CIEUC O NIEUN + 0xC1B9: 0xC878, //HANGUL SYLLABLE CIEUC O RIEUL + 0xC1BA: 0xC87A, //HANGUL SYLLABLE CIEUC O RIEULMIEUM + 0xC1BB: 0xC880, //HANGUL SYLLABLE CIEUC O MIEUM + 0xC1BC: 0xC881, //HANGUL SYLLABLE CIEUC O PIEUP + 0xC1BD: 0xC883, //HANGUL SYLLABLE CIEUC O SIOS + 0xC1BE: 0xC885, //HANGUL SYLLABLE CIEUC O IEUNG + 0xC1BF: 0xC886, //HANGUL SYLLABLE CIEUC O CIEUC + 0xC1C0: 0xC887, //HANGUL SYLLABLE CIEUC O CHIEUCH + 0xC1C1: 0xC88B, //HANGUL SYLLABLE CIEUC O HIEUH + 0xC1C2: 0xC88C, //HANGUL SYLLABLE CIEUC WA + 0xC1C3: 0xC88D, //HANGUL SYLLABLE CIEUC WA KIYEOK + 0xC1C4: 0xC894, //HANGUL SYLLABLE CIEUC WA RIEUL + 0xC1C5: 0xC89D, //HANGUL SYLLABLE CIEUC WA PIEUP + 0xC1C6: 0xC89F, //HANGUL SYLLABLE CIEUC WA SIOS + 0xC1C7: 0xC8A1, //HANGUL SYLLABLE CIEUC WA IEUNG + 0xC1C8: 0xC8A8, //HANGUL SYLLABLE CIEUC WAE + 0xC1C9: 0xC8BC, //HANGUL SYLLABLE CIEUC WAE SSANGSIOS + 0xC1CA: 0xC8BD, //HANGUL SYLLABLE CIEUC WAE IEUNG + 0xC1CB: 0xC8C4, //HANGUL SYLLABLE CIEUC OE + 0xC1CC: 0xC8C8, //HANGUL SYLLABLE CIEUC OE NIEUN + 0xC1CD: 0xC8CC, //HANGUL SYLLABLE CIEUC OE RIEUL + 0xC1CE: 0xC8D4, //HANGUL SYLLABLE CIEUC OE MIEUM + 0xC1CF: 0xC8D5, //HANGUL SYLLABLE CIEUC OE PIEUP + 0xC1D0: 0xC8D7, //HANGUL SYLLABLE CIEUC OE SIOS + 0xC1D1: 0xC8D9, //HANGUL SYLLABLE CIEUC OE IEUNG + 0xC1D2: 0xC8E0, //HANGUL SYLLABLE CIEUC YO + 0xC1D3: 0xC8E1, //HANGUL SYLLABLE CIEUC YO KIYEOK + 0xC1D4: 0xC8E4, //HANGUL SYLLABLE CIEUC YO NIEUN + 0xC1D5: 0xC8F5, //HANGUL SYLLABLE CIEUC YO IEUNG + 0xC1D6: 0xC8FC, //HANGUL SYLLABLE CIEUC U + 0xC1D7: 0xC8FD, //HANGUL SYLLABLE CIEUC U KIYEOK + 0xC1D8: 0xC900, //HANGUL SYLLABLE CIEUC U NIEUN + 0xC1D9: 0xC904, //HANGUL SYLLABLE CIEUC U RIEUL + 0xC1DA: 0xC905, //HANGUL SYLLABLE CIEUC U RIEULKIYEOK + 0xC1DB: 0xC906, //HANGUL SYLLABLE CIEUC U RIEULMIEUM + 0xC1DC: 0xC90C, //HANGUL SYLLABLE CIEUC U MIEUM + 0xC1DD: 0xC90D, //HANGUL SYLLABLE CIEUC U PIEUP + 0xC1DE: 0xC90F, //HANGUL SYLLABLE CIEUC U SIOS + 0xC1DF: 0xC911, //HANGUL SYLLABLE CIEUC U IEUNG + 0xC1E0: 0xC918, //HANGUL SYLLABLE CIEUC WEO + 0xC1E1: 0xC92C, //HANGUL SYLLABLE CIEUC WEO SSANGSIOS + 0xC1E2: 0xC934, //HANGUL SYLLABLE CIEUC WE + 0xC1E3: 0xC950, //HANGUL SYLLABLE CIEUC WI + 0xC1E4: 0xC951, //HANGUL SYLLABLE CIEUC WI KIYEOK + 0xC1E5: 0xC954, //HANGUL SYLLABLE CIEUC WI NIEUN + 0xC1E6: 0xC958, //HANGUL SYLLABLE CIEUC WI RIEUL + 0xC1E7: 0xC960, //HANGUL SYLLABLE CIEUC WI MIEUM + 0xC1E8: 0xC961, //HANGUL SYLLABLE CIEUC WI PIEUP + 0xC1E9: 0xC963, //HANGUL SYLLABLE CIEUC WI SIOS + 0xC1EA: 0xC96C, //HANGUL SYLLABLE CIEUC YU + 0xC1EB: 0xC970, //HANGUL SYLLABLE CIEUC YU NIEUN + 0xC1EC: 0xC974, //HANGUL SYLLABLE CIEUC YU RIEUL + 0xC1ED: 0xC97C, //HANGUL SYLLABLE CIEUC YU MIEUM + 0xC1EE: 0xC988, //HANGUL SYLLABLE CIEUC EU + 0xC1EF: 0xC989, //HANGUL SYLLABLE CIEUC EU KIYEOK + 0xC1F0: 0xC98C, //HANGUL SYLLABLE CIEUC EU NIEUN + 0xC1F1: 0xC990, //HANGUL SYLLABLE CIEUC EU RIEUL + 0xC1F2: 0xC998, //HANGUL SYLLABLE CIEUC EU MIEUM + 0xC1F3: 0xC999, //HANGUL SYLLABLE CIEUC EU PIEUP + 0xC1F4: 0xC99B, //HANGUL SYLLABLE CIEUC EU SIOS + 0xC1F5: 0xC99D, //HANGUL SYLLABLE CIEUC EU IEUNG + 0xC1F6: 0xC9C0, //HANGUL SYLLABLE CIEUC I + 0xC1F7: 0xC9C1, //HANGUL SYLLABLE CIEUC I KIYEOK + 0xC1F8: 0xC9C4, //HANGUL SYLLABLE CIEUC I NIEUN + 0xC1F9: 0xC9C7, //HANGUL SYLLABLE CIEUC I TIKEUT + 0xC1FA: 0xC9C8, //HANGUL SYLLABLE CIEUC I RIEUL + 0xC1FB: 0xC9CA, //HANGUL SYLLABLE CIEUC I RIEULMIEUM + 0xC1FC: 0xC9D0, //HANGUL SYLLABLE CIEUC I MIEUM + 0xC1FD: 0xC9D1, //HANGUL SYLLABLE CIEUC I PIEUP + 0xC1FE: 0xC9D3, //HANGUL SYLLABLE CIEUC I SIOS + 0xC241: 0xD5CA, //HANGUL SYLLABLE HIEUH EO SSANGKIYEOK + 0xC242: 0xD5CB, //HANGUL SYLLABLE HIEUH EO KIYEOKSIOS + 0xC243: 0xD5CD, //HANGUL SYLLABLE HIEUH EO NIEUNCIEUC + 0xC244: 0xD5CE, //HANGUL SYLLABLE HIEUH EO NIEUNHIEUH + 0xC245: 0xD5CF, //HANGUL SYLLABLE HIEUH EO TIKEUT + 0xC246: 0xD5D1, //HANGUL SYLLABLE HIEUH EO RIEULKIYEOK + 0xC247: 0xD5D3, //HANGUL SYLLABLE HIEUH EO RIEULPIEUP + 0xC248: 0xD5D4, //HANGUL SYLLABLE HIEUH EO RIEULSIOS + 0xC249: 0xD5D5, //HANGUL SYLLABLE HIEUH EO RIEULTHIEUTH + 0xC24A: 0xD5D6, //HANGUL SYLLABLE HIEUH EO RIEULPHIEUPH + 0xC24B: 0xD5D7, //HANGUL SYLLABLE HIEUH EO RIEULHIEUH + 0xC24C: 0xD5DA, //HANGUL SYLLABLE HIEUH EO PIEUPSIOS + 0xC24D: 0xD5DC, //HANGUL SYLLABLE HIEUH EO SSANGSIOS + 0xC24E: 0xD5DE, //HANGUL SYLLABLE HIEUH EO CIEUC + 0xC24F: 0xD5DF, //HANGUL SYLLABLE HIEUH EO CHIEUCH + 0xC250: 0xD5E0, //HANGUL SYLLABLE HIEUH EO KHIEUKH + 0xC251: 0xD5E1, //HANGUL SYLLABLE HIEUH EO THIEUTH + 0xC252: 0xD5E2, //HANGUL SYLLABLE HIEUH EO PHIEUPH + 0xC253: 0xD5E3, //HANGUL SYLLABLE HIEUH EO HIEUH + 0xC254: 0xD5E6, //HANGUL SYLLABLE HIEUH E SSANGKIYEOK + 0xC255: 0xD5E7, //HANGUL SYLLABLE HIEUH E KIYEOKSIOS + 0xC256: 0xD5E9, //HANGUL SYLLABLE HIEUH E NIEUNCIEUC + 0xC257: 0xD5EA, //HANGUL SYLLABLE HIEUH E NIEUNHIEUH + 0xC258: 0xD5EB, //HANGUL SYLLABLE HIEUH E TIKEUT + 0xC259: 0xD5ED, //HANGUL SYLLABLE HIEUH E RIEULKIYEOK + 0xC25A: 0xD5EE, //HANGUL SYLLABLE HIEUH E RIEULMIEUM + 0xC261: 0xD5EF, //HANGUL SYLLABLE HIEUH E RIEULPIEUP + 0xC262: 0xD5F0, //HANGUL SYLLABLE HIEUH E RIEULSIOS + 0xC263: 0xD5F1, //HANGUL SYLLABLE HIEUH E RIEULTHIEUTH + 0xC264: 0xD5F2, //HANGUL SYLLABLE HIEUH E RIEULPHIEUPH + 0xC265: 0xD5F3, //HANGUL SYLLABLE HIEUH E RIEULHIEUH + 0xC266: 0xD5F6, //HANGUL SYLLABLE HIEUH E PIEUPSIOS + 0xC267: 0xD5F8, //HANGUL SYLLABLE HIEUH E SSANGSIOS + 0xC268: 0xD5FA, //HANGUL SYLLABLE HIEUH E CIEUC + 0xC269: 0xD5FB, //HANGUL SYLLABLE HIEUH E CHIEUCH + 0xC26A: 0xD5FC, //HANGUL SYLLABLE HIEUH E KHIEUKH + 0xC26B: 0xD5FD, //HANGUL SYLLABLE HIEUH E THIEUTH + 0xC26C: 0xD5FE, //HANGUL SYLLABLE HIEUH E PHIEUPH + 0xC26D: 0xD5FF, //HANGUL SYLLABLE HIEUH E HIEUH + 0xC26E: 0xD602, //HANGUL SYLLABLE HIEUH YEO SSANGKIYEOK + 0xC26F: 0xD603, //HANGUL SYLLABLE HIEUH YEO KIYEOKSIOS + 0xC270: 0xD605, //HANGUL SYLLABLE HIEUH YEO NIEUNCIEUC + 0xC271: 0xD606, //HANGUL SYLLABLE HIEUH YEO NIEUNHIEUH + 0xC272: 0xD607, //HANGUL SYLLABLE HIEUH YEO TIKEUT + 0xC273: 0xD609, //HANGUL SYLLABLE HIEUH YEO RIEULKIYEOK + 0xC274: 0xD60A, //HANGUL SYLLABLE HIEUH YEO RIEULMIEUM + 0xC275: 0xD60B, //HANGUL SYLLABLE HIEUH YEO RIEULPIEUP + 0xC276: 0xD60C, //HANGUL SYLLABLE HIEUH YEO RIEULSIOS + 0xC277: 0xD60D, //HANGUL SYLLABLE HIEUH YEO RIEULTHIEUTH + 0xC278: 0xD60E, //HANGUL SYLLABLE HIEUH YEO RIEULPHIEUPH + 0xC279: 0xD60F, //HANGUL SYLLABLE HIEUH YEO RIEULHIEUH + 0xC27A: 0xD612, //HANGUL SYLLABLE HIEUH YEO PIEUPSIOS + 0xC281: 0xD616, //HANGUL SYLLABLE HIEUH YEO CIEUC + 0xC282: 0xD617, //HANGUL SYLLABLE HIEUH YEO CHIEUCH + 0xC283: 0xD618, //HANGUL SYLLABLE HIEUH YEO KHIEUKH + 0xC284: 0xD619, //HANGUL SYLLABLE HIEUH YEO THIEUTH + 0xC285: 0xD61A, //HANGUL SYLLABLE HIEUH YEO PHIEUPH + 0xC286: 0xD61B, //HANGUL SYLLABLE HIEUH YEO HIEUH + 0xC287: 0xD61D, //HANGUL SYLLABLE HIEUH YE KIYEOK + 0xC288: 0xD61E, //HANGUL SYLLABLE HIEUH YE SSANGKIYEOK + 0xC289: 0xD61F, //HANGUL SYLLABLE HIEUH YE KIYEOKSIOS + 0xC28A: 0xD621, //HANGUL SYLLABLE HIEUH YE NIEUNCIEUC + 0xC28B: 0xD622, //HANGUL SYLLABLE HIEUH YE NIEUNHIEUH + 0xC28C: 0xD623, //HANGUL SYLLABLE HIEUH YE TIKEUT + 0xC28D: 0xD625, //HANGUL SYLLABLE HIEUH YE RIEULKIYEOK + 0xC28E: 0xD626, //HANGUL SYLLABLE HIEUH YE RIEULMIEUM + 0xC28F: 0xD627, //HANGUL SYLLABLE HIEUH YE RIEULPIEUP + 0xC290: 0xD628, //HANGUL SYLLABLE HIEUH YE RIEULSIOS + 0xC291: 0xD629, //HANGUL SYLLABLE HIEUH YE RIEULTHIEUTH + 0xC292: 0xD62A, //HANGUL SYLLABLE HIEUH YE RIEULPHIEUPH + 0xC293: 0xD62B, //HANGUL SYLLABLE HIEUH YE RIEULHIEUH + 0xC294: 0xD62C, //HANGUL SYLLABLE HIEUH YE MIEUM + 0xC295: 0xD62E, //HANGUL SYLLABLE HIEUH YE PIEUPSIOS + 0xC296: 0xD62F, //HANGUL SYLLABLE HIEUH YE SIOS + 0xC297: 0xD630, //HANGUL SYLLABLE HIEUH YE SSANGSIOS + 0xC298: 0xD631, //HANGUL SYLLABLE HIEUH YE IEUNG + 0xC299: 0xD632, //HANGUL SYLLABLE HIEUH YE CIEUC + 0xC29A: 0xD633, //HANGUL SYLLABLE HIEUH YE CHIEUCH + 0xC29B: 0xD634, //HANGUL SYLLABLE HIEUH YE KHIEUKH + 0xC29C: 0xD635, //HANGUL SYLLABLE HIEUH YE THIEUTH + 0xC29D: 0xD636, //HANGUL SYLLABLE HIEUH YE PHIEUPH + 0xC29E: 0xD637, //HANGUL SYLLABLE HIEUH YE HIEUH + 0xC29F: 0xD63A, //HANGUL SYLLABLE HIEUH O SSANGKIYEOK + 0xC2A0: 0xD63B, //HANGUL SYLLABLE HIEUH O KIYEOKSIOS + 0xC2A1: 0xC9D5, //HANGUL SYLLABLE CIEUC I IEUNG + 0xC2A2: 0xC9D6, //HANGUL SYLLABLE CIEUC I CIEUC + 0xC2A3: 0xC9D9, //HANGUL SYLLABLE CIEUC I THIEUTH + 0xC2A4: 0xC9DA, //HANGUL SYLLABLE CIEUC I PHIEUPH + 0xC2A5: 0xC9DC, //HANGUL SYLLABLE SSANGCIEUC A + 0xC2A6: 0xC9DD, //HANGUL SYLLABLE SSANGCIEUC A KIYEOK + 0xC2A7: 0xC9E0, //HANGUL SYLLABLE SSANGCIEUC A NIEUN + 0xC2A8: 0xC9E2, //HANGUL SYLLABLE SSANGCIEUC A NIEUNHIEUH + 0xC2A9: 0xC9E4, //HANGUL SYLLABLE SSANGCIEUC A RIEUL + 0xC2AA: 0xC9E7, //HANGUL SYLLABLE SSANGCIEUC A RIEULPIEUP + 0xC2AB: 0xC9EC, //HANGUL SYLLABLE SSANGCIEUC A MIEUM + 0xC2AC: 0xC9ED, //HANGUL SYLLABLE SSANGCIEUC A PIEUP + 0xC2AD: 0xC9EF, //HANGUL SYLLABLE SSANGCIEUC A SIOS + 0xC2AE: 0xC9F0, //HANGUL SYLLABLE SSANGCIEUC A SSANGSIOS + 0xC2AF: 0xC9F1, //HANGUL SYLLABLE SSANGCIEUC A IEUNG + 0xC2B0: 0xC9F8, //HANGUL SYLLABLE SSANGCIEUC AE + 0xC2B1: 0xC9F9, //HANGUL SYLLABLE SSANGCIEUC AE KIYEOK + 0xC2B2: 0xC9FC, //HANGUL SYLLABLE SSANGCIEUC AE NIEUN + 0xC2B3: 0xCA00, //HANGUL SYLLABLE SSANGCIEUC AE RIEUL + 0xC2B4: 0xCA08, //HANGUL SYLLABLE SSANGCIEUC AE MIEUM + 0xC2B5: 0xCA09, //HANGUL SYLLABLE SSANGCIEUC AE PIEUP + 0xC2B6: 0xCA0B, //HANGUL SYLLABLE SSANGCIEUC AE SIOS + 0xC2B7: 0xCA0C, //HANGUL SYLLABLE SSANGCIEUC AE SSANGSIOS + 0xC2B8: 0xCA0D, //HANGUL SYLLABLE SSANGCIEUC AE IEUNG + 0xC2B9: 0xCA14, //HANGUL SYLLABLE SSANGCIEUC YA + 0xC2BA: 0xCA18, //HANGUL SYLLABLE SSANGCIEUC YA NIEUN + 0xC2BB: 0xCA29, //HANGUL SYLLABLE SSANGCIEUC YA IEUNG + 0xC2BC: 0xCA4C, //HANGUL SYLLABLE SSANGCIEUC EO + 0xC2BD: 0xCA4D, //HANGUL SYLLABLE SSANGCIEUC EO KIYEOK + 0xC2BE: 0xCA50, //HANGUL SYLLABLE SSANGCIEUC EO NIEUN + 0xC2BF: 0xCA54, //HANGUL SYLLABLE SSANGCIEUC EO RIEUL + 0xC2C0: 0xCA5C, //HANGUL SYLLABLE SSANGCIEUC EO MIEUM + 0xC2C1: 0xCA5D, //HANGUL SYLLABLE SSANGCIEUC EO PIEUP + 0xC2C2: 0xCA5F, //HANGUL SYLLABLE SSANGCIEUC EO SIOS + 0xC2C3: 0xCA60, //HANGUL SYLLABLE SSANGCIEUC EO SSANGSIOS + 0xC2C4: 0xCA61, //HANGUL SYLLABLE SSANGCIEUC EO IEUNG + 0xC2C5: 0xCA68, //HANGUL SYLLABLE SSANGCIEUC E + 0xC2C6: 0xCA7D, //HANGUL SYLLABLE SSANGCIEUC E IEUNG + 0xC2C7: 0xCA84, //HANGUL SYLLABLE SSANGCIEUC YEO + 0xC2C8: 0xCA98, //HANGUL SYLLABLE SSANGCIEUC YEO SSANGSIOS + 0xC2C9: 0xCABC, //HANGUL SYLLABLE SSANGCIEUC O + 0xC2CA: 0xCABD, //HANGUL SYLLABLE SSANGCIEUC O KIYEOK + 0xC2CB: 0xCAC0, //HANGUL SYLLABLE SSANGCIEUC O NIEUN + 0xC2CC: 0xCAC4, //HANGUL SYLLABLE SSANGCIEUC O RIEUL + 0xC2CD: 0xCACC, //HANGUL SYLLABLE SSANGCIEUC O MIEUM + 0xC2CE: 0xCACD, //HANGUL SYLLABLE SSANGCIEUC O PIEUP + 0xC2CF: 0xCACF, //HANGUL SYLLABLE SSANGCIEUC O SIOS + 0xC2D0: 0xCAD1, //HANGUL SYLLABLE SSANGCIEUC O IEUNG + 0xC2D1: 0xCAD3, //HANGUL SYLLABLE SSANGCIEUC O CHIEUCH + 0xC2D2: 0xCAD8, //HANGUL SYLLABLE SSANGCIEUC WA + 0xC2D3: 0xCAD9, //HANGUL SYLLABLE SSANGCIEUC WA KIYEOK + 0xC2D4: 0xCAE0, //HANGUL SYLLABLE SSANGCIEUC WA RIEUL + 0xC2D5: 0xCAEC, //HANGUL SYLLABLE SSANGCIEUC WA SSANGSIOS + 0xC2D6: 0xCAF4, //HANGUL SYLLABLE SSANGCIEUC WAE + 0xC2D7: 0xCB08, //HANGUL SYLLABLE SSANGCIEUC WAE SSANGSIOS + 0xC2D8: 0xCB10, //HANGUL SYLLABLE SSANGCIEUC OE + 0xC2D9: 0xCB14, //HANGUL SYLLABLE SSANGCIEUC OE NIEUN + 0xC2DA: 0xCB18, //HANGUL SYLLABLE SSANGCIEUC OE RIEUL + 0xC2DB: 0xCB20, //HANGUL SYLLABLE SSANGCIEUC OE MIEUM + 0xC2DC: 0xCB21, //HANGUL SYLLABLE SSANGCIEUC OE PIEUP + 0xC2DD: 0xCB41, //HANGUL SYLLABLE SSANGCIEUC YO IEUNG + 0xC2DE: 0xCB48, //HANGUL SYLLABLE SSANGCIEUC U + 0xC2DF: 0xCB49, //HANGUL SYLLABLE SSANGCIEUC U KIYEOK + 0xC2E0: 0xCB4C, //HANGUL SYLLABLE SSANGCIEUC U NIEUN + 0xC2E1: 0xCB50, //HANGUL SYLLABLE SSANGCIEUC U RIEUL + 0xC2E2: 0xCB58, //HANGUL SYLLABLE SSANGCIEUC U MIEUM + 0xC2E3: 0xCB59, //HANGUL SYLLABLE SSANGCIEUC U PIEUP + 0xC2E4: 0xCB5D, //HANGUL SYLLABLE SSANGCIEUC U IEUNG + 0xC2E5: 0xCB64, //HANGUL SYLLABLE SSANGCIEUC WEO + 0xC2E6: 0xCB78, //HANGUL SYLLABLE SSANGCIEUC WEO SSANGSIOS + 0xC2E7: 0xCB79, //HANGUL SYLLABLE SSANGCIEUC WEO IEUNG + 0xC2E8: 0xCB9C, //HANGUL SYLLABLE SSANGCIEUC WI + 0xC2E9: 0xCBB8, //HANGUL SYLLABLE SSANGCIEUC YU + 0xC2EA: 0xCBD4, //HANGUL SYLLABLE SSANGCIEUC EU + 0xC2EB: 0xCBE4, //HANGUL SYLLABLE SSANGCIEUC EU MIEUM + 0xC2EC: 0xCBE7, //HANGUL SYLLABLE SSANGCIEUC EU SIOS + 0xC2ED: 0xCBE9, //HANGUL SYLLABLE SSANGCIEUC EU IEUNG + 0xC2EE: 0xCC0C, //HANGUL SYLLABLE SSANGCIEUC I + 0xC2EF: 0xCC0D, //HANGUL SYLLABLE SSANGCIEUC I KIYEOK + 0xC2F0: 0xCC10, //HANGUL SYLLABLE SSANGCIEUC I NIEUN + 0xC2F1: 0xCC14, //HANGUL SYLLABLE SSANGCIEUC I RIEUL + 0xC2F2: 0xCC1C, //HANGUL SYLLABLE SSANGCIEUC I MIEUM + 0xC2F3: 0xCC1D, //HANGUL SYLLABLE SSANGCIEUC I PIEUP + 0xC2F4: 0xCC21, //HANGUL SYLLABLE SSANGCIEUC I IEUNG + 0xC2F5: 0xCC22, //HANGUL SYLLABLE SSANGCIEUC I CIEUC + 0xC2F6: 0xCC27, //HANGUL SYLLABLE SSANGCIEUC I HIEUH + 0xC2F7: 0xCC28, //HANGUL SYLLABLE CHIEUCH A + 0xC2F8: 0xCC29, //HANGUL SYLLABLE CHIEUCH A KIYEOK + 0xC2F9: 0xCC2C, //HANGUL SYLLABLE CHIEUCH A NIEUN + 0xC2FA: 0xCC2E, //HANGUL SYLLABLE CHIEUCH A NIEUNHIEUH + 0xC2FB: 0xCC30, //HANGUL SYLLABLE CHIEUCH A RIEUL + 0xC2FC: 0xCC38, //HANGUL SYLLABLE CHIEUCH A MIEUM + 0xC2FD: 0xCC39, //HANGUL SYLLABLE CHIEUCH A PIEUP + 0xC2FE: 0xCC3B, //HANGUL SYLLABLE CHIEUCH A SIOS + 0xC341: 0xD63D, //HANGUL SYLLABLE HIEUH O NIEUNCIEUC + 0xC342: 0xD63E, //HANGUL SYLLABLE HIEUH O NIEUNHIEUH + 0xC343: 0xD63F, //HANGUL SYLLABLE HIEUH O TIKEUT + 0xC344: 0xD641, //HANGUL SYLLABLE HIEUH O RIEULKIYEOK + 0xC345: 0xD642, //HANGUL SYLLABLE HIEUH O RIEULMIEUM + 0xC346: 0xD643, //HANGUL SYLLABLE HIEUH O RIEULPIEUP + 0xC347: 0xD644, //HANGUL SYLLABLE HIEUH O RIEULSIOS + 0xC348: 0xD646, //HANGUL SYLLABLE HIEUH O RIEULPHIEUPH + 0xC349: 0xD647, //HANGUL SYLLABLE HIEUH O RIEULHIEUH + 0xC34A: 0xD64A, //HANGUL SYLLABLE HIEUH O PIEUPSIOS + 0xC34B: 0xD64C, //HANGUL SYLLABLE HIEUH O SSANGSIOS + 0xC34C: 0xD64E, //HANGUL SYLLABLE HIEUH O CIEUC + 0xC34D: 0xD64F, //HANGUL SYLLABLE HIEUH O CHIEUCH + 0xC34E: 0xD650, //HANGUL SYLLABLE HIEUH O KHIEUKH + 0xC34F: 0xD652, //HANGUL SYLLABLE HIEUH O PHIEUPH + 0xC350: 0xD653, //HANGUL SYLLABLE HIEUH O HIEUH + 0xC351: 0xD656, //HANGUL SYLLABLE HIEUH WA SSANGKIYEOK + 0xC352: 0xD657, //HANGUL SYLLABLE HIEUH WA KIYEOKSIOS + 0xC353: 0xD659, //HANGUL SYLLABLE HIEUH WA NIEUNCIEUC + 0xC354: 0xD65A, //HANGUL SYLLABLE HIEUH WA NIEUNHIEUH + 0xC355: 0xD65B, //HANGUL SYLLABLE HIEUH WA TIKEUT + 0xC356: 0xD65D, //HANGUL SYLLABLE HIEUH WA RIEULKIYEOK + 0xC357: 0xD65E, //HANGUL SYLLABLE HIEUH WA RIEULMIEUM + 0xC358: 0xD65F, //HANGUL SYLLABLE HIEUH WA RIEULPIEUP + 0xC359: 0xD660, //HANGUL SYLLABLE HIEUH WA RIEULSIOS + 0xC35A: 0xD661, //HANGUL SYLLABLE HIEUH WA RIEULTHIEUTH + 0xC361: 0xD662, //HANGUL SYLLABLE HIEUH WA RIEULPHIEUPH + 0xC362: 0xD663, //HANGUL SYLLABLE HIEUH WA RIEULHIEUH + 0xC363: 0xD664, //HANGUL SYLLABLE HIEUH WA MIEUM + 0xC364: 0xD665, //HANGUL SYLLABLE HIEUH WA PIEUP + 0xC365: 0xD666, //HANGUL SYLLABLE HIEUH WA PIEUPSIOS + 0xC366: 0xD668, //HANGUL SYLLABLE HIEUH WA SSANGSIOS + 0xC367: 0xD66A, //HANGUL SYLLABLE HIEUH WA CIEUC + 0xC368: 0xD66B, //HANGUL SYLLABLE HIEUH WA CHIEUCH + 0xC369: 0xD66C, //HANGUL SYLLABLE HIEUH WA KHIEUKH + 0xC36A: 0xD66D, //HANGUL SYLLABLE HIEUH WA THIEUTH + 0xC36B: 0xD66E, //HANGUL SYLLABLE HIEUH WA PHIEUPH + 0xC36C: 0xD66F, //HANGUL SYLLABLE HIEUH WA HIEUH + 0xC36D: 0xD672, //HANGUL SYLLABLE HIEUH WAE SSANGKIYEOK + 0xC36E: 0xD673, //HANGUL SYLLABLE HIEUH WAE KIYEOKSIOS + 0xC36F: 0xD675, //HANGUL SYLLABLE HIEUH WAE NIEUNCIEUC + 0xC370: 0xD676, //HANGUL SYLLABLE HIEUH WAE NIEUNHIEUH + 0xC371: 0xD677, //HANGUL SYLLABLE HIEUH WAE TIKEUT + 0xC372: 0xD678, //HANGUL SYLLABLE HIEUH WAE RIEUL + 0xC373: 0xD679, //HANGUL SYLLABLE HIEUH WAE RIEULKIYEOK + 0xC374: 0xD67A, //HANGUL SYLLABLE HIEUH WAE RIEULMIEUM + 0xC375: 0xD67B, //HANGUL SYLLABLE HIEUH WAE RIEULPIEUP + 0xC376: 0xD67C, //HANGUL SYLLABLE HIEUH WAE RIEULSIOS + 0xC377: 0xD67D, //HANGUL SYLLABLE HIEUH WAE RIEULTHIEUTH + 0xC378: 0xD67E, //HANGUL SYLLABLE HIEUH WAE RIEULPHIEUPH + 0xC379: 0xD67F, //HANGUL SYLLABLE HIEUH WAE RIEULHIEUH + 0xC37A: 0xD680, //HANGUL SYLLABLE HIEUH WAE MIEUM + 0xC381: 0xD681, //HANGUL SYLLABLE HIEUH WAE PIEUP + 0xC382: 0xD682, //HANGUL SYLLABLE HIEUH WAE PIEUPSIOS + 0xC383: 0xD684, //HANGUL SYLLABLE HIEUH WAE SSANGSIOS + 0xC384: 0xD686, //HANGUL SYLLABLE HIEUH WAE CIEUC + 0xC385: 0xD687, //HANGUL SYLLABLE HIEUH WAE CHIEUCH + 0xC386: 0xD688, //HANGUL SYLLABLE HIEUH WAE KHIEUKH + 0xC387: 0xD689, //HANGUL SYLLABLE HIEUH WAE THIEUTH + 0xC388: 0xD68A, //HANGUL SYLLABLE HIEUH WAE PHIEUPH + 0xC389: 0xD68B, //HANGUL SYLLABLE HIEUH WAE HIEUH + 0xC38A: 0xD68E, //HANGUL SYLLABLE HIEUH OE SSANGKIYEOK + 0xC38B: 0xD68F, //HANGUL SYLLABLE HIEUH OE KIYEOKSIOS + 0xC38C: 0xD691, //HANGUL SYLLABLE HIEUH OE NIEUNCIEUC + 0xC38D: 0xD692, //HANGUL SYLLABLE HIEUH OE NIEUNHIEUH + 0xC38E: 0xD693, //HANGUL SYLLABLE HIEUH OE TIKEUT + 0xC38F: 0xD695, //HANGUL SYLLABLE HIEUH OE RIEULKIYEOK + 0xC390: 0xD696, //HANGUL SYLLABLE HIEUH OE RIEULMIEUM + 0xC391: 0xD697, //HANGUL SYLLABLE HIEUH OE RIEULPIEUP + 0xC392: 0xD698, //HANGUL SYLLABLE HIEUH OE RIEULSIOS + 0xC393: 0xD699, //HANGUL SYLLABLE HIEUH OE RIEULTHIEUTH + 0xC394: 0xD69A, //HANGUL SYLLABLE HIEUH OE RIEULPHIEUPH + 0xC395: 0xD69B, //HANGUL SYLLABLE HIEUH OE RIEULHIEUH + 0xC396: 0xD69C, //HANGUL SYLLABLE HIEUH OE MIEUM + 0xC397: 0xD69E, //HANGUL SYLLABLE HIEUH OE PIEUPSIOS + 0xC398: 0xD6A0, //HANGUL SYLLABLE HIEUH OE SSANGSIOS + 0xC399: 0xD6A2, //HANGUL SYLLABLE HIEUH OE CIEUC + 0xC39A: 0xD6A3, //HANGUL SYLLABLE HIEUH OE CHIEUCH + 0xC39B: 0xD6A4, //HANGUL SYLLABLE HIEUH OE KHIEUKH + 0xC39C: 0xD6A5, //HANGUL SYLLABLE HIEUH OE THIEUTH + 0xC39D: 0xD6A6, //HANGUL SYLLABLE HIEUH OE PHIEUPH + 0xC39E: 0xD6A7, //HANGUL SYLLABLE HIEUH OE HIEUH + 0xC39F: 0xD6A9, //HANGUL SYLLABLE HIEUH YO KIYEOK + 0xC3A0: 0xD6AA, //HANGUL SYLLABLE HIEUH YO SSANGKIYEOK + 0xC3A1: 0xCC3C, //HANGUL SYLLABLE CHIEUCH A SSANGSIOS + 0xC3A2: 0xCC3D, //HANGUL SYLLABLE CHIEUCH A IEUNG + 0xC3A3: 0xCC3E, //HANGUL SYLLABLE CHIEUCH A CIEUC + 0xC3A4: 0xCC44, //HANGUL SYLLABLE CHIEUCH AE + 0xC3A5: 0xCC45, //HANGUL SYLLABLE CHIEUCH AE KIYEOK + 0xC3A6: 0xCC48, //HANGUL SYLLABLE CHIEUCH AE NIEUN + 0xC3A7: 0xCC4C, //HANGUL SYLLABLE CHIEUCH AE RIEUL + 0xC3A8: 0xCC54, //HANGUL SYLLABLE CHIEUCH AE MIEUM + 0xC3A9: 0xCC55, //HANGUL SYLLABLE CHIEUCH AE PIEUP + 0xC3AA: 0xCC57, //HANGUL SYLLABLE CHIEUCH AE SIOS + 0xC3AB: 0xCC58, //HANGUL SYLLABLE CHIEUCH AE SSANGSIOS + 0xC3AC: 0xCC59, //HANGUL SYLLABLE CHIEUCH AE IEUNG + 0xC3AD: 0xCC60, //HANGUL SYLLABLE CHIEUCH YA + 0xC3AE: 0xCC64, //HANGUL SYLLABLE CHIEUCH YA NIEUN + 0xC3AF: 0xCC66, //HANGUL SYLLABLE CHIEUCH YA NIEUNHIEUH + 0xC3B0: 0xCC68, //HANGUL SYLLABLE CHIEUCH YA RIEUL + 0xC3B1: 0xCC70, //HANGUL SYLLABLE CHIEUCH YA MIEUM + 0xC3B2: 0xCC75, //HANGUL SYLLABLE CHIEUCH YA IEUNG + 0xC3B3: 0xCC98, //HANGUL SYLLABLE CHIEUCH EO + 0xC3B4: 0xCC99, //HANGUL SYLLABLE CHIEUCH EO KIYEOK + 0xC3B5: 0xCC9C, //HANGUL SYLLABLE CHIEUCH EO NIEUN + 0xC3B6: 0xCCA0, //HANGUL SYLLABLE CHIEUCH EO RIEUL + 0xC3B7: 0xCCA8, //HANGUL SYLLABLE CHIEUCH EO MIEUM + 0xC3B8: 0xCCA9, //HANGUL SYLLABLE CHIEUCH EO PIEUP + 0xC3B9: 0xCCAB, //HANGUL SYLLABLE CHIEUCH EO SIOS + 0xC3BA: 0xCCAC, //HANGUL SYLLABLE CHIEUCH EO SSANGSIOS + 0xC3BB: 0xCCAD, //HANGUL SYLLABLE CHIEUCH EO IEUNG + 0xC3BC: 0xCCB4, //HANGUL SYLLABLE CHIEUCH E + 0xC3BD: 0xCCB5, //HANGUL SYLLABLE CHIEUCH E KIYEOK + 0xC3BE: 0xCCB8, //HANGUL SYLLABLE CHIEUCH E NIEUN + 0xC3BF: 0xCCBC, //HANGUL SYLLABLE CHIEUCH E RIEUL + 0xC3C0: 0xCCC4, //HANGUL SYLLABLE CHIEUCH E MIEUM + 0xC3C1: 0xCCC5, //HANGUL SYLLABLE CHIEUCH E PIEUP + 0xC3C2: 0xCCC7, //HANGUL SYLLABLE CHIEUCH E SIOS + 0xC3C3: 0xCCC9, //HANGUL SYLLABLE CHIEUCH E IEUNG + 0xC3C4: 0xCCD0, //HANGUL SYLLABLE CHIEUCH YEO + 0xC3C5: 0xCCD4, //HANGUL SYLLABLE CHIEUCH YEO NIEUN + 0xC3C6: 0xCCE4, //HANGUL SYLLABLE CHIEUCH YEO SSANGSIOS + 0xC3C7: 0xCCEC, //HANGUL SYLLABLE CHIEUCH YE + 0xC3C8: 0xCCF0, //HANGUL SYLLABLE CHIEUCH YE NIEUN + 0xC3C9: 0xCD01, //HANGUL SYLLABLE CHIEUCH YE IEUNG + 0xC3CA: 0xCD08, //HANGUL SYLLABLE CHIEUCH O + 0xC3CB: 0xCD09, //HANGUL SYLLABLE CHIEUCH O KIYEOK + 0xC3CC: 0xCD0C, //HANGUL SYLLABLE CHIEUCH O NIEUN + 0xC3CD: 0xCD10, //HANGUL SYLLABLE CHIEUCH O RIEUL + 0xC3CE: 0xCD18, //HANGUL SYLLABLE CHIEUCH O MIEUM + 0xC3CF: 0xCD19, //HANGUL SYLLABLE CHIEUCH O PIEUP + 0xC3D0: 0xCD1B, //HANGUL SYLLABLE CHIEUCH O SIOS + 0xC3D1: 0xCD1D, //HANGUL SYLLABLE CHIEUCH O IEUNG + 0xC3D2: 0xCD24, //HANGUL SYLLABLE CHIEUCH WA + 0xC3D3: 0xCD28, //HANGUL SYLLABLE CHIEUCH WA NIEUN + 0xC3D4: 0xCD2C, //HANGUL SYLLABLE CHIEUCH WA RIEUL + 0xC3D5: 0xCD39, //HANGUL SYLLABLE CHIEUCH WA IEUNG + 0xC3D6: 0xCD5C, //HANGUL SYLLABLE CHIEUCH OE + 0xC3D7: 0xCD60, //HANGUL SYLLABLE CHIEUCH OE NIEUN + 0xC3D8: 0xCD64, //HANGUL SYLLABLE CHIEUCH OE RIEUL + 0xC3D9: 0xCD6C, //HANGUL SYLLABLE CHIEUCH OE MIEUM + 0xC3DA: 0xCD6D, //HANGUL SYLLABLE CHIEUCH OE PIEUP + 0xC3DB: 0xCD6F, //HANGUL SYLLABLE CHIEUCH OE SIOS + 0xC3DC: 0xCD71, //HANGUL SYLLABLE CHIEUCH OE IEUNG + 0xC3DD: 0xCD78, //HANGUL SYLLABLE CHIEUCH YO + 0xC3DE: 0xCD88, //HANGUL SYLLABLE CHIEUCH YO MIEUM + 0xC3DF: 0xCD94, //HANGUL SYLLABLE CHIEUCH U + 0xC3E0: 0xCD95, //HANGUL SYLLABLE CHIEUCH U KIYEOK + 0xC3E1: 0xCD98, //HANGUL SYLLABLE CHIEUCH U NIEUN + 0xC3E2: 0xCD9C, //HANGUL SYLLABLE CHIEUCH U RIEUL + 0xC3E3: 0xCDA4, //HANGUL SYLLABLE CHIEUCH U MIEUM + 0xC3E4: 0xCDA5, //HANGUL SYLLABLE CHIEUCH U PIEUP + 0xC3E5: 0xCDA7, //HANGUL SYLLABLE CHIEUCH U SIOS + 0xC3E6: 0xCDA9, //HANGUL SYLLABLE CHIEUCH U IEUNG + 0xC3E7: 0xCDB0, //HANGUL SYLLABLE CHIEUCH WEO + 0xC3E8: 0xCDC4, //HANGUL SYLLABLE CHIEUCH WEO SSANGSIOS + 0xC3E9: 0xCDCC, //HANGUL SYLLABLE CHIEUCH WE + 0xC3EA: 0xCDD0, //HANGUL SYLLABLE CHIEUCH WE NIEUN + 0xC3EB: 0xCDE8, //HANGUL SYLLABLE CHIEUCH WI + 0xC3EC: 0xCDEC, //HANGUL SYLLABLE CHIEUCH WI NIEUN + 0xC3ED: 0xCDF0, //HANGUL SYLLABLE CHIEUCH WI RIEUL + 0xC3EE: 0xCDF8, //HANGUL SYLLABLE CHIEUCH WI MIEUM + 0xC3EF: 0xCDF9, //HANGUL SYLLABLE CHIEUCH WI PIEUP + 0xC3F0: 0xCDFB, //HANGUL SYLLABLE CHIEUCH WI SIOS + 0xC3F1: 0xCDFD, //HANGUL SYLLABLE CHIEUCH WI IEUNG + 0xC3F2: 0xCE04, //HANGUL SYLLABLE CHIEUCH YU + 0xC3F3: 0xCE08, //HANGUL SYLLABLE CHIEUCH YU NIEUN + 0xC3F4: 0xCE0C, //HANGUL SYLLABLE CHIEUCH YU RIEUL + 0xC3F5: 0xCE14, //HANGUL SYLLABLE CHIEUCH YU MIEUM + 0xC3F6: 0xCE19, //HANGUL SYLLABLE CHIEUCH YU IEUNG + 0xC3F7: 0xCE20, //HANGUL SYLLABLE CHIEUCH EU + 0xC3F8: 0xCE21, //HANGUL SYLLABLE CHIEUCH EU KIYEOK + 0xC3F9: 0xCE24, //HANGUL SYLLABLE CHIEUCH EU NIEUN + 0xC3FA: 0xCE28, //HANGUL SYLLABLE CHIEUCH EU RIEUL + 0xC3FB: 0xCE30, //HANGUL SYLLABLE CHIEUCH EU MIEUM + 0xC3FC: 0xCE31, //HANGUL SYLLABLE CHIEUCH EU PIEUP + 0xC3FD: 0xCE33, //HANGUL SYLLABLE CHIEUCH EU SIOS + 0xC3FE: 0xCE35, //HANGUL SYLLABLE CHIEUCH EU IEUNG + 0xC441: 0xD6AB, //HANGUL SYLLABLE HIEUH YO KIYEOKSIOS + 0xC442: 0xD6AD, //HANGUL SYLLABLE HIEUH YO NIEUNCIEUC + 0xC443: 0xD6AE, //HANGUL SYLLABLE HIEUH YO NIEUNHIEUH + 0xC444: 0xD6AF, //HANGUL SYLLABLE HIEUH YO TIKEUT + 0xC445: 0xD6B1, //HANGUL SYLLABLE HIEUH YO RIEULKIYEOK + 0xC446: 0xD6B2, //HANGUL SYLLABLE HIEUH YO RIEULMIEUM + 0xC447: 0xD6B3, //HANGUL SYLLABLE HIEUH YO RIEULPIEUP + 0xC448: 0xD6B4, //HANGUL SYLLABLE HIEUH YO RIEULSIOS + 0xC449: 0xD6B5, //HANGUL SYLLABLE HIEUH YO RIEULTHIEUTH + 0xC44A: 0xD6B6, //HANGUL SYLLABLE HIEUH YO RIEULPHIEUPH + 0xC44B: 0xD6B7, //HANGUL SYLLABLE HIEUH YO RIEULHIEUH + 0xC44C: 0xD6B8, //HANGUL SYLLABLE HIEUH YO MIEUM + 0xC44D: 0xD6BA, //HANGUL SYLLABLE HIEUH YO PIEUPSIOS + 0xC44E: 0xD6BC, //HANGUL SYLLABLE HIEUH YO SSANGSIOS + 0xC44F: 0xD6BD, //HANGUL SYLLABLE HIEUH YO IEUNG + 0xC450: 0xD6BE, //HANGUL SYLLABLE HIEUH YO CIEUC + 0xC451: 0xD6BF, //HANGUL SYLLABLE HIEUH YO CHIEUCH + 0xC452: 0xD6C0, //HANGUL SYLLABLE HIEUH YO KHIEUKH + 0xC453: 0xD6C1, //HANGUL SYLLABLE HIEUH YO THIEUTH + 0xC454: 0xD6C2, //HANGUL SYLLABLE HIEUH YO PHIEUPH + 0xC455: 0xD6C3, //HANGUL SYLLABLE HIEUH YO HIEUH + 0xC456: 0xD6C6, //HANGUL SYLLABLE HIEUH U SSANGKIYEOK + 0xC457: 0xD6C7, //HANGUL SYLLABLE HIEUH U KIYEOKSIOS + 0xC458: 0xD6C9, //HANGUL SYLLABLE HIEUH U NIEUNCIEUC + 0xC459: 0xD6CA, //HANGUL SYLLABLE HIEUH U NIEUNHIEUH + 0xC45A: 0xD6CB, //HANGUL SYLLABLE HIEUH U TIKEUT + 0xC461: 0xD6CD, //HANGUL SYLLABLE HIEUH U RIEULKIYEOK + 0xC462: 0xD6CE, //HANGUL SYLLABLE HIEUH U RIEULMIEUM + 0xC463: 0xD6CF, //HANGUL SYLLABLE HIEUH U RIEULPIEUP + 0xC464: 0xD6D0, //HANGUL SYLLABLE HIEUH U RIEULSIOS + 0xC465: 0xD6D2, //HANGUL SYLLABLE HIEUH U RIEULPHIEUPH + 0xC466: 0xD6D3, //HANGUL SYLLABLE HIEUH U RIEULHIEUH + 0xC467: 0xD6D5, //HANGUL SYLLABLE HIEUH U PIEUP + 0xC468: 0xD6D6, //HANGUL SYLLABLE HIEUH U PIEUPSIOS + 0xC469: 0xD6D8, //HANGUL SYLLABLE HIEUH U SSANGSIOS + 0xC46A: 0xD6DA, //HANGUL SYLLABLE HIEUH U CIEUC + 0xC46B: 0xD6DB, //HANGUL SYLLABLE HIEUH U CHIEUCH + 0xC46C: 0xD6DC, //HANGUL SYLLABLE HIEUH U KHIEUKH + 0xC46D: 0xD6DD, //HANGUL SYLLABLE HIEUH U THIEUTH + 0xC46E: 0xD6DE, //HANGUL SYLLABLE HIEUH U PHIEUPH + 0xC46F: 0xD6DF, //HANGUL SYLLABLE HIEUH U HIEUH + 0xC470: 0xD6E1, //HANGUL SYLLABLE HIEUH WEO KIYEOK + 0xC471: 0xD6E2, //HANGUL SYLLABLE HIEUH WEO SSANGKIYEOK + 0xC472: 0xD6E3, //HANGUL SYLLABLE HIEUH WEO KIYEOKSIOS + 0xC473: 0xD6E5, //HANGUL SYLLABLE HIEUH WEO NIEUNCIEUC + 0xC474: 0xD6E6, //HANGUL SYLLABLE HIEUH WEO NIEUNHIEUH + 0xC475: 0xD6E7, //HANGUL SYLLABLE HIEUH WEO TIKEUT + 0xC476: 0xD6E9, //HANGUL SYLLABLE HIEUH WEO RIEULKIYEOK + 0xC477: 0xD6EA, //HANGUL SYLLABLE HIEUH WEO RIEULMIEUM + 0xC478: 0xD6EB, //HANGUL SYLLABLE HIEUH WEO RIEULPIEUP + 0xC479: 0xD6EC, //HANGUL SYLLABLE HIEUH WEO RIEULSIOS + 0xC47A: 0xD6ED, //HANGUL SYLLABLE HIEUH WEO RIEULTHIEUTH + 0xC481: 0xD6EE, //HANGUL SYLLABLE HIEUH WEO RIEULPHIEUPH + 0xC482: 0xD6EF, //HANGUL SYLLABLE HIEUH WEO RIEULHIEUH + 0xC483: 0xD6F1, //HANGUL SYLLABLE HIEUH WEO PIEUP + 0xC484: 0xD6F2, //HANGUL SYLLABLE HIEUH WEO PIEUPSIOS + 0xC485: 0xD6F3, //HANGUL SYLLABLE HIEUH WEO SIOS + 0xC486: 0xD6F4, //HANGUL SYLLABLE HIEUH WEO SSANGSIOS + 0xC487: 0xD6F6, //HANGUL SYLLABLE HIEUH WEO CIEUC + 0xC488: 0xD6F7, //HANGUL SYLLABLE HIEUH WEO CHIEUCH + 0xC489: 0xD6F8, //HANGUL SYLLABLE HIEUH WEO KHIEUKH + 0xC48A: 0xD6F9, //HANGUL SYLLABLE HIEUH WEO THIEUTH + 0xC48B: 0xD6FA, //HANGUL SYLLABLE HIEUH WEO PHIEUPH + 0xC48C: 0xD6FB, //HANGUL SYLLABLE HIEUH WEO HIEUH + 0xC48D: 0xD6FE, //HANGUL SYLLABLE HIEUH WE SSANGKIYEOK + 0xC48E: 0xD6FF, //HANGUL SYLLABLE HIEUH WE KIYEOKSIOS + 0xC48F: 0xD701, //HANGUL SYLLABLE HIEUH WE NIEUNCIEUC + 0xC490: 0xD702, //HANGUL SYLLABLE HIEUH WE NIEUNHIEUH + 0xC491: 0xD703, //HANGUL SYLLABLE HIEUH WE TIKEUT + 0xC492: 0xD705, //HANGUL SYLLABLE HIEUH WE RIEULKIYEOK + 0xC493: 0xD706, //HANGUL SYLLABLE HIEUH WE RIEULMIEUM + 0xC494: 0xD707, //HANGUL SYLLABLE HIEUH WE RIEULPIEUP + 0xC495: 0xD708, //HANGUL SYLLABLE HIEUH WE RIEULSIOS + 0xC496: 0xD709, //HANGUL SYLLABLE HIEUH WE RIEULTHIEUTH + 0xC497: 0xD70A, //HANGUL SYLLABLE HIEUH WE RIEULPHIEUPH + 0xC498: 0xD70B, //HANGUL SYLLABLE HIEUH WE RIEULHIEUH + 0xC499: 0xD70C, //HANGUL SYLLABLE HIEUH WE MIEUM + 0xC49A: 0xD70D, //HANGUL SYLLABLE HIEUH WE PIEUP + 0xC49B: 0xD70E, //HANGUL SYLLABLE HIEUH WE PIEUPSIOS + 0xC49C: 0xD70F, //HANGUL SYLLABLE HIEUH WE SIOS + 0xC49D: 0xD710, //HANGUL SYLLABLE HIEUH WE SSANGSIOS + 0xC49E: 0xD712, //HANGUL SYLLABLE HIEUH WE CIEUC + 0xC49F: 0xD713, //HANGUL SYLLABLE HIEUH WE CHIEUCH + 0xC4A0: 0xD714, //HANGUL SYLLABLE HIEUH WE KHIEUKH + 0xC4A1: 0xCE58, //HANGUL SYLLABLE CHIEUCH I + 0xC4A2: 0xCE59, //HANGUL SYLLABLE CHIEUCH I KIYEOK + 0xC4A3: 0xCE5C, //HANGUL SYLLABLE CHIEUCH I NIEUN + 0xC4A4: 0xCE5F, //HANGUL SYLLABLE CHIEUCH I TIKEUT + 0xC4A5: 0xCE60, //HANGUL SYLLABLE CHIEUCH I RIEUL + 0xC4A6: 0xCE61, //HANGUL SYLLABLE CHIEUCH I RIEULKIYEOK + 0xC4A7: 0xCE68, //HANGUL SYLLABLE CHIEUCH I MIEUM + 0xC4A8: 0xCE69, //HANGUL SYLLABLE CHIEUCH I PIEUP + 0xC4A9: 0xCE6B, //HANGUL SYLLABLE CHIEUCH I SIOS + 0xC4AA: 0xCE6D, //HANGUL SYLLABLE CHIEUCH I IEUNG + 0xC4AB: 0xCE74, //HANGUL SYLLABLE KHIEUKH A + 0xC4AC: 0xCE75, //HANGUL SYLLABLE KHIEUKH A KIYEOK + 0xC4AD: 0xCE78, //HANGUL SYLLABLE KHIEUKH A NIEUN + 0xC4AE: 0xCE7C, //HANGUL SYLLABLE KHIEUKH A RIEUL + 0xC4AF: 0xCE84, //HANGUL SYLLABLE KHIEUKH A MIEUM + 0xC4B0: 0xCE85, //HANGUL SYLLABLE KHIEUKH A PIEUP + 0xC4B1: 0xCE87, //HANGUL SYLLABLE KHIEUKH A SIOS + 0xC4B2: 0xCE89, //HANGUL SYLLABLE KHIEUKH A IEUNG + 0xC4B3: 0xCE90, //HANGUL SYLLABLE KHIEUKH AE + 0xC4B4: 0xCE91, //HANGUL SYLLABLE KHIEUKH AE KIYEOK + 0xC4B5: 0xCE94, //HANGUL SYLLABLE KHIEUKH AE NIEUN + 0xC4B6: 0xCE98, //HANGUL SYLLABLE KHIEUKH AE RIEUL + 0xC4B7: 0xCEA0, //HANGUL SYLLABLE KHIEUKH AE MIEUM + 0xC4B8: 0xCEA1, //HANGUL SYLLABLE KHIEUKH AE PIEUP + 0xC4B9: 0xCEA3, //HANGUL SYLLABLE KHIEUKH AE SIOS + 0xC4BA: 0xCEA4, //HANGUL SYLLABLE KHIEUKH AE SSANGSIOS + 0xC4BB: 0xCEA5, //HANGUL SYLLABLE KHIEUKH AE IEUNG + 0xC4BC: 0xCEAC, //HANGUL SYLLABLE KHIEUKH YA + 0xC4BD: 0xCEAD, //HANGUL SYLLABLE KHIEUKH YA KIYEOK + 0xC4BE: 0xCEC1, //HANGUL SYLLABLE KHIEUKH YA IEUNG + 0xC4BF: 0xCEE4, //HANGUL SYLLABLE KHIEUKH EO + 0xC4C0: 0xCEE5, //HANGUL SYLLABLE KHIEUKH EO KIYEOK + 0xC4C1: 0xCEE8, //HANGUL SYLLABLE KHIEUKH EO NIEUN + 0xC4C2: 0xCEEB, //HANGUL SYLLABLE KHIEUKH EO TIKEUT + 0xC4C3: 0xCEEC, //HANGUL SYLLABLE KHIEUKH EO RIEUL + 0xC4C4: 0xCEF4, //HANGUL SYLLABLE KHIEUKH EO MIEUM + 0xC4C5: 0xCEF5, //HANGUL SYLLABLE KHIEUKH EO PIEUP + 0xC4C6: 0xCEF7, //HANGUL SYLLABLE KHIEUKH EO SIOS + 0xC4C7: 0xCEF8, //HANGUL SYLLABLE KHIEUKH EO SSANGSIOS + 0xC4C8: 0xCEF9, //HANGUL SYLLABLE KHIEUKH EO IEUNG + 0xC4C9: 0xCF00, //HANGUL SYLLABLE KHIEUKH E + 0xC4CA: 0xCF01, //HANGUL SYLLABLE KHIEUKH E KIYEOK + 0xC4CB: 0xCF04, //HANGUL SYLLABLE KHIEUKH E NIEUN + 0xC4CC: 0xCF08, //HANGUL SYLLABLE KHIEUKH E RIEUL + 0xC4CD: 0xCF10, //HANGUL SYLLABLE KHIEUKH E MIEUM + 0xC4CE: 0xCF11, //HANGUL SYLLABLE KHIEUKH E PIEUP + 0xC4CF: 0xCF13, //HANGUL SYLLABLE KHIEUKH E SIOS + 0xC4D0: 0xCF15, //HANGUL SYLLABLE KHIEUKH E IEUNG + 0xC4D1: 0xCF1C, //HANGUL SYLLABLE KHIEUKH YEO + 0xC4D2: 0xCF20, //HANGUL SYLLABLE KHIEUKH YEO NIEUN + 0xC4D3: 0xCF24, //HANGUL SYLLABLE KHIEUKH YEO RIEUL + 0xC4D4: 0xCF2C, //HANGUL SYLLABLE KHIEUKH YEO MIEUM + 0xC4D5: 0xCF2D, //HANGUL SYLLABLE KHIEUKH YEO PIEUP + 0xC4D6: 0xCF2F, //HANGUL SYLLABLE KHIEUKH YEO SIOS + 0xC4D7: 0xCF30, //HANGUL SYLLABLE KHIEUKH YEO SSANGSIOS + 0xC4D8: 0xCF31, //HANGUL SYLLABLE KHIEUKH YEO IEUNG + 0xC4D9: 0xCF38, //HANGUL SYLLABLE KHIEUKH YE + 0xC4DA: 0xCF54, //HANGUL SYLLABLE KHIEUKH O + 0xC4DB: 0xCF55, //HANGUL SYLLABLE KHIEUKH O KIYEOK + 0xC4DC: 0xCF58, //HANGUL SYLLABLE KHIEUKH O NIEUN + 0xC4DD: 0xCF5C, //HANGUL SYLLABLE KHIEUKH O RIEUL + 0xC4DE: 0xCF64, //HANGUL SYLLABLE KHIEUKH O MIEUM + 0xC4DF: 0xCF65, //HANGUL SYLLABLE KHIEUKH O PIEUP + 0xC4E0: 0xCF67, //HANGUL SYLLABLE KHIEUKH O SIOS + 0xC4E1: 0xCF69, //HANGUL SYLLABLE KHIEUKH O IEUNG + 0xC4E2: 0xCF70, //HANGUL SYLLABLE KHIEUKH WA + 0xC4E3: 0xCF71, //HANGUL SYLLABLE KHIEUKH WA KIYEOK + 0xC4E4: 0xCF74, //HANGUL SYLLABLE KHIEUKH WA NIEUN + 0xC4E5: 0xCF78, //HANGUL SYLLABLE KHIEUKH WA RIEUL + 0xC4E6: 0xCF80, //HANGUL SYLLABLE KHIEUKH WA MIEUM + 0xC4E7: 0xCF85, //HANGUL SYLLABLE KHIEUKH WA IEUNG + 0xC4E8: 0xCF8C, //HANGUL SYLLABLE KHIEUKH WAE + 0xC4E9: 0xCFA1, //HANGUL SYLLABLE KHIEUKH WAE IEUNG + 0xC4EA: 0xCFA8, //HANGUL SYLLABLE KHIEUKH OE + 0xC4EB: 0xCFB0, //HANGUL SYLLABLE KHIEUKH OE RIEUL + 0xC4EC: 0xCFC4, //HANGUL SYLLABLE KHIEUKH YO + 0xC4ED: 0xCFE0, //HANGUL SYLLABLE KHIEUKH U + 0xC4EE: 0xCFE1, //HANGUL SYLLABLE KHIEUKH U KIYEOK + 0xC4EF: 0xCFE4, //HANGUL SYLLABLE KHIEUKH U NIEUN + 0xC4F0: 0xCFE8, //HANGUL SYLLABLE KHIEUKH U RIEUL + 0xC4F1: 0xCFF0, //HANGUL SYLLABLE KHIEUKH U MIEUM + 0xC4F2: 0xCFF1, //HANGUL SYLLABLE KHIEUKH U PIEUP + 0xC4F3: 0xCFF3, //HANGUL SYLLABLE KHIEUKH U SIOS + 0xC4F4: 0xCFF5, //HANGUL SYLLABLE KHIEUKH U IEUNG + 0xC4F5: 0xCFFC, //HANGUL SYLLABLE KHIEUKH WEO + 0xC4F6: 0xD000, //HANGUL SYLLABLE KHIEUKH WEO NIEUN + 0xC4F7: 0xD004, //HANGUL SYLLABLE KHIEUKH WEO RIEUL + 0xC4F8: 0xD011, //HANGUL SYLLABLE KHIEUKH WEO IEUNG + 0xC4F9: 0xD018, //HANGUL SYLLABLE KHIEUKH WE + 0xC4FA: 0xD02D, //HANGUL SYLLABLE KHIEUKH WE IEUNG + 0xC4FB: 0xD034, //HANGUL SYLLABLE KHIEUKH WI + 0xC4FC: 0xD035, //HANGUL SYLLABLE KHIEUKH WI KIYEOK + 0xC4FD: 0xD038, //HANGUL SYLLABLE KHIEUKH WI NIEUN + 0xC4FE: 0xD03C, //HANGUL SYLLABLE KHIEUKH WI RIEUL + 0xC541: 0xD715, //HANGUL SYLLABLE HIEUH WE THIEUTH + 0xC542: 0xD716, //HANGUL SYLLABLE HIEUH WE PHIEUPH + 0xC543: 0xD717, //HANGUL SYLLABLE HIEUH WE HIEUH + 0xC544: 0xD71A, //HANGUL SYLLABLE HIEUH WI SSANGKIYEOK + 0xC545: 0xD71B, //HANGUL SYLLABLE HIEUH WI KIYEOKSIOS + 0xC546: 0xD71D, //HANGUL SYLLABLE HIEUH WI NIEUNCIEUC + 0xC547: 0xD71E, //HANGUL SYLLABLE HIEUH WI NIEUNHIEUH + 0xC548: 0xD71F, //HANGUL SYLLABLE HIEUH WI TIKEUT + 0xC549: 0xD721, //HANGUL SYLLABLE HIEUH WI RIEULKIYEOK + 0xC54A: 0xD722, //HANGUL SYLLABLE HIEUH WI RIEULMIEUM + 0xC54B: 0xD723, //HANGUL SYLLABLE HIEUH WI RIEULPIEUP + 0xC54C: 0xD724, //HANGUL SYLLABLE HIEUH WI RIEULSIOS + 0xC54D: 0xD725, //HANGUL SYLLABLE HIEUH WI RIEULTHIEUTH + 0xC54E: 0xD726, //HANGUL SYLLABLE HIEUH WI RIEULPHIEUPH + 0xC54F: 0xD727, //HANGUL SYLLABLE HIEUH WI RIEULHIEUH + 0xC550: 0xD72A, //HANGUL SYLLABLE HIEUH WI PIEUPSIOS + 0xC551: 0xD72C, //HANGUL SYLLABLE HIEUH WI SSANGSIOS + 0xC552: 0xD72E, //HANGUL SYLLABLE HIEUH WI CIEUC + 0xC553: 0xD72F, //HANGUL SYLLABLE HIEUH WI CHIEUCH + 0xC554: 0xD730, //HANGUL SYLLABLE HIEUH WI KHIEUKH + 0xC555: 0xD731, //HANGUL SYLLABLE HIEUH WI THIEUTH + 0xC556: 0xD732, //HANGUL SYLLABLE HIEUH WI PHIEUPH + 0xC557: 0xD733, //HANGUL SYLLABLE HIEUH WI HIEUH + 0xC558: 0xD736, //HANGUL SYLLABLE HIEUH YU SSANGKIYEOK + 0xC559: 0xD737, //HANGUL SYLLABLE HIEUH YU KIYEOKSIOS + 0xC55A: 0xD739, //HANGUL SYLLABLE HIEUH YU NIEUNCIEUC + 0xC561: 0xD73A, //HANGUL SYLLABLE HIEUH YU NIEUNHIEUH + 0xC562: 0xD73B, //HANGUL SYLLABLE HIEUH YU TIKEUT + 0xC563: 0xD73D, //HANGUL SYLLABLE HIEUH YU RIEULKIYEOK + 0xC564: 0xD73E, //HANGUL SYLLABLE HIEUH YU RIEULMIEUM + 0xC565: 0xD73F, //HANGUL SYLLABLE HIEUH YU RIEULPIEUP + 0xC566: 0xD740, //HANGUL SYLLABLE HIEUH YU RIEULSIOS + 0xC567: 0xD741, //HANGUL SYLLABLE HIEUH YU RIEULTHIEUTH + 0xC568: 0xD742, //HANGUL SYLLABLE HIEUH YU RIEULPHIEUPH + 0xC569: 0xD743, //HANGUL SYLLABLE HIEUH YU RIEULHIEUH + 0xC56A: 0xD745, //HANGUL SYLLABLE HIEUH YU PIEUP + 0xC56B: 0xD746, //HANGUL SYLLABLE HIEUH YU PIEUPSIOS + 0xC56C: 0xD748, //HANGUL SYLLABLE HIEUH YU SSANGSIOS + 0xC56D: 0xD74A, //HANGUL SYLLABLE HIEUH YU CIEUC + 0xC56E: 0xD74B, //HANGUL SYLLABLE HIEUH YU CHIEUCH + 0xC56F: 0xD74C, //HANGUL SYLLABLE HIEUH YU KHIEUKH + 0xC570: 0xD74D, //HANGUL SYLLABLE HIEUH YU THIEUTH + 0xC571: 0xD74E, //HANGUL SYLLABLE HIEUH YU PHIEUPH + 0xC572: 0xD74F, //HANGUL SYLLABLE HIEUH YU HIEUH + 0xC573: 0xD752, //HANGUL SYLLABLE HIEUH EU SSANGKIYEOK + 0xC574: 0xD753, //HANGUL SYLLABLE HIEUH EU KIYEOKSIOS + 0xC575: 0xD755, //HANGUL SYLLABLE HIEUH EU NIEUNCIEUC + 0xC576: 0xD75A, //HANGUL SYLLABLE HIEUH EU RIEULMIEUM + 0xC577: 0xD75B, //HANGUL SYLLABLE HIEUH EU RIEULPIEUP + 0xC578: 0xD75C, //HANGUL SYLLABLE HIEUH EU RIEULSIOS + 0xC579: 0xD75D, //HANGUL SYLLABLE HIEUH EU RIEULTHIEUTH + 0xC57A: 0xD75E, //HANGUL SYLLABLE HIEUH EU RIEULPHIEUPH + 0xC581: 0xD75F, //HANGUL SYLLABLE HIEUH EU RIEULHIEUH + 0xC582: 0xD762, //HANGUL SYLLABLE HIEUH EU PIEUPSIOS + 0xC583: 0xD764, //HANGUL SYLLABLE HIEUH EU SSANGSIOS + 0xC584: 0xD766, //HANGUL SYLLABLE HIEUH EU CIEUC + 0xC585: 0xD767, //HANGUL SYLLABLE HIEUH EU CHIEUCH + 0xC586: 0xD768, //HANGUL SYLLABLE HIEUH EU KHIEUKH + 0xC587: 0xD76A, //HANGUL SYLLABLE HIEUH EU PHIEUPH + 0xC588: 0xD76B, //HANGUL SYLLABLE HIEUH EU HIEUH + 0xC589: 0xD76D, //HANGUL SYLLABLE HIEUH YI KIYEOK + 0xC58A: 0xD76E, //HANGUL SYLLABLE HIEUH YI SSANGKIYEOK + 0xC58B: 0xD76F, //HANGUL SYLLABLE HIEUH YI KIYEOKSIOS + 0xC58C: 0xD771, //HANGUL SYLLABLE HIEUH YI NIEUNCIEUC + 0xC58D: 0xD772, //HANGUL SYLLABLE HIEUH YI NIEUNHIEUH + 0xC58E: 0xD773, //HANGUL SYLLABLE HIEUH YI TIKEUT + 0xC58F: 0xD775, //HANGUL SYLLABLE HIEUH YI RIEULKIYEOK + 0xC590: 0xD776, //HANGUL SYLLABLE HIEUH YI RIEULMIEUM + 0xC591: 0xD777, //HANGUL SYLLABLE HIEUH YI RIEULPIEUP + 0xC592: 0xD778, //HANGUL SYLLABLE HIEUH YI RIEULSIOS + 0xC593: 0xD779, //HANGUL SYLLABLE HIEUH YI RIEULTHIEUTH + 0xC594: 0xD77A, //HANGUL SYLLABLE HIEUH YI RIEULPHIEUPH + 0xC595: 0xD77B, //HANGUL SYLLABLE HIEUH YI RIEULHIEUH + 0xC596: 0xD77E, //HANGUL SYLLABLE HIEUH YI PIEUPSIOS + 0xC597: 0xD77F, //HANGUL SYLLABLE HIEUH YI SIOS + 0xC598: 0xD780, //HANGUL SYLLABLE HIEUH YI SSANGSIOS + 0xC599: 0xD782, //HANGUL SYLLABLE HIEUH YI CIEUC + 0xC59A: 0xD783, //HANGUL SYLLABLE HIEUH YI CHIEUCH + 0xC59B: 0xD784, //HANGUL SYLLABLE HIEUH YI KHIEUKH + 0xC59C: 0xD785, //HANGUL SYLLABLE HIEUH YI THIEUTH + 0xC59D: 0xD786, //HANGUL SYLLABLE HIEUH YI PHIEUPH + 0xC59E: 0xD787, //HANGUL SYLLABLE HIEUH YI HIEUH + 0xC59F: 0xD78A, //HANGUL SYLLABLE HIEUH I SSANGKIYEOK + 0xC5A0: 0xD78B, //HANGUL SYLLABLE HIEUH I KIYEOKSIOS + 0xC5A1: 0xD044, //HANGUL SYLLABLE KHIEUKH WI MIEUM + 0xC5A2: 0xD045, //HANGUL SYLLABLE KHIEUKH WI PIEUP + 0xC5A3: 0xD047, //HANGUL SYLLABLE KHIEUKH WI SIOS + 0xC5A4: 0xD049, //HANGUL SYLLABLE KHIEUKH WI IEUNG + 0xC5A5: 0xD050, //HANGUL SYLLABLE KHIEUKH YU + 0xC5A6: 0xD054, //HANGUL SYLLABLE KHIEUKH YU NIEUN + 0xC5A7: 0xD058, //HANGUL SYLLABLE KHIEUKH YU RIEUL + 0xC5A8: 0xD060, //HANGUL SYLLABLE KHIEUKH YU MIEUM + 0xC5A9: 0xD06C, //HANGUL SYLLABLE KHIEUKH EU + 0xC5AA: 0xD06D, //HANGUL SYLLABLE KHIEUKH EU KIYEOK + 0xC5AB: 0xD070, //HANGUL SYLLABLE KHIEUKH EU NIEUN + 0xC5AC: 0xD074, //HANGUL SYLLABLE KHIEUKH EU RIEUL + 0xC5AD: 0xD07C, //HANGUL SYLLABLE KHIEUKH EU MIEUM + 0xC5AE: 0xD07D, //HANGUL SYLLABLE KHIEUKH EU PIEUP + 0xC5AF: 0xD081, //HANGUL SYLLABLE KHIEUKH EU IEUNG + 0xC5B0: 0xD0A4, //HANGUL SYLLABLE KHIEUKH I + 0xC5B1: 0xD0A5, //HANGUL SYLLABLE KHIEUKH I KIYEOK + 0xC5B2: 0xD0A8, //HANGUL SYLLABLE KHIEUKH I NIEUN + 0xC5B3: 0xD0AC, //HANGUL SYLLABLE KHIEUKH I RIEUL + 0xC5B4: 0xD0B4, //HANGUL SYLLABLE KHIEUKH I MIEUM + 0xC5B5: 0xD0B5, //HANGUL SYLLABLE KHIEUKH I PIEUP + 0xC5B6: 0xD0B7, //HANGUL SYLLABLE KHIEUKH I SIOS + 0xC5B7: 0xD0B9, //HANGUL SYLLABLE KHIEUKH I IEUNG + 0xC5B8: 0xD0C0, //HANGUL SYLLABLE THIEUTH A + 0xC5B9: 0xD0C1, //HANGUL SYLLABLE THIEUTH A KIYEOK + 0xC5BA: 0xD0C4, //HANGUL SYLLABLE THIEUTH A NIEUN + 0xC5BB: 0xD0C8, //HANGUL SYLLABLE THIEUTH A RIEUL + 0xC5BC: 0xD0C9, //HANGUL SYLLABLE THIEUTH A RIEULKIYEOK + 0xC5BD: 0xD0D0, //HANGUL SYLLABLE THIEUTH A MIEUM + 0xC5BE: 0xD0D1, //HANGUL SYLLABLE THIEUTH A PIEUP + 0xC5BF: 0xD0D3, //HANGUL SYLLABLE THIEUTH A SIOS + 0xC5C0: 0xD0D4, //HANGUL SYLLABLE THIEUTH A SSANGSIOS + 0xC5C1: 0xD0D5, //HANGUL SYLLABLE THIEUTH A IEUNG + 0xC5C2: 0xD0DC, //HANGUL SYLLABLE THIEUTH AE + 0xC5C3: 0xD0DD, //HANGUL SYLLABLE THIEUTH AE KIYEOK + 0xC5C4: 0xD0E0, //HANGUL SYLLABLE THIEUTH AE NIEUN + 0xC5C5: 0xD0E4, //HANGUL SYLLABLE THIEUTH AE RIEUL + 0xC5C6: 0xD0EC, //HANGUL SYLLABLE THIEUTH AE MIEUM + 0xC5C7: 0xD0ED, //HANGUL SYLLABLE THIEUTH AE PIEUP + 0xC5C8: 0xD0EF, //HANGUL SYLLABLE THIEUTH AE SIOS + 0xC5C9: 0xD0F0, //HANGUL SYLLABLE THIEUTH AE SSANGSIOS + 0xC5CA: 0xD0F1, //HANGUL SYLLABLE THIEUTH AE IEUNG + 0xC5CB: 0xD0F8, //HANGUL SYLLABLE THIEUTH YA + 0xC5CC: 0xD10D, //HANGUL SYLLABLE THIEUTH YA IEUNG + 0xC5CD: 0xD130, //HANGUL SYLLABLE THIEUTH EO + 0xC5CE: 0xD131, //HANGUL SYLLABLE THIEUTH EO KIYEOK + 0xC5CF: 0xD134, //HANGUL SYLLABLE THIEUTH EO NIEUN + 0xC5D0: 0xD138, //HANGUL SYLLABLE THIEUTH EO RIEUL + 0xC5D1: 0xD13A, //HANGUL SYLLABLE THIEUTH EO RIEULMIEUM + 0xC5D2: 0xD140, //HANGUL SYLLABLE THIEUTH EO MIEUM + 0xC5D3: 0xD141, //HANGUL SYLLABLE THIEUTH EO PIEUP + 0xC5D4: 0xD143, //HANGUL SYLLABLE THIEUTH EO SIOS + 0xC5D5: 0xD144, //HANGUL SYLLABLE THIEUTH EO SSANGSIOS + 0xC5D6: 0xD145, //HANGUL SYLLABLE THIEUTH EO IEUNG + 0xC5D7: 0xD14C, //HANGUL SYLLABLE THIEUTH E + 0xC5D8: 0xD14D, //HANGUL SYLLABLE THIEUTH E KIYEOK + 0xC5D9: 0xD150, //HANGUL SYLLABLE THIEUTH E NIEUN + 0xC5DA: 0xD154, //HANGUL SYLLABLE THIEUTH E RIEUL + 0xC5DB: 0xD15C, //HANGUL SYLLABLE THIEUTH E MIEUM + 0xC5DC: 0xD15D, //HANGUL SYLLABLE THIEUTH E PIEUP + 0xC5DD: 0xD15F, //HANGUL SYLLABLE THIEUTH E SIOS + 0xC5DE: 0xD161, //HANGUL SYLLABLE THIEUTH E IEUNG + 0xC5DF: 0xD168, //HANGUL SYLLABLE THIEUTH YEO + 0xC5E0: 0xD16C, //HANGUL SYLLABLE THIEUTH YEO NIEUN + 0xC5E1: 0xD17C, //HANGUL SYLLABLE THIEUTH YEO SSANGSIOS + 0xC5E2: 0xD184, //HANGUL SYLLABLE THIEUTH YE + 0xC5E3: 0xD188, //HANGUL SYLLABLE THIEUTH YE NIEUN + 0xC5E4: 0xD1A0, //HANGUL SYLLABLE THIEUTH O + 0xC5E5: 0xD1A1, //HANGUL SYLLABLE THIEUTH O KIYEOK + 0xC5E6: 0xD1A4, //HANGUL SYLLABLE THIEUTH O NIEUN + 0xC5E7: 0xD1A8, //HANGUL SYLLABLE THIEUTH O RIEUL + 0xC5E8: 0xD1B0, //HANGUL SYLLABLE THIEUTH O MIEUM + 0xC5E9: 0xD1B1, //HANGUL SYLLABLE THIEUTH O PIEUP + 0xC5EA: 0xD1B3, //HANGUL SYLLABLE THIEUTH O SIOS + 0xC5EB: 0xD1B5, //HANGUL SYLLABLE THIEUTH O IEUNG + 0xC5EC: 0xD1BA, //HANGUL SYLLABLE THIEUTH O PHIEUPH + 0xC5ED: 0xD1BC, //HANGUL SYLLABLE THIEUTH WA + 0xC5EE: 0xD1C0, //HANGUL SYLLABLE THIEUTH WA NIEUN + 0xC5EF: 0xD1D8, //HANGUL SYLLABLE THIEUTH WAE + 0xC5F0: 0xD1F4, //HANGUL SYLLABLE THIEUTH OE + 0xC5F1: 0xD1F8, //HANGUL SYLLABLE THIEUTH OE NIEUN + 0xC5F2: 0xD207, //HANGUL SYLLABLE THIEUTH OE SIOS + 0xC5F3: 0xD209, //HANGUL SYLLABLE THIEUTH OE IEUNG + 0xC5F4: 0xD210, //HANGUL SYLLABLE THIEUTH YO + 0xC5F5: 0xD22C, //HANGUL SYLLABLE THIEUTH U + 0xC5F6: 0xD22D, //HANGUL SYLLABLE THIEUTH U KIYEOK + 0xC5F7: 0xD230, //HANGUL SYLLABLE THIEUTH U NIEUN + 0xC5F8: 0xD234, //HANGUL SYLLABLE THIEUTH U RIEUL + 0xC5F9: 0xD23C, //HANGUL SYLLABLE THIEUTH U MIEUM + 0xC5FA: 0xD23D, //HANGUL SYLLABLE THIEUTH U PIEUP + 0xC5FB: 0xD23F, //HANGUL SYLLABLE THIEUTH U SIOS + 0xC5FC: 0xD241, //HANGUL SYLLABLE THIEUTH U IEUNG + 0xC5FD: 0xD248, //HANGUL SYLLABLE THIEUTH WEO + 0xC5FE: 0xD25C, //HANGUL SYLLABLE THIEUTH WEO SSANGSIOS + 0xC641: 0xD78D, //HANGUL SYLLABLE HIEUH I NIEUNCIEUC + 0xC642: 0xD78E, //HANGUL SYLLABLE HIEUH I NIEUNHIEUH + 0xC643: 0xD78F, //HANGUL SYLLABLE HIEUH I TIKEUT + 0xC644: 0xD791, //HANGUL SYLLABLE HIEUH I RIEULKIYEOK + 0xC645: 0xD792, //HANGUL SYLLABLE HIEUH I RIEULMIEUM + 0xC646: 0xD793, //HANGUL SYLLABLE HIEUH I RIEULPIEUP + 0xC647: 0xD794, //HANGUL SYLLABLE HIEUH I RIEULSIOS + 0xC648: 0xD795, //HANGUL SYLLABLE HIEUH I RIEULTHIEUTH + 0xC649: 0xD796, //HANGUL SYLLABLE HIEUH I RIEULPHIEUPH + 0xC64A: 0xD797, //HANGUL SYLLABLE HIEUH I RIEULHIEUH + 0xC64B: 0xD79A, //HANGUL SYLLABLE HIEUH I PIEUPSIOS + 0xC64C: 0xD79C, //HANGUL SYLLABLE HIEUH I SSANGSIOS + 0xC64D: 0xD79E, //HANGUL SYLLABLE HIEUH I CIEUC + 0xC64E: 0xD79F, //HANGUL SYLLABLE HIEUH I CHIEUCH + 0xC64F: 0xD7A0, //HANGUL SYLLABLE HIEUH I KHIEUKH + 0xC650: 0xD7A1, //HANGUL SYLLABLE HIEUH I THIEUTH + 0xC651: 0xD7A2, //HANGUL SYLLABLE HIEUH I PHIEUPH + 0xC652: 0xD7A3, //HANGUL SYLLABLE HIEUH I HIEUH + 0xC6A1: 0xD264, //HANGUL SYLLABLE THIEUTH WE + 0xC6A2: 0xD280, //HANGUL SYLLABLE THIEUTH WI + 0xC6A3: 0xD281, //HANGUL SYLLABLE THIEUTH WI KIYEOK + 0xC6A4: 0xD284, //HANGUL SYLLABLE THIEUTH WI NIEUN + 0xC6A5: 0xD288, //HANGUL SYLLABLE THIEUTH WI RIEUL + 0xC6A6: 0xD290, //HANGUL SYLLABLE THIEUTH WI MIEUM + 0xC6A7: 0xD291, //HANGUL SYLLABLE THIEUTH WI PIEUP + 0xC6A8: 0xD295, //HANGUL SYLLABLE THIEUTH WI IEUNG + 0xC6A9: 0xD29C, //HANGUL SYLLABLE THIEUTH YU + 0xC6AA: 0xD2A0, //HANGUL SYLLABLE THIEUTH YU NIEUN + 0xC6AB: 0xD2A4, //HANGUL SYLLABLE THIEUTH YU RIEUL + 0xC6AC: 0xD2AC, //HANGUL SYLLABLE THIEUTH YU MIEUM + 0xC6AD: 0xD2B1, //HANGUL SYLLABLE THIEUTH YU IEUNG + 0xC6AE: 0xD2B8, //HANGUL SYLLABLE THIEUTH EU + 0xC6AF: 0xD2B9, //HANGUL SYLLABLE THIEUTH EU KIYEOK + 0xC6B0: 0xD2BC, //HANGUL SYLLABLE THIEUTH EU NIEUN + 0xC6B1: 0xD2BF, //HANGUL SYLLABLE THIEUTH EU TIKEUT + 0xC6B2: 0xD2C0, //HANGUL SYLLABLE THIEUTH EU RIEUL + 0xC6B3: 0xD2C2, //HANGUL SYLLABLE THIEUTH EU RIEULMIEUM + 0xC6B4: 0xD2C8, //HANGUL SYLLABLE THIEUTH EU MIEUM + 0xC6B5: 0xD2C9, //HANGUL SYLLABLE THIEUTH EU PIEUP + 0xC6B6: 0xD2CB, //HANGUL SYLLABLE THIEUTH EU SIOS + 0xC6B7: 0xD2D4, //HANGUL SYLLABLE THIEUTH YI + 0xC6B8: 0xD2D8, //HANGUL SYLLABLE THIEUTH YI NIEUN + 0xC6B9: 0xD2DC, //HANGUL SYLLABLE THIEUTH YI RIEUL + 0xC6BA: 0xD2E4, //HANGUL SYLLABLE THIEUTH YI MIEUM + 0xC6BB: 0xD2E5, //HANGUL SYLLABLE THIEUTH YI PIEUP + 0xC6BC: 0xD2F0, //HANGUL SYLLABLE THIEUTH I + 0xC6BD: 0xD2F1, //HANGUL SYLLABLE THIEUTH I KIYEOK + 0xC6BE: 0xD2F4, //HANGUL SYLLABLE THIEUTH I NIEUN + 0xC6BF: 0xD2F8, //HANGUL SYLLABLE THIEUTH I RIEUL + 0xC6C0: 0xD300, //HANGUL SYLLABLE THIEUTH I MIEUM + 0xC6C1: 0xD301, //HANGUL SYLLABLE THIEUTH I PIEUP + 0xC6C2: 0xD303, //HANGUL SYLLABLE THIEUTH I SIOS + 0xC6C3: 0xD305, //HANGUL SYLLABLE THIEUTH I IEUNG + 0xC6C4: 0xD30C, //HANGUL SYLLABLE PHIEUPH A + 0xC6C5: 0xD30D, //HANGUL SYLLABLE PHIEUPH A KIYEOK + 0xC6C6: 0xD30E, //HANGUL SYLLABLE PHIEUPH A SSANGKIYEOK + 0xC6C7: 0xD310, //HANGUL SYLLABLE PHIEUPH A NIEUN + 0xC6C8: 0xD314, //HANGUL SYLLABLE PHIEUPH A RIEUL + 0xC6C9: 0xD316, //HANGUL SYLLABLE PHIEUPH A RIEULMIEUM + 0xC6CA: 0xD31C, //HANGUL SYLLABLE PHIEUPH A MIEUM + 0xC6CB: 0xD31D, //HANGUL SYLLABLE PHIEUPH A PIEUP + 0xC6CC: 0xD31F, //HANGUL SYLLABLE PHIEUPH A SIOS + 0xC6CD: 0xD320, //HANGUL SYLLABLE PHIEUPH A SSANGSIOS + 0xC6CE: 0xD321, //HANGUL SYLLABLE PHIEUPH A IEUNG + 0xC6CF: 0xD325, //HANGUL SYLLABLE PHIEUPH A THIEUTH + 0xC6D0: 0xD328, //HANGUL SYLLABLE PHIEUPH AE + 0xC6D1: 0xD329, //HANGUL SYLLABLE PHIEUPH AE KIYEOK + 0xC6D2: 0xD32C, //HANGUL SYLLABLE PHIEUPH AE NIEUN + 0xC6D3: 0xD330, //HANGUL SYLLABLE PHIEUPH AE RIEUL + 0xC6D4: 0xD338, //HANGUL SYLLABLE PHIEUPH AE MIEUM + 0xC6D5: 0xD339, //HANGUL SYLLABLE PHIEUPH AE PIEUP + 0xC6D6: 0xD33B, //HANGUL SYLLABLE PHIEUPH AE SIOS + 0xC6D7: 0xD33C, //HANGUL SYLLABLE PHIEUPH AE SSANGSIOS + 0xC6D8: 0xD33D, //HANGUL SYLLABLE PHIEUPH AE IEUNG + 0xC6D9: 0xD344, //HANGUL SYLLABLE PHIEUPH YA + 0xC6DA: 0xD345, //HANGUL SYLLABLE PHIEUPH YA KIYEOK + 0xC6DB: 0xD37C, //HANGUL SYLLABLE PHIEUPH EO + 0xC6DC: 0xD37D, //HANGUL SYLLABLE PHIEUPH EO KIYEOK + 0xC6DD: 0xD380, //HANGUL SYLLABLE PHIEUPH EO NIEUN + 0xC6DE: 0xD384, //HANGUL SYLLABLE PHIEUPH EO RIEUL + 0xC6DF: 0xD38C, //HANGUL SYLLABLE PHIEUPH EO MIEUM + 0xC6E0: 0xD38D, //HANGUL SYLLABLE PHIEUPH EO PIEUP + 0xC6E1: 0xD38F, //HANGUL SYLLABLE PHIEUPH EO SIOS + 0xC6E2: 0xD390, //HANGUL SYLLABLE PHIEUPH EO SSANGSIOS + 0xC6E3: 0xD391, //HANGUL SYLLABLE PHIEUPH EO IEUNG + 0xC6E4: 0xD398, //HANGUL SYLLABLE PHIEUPH E + 0xC6E5: 0xD399, //HANGUL SYLLABLE PHIEUPH E KIYEOK + 0xC6E6: 0xD39C, //HANGUL SYLLABLE PHIEUPH E NIEUN + 0xC6E7: 0xD3A0, //HANGUL SYLLABLE PHIEUPH E RIEUL + 0xC6E8: 0xD3A8, //HANGUL SYLLABLE PHIEUPH E MIEUM + 0xC6E9: 0xD3A9, //HANGUL SYLLABLE PHIEUPH E PIEUP + 0xC6EA: 0xD3AB, //HANGUL SYLLABLE PHIEUPH E SIOS + 0xC6EB: 0xD3AD, //HANGUL SYLLABLE PHIEUPH E IEUNG + 0xC6EC: 0xD3B4, //HANGUL SYLLABLE PHIEUPH YEO + 0xC6ED: 0xD3B8, //HANGUL SYLLABLE PHIEUPH YEO NIEUN + 0xC6EE: 0xD3BC, //HANGUL SYLLABLE PHIEUPH YEO RIEUL + 0xC6EF: 0xD3C4, //HANGUL SYLLABLE PHIEUPH YEO MIEUM + 0xC6F0: 0xD3C5, //HANGUL SYLLABLE PHIEUPH YEO PIEUP + 0xC6F1: 0xD3C8, //HANGUL SYLLABLE PHIEUPH YEO SSANGSIOS + 0xC6F2: 0xD3C9, //HANGUL SYLLABLE PHIEUPH YEO IEUNG + 0xC6F3: 0xD3D0, //HANGUL SYLLABLE PHIEUPH YE + 0xC6F4: 0xD3D8, //HANGUL SYLLABLE PHIEUPH YE RIEUL + 0xC6F5: 0xD3E1, //HANGUL SYLLABLE PHIEUPH YE PIEUP + 0xC6F6: 0xD3E3, //HANGUL SYLLABLE PHIEUPH YE SIOS + 0xC6F7: 0xD3EC, //HANGUL SYLLABLE PHIEUPH O + 0xC6F8: 0xD3ED, //HANGUL SYLLABLE PHIEUPH O KIYEOK + 0xC6F9: 0xD3F0, //HANGUL SYLLABLE PHIEUPH O NIEUN + 0xC6FA: 0xD3F4, //HANGUL SYLLABLE PHIEUPH O RIEUL + 0xC6FB: 0xD3FC, //HANGUL SYLLABLE PHIEUPH O MIEUM + 0xC6FC: 0xD3FD, //HANGUL SYLLABLE PHIEUPH O PIEUP + 0xC6FD: 0xD3FF, //HANGUL SYLLABLE PHIEUPH O SIOS + 0xC6FE: 0xD401, //HANGUL SYLLABLE PHIEUPH O IEUNG + 0xC7A1: 0xD408, //HANGUL SYLLABLE PHIEUPH WA + 0xC7A2: 0xD41D, //HANGUL SYLLABLE PHIEUPH WA IEUNG + 0xC7A3: 0xD440, //HANGUL SYLLABLE PHIEUPH OE + 0xC7A4: 0xD444, //HANGUL SYLLABLE PHIEUPH OE NIEUN + 0xC7A5: 0xD45C, //HANGUL SYLLABLE PHIEUPH YO + 0xC7A6: 0xD460, //HANGUL SYLLABLE PHIEUPH YO NIEUN + 0xC7A7: 0xD464, //HANGUL SYLLABLE PHIEUPH YO RIEUL + 0xC7A8: 0xD46D, //HANGUL SYLLABLE PHIEUPH YO PIEUP + 0xC7A9: 0xD46F, //HANGUL SYLLABLE PHIEUPH YO SIOS + 0xC7AA: 0xD478, //HANGUL SYLLABLE PHIEUPH U + 0xC7AB: 0xD479, //HANGUL SYLLABLE PHIEUPH U KIYEOK + 0xC7AC: 0xD47C, //HANGUL SYLLABLE PHIEUPH U NIEUN + 0xC7AD: 0xD47F, //HANGUL SYLLABLE PHIEUPH U TIKEUT + 0xC7AE: 0xD480, //HANGUL SYLLABLE PHIEUPH U RIEUL + 0xC7AF: 0xD482, //HANGUL SYLLABLE PHIEUPH U RIEULMIEUM + 0xC7B0: 0xD488, //HANGUL SYLLABLE PHIEUPH U MIEUM + 0xC7B1: 0xD489, //HANGUL SYLLABLE PHIEUPH U PIEUP + 0xC7B2: 0xD48B, //HANGUL SYLLABLE PHIEUPH U SIOS + 0xC7B3: 0xD48D, //HANGUL SYLLABLE PHIEUPH U IEUNG + 0xC7B4: 0xD494, //HANGUL SYLLABLE PHIEUPH WEO + 0xC7B5: 0xD4A9, //HANGUL SYLLABLE PHIEUPH WEO IEUNG + 0xC7B6: 0xD4CC, //HANGUL SYLLABLE PHIEUPH WI + 0xC7B7: 0xD4D0, //HANGUL SYLLABLE PHIEUPH WI NIEUN + 0xC7B8: 0xD4D4, //HANGUL SYLLABLE PHIEUPH WI RIEUL + 0xC7B9: 0xD4DC, //HANGUL SYLLABLE PHIEUPH WI MIEUM + 0xC7BA: 0xD4DF, //HANGUL SYLLABLE PHIEUPH WI SIOS + 0xC7BB: 0xD4E8, //HANGUL SYLLABLE PHIEUPH YU + 0xC7BC: 0xD4EC, //HANGUL SYLLABLE PHIEUPH YU NIEUN + 0xC7BD: 0xD4F0, //HANGUL SYLLABLE PHIEUPH YU RIEUL + 0xC7BE: 0xD4F8, //HANGUL SYLLABLE PHIEUPH YU MIEUM + 0xC7BF: 0xD4FB, //HANGUL SYLLABLE PHIEUPH YU SIOS + 0xC7C0: 0xD4FD, //HANGUL SYLLABLE PHIEUPH YU IEUNG + 0xC7C1: 0xD504, //HANGUL SYLLABLE PHIEUPH EU + 0xC7C2: 0xD508, //HANGUL SYLLABLE PHIEUPH EU NIEUN + 0xC7C3: 0xD50C, //HANGUL SYLLABLE PHIEUPH EU RIEUL + 0xC7C4: 0xD514, //HANGUL SYLLABLE PHIEUPH EU MIEUM + 0xC7C5: 0xD515, //HANGUL SYLLABLE PHIEUPH EU PIEUP + 0xC7C6: 0xD517, //HANGUL SYLLABLE PHIEUPH EU SIOS + 0xC7C7: 0xD53C, //HANGUL SYLLABLE PHIEUPH I + 0xC7C8: 0xD53D, //HANGUL SYLLABLE PHIEUPH I KIYEOK + 0xC7C9: 0xD540, //HANGUL SYLLABLE PHIEUPH I NIEUN + 0xC7CA: 0xD544, //HANGUL SYLLABLE PHIEUPH I RIEUL + 0xC7CB: 0xD54C, //HANGUL SYLLABLE PHIEUPH I MIEUM + 0xC7CC: 0xD54D, //HANGUL SYLLABLE PHIEUPH I PIEUP + 0xC7CD: 0xD54F, //HANGUL SYLLABLE PHIEUPH I SIOS + 0xC7CE: 0xD551, //HANGUL SYLLABLE PHIEUPH I IEUNG + 0xC7CF: 0xD558, //HANGUL SYLLABLE HIEUH A + 0xC7D0: 0xD559, //HANGUL SYLLABLE HIEUH A KIYEOK + 0xC7D1: 0xD55C, //HANGUL SYLLABLE HIEUH A NIEUN + 0xC7D2: 0xD560, //HANGUL SYLLABLE HIEUH A RIEUL + 0xC7D3: 0xD565, //HANGUL SYLLABLE HIEUH A RIEULTHIEUTH + 0xC7D4: 0xD568, //HANGUL SYLLABLE HIEUH A MIEUM + 0xC7D5: 0xD569, //HANGUL SYLLABLE HIEUH A PIEUP + 0xC7D6: 0xD56B, //HANGUL SYLLABLE HIEUH A SIOS + 0xC7D7: 0xD56D, //HANGUL SYLLABLE HIEUH A IEUNG + 0xC7D8: 0xD574, //HANGUL SYLLABLE HIEUH AE + 0xC7D9: 0xD575, //HANGUL SYLLABLE HIEUH AE KIYEOK + 0xC7DA: 0xD578, //HANGUL SYLLABLE HIEUH AE NIEUN + 0xC7DB: 0xD57C, //HANGUL SYLLABLE HIEUH AE RIEUL + 0xC7DC: 0xD584, //HANGUL SYLLABLE HIEUH AE MIEUM + 0xC7DD: 0xD585, //HANGUL SYLLABLE HIEUH AE PIEUP + 0xC7DE: 0xD587, //HANGUL SYLLABLE HIEUH AE SIOS + 0xC7DF: 0xD588, //HANGUL SYLLABLE HIEUH AE SSANGSIOS + 0xC7E0: 0xD589, //HANGUL SYLLABLE HIEUH AE IEUNG + 0xC7E1: 0xD590, //HANGUL SYLLABLE HIEUH YA + 0xC7E2: 0xD5A5, //HANGUL SYLLABLE HIEUH YA IEUNG + 0xC7E3: 0xD5C8, //HANGUL SYLLABLE HIEUH EO + 0xC7E4: 0xD5C9, //HANGUL SYLLABLE HIEUH EO KIYEOK + 0xC7E5: 0xD5CC, //HANGUL SYLLABLE HIEUH EO NIEUN + 0xC7E6: 0xD5D0, //HANGUL SYLLABLE HIEUH EO RIEUL + 0xC7E7: 0xD5D2, //HANGUL SYLLABLE HIEUH EO RIEULMIEUM + 0xC7E8: 0xD5D8, //HANGUL SYLLABLE HIEUH EO MIEUM + 0xC7E9: 0xD5D9, //HANGUL SYLLABLE HIEUH EO PIEUP + 0xC7EA: 0xD5DB, //HANGUL SYLLABLE HIEUH EO SIOS + 0xC7EB: 0xD5DD, //HANGUL SYLLABLE HIEUH EO IEUNG + 0xC7EC: 0xD5E4, //HANGUL SYLLABLE HIEUH E + 0xC7ED: 0xD5E5, //HANGUL SYLLABLE HIEUH E KIYEOK + 0xC7EE: 0xD5E8, //HANGUL SYLLABLE HIEUH E NIEUN + 0xC7EF: 0xD5EC, //HANGUL SYLLABLE HIEUH E RIEUL + 0xC7F0: 0xD5F4, //HANGUL SYLLABLE HIEUH E MIEUM + 0xC7F1: 0xD5F5, //HANGUL SYLLABLE HIEUH E PIEUP + 0xC7F2: 0xD5F7, //HANGUL SYLLABLE HIEUH E SIOS + 0xC7F3: 0xD5F9, //HANGUL SYLLABLE HIEUH E IEUNG + 0xC7F4: 0xD600, //HANGUL SYLLABLE HIEUH YEO + 0xC7F5: 0xD601, //HANGUL SYLLABLE HIEUH YEO KIYEOK + 0xC7F6: 0xD604, //HANGUL SYLLABLE HIEUH YEO NIEUN + 0xC7F7: 0xD608, //HANGUL SYLLABLE HIEUH YEO RIEUL + 0xC7F8: 0xD610, //HANGUL SYLLABLE HIEUH YEO MIEUM + 0xC7F9: 0xD611, //HANGUL SYLLABLE HIEUH YEO PIEUP + 0xC7FA: 0xD613, //HANGUL SYLLABLE HIEUH YEO SIOS + 0xC7FB: 0xD614, //HANGUL SYLLABLE HIEUH YEO SSANGSIOS + 0xC7FC: 0xD615, //HANGUL SYLLABLE HIEUH YEO IEUNG + 0xC7FD: 0xD61C, //HANGUL SYLLABLE HIEUH YE + 0xC7FE: 0xD620, //HANGUL SYLLABLE HIEUH YE NIEUN + 0xC8A1: 0xD624, //HANGUL SYLLABLE HIEUH YE RIEUL + 0xC8A2: 0xD62D, //HANGUL SYLLABLE HIEUH YE PIEUP + 0xC8A3: 0xD638, //HANGUL SYLLABLE HIEUH O + 0xC8A4: 0xD639, //HANGUL SYLLABLE HIEUH O KIYEOK + 0xC8A5: 0xD63C, //HANGUL SYLLABLE HIEUH O NIEUN + 0xC8A6: 0xD640, //HANGUL SYLLABLE HIEUH O RIEUL + 0xC8A7: 0xD645, //HANGUL SYLLABLE HIEUH O RIEULTHIEUTH + 0xC8A8: 0xD648, //HANGUL SYLLABLE HIEUH O MIEUM + 0xC8A9: 0xD649, //HANGUL SYLLABLE HIEUH O PIEUP + 0xC8AA: 0xD64B, //HANGUL SYLLABLE HIEUH O SIOS + 0xC8AB: 0xD64D, //HANGUL SYLLABLE HIEUH O IEUNG + 0xC8AC: 0xD651, //HANGUL SYLLABLE HIEUH O THIEUTH + 0xC8AD: 0xD654, //HANGUL SYLLABLE HIEUH WA + 0xC8AE: 0xD655, //HANGUL SYLLABLE HIEUH WA KIYEOK + 0xC8AF: 0xD658, //HANGUL SYLLABLE HIEUH WA NIEUN + 0xC8B0: 0xD65C, //HANGUL SYLLABLE HIEUH WA RIEUL + 0xC8B1: 0xD667, //HANGUL SYLLABLE HIEUH WA SIOS + 0xC8B2: 0xD669, //HANGUL SYLLABLE HIEUH WA IEUNG + 0xC8B3: 0xD670, //HANGUL SYLLABLE HIEUH WAE + 0xC8B4: 0xD671, //HANGUL SYLLABLE HIEUH WAE KIYEOK + 0xC8B5: 0xD674, //HANGUL SYLLABLE HIEUH WAE NIEUN + 0xC8B6: 0xD683, //HANGUL SYLLABLE HIEUH WAE SIOS + 0xC8B7: 0xD685, //HANGUL SYLLABLE HIEUH WAE IEUNG + 0xC8B8: 0xD68C, //HANGUL SYLLABLE HIEUH OE + 0xC8B9: 0xD68D, //HANGUL SYLLABLE HIEUH OE KIYEOK + 0xC8BA: 0xD690, //HANGUL SYLLABLE HIEUH OE NIEUN + 0xC8BB: 0xD694, //HANGUL SYLLABLE HIEUH OE RIEUL + 0xC8BC: 0xD69D, //HANGUL SYLLABLE HIEUH OE PIEUP + 0xC8BD: 0xD69F, //HANGUL SYLLABLE HIEUH OE SIOS + 0xC8BE: 0xD6A1, //HANGUL SYLLABLE HIEUH OE IEUNG + 0xC8BF: 0xD6A8, //HANGUL SYLLABLE HIEUH YO + 0xC8C0: 0xD6AC, //HANGUL SYLLABLE HIEUH YO NIEUN + 0xC8C1: 0xD6B0, //HANGUL SYLLABLE HIEUH YO RIEUL + 0xC8C2: 0xD6B9, //HANGUL SYLLABLE HIEUH YO PIEUP + 0xC8C3: 0xD6BB, //HANGUL SYLLABLE HIEUH YO SIOS + 0xC8C4: 0xD6C4, //HANGUL SYLLABLE HIEUH U + 0xC8C5: 0xD6C5, //HANGUL SYLLABLE HIEUH U KIYEOK + 0xC8C6: 0xD6C8, //HANGUL SYLLABLE HIEUH U NIEUN + 0xC8C7: 0xD6CC, //HANGUL SYLLABLE HIEUH U RIEUL + 0xC8C8: 0xD6D1, //HANGUL SYLLABLE HIEUH U RIEULTHIEUTH + 0xC8C9: 0xD6D4, //HANGUL SYLLABLE HIEUH U MIEUM + 0xC8CA: 0xD6D7, //HANGUL SYLLABLE HIEUH U SIOS + 0xC8CB: 0xD6D9, //HANGUL SYLLABLE HIEUH U IEUNG + 0xC8CC: 0xD6E0, //HANGUL SYLLABLE HIEUH WEO + 0xC8CD: 0xD6E4, //HANGUL SYLLABLE HIEUH WEO NIEUN + 0xC8CE: 0xD6E8, //HANGUL SYLLABLE HIEUH WEO RIEUL + 0xC8CF: 0xD6F0, //HANGUL SYLLABLE HIEUH WEO MIEUM + 0xC8D0: 0xD6F5, //HANGUL SYLLABLE HIEUH WEO IEUNG + 0xC8D1: 0xD6FC, //HANGUL SYLLABLE HIEUH WE + 0xC8D2: 0xD6FD, //HANGUL SYLLABLE HIEUH WE KIYEOK + 0xC8D3: 0xD700, //HANGUL SYLLABLE HIEUH WE NIEUN + 0xC8D4: 0xD704, //HANGUL SYLLABLE HIEUH WE RIEUL + 0xC8D5: 0xD711, //HANGUL SYLLABLE HIEUH WE IEUNG + 0xC8D6: 0xD718, //HANGUL SYLLABLE HIEUH WI + 0xC8D7: 0xD719, //HANGUL SYLLABLE HIEUH WI KIYEOK + 0xC8D8: 0xD71C, //HANGUL SYLLABLE HIEUH WI NIEUN + 0xC8D9: 0xD720, //HANGUL SYLLABLE HIEUH WI RIEUL + 0xC8DA: 0xD728, //HANGUL SYLLABLE HIEUH WI MIEUM + 0xC8DB: 0xD729, //HANGUL SYLLABLE HIEUH WI PIEUP + 0xC8DC: 0xD72B, //HANGUL SYLLABLE HIEUH WI SIOS + 0xC8DD: 0xD72D, //HANGUL SYLLABLE HIEUH WI IEUNG + 0xC8DE: 0xD734, //HANGUL SYLLABLE HIEUH YU + 0xC8DF: 0xD735, //HANGUL SYLLABLE HIEUH YU KIYEOK + 0xC8E0: 0xD738, //HANGUL SYLLABLE HIEUH YU NIEUN + 0xC8E1: 0xD73C, //HANGUL SYLLABLE HIEUH YU RIEUL + 0xC8E2: 0xD744, //HANGUL SYLLABLE HIEUH YU MIEUM + 0xC8E3: 0xD747, //HANGUL SYLLABLE HIEUH YU SIOS + 0xC8E4: 0xD749, //HANGUL SYLLABLE HIEUH YU IEUNG + 0xC8E5: 0xD750, //HANGUL SYLLABLE HIEUH EU + 0xC8E6: 0xD751, //HANGUL SYLLABLE HIEUH EU KIYEOK + 0xC8E7: 0xD754, //HANGUL SYLLABLE HIEUH EU NIEUN + 0xC8E8: 0xD756, //HANGUL SYLLABLE HIEUH EU NIEUNHIEUH + 0xC8E9: 0xD757, //HANGUL SYLLABLE HIEUH EU TIKEUT + 0xC8EA: 0xD758, //HANGUL SYLLABLE HIEUH EU RIEUL + 0xC8EB: 0xD759, //HANGUL SYLLABLE HIEUH EU RIEULKIYEOK + 0xC8EC: 0xD760, //HANGUL SYLLABLE HIEUH EU MIEUM + 0xC8ED: 0xD761, //HANGUL SYLLABLE HIEUH EU PIEUP + 0xC8EE: 0xD763, //HANGUL SYLLABLE HIEUH EU SIOS + 0xC8EF: 0xD765, //HANGUL SYLLABLE HIEUH EU IEUNG + 0xC8F0: 0xD769, //HANGUL SYLLABLE HIEUH EU THIEUTH + 0xC8F1: 0xD76C, //HANGUL SYLLABLE HIEUH YI + 0xC8F2: 0xD770, //HANGUL SYLLABLE HIEUH YI NIEUN + 0xC8F3: 0xD774, //HANGUL SYLLABLE HIEUH YI RIEUL + 0xC8F4: 0xD77C, //HANGUL SYLLABLE HIEUH YI MIEUM + 0xC8F5: 0xD77D, //HANGUL SYLLABLE HIEUH YI PIEUP + 0xC8F6: 0xD781, //HANGUL SYLLABLE HIEUH YI IEUNG + 0xC8F7: 0xD788, //HANGUL SYLLABLE HIEUH I + 0xC8F8: 0xD789, //HANGUL SYLLABLE HIEUH I KIYEOK + 0xC8F9: 0xD78C, //HANGUL SYLLABLE HIEUH I NIEUN + 0xC8FA: 0xD790, //HANGUL SYLLABLE HIEUH I RIEUL + 0xC8FB: 0xD798, //HANGUL SYLLABLE HIEUH I MIEUM + 0xC8FC: 0xD799, //HANGUL SYLLABLE HIEUH I PIEUP + 0xC8FD: 0xD79B, //HANGUL SYLLABLE HIEUH I SIOS + 0xC8FE: 0xD79D, //HANGUL SYLLABLE HIEUH I IEUNG + 0xCAA1: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x5374, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x6164, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x73CF, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x811A, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x687F, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x764E, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x78F5, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x4E6B, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x525B, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x5808, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x5F3A, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x757A, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x500B, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x584F, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x613E, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x69EA, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0xF900, //CJK COMPATIBILITY IDEOGRAPH + 0xCBD1: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0xF901, //CJK COMPATIBILITY IDEOGRAPH + 0xCBD7: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0xF902, //CJK COMPATIBILITY IDEOGRAPH + 0xCBE8: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x5091, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x5109, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x528D, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5292, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x8FF2, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x5805, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x5770, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x6176, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x5553, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x583A, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x6537, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x7690, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x82FD, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0xF903, //CJK COMPATIBILITY IDEOGRAPH + 0xCDD0: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0xF904, //CJK COMPATIBILITY IDEOGRAPH + 0xCDE9: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0xF905, //CJK COMPATIBILITY IDEOGRAPH + 0xCEAE: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x6163, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x709A, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x639B, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x584A, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x652A, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x5340, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x5614, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x5775, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x8009, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x570B, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x6372, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x6DC3, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0xF906, //CJK COMPATIBILITY IDEOGRAPH + 0xCFFC: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0xF907, //CJK COMPATIBILITY IDEOGRAPH + 0xD0A3: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0xF908, //CJK COMPATIBILITY IDEOGRAPH + 0xD0B9: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x524B, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x5287, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x6975, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x52A4, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0xF909, //CJK COMPATIBILITY IDEOGRAPH + 0xD0D1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x6611, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0xF90A, //CJK COMPATIBILITY IDEOGRAPH + 0xD0DE: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x6271, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x65E3, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x671E, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x7398, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x7482, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x802D, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x513A, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0xF90B, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D5: 0xF90C, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D6: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0xF90D, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D9: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0xF90E, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DC: 0xF90F, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DD: 0xF910, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DE: 0xF911, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DF: 0xF912, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E0: 0xF913, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E1: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0xF914, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E3: 0xF915, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E4: 0xF916, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E5: 0xF917, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E6: 0xF918, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E7: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0xF919, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E9: 0xF91A, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EA: 0xF91B, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EB: 0xF91C, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EC: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0xF91D, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EE: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0xF91E, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F0: 0xF91F, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F1: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0xF920, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F3: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0xF921, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F7: 0x678F, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0xF922, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FB: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0xF923, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FD: 0xF924, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FE: 0xF925, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A1: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0xF926, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A3: 0xF927, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0xF928, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A8: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A9: 0xF92A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AA: 0xF92B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AB: 0xF92C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AC: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0xF92D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AE: 0x5167, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0xF92E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2B3: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x649A, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x79CA, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x5BD7, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0xF92F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2BF: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0xF930, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C3: 0xF931, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C4: 0xF932, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C5: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0xF933, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C7: 0xF934, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C8: 0xF935, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C9: 0xF936, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CA: 0xF937, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CB: 0xF938, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CC: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0xF939, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CE: 0xF93A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CF: 0xF93B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D0: 0xF93C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D1: 0xF93D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D2: 0xF93E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D3: 0xF93F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D4: 0xF940, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D5: 0xF941, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D6: 0xF942, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D7: 0xF943, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D8: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0xF944, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DA: 0xF945, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DB: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0xF946, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DF: 0xF947, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E0: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0xF948, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E2: 0xF949, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E3: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0xF94A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E5: 0xF94B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E6: 0xF94C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E7: 0xF94D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E8: 0xF94E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E9: 0xF94F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EA: 0xF950, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EB: 0xF951, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EC: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x677B, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0xF952, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F1: 0xF953, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F2: 0xF954, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F3: 0xF955, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F4: 0xF956, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F5: 0xF957, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F6: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0xF958, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F8: 0xF959, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F9: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x5718, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x6FBE, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x7553, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x6207, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x5788, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x576E, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x5716, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x5857, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x6417, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x7006, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x711E, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x4E6D, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x6771, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x6793, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0xF95A, //CJK COMPATIBILITY IDEOGRAPH + 0xD4E7: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0xF95B, //CJK COMPATIBILITY IDEOGRAPH + 0xD4FD: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0xF95C, //CJK COMPATIBILITY IDEOGRAPH + 0xD5A6: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0xF95D, //CJK COMPATIBILITY IDEOGRAPH + 0xD5AC: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0xF95E, //CJK COMPATIBILITY IDEOGRAPH + 0xD5AF: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x64E5, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x652C, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x5006, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x5169, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x5137, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x5442, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x616E, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6190, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x6200, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6523, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x7149, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x6582, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0xF95F, //CJK COMPATIBILITY IDEOGRAPH + 0xD6B9: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0xF960, //CJK COMPATIBILITY IDEOGRAPH + 0xD6CE: 0x6488, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x6727, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x7027, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x5289, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x7460, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x502B, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x6144, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0xF961, //CJK COMPATIBILITY IDEOGRAPH + 0xD7CC: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x550E, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0xF962, //CJK COMPATIBILITY IDEOGRAPH + 0xD7E5: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xD7FA: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xD7FB: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xD7FC: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xD7FD: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xD7FE: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x534D, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x6669, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x551C, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x6927, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x5922, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x732B, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x7AD7, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x6959, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x7121, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x73F7, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x5011, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x554F, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x525D, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x9262, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x5023, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0xF963, //CJK COMPATIBILITY IDEOGRAPH + 0xDBC6: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x6822, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x7169, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0xF964, //CJK COMPATIBILITY IDEOGRAPH + 0xDBE5: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0xF965, //CJK COMPATIBILITY IDEOGRAPH + 0xDCA6: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x5225, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x5002, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x5C5B, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x5E77, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x663A, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x68C5, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x8F27, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x9A08, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x5831, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x6E7A, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x73E4, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x4E76, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x71A2, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0xF966, //CJK COMPATIBILITY IDEOGRAPH + 0xDDA6: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x5674, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x596E, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x6610, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0xF967, //CJK COMPATIBILITY IDEOGRAPH + 0xDDD6: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x5099, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x618A, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0xF968, //CJK COMPATIBILITY IDEOGRAPH + 0xDDF5: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xDDFD: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x7015, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x6191, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x6368, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0xF969, //CJK COMPATIBILITY IDEOGRAPH + 0xDEFD: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0xF96A, //CJK COMPATIBILITY IDEOGRAPH + 0xDFA1: 0x5098, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x522A, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x7523, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x4E77, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0xF96B, //CJK COMPATIBILITY IDEOGRAPH + 0xDFB4: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x6E17, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x63F7, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x511F, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x5617, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x5C19, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0xF96C, //CJK COMPATIBILITY IDEOGRAPH + 0xDFE2: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0xF96D, //CJK COMPATIBILITY IDEOGRAPH + 0xDFE9: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x637F, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x654D, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x596D, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x657E, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x9425, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x994D, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x5368, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x651D, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0xF96E, //CJK COMPATIBILITY IDEOGRAPH + 0xE0F2: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x73F9, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0xF96F, //CJK COMPATIBILITY IDEOGRAPH + 0xE1AE: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x562F, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x6383, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x758E, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x9061, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x640D, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x98E1, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0xF970, //CJK COMPATIBILITY IDEOGRAPH + 0xE1EE: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x5CC0, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x6578, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x74B9, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x6812, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x696F, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x6A53, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x6607, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x5AA4, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x6642, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x67BE, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x7BD2, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x613C, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0xF971, //CJK COMPATIBILITY IDEOGRAPH + 0xE3F6: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0xF972, //CJK COMPATIBILITY IDEOGRAPH + 0xE4A2: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0xF973, //CJK COMPATIBILITY IDEOGRAPH + 0xE4AA: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x5152, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x555E, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x580A, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x9854, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x5535, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x611B, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x788D, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x503B, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0xF974, //CJK COMPATIBILITY IDEOGRAPH + 0xE5AF: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0xF975, //CJK COMPATIBILITY IDEOGRAPH + 0xE5B2: 0xF976, //CJK COMPATIBILITY IDEOGRAPH + 0xE5B3: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0xF977, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BA: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0xF978, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BC: 0xF979, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BD: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x656D, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x6698, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0xF97A, //CJK COMPATIBILITY IDEOGRAPH + 0xE5C5: 0x694A, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0xF97B, //CJK COMPATIBILITY IDEOGRAPH + 0xE5CF: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0xF97C, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D1: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0xF97D, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D3: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0xF97E, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D7: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x5104, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x5B7C, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x8616, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x513C, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x696D, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x5186, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0xF97F, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FB: 0xF980, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FC: 0xF981, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FD: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0xF982, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A1: 0xF983, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A2: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0xF984, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A5: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x7916, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0xF985, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A8: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0xF986, //CJK COMPATIBILITY IDEOGRAPH + 0xE6AE: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0xF987, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B0: 0xF988, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B1: 0xF989, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B2: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0xF98A, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B4: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0xF98B, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B8: 0xF98C, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B9: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0xF98D, //CJK COMPATIBILITY IDEOGRAPH + 0xE6BD: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x5827, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x59F8, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0xF98E, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C5: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0xF98F, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C7: 0xF990, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C8: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x633B, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0xF991, //CJK COMPATIBILITY IDEOGRAPH + 0xE6CB: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0xF992, //CJK COMPATIBILITY IDEOGRAPH + 0xE6D3: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x7159, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0xF993, //CJK COMPATIBILITY IDEOGRAPH + 0xE6D7: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0xF994, //CJK COMPATIBILITY IDEOGRAPH + 0xE6DA: 0x784F, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0xF995, //CJK COMPATIBILITY IDEOGRAPH + 0xE6DD: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0xF996, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E0: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0xF997, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E2: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0xF998, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E5: 0xF999, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E6: 0xF99A, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E7: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0xF99B, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E9: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0xF99C, //CJK COMPATIBILITY IDEOGRAPH + 0xE6EB: 0xF99D, //CJK COMPATIBILITY IDEOGRAPH + 0xE6EC: 0xF99E, //CJK COMPATIBILITY IDEOGRAPH + 0xE6ED: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0xF99F, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F0: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0xF9A0, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F2: 0xF9A1, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F3: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0xF9A2, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F6: 0xF9A3, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F7: 0xF9A4, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F8: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0xF9A5, //CJK COMPATIBILITY IDEOGRAPH + 0xE6FA: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x8276, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0xF9A6, //CJK COMPATIBILITY IDEOGRAPH + 0xE7A2: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x9AE5, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0xF9A7, //CJK COMPATIBILITY IDEOGRAPH + 0xE7A7: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0xF9A8, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AA: 0xF9A9, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AB: 0x584B, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0xF9AA, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AD: 0xF9AB, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AE: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0xF9AC, //CJK COMPATIBILITY IDEOGRAPH + 0xE7B1: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x668E, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x6FDA, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x702F, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x7150, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0xF9AD, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C0: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0xF9AE, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C2: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0xF9AF, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C7: 0xF9B0, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C8: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0xF9B1, //CJK COMPATIBILITY IDEOGRAPH + 0xE7CC: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0xF9B2, //CJK COMPATIBILITY IDEOGRAPH + 0xE7CE: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0xF9B3, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D0: 0xF9B4, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D1: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0xF9B5, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D4: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0xF9B6, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E0: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0xF9B7, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E5: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0xF9B8, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E7: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x5433, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x5862, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x5967, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0xF9B9, //CJK COMPATIBILITY IDEOGRAPH + 0xE7F8: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x65FF, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x7B7D, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x7465, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x6900, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x7413, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0xF9BA, //CJK COMPATIBILITY IDEOGRAPH + 0xE8E8: 0xF9BB, //CJK COMPATIBILITY IDEOGRAPH + 0xE8E9: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0xF9BC, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F1: 0xF9BD, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F2: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x6416, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x6493, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0xF9BE, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F8: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0xF9BF, //CJK COMPATIBILITY IDEOGRAPH + 0xE8FA: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0xF9C0, //CJK COMPATIBILITY IDEOGRAPH + 0xE8FC: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0xF9C1, //CJK COMPATIBILITY IDEOGRAPH + 0xE9A1: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0xF9C2, //CJK COMPATIBILITY IDEOGRAPH + 0xE9A8: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0xF9C3, //CJK COMPATIBILITY IDEOGRAPH + 0xE9AD: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x617E, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x6142, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0xF9C4, //CJK COMPATIBILITY IDEOGRAPH + 0xE9CD: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x512A, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6182, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x7991, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x682F, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x7A36, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0xF9C5, //CJK COMPATIBILITY IDEOGRAPH + 0xE9F8: 0x6A52, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x7189, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x4E90, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x5713, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x5712, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0xF9C6, //CJK COMPATIBILITY IDEOGRAPH + 0xEAC2: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x5049, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x570D, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x6690, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x853F, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x516A, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0xF9C7, //CJK COMPATIBILITY IDEOGRAPH + 0xEAE6: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0xF9C8, //CJK COMPATIBILITY IDEOGRAPH + 0xEAF5: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0xF9C9, //CJK COMPATIBILITY IDEOGRAPH + 0xEAF8: 0x6961, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x6962, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0xF9CA, //CJK COMPATIBILITY IDEOGRAPH + 0xEAFD: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0xF9CB, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA1: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0xF9CC, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA5: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0xF9CD, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA8: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0xF9CE, //CJK COMPATIBILITY IDEOGRAPH + 0xEBAA: 0xF9CF, //CJK COMPATIBILITY IDEOGRAPH + 0xEBAB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0xF9D0, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBB: 0xF9D1, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBC: 0x5809, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0xF9D2, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBE: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0xF9D3, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC2: 0xF9D4, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC3: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x596B, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0xF9D5, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC7: 0xF9D6, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC8: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x73A7, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0xF9D7, //CJK COMPATIBILITY IDEOGRAPH + 0xEBCD: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0xF9D8, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD0: 0xF9D9, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD1: 0xF9DA, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD2: 0xF9DB, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD3: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x701C, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD9: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x6147, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x5100, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0xF9DD, //CJK COMPATIBILITY IDEOGRAPH + 0xECA7: 0xF9DE, //CJK COMPATIBILITY IDEOGRAPH + 0xECA8: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0xF9DF, //CJK COMPATIBILITY IDEOGRAPH + 0xECAB: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x5F5B, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0xF9E0, //CJK COMPATIBILITY IDEOGRAPH + 0xECB0: 0xF9E1, //CJK COMPATIBILITY IDEOGRAPH + 0xECB1: 0xF9E2, //CJK COMPATIBILITY IDEOGRAPH + 0xECB2: 0xF9E3, //CJK COMPATIBILITY IDEOGRAPH + 0xECB3: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0xF9E4, //CJK COMPATIBILITY IDEOGRAPH + 0xECB6: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0xF9E5, //CJK COMPATIBILITY IDEOGRAPH + 0xECB9: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0xF9E6, //CJK COMPATIBILITY IDEOGRAPH + 0xECBB: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0xF9E7, //CJK COMPATIBILITY IDEOGRAPH + 0xECC1: 0xF9E8, //CJK COMPATIBILITY IDEOGRAPH + 0xECC2: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0xF9E9, //CJK COMPATIBILITY IDEOGRAPH + 0xECC6: 0xF9EA, //CJK COMPATIBILITY IDEOGRAPH + 0xECC7: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0xF9EB, //CJK COMPATIBILITY IDEOGRAPH + 0xECCA: 0xF9EC, //CJK COMPATIBILITY IDEOGRAPH + 0xECCB: 0x7037, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0xF9ED, //CJK COMPATIBILITY IDEOGRAPH + 0xECD6: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0xF9EE, //CJK COMPATIBILITY IDEOGRAPH + 0xECDE: 0xF9EF, //CJK COMPATIBILITY IDEOGRAPH + 0xECDF: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0xF9F0, //CJK COMPATIBILITY IDEOGRAPH + 0xECE2: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0xF9F1, //CJK COMPATIBILITY IDEOGRAPH + 0xECE5: 0x976D, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0xF9F2, //CJK COMPATIBILITY IDEOGRAPH + 0xECE8: 0xF9F3, //CJK COMPATIBILITY IDEOGRAPH + 0xECE9: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0xF9F4, //CJK COMPATIBILITY IDEOGRAPH + 0xECF8: 0xF9F5, //CJK COMPATIBILITY IDEOGRAPH + 0xECF9: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0xF9F6, //CJK COMPATIBILITY IDEOGRAPH + 0xECFB: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x5344, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0xF9F7, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA2: 0xF9F8, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA3: 0xF9F9, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x82BF, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x5834, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x596C, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x6B0C, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0xF9FA, //CJK COMPATIBILITY IDEOGRAPH + 0xEDEF: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x707D, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x5132, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x732A, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x6575, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0xF9FB, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDC: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x5861, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x587C, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x6230, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x7551, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x985A, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x5075, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x6678, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x701E, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x8AEA, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x5291, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x689D, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x5027, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x616B, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x546A, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x665D, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x5101, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x710C, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x8846, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x537D, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x646F, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0xF9FC, //CJK COMPATIBILITY IDEOGRAPH + 0xF2BE: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x5875, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x6422, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x6649, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x664B, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x686D, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x7468, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x74C6, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0xF9FD, //CJK COMPATIBILITY IDEOGRAPH + 0xF2FB: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0xF9FE, //CJK COMPATIBILITY IDEOGRAPH + 0xF3B2: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x643E, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x7740, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x5239, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x5879, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x6158, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x6159, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x5009, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x5275, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x6134, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x518A, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0xF9FF, //CJK COMPATIBILITY IDEOGRAPH + 0xF4A8: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x617D, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x751B, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0xFA00, //CJK COMPATIBILITY IDEOGRAPH + 0xF4EF: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x585A, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x60A4, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x6181, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x589C, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x7443, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x672E, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x5074, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x5024, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x6065, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x6894, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x5247, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x6736, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x6955, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0xFA01, //CJK COMPATIBILITY IDEOGRAPH + 0xF6F5: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0xFA02, //CJK COMPATIBILITY IDEOGRAPH + 0xF6F7: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x666B, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x7438, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x5451, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x5606, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x619A, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x7058, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x596A, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0xFA03, //CJK COMPATIBILITY IDEOGRAPH + 0xF7B9: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x514C, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x614B, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0xFA04, //CJK COMPATIBILITY IDEOGRAPH + 0xF7C9: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x6491, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x6504, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x514E, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x615F, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0xFA05, //CJK COMPATIBILITY IDEOGRAPH + 0xF7D4: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x5078, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x5742, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xF8A1: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xF8A2: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xF8A3: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xF8A4: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xF8A5: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xF8A6: 0x5504, //CJK UNIFIED IDEOGRAPH + 0xF8A7: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xF8A8: 0x6557, //CJK UNIFIED IDEOGRAPH + 0xF8A9: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xF8AA: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0xF8AB: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xF8AC: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xF8AD: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xF8AE: 0x8987, //CJK UNIFIED IDEOGRAPH + 0xF8AF: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xF8B0: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xF8B1: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xF8B2: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xF8B3: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xF8B4: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xF8B5: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xF8B6: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xF8B7: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xF8B8: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xF8B9: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xF8BA: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xF8BB: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xF8BC: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xF8BD: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xF8BE: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xF8BF: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xF8C0: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xF8C1: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xF8C2: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xF8C3: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xF8C4: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xF8C5: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xF8C6: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xF8C7: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0xF8C8: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0xF8C9: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xF8CA: 0x6583, //CJK UNIFIED IDEOGRAPH + 0xF8CB: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xF8CC: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xF8CD: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xF8CE: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xF8CF: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0xF8D0: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xF8D1: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xF8D2: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xF8D3: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xF8D4: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xF8D5: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xF8D6: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xF8D7: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xF8D8: 0x629B, //CJK UNIFIED IDEOGRAPH + 0xF8D9: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xF8DA: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xF8DB: 0xFA06, //CJK COMPATIBILITY IDEOGRAPH + 0xF8DC: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xF8DD: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xF8DE: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xF8DF: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xF8E0: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xF8E1: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xF8E2: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xF8E3: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xF8E4: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xF8E5: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xF8E6: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xF8E7: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xF8E8: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xF8E9: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xF8EA: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xF8EB: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xF8EC: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xF8ED: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xF8EE: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xF8EF: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xF8F0: 0xFA07, //CJK COMPATIBILITY IDEOGRAPH + 0xF8F1: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0xF8F2: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xF8F3: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xF8F4: 0x6153, //CJK UNIFIED IDEOGRAPH + 0xF8F5: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xF8F6: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0xF8F7: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xF8F8: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xF8F9: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xF8FA: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xF8FB: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xF8FC: 0x98C7, //CJK UNIFIED IDEOGRAPH + 0xF8FD: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xF8FE: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xF9A1: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xF9A2: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xF9A3: 0x6953, //CJK UNIFIED IDEOGRAPH + 0xF9A4: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xF9A5: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xF9A6: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xF9A7: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xF9A8: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xF9A9: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xF9AA: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xF9AB: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xF9AC: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xF9AD: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xF9AE: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xF9AF: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xF9B0: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xF9B1: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xF9B2: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xF9B3: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xF9B4: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xF9B5: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xF9B6: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xF9B7: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xF9B8: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xF9B9: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xF9BA: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xF9BB: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xF9BC: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xF9BD: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0xF9BE: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xF9BF: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0xF9C0: 0x6630, //CJK UNIFIED IDEOGRAPH + 0xF9C1: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xF9C2: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xF9C3: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xF9C4: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xF9C5: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xF9C6: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xF9C7: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xF9C8: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xF9C9: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xF9CA: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0xF9CB: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xF9CC: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xF9CD: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xF9CE: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xF9CF: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xF9D0: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xF9D1: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xF9D2: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xF9D3: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0xF9D4: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xF9D5: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xF9D6: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xF9D7: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xF9D8: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xF9D9: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xF9DA: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xF9DB: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xF9DC: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xF9DD: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xF9DE: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xF9DF: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xF9E0: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xF9E1: 0x5563, //CJK UNIFIED IDEOGRAPH + 0xF9E2: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xF9E3: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0xF9E4: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xF9E5: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xF9E6: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xF9E7: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xF9E8: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xF9E9: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xF9EA: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xF9EB: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xF9EC: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xF9ED: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xF9EE: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xF9EF: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xF9F0: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xF9F1: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xF9F2: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xF9F3: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0xF9F4: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xF9F5: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xF9F6: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xF9F7: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xF9F8: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xF9F9: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xF9FA: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xF9FB: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xF9FC: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xF9FD: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xF9FE: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xFAA1: 0xFA08, //CJK COMPATIBILITY IDEOGRAPH + 0xFAA2: 0xFA09, //CJK COMPATIBILITY IDEOGRAPH + 0xFAA3: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xFAA4: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xFAA5: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xFAA6: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xFAA7: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xFAA8: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xFAA9: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xFAAA: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xFAAB: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xFAAC: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xFAAD: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xFAAE: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xFAAF: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xFAB0: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xFAB1: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xFAB2: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xFAB3: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xFAB4: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xFAB5: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xFAB6: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xFAB7: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xFAB8: 0x5016, //CJK UNIFIED IDEOGRAPH + 0xFAB9: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xFABA: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xFABB: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xFABC: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xFABD: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xFABE: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xFABF: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0xFAC0: 0x73E6, //CJK UNIFIED IDEOGRAPH + 0xFAC1: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xFAC2: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xFAC3: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xFAC4: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xFAC5: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xFAC6: 0x5653, //CJK UNIFIED IDEOGRAPH + 0xFAC7: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xFAC8: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xFAC9: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xFACA: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0xFACB: 0x6AF6, //CJK UNIFIED IDEOGRAPH + 0xFACC: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xFACD: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xFACE: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xFACF: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xFAD0: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xFAD1: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xFAD2: 0x7200, //CJK UNIFIED IDEOGRAPH + 0xFAD3: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xFAD4: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xFAD5: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0xFAD6: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0xFAD7: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xFAD8: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0xFAD9: 0x665B, //CJK UNIFIED IDEOGRAPH + 0xFADA: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xFADB: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xFADC: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xFADD: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xFADE: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xFADF: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xFAE0: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xFAE1: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xFAE2: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xFAE3: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xFAE4: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xFAE5: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xFAE6: 0xFA0A, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE7: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xFAE8: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xFAE9: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xFAEA: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xFAEB: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xFAEC: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xFAED: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xFAEE: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xFAEF: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0xFAF0: 0x5354, //CJK UNIFIED IDEOGRAPH + 0xFAF1: 0x593E, //CJK UNIFIED IDEOGRAPH + 0xFAF2: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0xFAF3: 0x633E, //CJK UNIFIED IDEOGRAPH + 0xFAF4: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0xFAF5: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xFAF6: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xFAF7: 0x8107, //CJK UNIFIED IDEOGRAPH + 0xFAF8: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xFAF9: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xFAFA: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xFAFB: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xFAFC: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xFAFD: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xFAFE: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xFBA1: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xFBA2: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0xFBA3: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0xFBA4: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xFBA5: 0x7050, //CJK UNIFIED IDEOGRAPH + 0xFBA6: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xFBA7: 0x7192, //CJK UNIFIED IDEOGRAPH + 0xFBA8: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xFBA9: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xFBAA: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xFBAB: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xFBAC: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xFBAD: 0x9008, //CJK UNIFIED IDEOGRAPH + 0xFBAE: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xFBAF: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xFBB0: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xFBB1: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xFBB2: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xFBB3: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xFBB4: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xFBB5: 0x66B3, //CJK UNIFIED IDEOGRAPH + 0xFBB6: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xFBB7: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xFBB8: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xFBB9: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xFBBA: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xFBBB: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xFBBC: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xFBBD: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xFBBE: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0xFBBF: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xFBC0: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xFBC1: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xFBC2: 0x6236, //CJK UNIFIED IDEOGRAPH + 0xFBC3: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xFBC4: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xFBC5: 0x6667, //CJK UNIFIED IDEOGRAPH + 0xFBC6: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xFBC7: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xFBC8: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xFBC9: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xFBCA: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0xFBCB: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0xFBCC: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xFBCD: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0xFBCE: 0x705D, //CJK UNIFIED IDEOGRAPH + 0xFBCF: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xFBD0: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xFBD1: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xFBD2: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xFBD3: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xFBD4: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xFBD5: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xFBD6: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xFBD7: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xFBD8: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0xFBD9: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xFBDA: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xFBDB: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xFBDC: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xFBDD: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xFBDE: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xFBDF: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xFBE0: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xFBE1: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xFBE2: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xFBE3: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xFBE4: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xFBE5: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xFBE6: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xFBE7: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xFBE8: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xFBE9: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0xFBEA: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xFBEB: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xFBEC: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xFBED: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xFBEE: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xFBEF: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xFBF0: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xFBF1: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xFBF2: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xFBF3: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xFBF4: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xFBF5: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xFBF6: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xFBF7: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xFBF8: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xFBF9: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xFBFA: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xFBFB: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0xFBFC: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0xFBFD: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xFBFE: 0x7575, //CJK UNIFIED IDEOGRAPH + 0xFCA1: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xFCA2: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xFCA3: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xFCA4: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xFCA5: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xFCA6: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xFCA7: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xFCA8: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xFCA9: 0xFA0B, //CJK COMPATIBILITY IDEOGRAPH + 0xFCAA: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0xFCAB: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xFCAC: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xFCAD: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xFCAE: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xFCAF: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xFCB0: 0x559A, //CJK UNIFIED IDEOGRAPH + 0xFCB1: 0x5950, //CJK UNIFIED IDEOGRAPH + 0xFCB2: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xFCB3: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xFCB4: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xFCB5: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0xFCB6: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0xFCB7: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xFCB8: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xFCB9: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0xFCBA: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xFCBB: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xFCBC: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xFCBD: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xFCBE: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xFCBF: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xFCC0: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xFCC1: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xFCC2: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xFCC3: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xFCC4: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xFCC5: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xFCC6: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xFCC7: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xFCC8: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xFCC9: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xFCCA: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xFCCB: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xFCCC: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xFCCD: 0x6644, //CJK UNIFIED IDEOGRAPH + 0xFCCE: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0xFCCF: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0xFCD0: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xFCD1: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0xFCD2: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xFCD3: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xFCD4: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xFCD5: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xFCD6: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xFCD7: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xFCD8: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xFCD9: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xFCDA: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xFCDB: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xFCDC: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xFCDD: 0x532F, //CJK UNIFIED IDEOGRAPH + 0xFCDE: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xFCDF: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0xFCE0: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xFCE1: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xFCE2: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xFCE3: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0xFCE4: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xFCE5: 0x6703, //CJK UNIFIED IDEOGRAPH + 0xFCE6: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0xFCE7: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xFCE8: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0xFCE9: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xFCEA: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xFCEB: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xFCEC: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xFCED: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xFCEE: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xFCEF: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xFCF0: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xFCF1: 0x5283, //CJK UNIFIED IDEOGRAPH + 0xFCF2: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xFCF3: 0x5B96, //CJK UNIFIED IDEOGRAPH + 0xFCF4: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xFCF5: 0x9404, //CJK UNIFIED IDEOGRAPH + 0xFCF6: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xFCF7: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xFCF8: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xFCF9: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xFCFA: 0x6585, //CJK UNIFIED IDEOGRAPH + 0xFCFB: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0xFCFC: 0x689F, //CJK UNIFIED IDEOGRAPH + 0xFCFD: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0xFCFE: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xFDA1: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xFDA2: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xFDA3: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xFDA4: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xFDA5: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xFDA6: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xFDA7: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xFDA8: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xFDA9: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xFDAA: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xFDAB: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xFDAC: 0x5E3F, //CJK UNIFIED IDEOGRAPH + 0xFDAD: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xFDAE: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xFDAF: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xFDB0: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xFDB1: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xFDB2: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xFDB3: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0xFDB4: 0x5864, //CJK UNIFIED IDEOGRAPH + 0xFDB5: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0xFDB6: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xFDB7: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xFDB8: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xFDB9: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xFDBA: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xFDBB: 0x6688, //CJK UNIFIED IDEOGRAPH + 0xFDBC: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xFDBD: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xFDBE: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xFDBF: 0x714A, //CJK UNIFIED IDEOGRAPH + 0xFDC0: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xFDC1: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xFDC2: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xFDC3: 0x6BC1, //CJK UNIFIED IDEOGRAPH + 0xFDC4: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0xFDC5: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xFDC6: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0xFDC7: 0x6689, //CJK UNIFIED IDEOGRAPH + 0xFDC8: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xFDC9: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xFDCA: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xFDCB: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xFDCC: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xFDCD: 0x643A, //CJK UNIFIED IDEOGRAPH + 0xFDCE: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xFDCF: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xFDD0: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xFDD1: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xFDD2: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xFDD3: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xFDD4: 0x5147, //CJK UNIFIED IDEOGRAPH + 0xFDD5: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xFDD6: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xFDD7: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0xFDD8: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xFDD9: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xFDDA: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xFDDB: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xFDDC: 0x7098, //CJK UNIFIED IDEOGRAPH + 0xFDDD: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xFDDE: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xFDDF: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xFDE0: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xFDE1: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xFDE2: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xFDE3: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0xFDE4: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xFDE5: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xFDE6: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xFDE7: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xFDE8: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xFDE9: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xFDEA: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xFDEB: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0xFDEC: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xFDED: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xFDEE: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0xFDEF: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xFDF0: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xFDF1: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xFDF2: 0x6199, //CJK UNIFIED IDEOGRAPH + 0xFDF3: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xFDF4: 0x6231, //CJK UNIFIED IDEOGRAPH + 0xFDF5: 0x665E, //CJK UNIFIED IDEOGRAPH + 0xFDF6: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xFDF7: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xFDF8: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xFDF9: 0x71BA, //CJK UNIFIED IDEOGRAPH + 0xFDFA: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xFDFB: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xFDFC: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xFDFD: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xFDFE: 0x8A70, //CJK UNIFIED IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go new file mode 100644 index 0000000..1301cd0 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go @@ -0,0 +1,13767 @@ +package cp + +var cp950 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0xA140: 0x3000, //IDEOGRAPHIC SPACE + 0xA141: 0xFF0C, //FULLWIDTH COMMA + 0xA142: 0x3001, //IDEOGRAPHIC COMMA + 0xA143: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA144: 0xFF0E, //FULLWIDTH FULL STOP + 0xA145: 0x2027, //HYPHENATION POINT + 0xA146: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA147: 0xFF1A, //FULLWIDTH COLON + 0xA148: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA149: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA14A: 0xFE30, //PRESENTATION FORM FOR VERTICAL TWO DOT LEADER + 0xA14B: 0x2026, //HORIZONTAL ELLIPSIS + 0xA14C: 0x2025, //TWO DOT LEADER + 0xA14D: 0xFE50, //SMALL COMMA + 0xA14E: 0xFE51, //SMALL IDEOGRAPHIC COMMA + 0xA14F: 0xFE52, //SMALL FULL STOP + 0xA150: 0x00B7, //MIDDLE DOT + 0xA151: 0xFE54, //SMALL SEMICOLON + 0xA152: 0xFE55, //SMALL COLON + 0xA153: 0xFE56, //SMALL QUESTION MARK + 0xA154: 0xFE57, //SMALL EXCLAMATION MARK + 0xA155: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA156: 0x2013, //EN DASH + 0xA157: 0xFE31, //PRESENTATION FORM FOR VERTICAL EM DASH + 0xA158: 0x2014, //EM DASH + 0xA159: 0xFE33, //PRESENTATION FORM FOR VERTICAL LOW LINE + 0xA15A: 0x2574, //BOX DRAWINGS LIGHT LEFT + 0xA15B: 0xFE34, //PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + 0xA15C: 0xFE4F, //WAVY LOW LINE + 0xA15D: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA15E: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA15F: 0xFE35, //PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS + 0xA160: 0xFE36, //PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS + 0xA161: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA162: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA163: 0xFE37, //PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET + 0xA164: 0xFE38, //PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET + 0xA165: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA166: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA167: 0xFE39, //PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET + 0xA168: 0xFE3A, //PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET + 0xA169: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA16A: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA16B: 0xFE3B, //PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET + 0xA16C: 0xFE3C, //PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET + 0xA16D: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA16E: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA16F: 0xFE3D, //PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET + 0xA170: 0xFE3E, //PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET + 0xA171: 0x3008, //LEFT ANGLE BRACKET + 0xA172: 0x3009, //RIGHT ANGLE BRACKET + 0xA173: 0xFE3F, //PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET + 0xA174: 0xFE40, //PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET + 0xA175: 0x300C, //LEFT CORNER BRACKET + 0xA176: 0x300D, //RIGHT CORNER BRACKET + 0xA177: 0xFE41, //PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET + 0xA178: 0xFE42, //PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET + 0xA179: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA17A: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA17B: 0xFE43, //PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET + 0xA17C: 0xFE44, //PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET + 0xA17D: 0xFE59, //SMALL LEFT PARENTHESIS + 0xA17E: 0xFE5A, //SMALL RIGHT PARENTHESIS + 0xA1A1: 0xFE5B, //SMALL LEFT CURLY BRACKET + 0xA1A2: 0xFE5C, //SMALL RIGHT CURLY BRACKET + 0xA1A3: 0xFE5D, //SMALL LEFT TORTOISE SHELL BRACKET + 0xA1A4: 0xFE5E, //SMALL RIGHT TORTOISE SHELL BRACKET + 0xA1A5: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1A6: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1A7: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1A8: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1A9: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0xA1AA: 0x301E, //DOUBLE PRIME QUOTATION MARK + 0xA1AB: 0x2035, //REVERSED PRIME + 0xA1AC: 0x2032, //PRIME + 0xA1AD: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA1AE: 0xFF06, //FULLWIDTH AMPERSAND + 0xA1AF: 0xFF0A, //FULLWIDTH ASTERISK + 0xA1B0: 0x203B, //REFERENCE MARK + 0xA1B1: 0x00A7, //SECTION SIGN + 0xA1B2: 0x3003, //DITTO MARK + 0xA1B3: 0x25CB, //WHITE CIRCLE + 0xA1B4: 0x25CF, //BLACK CIRCLE + 0xA1B5: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1B6: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1B7: 0x25CE, //BULLSEYE + 0xA1B8: 0x2606, //WHITE STAR + 0xA1B9: 0x2605, //BLACK STAR + 0xA1BA: 0x25C7, //WHITE DIAMOND + 0xA1BB: 0x25C6, //BLACK DIAMOND + 0xA1BC: 0x25A1, //WHITE SQUARE + 0xA1BD: 0x25A0, //BLACK SQUARE + 0xA1BE: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA1BF: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA1C0: 0x32A3, //CIRCLED IDEOGRAPH CORRECT + 0xA1C1: 0x2105, //CARE OF + 0xA1C2: 0x00AF, //MACRON + 0xA1C3: 0xFFE3, //FULLWIDTH MACRON + 0xA1C4: 0xFF3F, //FULLWIDTH LOW LINE + 0xA1C5: 0x02CD, //MODIFIER LETTER LOW MACRON + 0xA1C6: 0xFE49, //DASHED OVERLINE + 0xA1C7: 0xFE4A, //CENTRELINE OVERLINE + 0xA1C8: 0xFE4D, //DASHED LOW LINE + 0xA1C9: 0xFE4E, //CENTRELINE LOW LINE + 0xA1CA: 0xFE4B, //WAVY OVERLINE + 0xA1CB: 0xFE4C, //DOUBLE WAVY OVERLINE + 0xA1CC: 0xFE5F, //SMALL NUMBER SIGN + 0xA1CD: 0xFE60, //SMALL AMPERSAND + 0xA1CE: 0xFE61, //SMALL ASTERISK + 0xA1CF: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA1D0: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA1D1: 0x00D7, //MULTIPLICATION SIGN + 0xA1D2: 0x00F7, //DIVISION SIGN + 0xA1D3: 0x00B1, //PLUS-MINUS SIGN + 0xA1D4: 0x221A, //SQUARE ROOT + 0xA1D5: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA1D6: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA1D7: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA1D8: 0x2266, //LESS-THAN OVER EQUAL TO + 0xA1D9: 0x2267, //GREATER-THAN OVER EQUAL TO + 0xA1DA: 0x2260, //NOT EQUAL TO + 0xA1DB: 0x221E, //INFINITY + 0xA1DC: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA1DD: 0x2261, //IDENTICAL TO + 0xA1DE: 0xFE62, //SMALL PLUS SIGN + 0xA1DF: 0xFE63, //SMALL HYPHEN-MINUS + 0xA1E0: 0xFE64, //SMALL LESS-THAN SIGN + 0xA1E1: 0xFE65, //SMALL GREATER-THAN SIGN + 0xA1E2: 0xFE66, //SMALL EQUALS SIGN + 0xA1E3: 0xFF5E, //FULLWIDTH TILDE + 0xA1E4: 0x2229, //INTERSECTION + 0xA1E5: 0x222A, //UNION + 0xA1E6: 0x22A5, //UP TACK + 0xA1E7: 0x2220, //ANGLE + 0xA1E8: 0x221F, //RIGHT ANGLE + 0xA1E9: 0x22BF, //RIGHT TRIANGLE + 0xA1EA: 0x33D2, //SQUARE LOG + 0xA1EB: 0x33D1, //SQUARE LN + 0xA1EC: 0x222B, //INTEGRAL + 0xA1ED: 0x222E, //CONTOUR INTEGRAL + 0xA1EE: 0x2235, //BECAUSE + 0xA1EF: 0x2234, //THEREFORE + 0xA1F0: 0x2640, //FEMALE SIGN + 0xA1F1: 0x2642, //MALE SIGN + 0xA1F2: 0x2295, //CIRCLED PLUS + 0xA1F3: 0x2299, //CIRCLED DOT OPERATOR + 0xA1F4: 0x2191, //UPWARDS ARROW + 0xA1F5: 0x2193, //DOWNWARDS ARROW + 0xA1F6: 0x2190, //LEFTWARDS ARROW + 0xA1F7: 0x2192, //RIGHTWARDS ARROW + 0xA1F8: 0x2196, //NORTH WEST ARROW + 0xA1F9: 0x2197, //NORTH EAST ARROW + 0xA1FA: 0x2199, //SOUTH WEST ARROW + 0xA1FB: 0x2198, //SOUTH EAST ARROW + 0xA1FC: 0x2225, //PARALLEL TO + 0xA1FD: 0x2223, //DIVIDES + 0xA1FE: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA240: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA241: 0x2215, //DIVISION SLASH + 0xA242: 0xFE68, //SMALL REVERSE SOLIDUS + 0xA243: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA244: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA245: 0x3012, //POSTAL MARK + 0xA246: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA247: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA248: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA249: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA24A: 0x2103, //DEGREE CELSIUS + 0xA24B: 0x2109, //DEGREE FAHRENHEIT + 0xA24C: 0xFE69, //SMALL DOLLAR SIGN + 0xA24D: 0xFE6A, //SMALL PERCENT SIGN + 0xA24E: 0xFE6B, //SMALL COMMERCIAL AT + 0xA24F: 0x33D5, //SQUARE MIL + 0xA250: 0x339C, //SQUARE MM + 0xA251: 0x339D, //SQUARE CM + 0xA252: 0x339E, //SQUARE KM + 0xA253: 0x33CE, //SQUARE KM CAPITAL + 0xA254: 0x33A1, //SQUARE M SQUARED + 0xA255: 0x338E, //SQUARE MG + 0xA256: 0x338F, //SQUARE KG + 0xA257: 0x33C4, //SQUARE CC + 0xA258: 0x00B0, //DEGREE SIGN + 0xA259: 0x5159, //CJK UNIFIED IDEOGRAPH + 0xA25A: 0x515B, //CJK UNIFIED IDEOGRAPH + 0xA25B: 0x515E, //CJK UNIFIED IDEOGRAPH + 0xA25C: 0x515D, //CJK UNIFIED IDEOGRAPH + 0xA25D: 0x5161, //CJK UNIFIED IDEOGRAPH + 0xA25E: 0x5163, //CJK UNIFIED IDEOGRAPH + 0xA25F: 0x55E7, //CJK UNIFIED IDEOGRAPH + 0xA260: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xA261: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0xA262: 0x2581, //LOWER ONE EIGHTH BLOCK + 0xA263: 0x2582, //LOWER ONE QUARTER BLOCK + 0xA264: 0x2583, //LOWER THREE EIGHTHS BLOCK + 0xA265: 0x2584, //LOWER HALF BLOCK + 0xA266: 0x2585, //LOWER FIVE EIGHTHS BLOCK + 0xA267: 0x2586, //LOWER THREE QUARTERS BLOCK + 0xA268: 0x2587, //LOWER SEVEN EIGHTHS BLOCK + 0xA269: 0x2588, //FULL BLOCK + 0xA26A: 0x258F, //LEFT ONE EIGHTH BLOCK + 0xA26B: 0x258E, //LEFT ONE QUARTER BLOCK + 0xA26C: 0x258D, //LEFT THREE EIGHTHS BLOCK + 0xA26D: 0x258C, //LEFT HALF BLOCK + 0xA26E: 0x258B, //LEFT FIVE EIGHTHS BLOCK + 0xA26F: 0x258A, //LEFT THREE QUARTERS BLOCK + 0xA270: 0x2589, //LEFT SEVEN EIGHTHS BLOCK + 0xA271: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA272: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA273: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA274: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA275: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA276: 0x2594, //UPPER ONE EIGHTH BLOCK + 0xA277: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA278: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA279: 0x2595, //RIGHT ONE EIGHTH BLOCK + 0xA27A: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA27B: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA27C: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA27D: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA27E: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xA2A1: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xA2A2: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xA2A3: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xA2A4: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xA2A5: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xA2A6: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xA2A7: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xA2A8: 0x25E2, //BLACK LOWER RIGHT TRIANGLE + 0xA2A9: 0x25E3, //BLACK LOWER LEFT TRIANGLE + 0xA2AA: 0x25E5, //BLACK UPPER RIGHT TRIANGLE + 0xA2AB: 0x25E4, //BLACK UPPER LEFT TRIANGLE + 0xA2AC: 0x2571, //BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + 0xA2AD: 0x2572, //BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + 0xA2AE: 0x2573, //BOX DRAWINGS LIGHT DIAGONAL CROSS + 0xA2AF: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA2B0: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA2B1: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA2B2: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA2B3: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA2B4: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA2B5: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA2B6: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA2B7: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA2B8: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA2B9: 0x2160, //ROMAN NUMERAL ONE + 0xA2BA: 0x2161, //ROMAN NUMERAL TWO + 0xA2BB: 0x2162, //ROMAN NUMERAL THREE + 0xA2BC: 0x2163, //ROMAN NUMERAL FOUR + 0xA2BD: 0x2164, //ROMAN NUMERAL FIVE + 0xA2BE: 0x2165, //ROMAN NUMERAL SIX + 0xA2BF: 0x2166, //ROMAN NUMERAL SEVEN + 0xA2C0: 0x2167, //ROMAN NUMERAL EIGHT + 0xA2C1: 0x2168, //ROMAN NUMERAL NINE + 0xA2C2: 0x2169, //ROMAN NUMERAL TEN + 0xA2C3: 0x3021, //HANGZHOU NUMERAL ONE + 0xA2C4: 0x3022, //HANGZHOU NUMERAL TWO + 0xA2C5: 0x3023, //HANGZHOU NUMERAL THREE + 0xA2C6: 0x3024, //HANGZHOU NUMERAL FOUR + 0xA2C7: 0x3025, //HANGZHOU NUMERAL FIVE + 0xA2C8: 0x3026, //HANGZHOU NUMERAL SIX + 0xA2C9: 0x3027, //HANGZHOU NUMERAL SEVEN + 0xA2CA: 0x3028, //HANGZHOU NUMERAL EIGHT + 0xA2CB: 0x3029, //HANGZHOU NUMERAL NINE + 0xA2CC: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xA2CD: 0x5344, //CJK UNIFIED IDEOGRAPH + 0xA2CE: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xA2CF: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA2D0: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA2D1: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA2D2: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA2D3: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA2D4: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA2D5: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA2D6: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA2D7: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA2D8: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA2D9: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA2DA: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA2DB: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA2DC: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA2DD: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA2DE: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA2DF: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA2E0: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA2E1: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA2E2: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA2E3: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA2E4: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA2E5: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA2E6: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA2E7: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA2E8: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA2E9: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA2EA: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA2EB: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA2EC: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA2ED: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA2EE: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA2EF: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA2F0: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA2F1: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA2F2: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA2F3: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA2F4: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA2F5: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA2F6: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA2F7: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA2F8: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA2F9: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA2FA: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA2FB: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA2FC: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA2FD: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA2FE: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA340: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA341: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA342: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA343: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA344: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA345: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA346: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA347: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA348: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA349: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA34A: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA34B: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA34C: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA34D: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA34E: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA34F: 0x039C, //GREEK CAPITAL LETTER MU + 0xA350: 0x039D, //GREEK CAPITAL LETTER NU + 0xA351: 0x039E, //GREEK CAPITAL LETTER XI + 0xA352: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA353: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA354: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA355: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA356: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA357: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA358: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA359: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA35A: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA35B: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA35C: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA35D: 0x03B2, //GREEK SMALL LETTER BETA + 0xA35E: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA35F: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA360: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA361: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA362: 0x03B7, //GREEK SMALL LETTER ETA + 0xA363: 0x03B8, //GREEK SMALL LETTER THETA + 0xA364: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA365: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA366: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA367: 0x03BC, //GREEK SMALL LETTER MU + 0xA368: 0x03BD, //GREEK SMALL LETTER NU + 0xA369: 0x03BE, //GREEK SMALL LETTER XI + 0xA36A: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA36B: 0x03C0, //GREEK SMALL LETTER PI + 0xA36C: 0x03C1, //GREEK SMALL LETTER RHO + 0xA36D: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA36E: 0x03C4, //GREEK SMALL LETTER TAU + 0xA36F: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA370: 0x03C6, //GREEK SMALL LETTER PHI + 0xA371: 0x03C7, //GREEK SMALL LETTER CHI + 0xA372: 0x03C8, //GREEK SMALL LETTER PSI + 0xA373: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA374: 0x3105, //BOPOMOFO LETTER B + 0xA375: 0x3106, //BOPOMOFO LETTER P + 0xA376: 0x3107, //BOPOMOFO LETTER M + 0xA377: 0x3108, //BOPOMOFO LETTER F + 0xA378: 0x3109, //BOPOMOFO LETTER D + 0xA379: 0x310A, //BOPOMOFO LETTER T + 0xA37A: 0x310B, //BOPOMOFO LETTER N + 0xA37B: 0x310C, //BOPOMOFO LETTER L + 0xA37C: 0x310D, //BOPOMOFO LETTER G + 0xA37D: 0x310E, //BOPOMOFO LETTER K + 0xA37E: 0x310F, //BOPOMOFO LETTER H + 0xA3A1: 0x3110, //BOPOMOFO LETTER J + 0xA3A2: 0x3111, //BOPOMOFO LETTER Q + 0xA3A3: 0x3112, //BOPOMOFO LETTER X + 0xA3A4: 0x3113, //BOPOMOFO LETTER ZH + 0xA3A5: 0x3114, //BOPOMOFO LETTER CH + 0xA3A6: 0x3115, //BOPOMOFO LETTER SH + 0xA3A7: 0x3116, //BOPOMOFO LETTER R + 0xA3A8: 0x3117, //BOPOMOFO LETTER Z + 0xA3A9: 0x3118, //BOPOMOFO LETTER C + 0xA3AA: 0x3119, //BOPOMOFO LETTER S + 0xA3AB: 0x311A, //BOPOMOFO LETTER A + 0xA3AC: 0x311B, //BOPOMOFO LETTER O + 0xA3AD: 0x311C, //BOPOMOFO LETTER E + 0xA3AE: 0x311D, //BOPOMOFO LETTER EH + 0xA3AF: 0x311E, //BOPOMOFO LETTER AI + 0xA3B0: 0x311F, //BOPOMOFO LETTER EI + 0xA3B1: 0x3120, //BOPOMOFO LETTER AU + 0xA3B2: 0x3121, //BOPOMOFO LETTER OU + 0xA3B3: 0x3122, //BOPOMOFO LETTER AN + 0xA3B4: 0x3123, //BOPOMOFO LETTER EN + 0xA3B5: 0x3124, //BOPOMOFO LETTER ANG + 0xA3B6: 0x3125, //BOPOMOFO LETTER ENG + 0xA3B7: 0x3126, //BOPOMOFO LETTER ER + 0xA3B8: 0x3127, //BOPOMOFO LETTER I + 0xA3B9: 0x3128, //BOPOMOFO LETTER U + 0xA3BA: 0x3129, //BOPOMOFO LETTER IU + 0xA3BB: 0x02D9, //DOT ABOVE + 0xA3BC: 0x02C9, //MODIFIER LETTER MACRON + 0xA3BD: 0x02CA, //MODIFIER LETTER ACUTE ACCENT + 0xA3BE: 0x02C7, //CARON + 0xA3BF: 0x02CB, //MODIFIER LETTER GRAVE ACCENT + 0xA3E1: 0x20AC, //EURO SIGN + 0xA440: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xA441: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xA442: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xA443: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xA444: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xA445: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xA446: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xA447: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xA448: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xA449: 0x513F, //CJK UNIFIED IDEOGRAPH + 0xA44A: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xA44B: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xA44C: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0xA44D: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xA44E: 0x5201, //CJK UNIFIED IDEOGRAPH + 0xA44F: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xA450: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xA451: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xA452: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xA453: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xA454: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xA455: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xA456: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xA457: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xA458: 0x4E2B, //CJK UNIFIED IDEOGRAPH + 0xA459: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xA45A: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xA45B: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xA45C: 0x4E48, //CJK UNIFIED IDEOGRAPH + 0xA45D: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xA45E: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xA45F: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xA460: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xA461: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xA462: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xA463: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xA464: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xA465: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xA466: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xA467: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xA468: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xA469: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xA46A: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xA46B: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xA46C: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xA46D: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xA46E: 0x5B53, //CJK UNIFIED IDEOGRAPH + 0xA46F: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xA470: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xA471: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0xA472: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xA473: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xA474: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xA475: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xA476: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xA477: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xA478: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xA479: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xA47A: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xA47B: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0xA47C: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0xA47D: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xA47E: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xA4A1: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xA4A2: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0xA4A3: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xA4A4: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xA4A5: 0x4E30, //CJK UNIFIED IDEOGRAPH + 0xA4A6: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xA4A7: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xA4A8: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xA4A9: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xA4AA: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xA4AB: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xA4AC: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xA4AD: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xA4AE: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xA4AF: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xA4B0: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xA4B1: 0x4EC3, //CJK UNIFIED IDEOGRAPH + 0xA4B2: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0xA4B3: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xA4B4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xA4B5: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xA4B6: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xA4B7: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xA4B8: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xA4B9: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xA4BA: 0x5167, //CJK UNIFIED IDEOGRAPH + 0xA4BB: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xA4BC: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xA4BD: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xA4BE: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xA4BF: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xA4C0: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xA4C1: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xA4C2: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xA4C3: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0xA4C4: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xA4C5: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xA4C6: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xA4C7: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xA4C8: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xA4C9: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xA4CA: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xA4CB: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xA4CC: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xA4CD: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xA4CE: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xA4CF: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xA4D0: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xA4D1: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xA4D2: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xA4D3: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xA4D4: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xA4D5: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xA4D6: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xA4D7: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xA4D8: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xA4D9: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xA4DA: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xA4DB: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xA4DC: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0xA4DD: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0xA4DE: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xA4DF: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xA4E0: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xA4E1: 0x6236, //CJK UNIFIED IDEOGRAPH + 0xA4E2: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xA4E3: 0x624E, //CJK UNIFIED IDEOGRAPH + 0xA4E4: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xA4E5: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xA4E6: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xA4E7: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xA4E8: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xA4E9: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xA4EA: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xA4EB: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xA4EC: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xA4ED: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xA4EE: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xA4EF: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0xA4F0: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xA4F1: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xA4F2: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xA4F3: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xA4F4: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xA4F5: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xA4F6: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xA4F7: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xA4F8: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xA4F9: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xA4FA: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xA4FB: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xA4FC: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xA4FD: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xA4FE: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xA540: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xA541: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xA542: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xA543: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xA544: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xA545: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xA546: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xA547: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xA548: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xA549: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xA54A: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xA54B: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xA54C: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xA54D: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xA54E: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xA54F: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xA550: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xA551: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0xA552: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xA553: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xA554: 0x5189, //CJK UNIFIED IDEOGRAPH + 0xA555: 0x518A, //CJK UNIFIED IDEOGRAPH + 0xA556: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xA557: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xA558: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xA559: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xA55A: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xA55B: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xA55C: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xA55D: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xA55E: 0x5306, //CJK UNIFIED IDEOGRAPH + 0xA55F: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xA560: 0x531D, //CJK UNIFIED IDEOGRAPH + 0xA561: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xA562: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xA563: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xA564: 0x5361, //CJK UNIFIED IDEOGRAPH + 0xA565: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xA566: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xA567: 0x536E, //CJK UNIFIED IDEOGRAPH + 0xA568: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xA569: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xA56A: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xA56B: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xA56C: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xA56D: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0xA56E: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xA56F: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0xA570: 0x53FC, //CJK UNIFIED IDEOGRAPH + 0xA571: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xA572: 0x53F5, //CJK UNIFIED IDEOGRAPH + 0xA573: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xA574: 0x53E6, //CJK UNIFIED IDEOGRAPH + 0xA575: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xA576: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xA577: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xA578: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xA579: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xA57A: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xA57B: 0x53FB, //CJK UNIFIED IDEOGRAPH + 0xA57C: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xA57D: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xA57E: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xA5A1: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xA5A2: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xA5A3: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xA5A4: 0x5976, //CJK UNIFIED IDEOGRAPH + 0xA5A5: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xA5A6: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0xA5A7: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xA5A8: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xA5A9: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xA5AA: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xA5AB: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xA5AC: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xA5AD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xA5AE: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xA5AF: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xA5B0: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xA5B1: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xA5B2: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xA5B3: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xA5B4: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xA5B5: 0x6254, //CJK UNIFIED IDEOGRAPH + 0xA5B6: 0x6252, //CJK UNIFIED IDEOGRAPH + 0xA5B7: 0x6251, //CJK UNIFIED IDEOGRAPH + 0xA5B8: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xA5B9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xA5BA: 0x672E, //CJK UNIFIED IDEOGRAPH + 0xA5BB: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xA5BC: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xA5BD: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xA5BE: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xA5BF: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xA5C0: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xA5C1: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xA5C2: 0x6C10, //CJK UNIFIED IDEOGRAPH + 0xA5C3: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xA5C4: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xA5C5: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xA5C6: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0xA5C7: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xA5C8: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xA5C9: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xA5CA: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xA5CB: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xA5CC: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xA5CD: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xA5CE: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xA5CF: 0x7529, //CJK UNIFIED IDEOGRAPH + 0xA5D0: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xA5D1: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xA5D2: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xA5D3: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xA5D4: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xA5D5: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xA5D6: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xA5D7: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xA5D8: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xA5D9: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xA5DA: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xA5DB: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xA5DC: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xA5DD: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xA5DE: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xA5DF: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xA5E0: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xA5E1: 0x4E1F, //CJK UNIFIED IDEOGRAPH + 0xA5E2: 0x4E52, //CJK UNIFIED IDEOGRAPH + 0xA5E3: 0x4E53, //CJK UNIFIED IDEOGRAPH + 0xA5E4: 0x4E69, //CJK UNIFIED IDEOGRAPH + 0xA5E5: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0xA5E6: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xA5E7: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xA5E8: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xA5E9: 0x4EFF, //CJK UNIFIED IDEOGRAPH + 0xA5EA: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xA5EB: 0x4F19, //CJK UNIFIED IDEOGRAPH + 0xA5EC: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xA5ED: 0x4F15, //CJK UNIFIED IDEOGRAPH + 0xA5EE: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xA5EF: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xA5F0: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xA5F1: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xA5F2: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xA5F3: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xA5F4: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xA5F5: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xA5F6: 0x4EF3, //CJK UNIFIED IDEOGRAPH + 0xA5F7: 0x4EFD, //CJK UNIFIED IDEOGRAPH + 0xA5F8: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xA5F9: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0xA5FA: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xA5FB: 0x5147, //CJK UNIFIED IDEOGRAPH + 0xA5FC: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xA5FD: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xA5FE: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xA640: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xA641: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xA642: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0xA643: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xA644: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xA645: 0x5212, //CJK UNIFIED IDEOGRAPH + 0xA646: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xA647: 0x5216, //CJK UNIFIED IDEOGRAPH + 0xA648: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xA649: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xA64A: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xA64B: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xA64C: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xA64D: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xA64E: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xA64F: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xA650: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xA651: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xA652: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xA653: 0x5401, //CJK UNIFIED IDEOGRAPH + 0xA654: 0x540B, //CJK UNIFIED IDEOGRAPH + 0xA655: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xA656: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xA657: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xA658: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xA659: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xA65A: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xA65B: 0x5406, //CJK UNIFIED IDEOGRAPH + 0xA65C: 0x5412, //CJK UNIFIED IDEOGRAPH + 0xA65D: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xA65E: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xA65F: 0x56DD, //CJK UNIFIED IDEOGRAPH + 0xA660: 0x5733, //CJK UNIFIED IDEOGRAPH + 0xA661: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xA662: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xA663: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xA664: 0x572C, //CJK UNIFIED IDEOGRAPH + 0xA665: 0x572F, //CJK UNIFIED IDEOGRAPH + 0xA666: 0x5729, //CJK UNIFIED IDEOGRAPH + 0xA667: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xA668: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xA669: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xA66A: 0x5938, //CJK UNIFIED IDEOGRAPH + 0xA66B: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xA66C: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xA66D: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xA66E: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xA66F: 0x5979, //CJK UNIFIED IDEOGRAPH + 0xA670: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xA671: 0x5981, //CJK UNIFIED IDEOGRAPH + 0xA672: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xA673: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xA674: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xA675: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xA676: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xA677: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xA678: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xA679: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xA67A: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xA67B: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xA67C: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xA67D: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0xA67E: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xA6A1: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xA6A2: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xA6A3: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xA6A4: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xA6A5: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xA6A6: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xA6A7: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xA6A8: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xA6A9: 0x6263, //CJK UNIFIED IDEOGRAPH + 0xA6AA: 0x625B, //CJK UNIFIED IDEOGRAPH + 0xA6AB: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xA6AC: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xA6AD: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xA6AE: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xA6AF: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xA6B0: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xA6B1: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xA6B2: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xA6B3: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xA6B4: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xA6B5: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xA6B6: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xA6B7: 0x6735, //CJK UNIFIED IDEOGRAPH + 0xA6B8: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xA6B9: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xA6BA: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xA6BB: 0x6C16, //CJK UNIFIED IDEOGRAPH + 0xA6BC: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xA6BD: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xA6BE: 0x6C59, //CJK UNIFIED IDEOGRAPH + 0xA6BF: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xA6C0: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xA6C1: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xA6C2: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xA6C3: 0x6C61, //CJK UNIFIED IDEOGRAPH + 0xA6C4: 0x6C5B, //CJK UNIFIED IDEOGRAPH + 0xA6C5: 0x6C4D, //CJK UNIFIED IDEOGRAPH + 0xA6C6: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0xA6C7: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xA6C8: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xA6C9: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xA6CA: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xA6CB: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xA6CC: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xA6CD: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0xA6CE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xA6CF: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xA6D0: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xA6D1: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xA6D2: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xA6D3: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xA6D4: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xA6D5: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xA6D6: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xA6D7: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xA6D8: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xA6D9: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xA6DA: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xA6DB: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xA6DC: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xA6DD: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xA6DE: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xA6DF: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xA6E0: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xA6E1: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xA6E2: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xA6E3: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xA6E4: 0x866B, //CJK UNIFIED IDEOGRAPH + 0xA6E5: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xA6E6: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xA6E7: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xA6E8: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xA6E9: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xA6EA: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xA6EB: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xA6EC: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xA6ED: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xA6EE: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0xA6EF: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0xA6F0: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0xA6F1: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xA6F2: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xA6F3: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xA6F4: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0xA6F5: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xA6F6: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xA6F7: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xA6F8: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xA6F9: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xA6FA: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xA6FB: 0x4F54, //CJK UNIFIED IDEOGRAPH + 0xA6FC: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xA6FD: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xA6FE: 0x4F63, //CJK UNIFIED IDEOGRAPH + 0xA740: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xA741: 0x4F60, //CJK UNIFIED IDEOGRAPH + 0xA742: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xA743: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xA744: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xA745: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xA746: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0xA747: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0xA748: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xA749: 0x514C, //CJK UNIFIED IDEOGRAPH + 0xA74A: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xA74B: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xA74C: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xA74D: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xA74E: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xA74F: 0x5225, //CJK UNIFIED IDEOGRAPH + 0xA750: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xA751: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xA752: 0x522A, //CJK UNIFIED IDEOGRAPH + 0xA753: 0x5228, //CJK UNIFIED IDEOGRAPH + 0xA754: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xA755: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xA756: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xA757: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0xA758: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xA759: 0x5373, //CJK UNIFIED IDEOGRAPH + 0xA75A: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xA75B: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xA75C: 0x542D, //CJK UNIFIED IDEOGRAPH + 0xA75D: 0x541E, //CJK UNIFIED IDEOGRAPH + 0xA75E: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xA75F: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xA760: 0x544E, //CJK UNIFIED IDEOGRAPH + 0xA761: 0x5427, //CJK UNIFIED IDEOGRAPH + 0xA762: 0x5446, //CJK UNIFIED IDEOGRAPH + 0xA763: 0x5443, //CJK UNIFIED IDEOGRAPH + 0xA764: 0x5433, //CJK UNIFIED IDEOGRAPH + 0xA765: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xA766: 0x5442, //CJK UNIFIED IDEOGRAPH + 0xA767: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xA768: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xA769: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xA76A: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xA76B: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xA76C: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xA76D: 0x542E, //CJK UNIFIED IDEOGRAPH + 0xA76E: 0x5435, //CJK UNIFIED IDEOGRAPH + 0xA76F: 0x5436, //CJK UNIFIED IDEOGRAPH + 0xA770: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xA771: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xA772: 0x5440, //CJK UNIFIED IDEOGRAPH + 0xA773: 0x5431, //CJK UNIFIED IDEOGRAPH + 0xA774: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xA775: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xA776: 0x542C, //CJK UNIFIED IDEOGRAPH + 0xA777: 0x56EA, //CJK UNIFIED IDEOGRAPH + 0xA778: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xA779: 0x56E4, //CJK UNIFIED IDEOGRAPH + 0xA77A: 0x56EB, //CJK UNIFIED IDEOGRAPH + 0xA77B: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xA77C: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xA77D: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xA77E: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xA7A1: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xA7A2: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xA7A3: 0x573E, //CJK UNIFIED IDEOGRAPH + 0xA7A4: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xA7A5: 0x574F, //CJK UNIFIED IDEOGRAPH + 0xA7A6: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xA7A7: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0xA7A8: 0x593E, //CJK UNIFIED IDEOGRAPH + 0xA7A9: 0x599D, //CJK UNIFIED IDEOGRAPH + 0xA7AA: 0x5992, //CJK UNIFIED IDEOGRAPH + 0xA7AB: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xA7AC: 0x599E, //CJK UNIFIED IDEOGRAPH + 0xA7AD: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0xA7AE: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xA7AF: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xA7B0: 0x598D, //CJK UNIFIED IDEOGRAPH + 0xA7B1: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xA7B2: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xA7B3: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xA7B4: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xA7B5: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xA7B6: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xA7B7: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xA7B8: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0xA7B9: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xA7BA: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xA7BB: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xA7BC: 0x5C2C, //CJK UNIFIED IDEOGRAPH + 0xA7BD: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xA7BE: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0xA7BF: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xA7C0: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xA7C1: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xA7C2: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xA7C3: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0xA7C4: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0xA7C5: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xA7C6: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xA7C7: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xA7C8: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xA7C9: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xA7CA: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xA7CB: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xA7CC: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xA7CD: 0x5F64, //CJK UNIFIED IDEOGRAPH + 0xA7CE: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xA7CF: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xA7D0: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xA7D1: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xA7D2: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xA7D3: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xA7D4: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xA7D5: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0xA7D6: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xA7D7: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0xA7D8: 0x5FEA, //CJK UNIFIED IDEOGRAPH + 0xA7D9: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xA7DA: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xA7DB: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xA7DC: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xA7DD: 0x6296, //CJK UNIFIED IDEOGRAPH + 0xA7DE: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xA7DF: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xA7E0: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xA7E1: 0x626D, //CJK UNIFIED IDEOGRAPH + 0xA7E2: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xA7E3: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xA7E4: 0x627E, //CJK UNIFIED IDEOGRAPH + 0xA7E5: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xA7E6: 0x6273, //CJK UNIFIED IDEOGRAPH + 0xA7E7: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xA7E8: 0x626F, //CJK UNIFIED IDEOGRAPH + 0xA7E9: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xA7EA: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xA7EB: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xA7EC: 0x6293, //CJK UNIFIED IDEOGRAPH + 0xA7ED: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xA7EE: 0x6286, //CJK UNIFIED IDEOGRAPH + 0xA7EF: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xA7F0: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xA7F1: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xA7F2: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xA7F3: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xA7F4: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xA7F5: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xA7F6: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xA7F7: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xA7F8: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xA7F9: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xA7FA: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xA7FB: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xA7FC: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xA7FD: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xA7FE: 0x6760, //CJK UNIFIED IDEOGRAPH + 0xA840: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xA841: 0x6757, //CJK UNIFIED IDEOGRAPH + 0xA842: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xA843: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xA844: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xA845: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xA846: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xA847: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xA848: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xA849: 0x6C89, //CJK UNIFIED IDEOGRAPH + 0xA84A: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xA84B: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xA84C: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xA84D: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0xA84E: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xA84F: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xA850: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xA851: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xA852: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0xA853: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0xA854: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xA855: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xA856: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xA857: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xA858: 0x6C74, //CJK UNIFIED IDEOGRAPH + 0xA859: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xA85A: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xA85B: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0xA85C: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xA85D: 0x6C98, //CJK UNIFIED IDEOGRAPH + 0xA85E: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xA85F: 0x7076, //CJK UNIFIED IDEOGRAPH + 0xA860: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xA861: 0x707D, //CJK UNIFIED IDEOGRAPH + 0xA862: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xA863: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xA864: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xA865: 0x7260, //CJK UNIFIED IDEOGRAPH + 0xA866: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xA867: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xA868: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xA869: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xA86A: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xA86B: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xA86C: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xA86D: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xA86E: 0x76EF, //CJK UNIFIED IDEOGRAPH + 0xA86F: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xA870: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xA871: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xA872: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xA873: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xA874: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xA875: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xA876: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xA877: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xA878: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xA879: 0x8098, //CJK UNIFIED IDEOGRAPH + 0xA87A: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xA87B: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xA87C: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xA87D: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xA87E: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xA8A1: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xA8A2: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xA8A3: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xA8A4: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xA8A5: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xA8A6: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xA8A7: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xA8A8: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xA8A9: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xA8AA: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xA8AB: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xA8AC: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xA8AD: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xA8AE: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xA8AF: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xA8B0: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xA8B1: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xA8B2: 0x8FC6, //CJK UNIFIED IDEOGRAPH + 0xA8B3: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xA8B4: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0xA8B5: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xA8B6: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xA8B7: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xA8B8: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xA8B9: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xA8BA: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xA8BB: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xA8BC: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0xA8BD: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xA8BE: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xA8BF: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xA8C0: 0x9631, //CJK UNIFIED IDEOGRAPH + 0xA8C1: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xA8C2: 0x962C, //CJK UNIFIED IDEOGRAPH + 0xA8C3: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0xA8C4: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xA8C5: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xA8C6: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xA8C7: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xA8C8: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0xA8C9: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xA8CA: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xA8CB: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xA8CC: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xA8CD: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xA8CE: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xA8CF: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xA8D0: 0x4F6C, //CJK UNIFIED IDEOGRAPH + 0xA8D1: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xA8D2: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xA8D3: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0xA8D4: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xA8D5: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xA8D6: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0xA8D7: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xA8D8: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xA8D9: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0xA8DA: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0xA8DB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xA8DC: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xA8DD: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xA8DE: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0xA8DF: 0x5154, //CJK UNIFIED IDEOGRAPH + 0xA8E0: 0x5152, //CJK UNIFIED IDEOGRAPH + 0xA8E1: 0x5155, //CJK UNIFIED IDEOGRAPH + 0xA8E2: 0x5169, //CJK UNIFIED IDEOGRAPH + 0xA8E3: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xA8E4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xA8E5: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xA8E6: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xA8E7: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xA8E8: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xA8E9: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xA8EA: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xA8EB: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xA8EC: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xA8ED: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xA8EE: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xA8EF: 0x5241, //CJK UNIFIED IDEOGRAPH + 0xA8F0: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xA8F1: 0x52BB, //CJK UNIFIED IDEOGRAPH + 0xA8F2: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xA8F3: 0x5354, //CJK UNIFIED IDEOGRAPH + 0xA8F4: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xA8F5: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xA8F6: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xA8F7: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xA8F8: 0x5378, //CJK UNIFIED IDEOGRAPH + 0xA8F9: 0x5379, //CJK UNIFIED IDEOGRAPH + 0xA8FA: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xA8FB: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xA8FC: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xA8FD: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xA8FE: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xA940: 0x5496, //CJK UNIFIED IDEOGRAPH + 0xA941: 0x5478, //CJK UNIFIED IDEOGRAPH + 0xA942: 0x5495, //CJK UNIFIED IDEOGRAPH + 0xA943: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xA944: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xA945: 0x5477, //CJK UNIFIED IDEOGRAPH + 0xA946: 0x5484, //CJK UNIFIED IDEOGRAPH + 0xA947: 0x5492, //CJK UNIFIED IDEOGRAPH + 0xA948: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xA949: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xA94A: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xA94B: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xA94C: 0x5476, //CJK UNIFIED IDEOGRAPH + 0xA94D: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xA94E: 0x549A, //CJK UNIFIED IDEOGRAPH + 0xA94F: 0x5462, //CJK UNIFIED IDEOGRAPH + 0xA950: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xA951: 0x548B, //CJK UNIFIED IDEOGRAPH + 0xA952: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xA953: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xA954: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xA955: 0x5783, //CJK UNIFIED IDEOGRAPH + 0xA956: 0x5777, //CJK UNIFIED IDEOGRAPH + 0xA957: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xA958: 0x5769, //CJK UNIFIED IDEOGRAPH + 0xA959: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xA95A: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xA95B: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xA95C: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xA95D: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xA95E: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xA95F: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xA960: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xA961: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xA962: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xA963: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xA964: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xA965: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xA966: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xA967: 0x59AE, //CJK UNIFIED IDEOGRAPH + 0xA968: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xA969: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xA96A: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xA96B: 0x59CD, //CJK UNIFIED IDEOGRAPH + 0xA96C: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xA96D: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xA96E: 0x59CA, //CJK UNIFIED IDEOGRAPH + 0xA96F: 0x59AF, //CJK UNIFIED IDEOGRAPH + 0xA970: 0x59B3, //CJK UNIFIED IDEOGRAPH + 0xA971: 0x59D2, //CJK UNIFIED IDEOGRAPH + 0xA972: 0x59C5, //CJK UNIFIED IDEOGRAPH + 0xA973: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xA974: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xA975: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xA976: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xA977: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xA978: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xA979: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xA97A: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xA97B: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xA97C: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0xA97D: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xA97E: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xA9A1: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0xA9A2: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xA9A3: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0xA9A4: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xA9A5: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xA9A6: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xA9A7: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xA9A8: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xA9A9: 0x5E18, //CJK UNIFIED IDEOGRAPH + 0xA9AA: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0xA9AB: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xA9AC: 0x5E15, //CJK UNIFIED IDEOGRAPH + 0xA9AD: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xA9AE: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xA9AF: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xA9B0: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xA9B1: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xA9B2: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xA9B3: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xA9B4: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0xA9B5: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xA9B6: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xA9B7: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xA9B8: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xA9B9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xA9BA: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xA9BB: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0xA9BC: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xA9BD: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0xA9BE: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xA9BF: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xA9C0: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xA9C1: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xA9C2: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xA9C3: 0x6014, //CJK UNIFIED IDEOGRAPH + 0xA9C4: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xA9C5: 0x6035, //CJK UNIFIED IDEOGRAPH + 0xA9C6: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xA9C7: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xA9C8: 0x6015, //CJK UNIFIED IDEOGRAPH + 0xA9C9: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xA9CA: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xA9CB: 0x6029, //CJK UNIFIED IDEOGRAPH + 0xA9CC: 0x602B, //CJK UNIFIED IDEOGRAPH + 0xA9CD: 0x601B, //CJK UNIFIED IDEOGRAPH + 0xA9CE: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xA9CF: 0x6215, //CJK UNIFIED IDEOGRAPH + 0xA9D0: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xA9D1: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xA9D2: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xA9D3: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xA9D4: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xA9D5: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xA9D6: 0x62C4, //CJK UNIFIED IDEOGRAPH + 0xA9D7: 0x62BF, //CJK UNIFIED IDEOGRAPH + 0xA9D8: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xA9D9: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xA9DA: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xA9DB: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xA9DC: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xA9DD: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xA9DE: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xA9DF: 0x62CB, //CJK UNIFIED IDEOGRAPH + 0xA9E0: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xA9E1: 0x62A8, //CJK UNIFIED IDEOGRAPH + 0xA9E2: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xA9E3: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xA9E4: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xA9E5: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xA9E6: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xA9E7: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xA9E8: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xA9E9: 0x62DA, //CJK UNIFIED IDEOGRAPH + 0xA9EA: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xA9EB: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xA9EC: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xA9ED: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xA9EE: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0xA9EF: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0xA9F0: 0x62CE, //CJK UNIFIED IDEOGRAPH + 0xA9F1: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xA9F2: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xA9F3: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xA9F4: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xA9F5: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xA9F6: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xA9F7: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xA9F8: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xA9F9: 0x6602, //CJK UNIFIED IDEOGRAPH + 0xA9FA: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xA9FB: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xA9FC: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xA9FD: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xA9FE: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xAA40: 0x6607, //CJK UNIFIED IDEOGRAPH + 0xAA41: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xAA42: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xAA43: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xAA44: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xAA45: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xAA46: 0x6771, //CJK UNIFIED IDEOGRAPH + 0xAA47: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xAA48: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xAA49: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xAA4A: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xAA4B: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xAA4C: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xAA4D: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xAA4E: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xAA4F: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xAA50: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xAA51: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xAA52: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xAA53: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xAA54: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xAA55: 0x6793, //CJK UNIFIED IDEOGRAPH + 0xAA56: 0x677C, //CJK UNIFIED IDEOGRAPH + 0xAA57: 0x676A, //CJK UNIFIED IDEOGRAPH + 0xAA58: 0x6772, //CJK UNIFIED IDEOGRAPH + 0xAA59: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xAA5A: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xAA5B: 0x6B67, //CJK UNIFIED IDEOGRAPH + 0xAA5C: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0xAA5D: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xAA5E: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0xAA5F: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xAA60: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xAA61: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xAA62: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0xAA63: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xAA64: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xAA65: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xAA66: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xAA67: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xAA68: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xAA69: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xAA6A: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xAA6B: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xAA6C: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xAA6D: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xAA6E: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xAA6F: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xAA70: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0xAA71: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xAA72: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xAA73: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0xAA74: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0xAA75: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xAA76: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xAA77: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xAA78: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xAA79: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xAA7A: 0x6CAC, //CJK UNIFIED IDEOGRAPH + 0xAA7B: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xAA7C: 0x6CDC, //CJK UNIFIED IDEOGRAPH + 0xAA7D: 0x6CD6, //CJK UNIFIED IDEOGRAPH + 0xAA7E: 0x6CE0, //CJK UNIFIED IDEOGRAPH + 0xAAA1: 0x7095, //CJK UNIFIED IDEOGRAPH + 0xAAA2: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xAAA3: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xAAA4: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xAAA5: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xAAA6: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xAAA7: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xAAA8: 0x7238, //CJK UNIFIED IDEOGRAPH + 0xAAA9: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xAAAA: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xAAAB: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xAAAC: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xAAAD: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xAAAE: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xAAAF: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xAAB0: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xAAB1: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xAAB2: 0x73A8, //CJK UNIFIED IDEOGRAPH + 0xAAB3: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xAAB4: 0x73AB, //CJK UNIFIED IDEOGRAPH + 0xAAB5: 0x73A5, //CJK UNIFIED IDEOGRAPH + 0xAAB6: 0x753D, //CJK UNIFIED IDEOGRAPH + 0xAAB7: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xAAB8: 0x7599, //CJK UNIFIED IDEOGRAPH + 0xAAB9: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xAABA: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xAABB: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xAABC: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xAABD: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xAABE: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xAABF: 0x77FD, //CJK UNIFIED IDEOGRAPH + 0xAAC0: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xAAC1: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xAAC2: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xAAC3: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xAAC4: 0x79C8, //CJK UNIFIED IDEOGRAPH + 0xAAC5: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xAAC6: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xAAC7: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xAAC8: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xAAC9: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xAACA: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xAACB: 0x7F8B, //CJK UNIFIED IDEOGRAPH + 0xAACC: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xAACD: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xAACE: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xAACF: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xAAD0: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xAAD1: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xAAD2: 0x80AB, //CJK UNIFIED IDEOGRAPH + 0xAAD3: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xAAD4: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xAAD5: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xAAD6: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xAAD7: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xAAD8: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xAAD9: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xAADA: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xAADB: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xAADC: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xAADD: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xAADE: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xAADF: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xAAE0: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xAAE1: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xAAE2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xAAE3: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xAAE4: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xAAE5: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xAAE6: 0x82A3, //CJK UNIFIED IDEOGRAPH + 0xAAE7: 0x82B0, //CJK UNIFIED IDEOGRAPH + 0xAAE8: 0x82BE, //CJK UNIFIED IDEOGRAPH + 0xAAE9: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xAAEA: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xAAEB: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xAAEC: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xAAED: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xAAEE: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xAAEF: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xAAF0: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xAAF1: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xAAF2: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xAAF3: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xAAF4: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xAAF5: 0x90B6, //CJK UNIFIED IDEOGRAPH + 0xAAF6: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xAAF7: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xAAF8: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xAAF9: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xAAFA: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xAAFB: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xAAFC: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xAAFD: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xAAFE: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xAB40: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xAB41: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xAB42: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xAB43: 0x9752, //CJK UNIFIED IDEOGRAPH + 0xAB44: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xAB45: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0xAB46: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xAB47: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xAB48: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xAB49: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xAB4A: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xAB4B: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xAB4C: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0xAB4D: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xAB4E: 0x4FCF, //CJK UNIFIED IDEOGRAPH + 0xAB4F: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xAB50: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xAB51: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0xAB52: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0xAB53: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xAB54: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xAB55: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xAB56: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xAB57: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0xAB58: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xAB59: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0xAB5A: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xAB5B: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xAB5C: 0x4FDE, //CJK UNIFIED IDEOGRAPH + 0xAB5D: 0x4FB7, //CJK UNIFIED IDEOGRAPH + 0xAB5E: 0x5157, //CJK UNIFIED IDEOGRAPH + 0xAB5F: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xAB60: 0x5191, //CJK UNIFIED IDEOGRAPH + 0xAB61: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xAB62: 0x524E, //CJK UNIFIED IDEOGRAPH + 0xAB63: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xAB64: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xAB65: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xAB66: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xAB67: 0x524B, //CJK UNIFIED IDEOGRAPH + 0xAB68: 0x5247, //CJK UNIFIED IDEOGRAPH + 0xAB69: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xAB6A: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xAB6B: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xAB6C: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0xAB6D: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xAB6E: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xAB6F: 0x537B, //CJK UNIFIED IDEOGRAPH + 0xAB70: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xAB71: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xAB72: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xAB73: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xAB74: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xAB75: 0x54CE, //CJK UNIFIED IDEOGRAPH + 0xAB76: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xAB77: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xAB78: 0x54A6, //CJK UNIFIED IDEOGRAPH + 0xAB79: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xAB7A: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0xAB7B: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0xAB7C: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xAB7D: 0x54AA, //CJK UNIFIED IDEOGRAPH + 0xAB7E: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xABA1: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xABA2: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xABA3: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0xABA4: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xABA5: 0x54B1, //CJK UNIFIED IDEOGRAPH + 0xABA6: 0x54BB, //CJK UNIFIED IDEOGRAPH + 0xABA7: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xABA8: 0x54A7, //CJK UNIFIED IDEOGRAPH + 0xABA9: 0x54BF, //CJK UNIFIED IDEOGRAPH + 0xABAA: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0xABAB: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xABAC: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xABAD: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xABAE: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xABAF: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xABB0: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xABB1: 0x57AE, //CJK UNIFIED IDEOGRAPH + 0xABB2: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xABB3: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xABB4: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xABB5: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xABB6: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xABB7: 0x5950, //CJK UNIFIED IDEOGRAPH + 0xABB8: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xABB9: 0x59D8, //CJK UNIFIED IDEOGRAPH + 0xABBA: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xABBB: 0x59E3, //CJK UNIFIED IDEOGRAPH + 0xABBC: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xABBD: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xABBE: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0xABBF: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0xABC0: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xABC1: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0xABC2: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xABC3: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xABC4: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xABC5: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xABC6: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xABC7: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xABC8: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xABC9: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xABCA: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xABCB: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xABCC: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0xABCD: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0xABCE: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xABCF: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xABD0: 0x5CD2, //CJK UNIFIED IDEOGRAPH + 0xABD1: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xABD2: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xABD3: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0xABD4: 0x5E1F, //CJK UNIFIED IDEOGRAPH + 0xABD5: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xABD6: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xABD7: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xABD8: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xABD9: 0x5F08, //CJK UNIFIED IDEOGRAPH + 0xABDA: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0xABDB: 0x5F65, //CJK UNIFIED IDEOGRAPH + 0xABDC: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0xABDD: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xABDE: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xABDF: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xABE0: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xABE1: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xABE2: 0x5F89, //CJK UNIFIED IDEOGRAPH + 0xABE3: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xABE4: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xABE5: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xABE6: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xABE7: 0x600E, //CJK UNIFIED IDEOGRAPH + 0xABE8: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xABE9: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xABEA: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xABEB: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xABEC: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xABED: 0x6046, //CJK UNIFIED IDEOGRAPH + 0xABEE: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xABEF: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xABF0: 0x606B, //CJK UNIFIED IDEOGRAPH + 0xABF1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xABF2: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xABF3: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xABF4: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xABF5: 0x6316, //CJK UNIFIED IDEOGRAPH + 0xABF6: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xABF7: 0x62FC, //CJK UNIFIED IDEOGRAPH + 0xABF8: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xABF9: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xABFA: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xABFB: 0x62FD, //CJK UNIFIED IDEOGRAPH + 0xABFC: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xABFD: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xABFE: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xAC40: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xAC41: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xAC42: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xAC43: 0x62F4, //CJK UNIFIED IDEOGRAPH + 0xAC44: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xAC45: 0x6302, //CJK UNIFIED IDEOGRAPH + 0xAC46: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xAC47: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xAC48: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xAC49: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xAC4A: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0xAC4B: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xAC4C: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xAC4D: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xAC4E: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xAC4F: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xAC50: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xAC51: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xAC52: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xAC53: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xAC54: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xAC55: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0xAC56: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xAC57: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xAC58: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xAC59: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xAC5A: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xAC5B: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xAC5C: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xAC5D: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0xAC5E: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xAC5F: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xAC60: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xAC61: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xAC62: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0xAC63: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xAC64: 0x67E5, //CJK UNIFIED IDEOGRAPH + 0xAC65: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xAC66: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xAC67: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0xAC68: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xAC69: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xAC6A: 0x67D9, //CJK UNIFIED IDEOGRAPH + 0xAC6B: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0xAC6C: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xAC6D: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xAC6E: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xAC6F: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xAC70: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xAC71: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xAC72: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xAC73: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xAC74: 0x6C1F, //CJK UNIFIED IDEOGRAPH + 0xAC75: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xAC76: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xAC77: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xAC78: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xAC79: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xAC7A: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xAC7B: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xAC7C: 0x6D31, //CJK UNIFIED IDEOGRAPH + 0xAC7D: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xAC7E: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xACA1: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xACA2: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xACA3: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xACA4: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0xACA5: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xACA6: 0x6CF5, //CJK UNIFIED IDEOGRAPH + 0xACA7: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xACA8: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xACA9: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0xACAA: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0xACAB: 0x6D2E, //CJK UNIFIED IDEOGRAPH + 0xACAC: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xACAD: 0x6D0E, //CJK UNIFIED IDEOGRAPH + 0xACAE: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0xACAF: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xACB0: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0xACB1: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xACB2: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xACB3: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xACB4: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xACB5: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xACB6: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xACB7: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0xACB8: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xACB9: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xACBA: 0x726F, //CJK UNIFIED IDEOGRAPH + 0xACBB: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xACBC: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xACBD: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xACBE: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xACBF: 0x73B7, //CJK UNIFIED IDEOGRAPH + 0xACC0: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xACC1: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xACC2: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xACC3: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xACC4: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xACC5: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xACC6: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xACC7: 0x752D, //CJK UNIFIED IDEOGRAPH + 0xACC8: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xACC9: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xACCA: 0x754E, //CJK UNIFIED IDEOGRAPH + 0xACCB: 0x754B, //CJK UNIFIED IDEOGRAPH + 0xACCC: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xACCD: 0x75A4, //CJK UNIFIED IDEOGRAPH + 0xACCE: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xACCF: 0x75A2, //CJK UNIFIED IDEOGRAPH + 0xACD0: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xACD1: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xACD2: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xACD3: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xACD4: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xACD5: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xACD6: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xACD7: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xACD8: 0x76C5, //CJK UNIFIED IDEOGRAPH + 0xACD9: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xACDA: 0x76F9, //CJK UNIFIED IDEOGRAPH + 0xACDB: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xACDC: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xACDD: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xACDE: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xACDF: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xACE0: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xACE1: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xACE2: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xACE3: 0x7814, //CJK UNIFIED IDEOGRAPH + 0xACE4: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xACE5: 0x780D, //CJK UNIFIED IDEOGRAPH + 0xACE6: 0x7946, //CJK UNIFIED IDEOGRAPH + 0xACE7: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xACE8: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xACE9: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xACEA: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xACEB: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xACEC: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xACED: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xACEE: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xACEF: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xACF0: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xACF1: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xACF2: 0x7AFD, //CJK UNIFIED IDEOGRAPH + 0xACF3: 0x7C7D, //CJK UNIFIED IDEOGRAPH + 0xACF4: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xACF5: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xACF6: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xACF7: 0x7D09, //CJK UNIFIED IDEOGRAPH + 0xACF8: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xACF9: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xACFA: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xACFB: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xACFC: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xACFD: 0x7FBF, //CJK UNIFIED IDEOGRAPH + 0xACFE: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xAD40: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xAD41: 0x800D, //CJK UNIFIED IDEOGRAPH + 0xAD42: 0x8011, //CJK UNIFIED IDEOGRAPH + 0xAD43: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xAD44: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xAD45: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xAD46: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xAD47: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xAD48: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xAD49: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xAD4A: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xAD4B: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xAD4C: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xAD4D: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xAD4E: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xAD4F: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xAD50: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xAD51: 0x8222, //CJK UNIFIED IDEOGRAPH + 0xAD52: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xAD53: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xAD54: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xAD55: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xAD56: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xAD57: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xAD58: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xAD59: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xAD5A: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xAD5B: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xAD5C: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xAD5D: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xAD5E: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xAD5F: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xAD60: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xAD61: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xAD62: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xAD63: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xAD64: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0xAD65: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xAD66: 0x82EF, //CJK UNIFIED IDEOGRAPH + 0xAD67: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xAD68: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xAD69: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xAD6A: 0x867B, //CJK UNIFIED IDEOGRAPH + 0xAD6B: 0x867A, //CJK UNIFIED IDEOGRAPH + 0xAD6C: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xAD6D: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xAD6E: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xAD6F: 0x89D4, //CJK UNIFIED IDEOGRAPH + 0xAD70: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xAD71: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xAD72: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xAD73: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xAD74: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xAD75: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xAD76: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xAD77: 0x8DB4, //CJK UNIFIED IDEOGRAPH + 0xAD78: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xAD79: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xAD7A: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xAD7B: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xAD7C: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xAD7D: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xAD7E: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xADA1: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xADA2: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xADA3: 0x8FE4, //CJK UNIFIED IDEOGRAPH + 0xADA4: 0x8FE8, //CJK UNIFIED IDEOGRAPH + 0xADA5: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xADA6: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0xADA7: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xADA8: 0x90C3, //CJK UNIFIED IDEOGRAPH + 0xADA9: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xADAA: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xADAB: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xADAC: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xADAD: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xADAE: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xADAF: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xADB0: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xADB1: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xADB2: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xADB3: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xADB4: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xADB5: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xADB6: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xADB7: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xADB8: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xADB9: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xADBA: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xADBB: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xADBC: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xADBD: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0xADBE: 0x500C, //CJK UNIFIED IDEOGRAPH + 0xADBF: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xADC0: 0x5023, //CJK UNIFIED IDEOGRAPH + 0xADC1: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xADC2: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xADC3: 0x5025, //CJK UNIFIED IDEOGRAPH + 0xADC4: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xADC5: 0x5029, //CJK UNIFIED IDEOGRAPH + 0xADC6: 0x5016, //CJK UNIFIED IDEOGRAPH + 0xADC7: 0x5006, //CJK UNIFIED IDEOGRAPH + 0xADC8: 0x503C, //CJK UNIFIED IDEOGRAPH + 0xADC9: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xADCA: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xADCB: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xADCC: 0x5011, //CJK UNIFIED IDEOGRAPH + 0xADCD: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xADCE: 0x5000, //CJK UNIFIED IDEOGRAPH + 0xADCF: 0x5014, //CJK UNIFIED IDEOGRAPH + 0xADD0: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xADD1: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xADD2: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xADD3: 0x500B, //CJK UNIFIED IDEOGRAPH + 0xADD4: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xADD5: 0x5018, //CJK UNIFIED IDEOGRAPH + 0xADD6: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xADD7: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xADD8: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xADD9: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xADDA: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0xADDB: 0x502B, //CJK UNIFIED IDEOGRAPH + 0xADDC: 0x5009, //CJK UNIFIED IDEOGRAPH + 0xADDD: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xADDE: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0xADDF: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xADE0: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0xADE1: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0xADE2: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xADE3: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xADE4: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xADE5: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xADE6: 0x525C, //CJK UNIFIED IDEOGRAPH + 0xADE7: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xADE8: 0x525B, //CJK UNIFIED IDEOGRAPH + 0xADE9: 0x525D, //CJK UNIFIED IDEOGRAPH + 0xADEA: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xADEB: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xADEC: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xADED: 0x539D, //CJK UNIFIED IDEOGRAPH + 0xADEE: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0xADEF: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xADF0: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xADF1: 0x5501, //CJK UNIFIED IDEOGRAPH + 0xADF2: 0x5537, //CJK UNIFIED IDEOGRAPH + 0xADF3: 0x54FC, //CJK UNIFIED IDEOGRAPH + 0xADF4: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xADF5: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xADF6: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xADF7: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xADF8: 0x5514, //CJK UNIFIED IDEOGRAPH + 0xADF9: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0xADFA: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xADFB: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0xADFC: 0x5509, //CJK UNIFIED IDEOGRAPH + 0xADFD: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xADFE: 0x54EA, //CJK UNIFIED IDEOGRAPH + 0xAE40: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0xAE41: 0x5527, //CJK UNIFIED IDEOGRAPH + 0xAE42: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xAE43: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0xAE44: 0x550F, //CJK UNIFIED IDEOGRAPH + 0xAE45: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xAE46: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xAE47: 0x57C2, //CJK UNIFIED IDEOGRAPH + 0xAE48: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0xAE49: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xAE4A: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xAE4B: 0x5809, //CJK UNIFIED IDEOGRAPH + 0xAE4C: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xAE4D: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xAE4E: 0x5958, //CJK UNIFIED IDEOGRAPH + 0xAE4F: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xAE50: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xAE51: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xAE52: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xAE53: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xAE54: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0xAE55: 0x5A13, //CJK UNIFIED IDEOGRAPH + 0xAE56: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xAE57: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xAE58: 0x5A23, //CJK UNIFIED IDEOGRAPH + 0xAE59: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xAE5A: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xAE5B: 0x5A0C, //CJK UNIFIED IDEOGRAPH + 0xAE5C: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0xAE5D: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0xAE5E: 0x5C58, //CJK UNIFIED IDEOGRAPH + 0xAE5F: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xAE60: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xAE61: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xAE62: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xAE63: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0xAE64: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xAE65: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xAE66: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xAE67: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xAE68: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xAE69: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xAE6A: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0xAE6B: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0xAE6C: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0xAE6D: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xAE6E: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0xAE6F: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xAE70: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xAE71: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0xAE72: 0x5D01, //CJK UNIFIED IDEOGRAPH + 0xAE73: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0xAE74: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xAE75: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xAE76: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0xAE77: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0xAE78: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xAE79: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xAE7A: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xAE7B: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xAE7C: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0xAE7D: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xAE7E: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xAEA1: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xAEA2: 0x6065, //CJK UNIFIED IDEOGRAPH + 0xAEA3: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xAEA4: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xAEA5: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xAEA6: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xAEA7: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xAEA8: 0x6084, //CJK UNIFIED IDEOGRAPH + 0xAEA9: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xAEAA: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xAEAB: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xAEAC: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xAEAD: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xAEAE: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xAEAF: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xAEB0: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xAEB1: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xAEB2: 0x6308, //CJK UNIFIED IDEOGRAPH + 0xAEB3: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xAEB4: 0x634E, //CJK UNIFIED IDEOGRAPH + 0xAEB5: 0x633E, //CJK UNIFIED IDEOGRAPH + 0xAEB6: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xAEB7: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xAEB8: 0x6342, //CJK UNIFIED IDEOGRAPH + 0xAEB9: 0x6346, //CJK UNIFIED IDEOGRAPH + 0xAEBA: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xAEBB: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xAEBC: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xAEBD: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xAEBE: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xAEBF: 0x632A, //CJK UNIFIED IDEOGRAPH + 0xAEC0: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xAEC1: 0x6328, //CJK UNIFIED IDEOGRAPH + 0xAEC2: 0x634D, //CJK UNIFIED IDEOGRAPH + 0xAEC3: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xAEC4: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xAEC5: 0x6549, //CJK UNIFIED IDEOGRAPH + 0xAEC6: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xAEC7: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xAEC8: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xAEC9: 0x6642, //CJK UNIFIED IDEOGRAPH + 0xAECA: 0x6649, //CJK UNIFIED IDEOGRAPH + 0xAECB: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xAECC: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xAECD: 0x6652, //CJK UNIFIED IDEOGRAPH + 0xAECE: 0x664C, //CJK UNIFIED IDEOGRAPH + 0xAECF: 0x6645, //CJK UNIFIED IDEOGRAPH + 0xAED0: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xAED1: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0xAED2: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xAED3: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xAED4: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xAED5: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xAED6: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xAED7: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xAED8: 0x6846, //CJK UNIFIED IDEOGRAPH + 0xAED9: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xAEDA: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xAEDB: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xAEDC: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xAEDD: 0x6829, //CJK UNIFIED IDEOGRAPH + 0xAEDE: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xAEDF: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xAEE0: 0x684C, //CJK UNIFIED IDEOGRAPH + 0xAEE1: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xAEE2: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xAEE3: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xAEE4: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xAEE5: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xAEE6: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xAEE7: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xAEE8: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xAEE9: 0x6845, //CJK UNIFIED IDEOGRAPH + 0xAEEA: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xAEEB: 0x6818, //CJK UNIFIED IDEOGRAPH + 0xAEEC: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xAEED: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xAEEE: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xAEEF: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xAEF0: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0xAEF1: 0x6C27, //CJK UNIFIED IDEOGRAPH + 0xAEF2: 0x6C28, //CJK UNIFIED IDEOGRAPH + 0xAEF3: 0x6C26, //CJK UNIFIED IDEOGRAPH + 0xAEF4: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0xAEF5: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xAEF6: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xAEF7: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xAEF8: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xAEF9: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xAEFA: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xAEFB: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xAEFC: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xAEFD: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xAEFE: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xAF40: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0xAF41: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xAF42: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xAF43: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xAF44: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xAF45: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xAF46: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xAF47: 0x6D8A, //CJK UNIFIED IDEOGRAPH + 0xAF48: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0xAF49: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xAF4A: 0x6D65, //CJK UNIFIED IDEOGRAPH + 0xAF4B: 0x6D94, //CJK UNIFIED IDEOGRAPH + 0xAF4C: 0x70CA, //CJK UNIFIED IDEOGRAPH + 0xAF4D: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xAF4E: 0x70E4, //CJK UNIFIED IDEOGRAPH + 0xAF4F: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xAF50: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xAF51: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0xAF52: 0x7239, //CJK UNIFIED IDEOGRAPH + 0xAF53: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xAF54: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xAF55: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xAF56: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xAF57: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xAF58: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xAF59: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xAF5A: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xAF5B: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xAF5C: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xAF5D: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xAF5E: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xAF5F: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xAF60: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xAF61: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xAF62: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xAF63: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xAF64: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xAF65: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xAF66: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xAF67: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xAF68: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xAF69: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xAF6A: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xAF6B: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xAF6C: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xAF6D: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xAF6E: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xAF6F: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xAF70: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xAF71: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xAF72: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xAF73: 0x76CE, //CJK UNIFIED IDEOGRAPH + 0xAF74: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xAF75: 0x771F, //CJK UNIFIED IDEOGRAPH + 0xAF76: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xAF77: 0x7728, //CJK UNIFIED IDEOGRAPH + 0xAF78: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xAF79: 0x7830, //CJK UNIFIED IDEOGRAPH + 0xAF7A: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xAF7B: 0x7838, //CJK UNIFIED IDEOGRAPH + 0xAF7C: 0x781D, //CJK UNIFIED IDEOGRAPH + 0xAF7D: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xAF7E: 0x7837, //CJK UNIFIED IDEOGRAPH + 0xAFA1: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xAFA2: 0x782D, //CJK UNIFIED IDEOGRAPH + 0xAFA3: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xAFA4: 0x781F, //CJK UNIFIED IDEOGRAPH + 0xAFA5: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xAFA6: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xAFA7: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xAFA8: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xAFA9: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xAFAA: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xAFAB: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xAFAC: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xAFAD: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xAFAE: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xAFAF: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xAFB0: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xAFB1: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xAFB2: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xAFB3: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xAFB4: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xAFB5: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xAFB6: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xAFB7: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xAFB8: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xAFB9: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xAFBA: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xAFBB: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xAFBC: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xAFBD: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xAFBE: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xAFBF: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xAFC0: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xAFC1: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xAFC2: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xAFC3: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xAFC4: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xAFC5: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xAFC6: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xAFC7: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xAFC8: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xAFC9: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xAFCA: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xAFCB: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xAFCC: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xAFCD: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xAFCE: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xAFCF: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xAFD0: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xAFD1: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xAFD2: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xAFD3: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xAFD4: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xAFD5: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xAFD6: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xAFD7: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xAFD8: 0x80F0, //CJK UNIFIED IDEOGRAPH + 0xAFD9: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xAFDA: 0x80ED, //CJK UNIFIED IDEOGRAPH + 0xAFDB: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xAFDC: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xAFDD: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xAFDE: 0x80F3, //CJK UNIFIED IDEOGRAPH + 0xAFDF: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xAFE0: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xAFE1: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xAFE2: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xAFE3: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xAFE4: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xAFE5: 0x81EC, //CJK UNIFIED IDEOGRAPH + 0xAFE6: 0x8200, //CJK UNIFIED IDEOGRAPH + 0xAFE7: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xAFE8: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xAFE9: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xAFEA: 0x8228, //CJK UNIFIED IDEOGRAPH + 0xAFEB: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xAFEC: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xAFED: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xAFEE: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xAFEF: 0x8354, //CJK UNIFIED IDEOGRAPH + 0xAFF0: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xAFF1: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xAFF2: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xAFF3: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xAFF4: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xAFF5: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xAFF6: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xAFF7: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xAFF8: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xAFF9: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xAFFA: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xAFFB: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xAFFC: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xAFFD: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xAFFE: 0x8343, //CJK UNIFIED IDEOGRAPH + 0xB040: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xB041: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xB042: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xB043: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xB044: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xB045: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xB046: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xB047: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xB048: 0x869C, //CJK UNIFIED IDEOGRAPH + 0xB049: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xB04A: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xB04B: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xB04C: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xB04D: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xB04E: 0x8879, //CJK UNIFIED IDEOGRAPH + 0xB04F: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xB050: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xB051: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xB052: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xB053: 0x8A15, //CJK UNIFIED IDEOGRAPH + 0xB054: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xB055: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xB056: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xB057: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xB058: 0x8A0F, //CJK UNIFIED IDEOGRAPH + 0xB059: 0x8A11, //CJK UNIFIED IDEOGRAPH + 0xB05A: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xB05B: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xB05C: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xB05D: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xB05E: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xB05F: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xB060: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xB061: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xB062: 0x8ED4, //CJK UNIFIED IDEOGRAPH + 0xB063: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xB064: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xB065: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xB066: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xB067: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xB068: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xB069: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xB06A: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xB06B: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xB06C: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xB06D: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xB06E: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xB06F: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xB070: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xB071: 0x90DD, //CJK UNIFIED IDEOGRAPH + 0xB072: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xB073: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xB074: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xB075: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xB076: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xB077: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xB078: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xB079: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xB07A: 0x91D9, //CJK UNIFIED IDEOGRAPH + 0xB07B: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xB07C: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xB07D: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xB07E: 0x9661, //CJK UNIFIED IDEOGRAPH + 0xB0A1: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xB0A2: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xB0A3: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xB0A4: 0x9658, //CJK UNIFIED IDEOGRAPH + 0xB0A5: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xB0A6: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xB0A7: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xB0A8: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xB0A9: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xB0AA: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xB0AB: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xB0AC: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xB0AD: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xB0AE: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xB0AF: 0x507A, //CJK UNIFIED IDEOGRAPH + 0xB0B0: 0x507D, //CJK UNIFIED IDEOGRAPH + 0xB0B1: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xB0B2: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xB0B3: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xB0B4: 0x504C, //CJK UNIFIED IDEOGRAPH + 0xB0B5: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xB0B6: 0x5049, //CJK UNIFIED IDEOGRAPH + 0xB0B7: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xB0B8: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xB0B9: 0x504E, //CJK UNIFIED IDEOGRAPH + 0xB0BA: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xB0BB: 0x5075, //CJK UNIFIED IDEOGRAPH + 0xB0BC: 0x5074, //CJK UNIFIED IDEOGRAPH + 0xB0BD: 0x5077, //CJK UNIFIED IDEOGRAPH + 0xB0BE: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xB0BF: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xB0C0: 0x506F, //CJK UNIFIED IDEOGRAPH + 0xB0C1: 0x506D, //CJK UNIFIED IDEOGRAPH + 0xB0C2: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xB0C3: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xB0C4: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xB0C5: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xB0C6: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xB0C7: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xB0C8: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0xB0C9: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xB0CA: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0xB0CB: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xB0CC: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xB0CD: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xB0CE: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xB0CF: 0x5340, //CJK UNIFIED IDEOGRAPH + 0xB0D0: 0x533E, //CJK UNIFIED IDEOGRAPH + 0xB0D1: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0xB0D2: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xB0D3: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xB0D4: 0x556A, //CJK UNIFIED IDEOGRAPH + 0xB0D5: 0x5566, //CJK UNIFIED IDEOGRAPH + 0xB0D6: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xB0D7: 0x555E, //CJK UNIFIED IDEOGRAPH + 0xB0D8: 0x5561, //CJK UNIFIED IDEOGRAPH + 0xB0D9: 0x5543, //CJK UNIFIED IDEOGRAPH + 0xB0DA: 0x554A, //CJK UNIFIED IDEOGRAPH + 0xB0DB: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xB0DC: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xB0DD: 0x554F, //CJK UNIFIED IDEOGRAPH + 0xB0DE: 0x5555, //CJK UNIFIED IDEOGRAPH + 0xB0DF: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xB0E0: 0x5564, //CJK UNIFIED IDEOGRAPH + 0xB0E1: 0x5538, //CJK UNIFIED IDEOGRAPH + 0xB0E2: 0x552E, //CJK UNIFIED IDEOGRAPH + 0xB0E3: 0x555C, //CJK UNIFIED IDEOGRAPH + 0xB0E4: 0x552C, //CJK UNIFIED IDEOGRAPH + 0xB0E5: 0x5563, //CJK UNIFIED IDEOGRAPH + 0xB0E6: 0x5533, //CJK UNIFIED IDEOGRAPH + 0xB0E7: 0x5541, //CJK UNIFIED IDEOGRAPH + 0xB0E8: 0x5557, //CJK UNIFIED IDEOGRAPH + 0xB0E9: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xB0EA: 0x570B, //CJK UNIFIED IDEOGRAPH + 0xB0EB: 0x5709, //CJK UNIFIED IDEOGRAPH + 0xB0EC: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xB0ED: 0x5805, //CJK UNIFIED IDEOGRAPH + 0xB0EE: 0x580A, //CJK UNIFIED IDEOGRAPH + 0xB0EF: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xB0F0: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xB0F1: 0x57E4, //CJK UNIFIED IDEOGRAPH + 0xB0F2: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xB0F3: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xB0F4: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xB0F5: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0xB0F6: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xB0F7: 0x5920, //CJK UNIFIED IDEOGRAPH + 0xB0F8: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xB0F9: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xB0FA: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0xB0FB: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xB0FC: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0xB0FD: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0xB0FE: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0xB140: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xB141: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xB142: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xB143: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xB144: 0x5A4A, //CJK UNIFIED IDEOGRAPH + 0xB145: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xB146: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xB147: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xB148: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xB149: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xB14A: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xB14B: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xB14C: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xB14D: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0xB14E: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0xB14F: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xB150: 0x5C5C, //CJK UNIFIED IDEOGRAPH + 0xB151: 0x5C5D, //CJK UNIFIED IDEOGRAPH + 0xB152: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xB153: 0x5D06, //CJK UNIFIED IDEOGRAPH + 0xB154: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xB155: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0xB156: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xB157: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0xB158: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0xB159: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xB15A: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xB15B: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0xB15C: 0x5D24, //CJK UNIFIED IDEOGRAPH + 0xB15D: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xB15E: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0xB15F: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xB160: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xB161: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0xB162: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0xB163: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0xB164: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xB165: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xB166: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xB167: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xB168: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xB169: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0xB16A: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0xB16B: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xB16C: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xB16D: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xB16E: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0xB16F: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xB170: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xB171: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0xB172: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xB173: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xB174: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0xB175: 0x5F9C, //CJK UNIFIED IDEOGRAPH + 0xB176: 0x607F, //CJK UNIFIED IDEOGRAPH + 0xB177: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xB178: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xB179: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xB17A: 0x60A8, //CJK UNIFIED IDEOGRAPH + 0xB17B: 0x60CB, //CJK UNIFIED IDEOGRAPH + 0xB17C: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xB17D: 0x60E6, //CJK UNIFIED IDEOGRAPH + 0xB17E: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0xB1A1: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xB1A2: 0x60BB, //CJK UNIFIED IDEOGRAPH + 0xB1A3: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0xB1A4: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xB1A5: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xB1A6: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0xB1A7: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xB1A8: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0xB1A9: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xB1AA: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xB1AB: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xB1AC: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0xB1AD: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xB1AE: 0x621B, //CJK UNIFIED IDEOGRAPH + 0xB1AF: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xB1B0: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xB1B1: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xB1B2: 0x6372, //CJK UNIFIED IDEOGRAPH + 0xB1B3: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xB1B4: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xB1B5: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xB1B6: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xB1B7: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xB1B8: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xB1B9: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xB1BA: 0x6371, //CJK UNIFIED IDEOGRAPH + 0xB1BB: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xB1BC: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xB1BD: 0x6383, //CJK UNIFIED IDEOGRAPH + 0xB1BE: 0x639B, //CJK UNIFIED IDEOGRAPH + 0xB1BF: 0x636B, //CJK UNIFIED IDEOGRAPH + 0xB1C0: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xB1C1: 0x6384, //CJK UNIFIED IDEOGRAPH + 0xB1C2: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xB1C3: 0x6399, //CJK UNIFIED IDEOGRAPH + 0xB1C4: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0xB1C5: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0xB1C6: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xB1C7: 0x638F, //CJK UNIFIED IDEOGRAPH + 0xB1C8: 0x6380, //CJK UNIFIED IDEOGRAPH + 0xB1C9: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xB1CA: 0x6369, //CJK UNIFIED IDEOGRAPH + 0xB1CB: 0x6368, //CJK UNIFIED IDEOGRAPH + 0xB1CC: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xB1CD: 0x655D, //CJK UNIFIED IDEOGRAPH + 0xB1CE: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xB1CF: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xB1D0: 0x6559, //CJK UNIFIED IDEOGRAPH + 0xB1D1: 0x6557, //CJK UNIFIED IDEOGRAPH + 0xB1D2: 0x555F, //CJK UNIFIED IDEOGRAPH + 0xB1D3: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xB1D4: 0x6558, //CJK UNIFIED IDEOGRAPH + 0xB1D5: 0x6555, //CJK UNIFIED IDEOGRAPH + 0xB1D6: 0x6554, //CJK UNIFIED IDEOGRAPH + 0xB1D7: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xB1D8: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xB1D9: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0xB1DA: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xB1DB: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xB1DC: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xB1DD: 0x65CE, //CJK UNIFIED IDEOGRAPH + 0xB1DE: 0x665D, //CJK UNIFIED IDEOGRAPH + 0xB1DF: 0x665A, //CJK UNIFIED IDEOGRAPH + 0xB1E0: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xB1E1: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xB1E2: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xB1E3: 0x665E, //CJK UNIFIED IDEOGRAPH + 0xB1E4: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xB1E5: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0xB1E6: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xB1E7: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xB1E8: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xB1E9: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xB1EA: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xB1EB: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xB1EC: 0x687F, //CJK UNIFIED IDEOGRAPH + 0xB1ED: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xB1EE: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0xB1EF: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xB1F0: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xB1F1: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xB1F2: 0x6883, //CJK UNIFIED IDEOGRAPH + 0xB1F3: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0xB1F4: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xB1F5: 0x6886, //CJK UNIFIED IDEOGRAPH + 0xB1F6: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xB1F7: 0x6894, //CJK UNIFIED IDEOGRAPH + 0xB1F8: 0x689D, //CJK UNIFIED IDEOGRAPH + 0xB1F9: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xB1FA: 0x689F, //CJK UNIFIED IDEOGRAPH + 0xB1FB: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0xB1FC: 0x6882, //CJK UNIFIED IDEOGRAPH + 0xB1FD: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xB1FE: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0xB240: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xB241: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0xB242: 0x6C2B, //CJK UNIFIED IDEOGRAPH + 0xB243: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xB244: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0xB245: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xB246: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xB247: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xB248: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xB249: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0xB24A: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0xB24B: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xB24C: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0xB24D: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0xB24E: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xB24F: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xB250: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xB251: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xB252: 0x6DAE, //CJK UNIFIED IDEOGRAPH + 0xB253: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xB254: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xB255: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0xB256: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xB257: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0xB258: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xB259: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0xB25A: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xB25B: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xB25C: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0xB25D: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xB25E: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xB25F: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0xB260: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xB261: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xB262: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0xB263: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xB264: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xB265: 0x6DAA, //CJK UNIFIED IDEOGRAPH + 0xB266: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0xB267: 0x6DBF, //CJK UNIFIED IDEOGRAPH + 0xB268: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0xB269: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xB26A: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xB26B: 0x710A, //CJK UNIFIED IDEOGRAPH + 0xB26C: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xB26D: 0x70EF, //CJK UNIFIED IDEOGRAPH + 0xB26E: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xB26F: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xB270: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xB271: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xB272: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xB273: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xB274: 0x7313, //CJK UNIFIED IDEOGRAPH + 0xB275: 0x7319, //CJK UNIFIED IDEOGRAPH + 0xB276: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xB277: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xB278: 0x740A, //CJK UNIFIED IDEOGRAPH + 0xB279: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xB27A: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xB27B: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xB27C: 0x740D, //CJK UNIFIED IDEOGRAPH + 0xB27D: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xB27E: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0xB2A1: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xB2A2: 0x751C, //CJK UNIFIED IDEOGRAPH + 0xB2A3: 0x7522, //CJK UNIFIED IDEOGRAPH + 0xB2A4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xB2A5: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xB2A6: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xB2A7: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xB2A8: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xB2A9: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xB2AA: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xB2AB: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xB2AC: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xB2AD: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xB2AE: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xB2AF: 0x76D4, //CJK UNIFIED IDEOGRAPH + 0xB2B0: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xB2B1: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xB2B2: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xB2B3: 0x773E, //CJK UNIFIED IDEOGRAPH + 0xB2B4: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xB2B5: 0x7736, //CJK UNIFIED IDEOGRAPH + 0xB2B6: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xB2B7: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xB2B8: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xB2B9: 0x7843, //CJK UNIFIED IDEOGRAPH + 0xB2BA: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xB2BB: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xB2BC: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xB2BD: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xB2BE: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xB2BF: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xB2C0: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xB2C1: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xB2C2: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xB2C3: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xB2C4: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xB2C5: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xB2C6: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xB2C7: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xB2C8: 0x7B2E, //CJK UNIFIED IDEOGRAPH + 0xB2C9: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xB2CA: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xB2CB: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xB2CC: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xB2CD: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xB2CE: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xB2CF: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xB2D0: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xB2D1: 0x7D3C, //CJK UNIFIED IDEOGRAPH + 0xB2D2: 0x7D40, //CJK UNIFIED IDEOGRAPH + 0xB2D3: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xB2D4: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xB2D5: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xB2D6: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xB2D7: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xB2D8: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xB2D9: 0x7D31, //CJK UNIFIED IDEOGRAPH + 0xB2DA: 0x7F3D, //CJK UNIFIED IDEOGRAPH + 0xB2DB: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xB2DC: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xB2DD: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xB2DE: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xB2DF: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xB2E0: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xB2E1: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xB2E2: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xB2E3: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xB2E4: 0x8116, //CJK UNIFIED IDEOGRAPH + 0xB2E5: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xB2E6: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xB2E7: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xB2E8: 0x8130, //CJK UNIFIED IDEOGRAPH + 0xB2E9: 0x8124, //CJK UNIFIED IDEOGRAPH + 0xB2EA: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xB2EB: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xB2EC: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xB2ED: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xB2EE: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xB2EF: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xB2F0: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xB2F1: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xB2F2: 0x8378, //CJK UNIFIED IDEOGRAPH + 0xB2F3: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xB2F4: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xB2F5: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xB2F6: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xB2F7: 0x8392, //CJK UNIFIED IDEOGRAPH + 0xB2F8: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xB2F9: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xB2FA: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xB2FB: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xB2FC: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xB2FD: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xB2FE: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xB340: 0x8386, //CJK UNIFIED IDEOGRAPH + 0xB341: 0x83A7, //CJK UNIFIED IDEOGRAPH + 0xB342: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xB343: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xB344: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xB345: 0x86C0, //CJK UNIFIED IDEOGRAPH + 0xB346: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xB347: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xB348: 0x86B5, //CJK UNIFIED IDEOGRAPH + 0xB349: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xB34A: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xB34B: 0x86B1, //CJK UNIFIED IDEOGRAPH + 0xB34C: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xB34D: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xB34E: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xB34F: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xB350: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xB351: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xB352: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xB353: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xB354: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xB355: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xB356: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xB357: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xB358: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xB359: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xB35A: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xB35B: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xB35C: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xB35D: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xB35E: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xB35F: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xB360: 0x8A22, //CJK UNIFIED IDEOGRAPH + 0xB361: 0x8C49, //CJK UNIFIED IDEOGRAPH + 0xB362: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xB363: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xB364: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xB365: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xB366: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xB367: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xB368: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xB369: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xB36A: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xB36B: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xB36C: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xB36D: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xB36E: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xB36F: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xB370: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xB371: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xB372: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xB373: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xB374: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xB375: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xB376: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xB377: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xB378: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xB379: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xB37A: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xB37B: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xB37C: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xB37D: 0x901B, //CJK UNIFIED IDEOGRAPH + 0xB37E: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xB3A1: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xB3A2: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xB3A3: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xB3A4: 0x9157, //CJK UNIFIED IDEOGRAPH + 0xB3A5: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xB3A6: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xB3A7: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0xB3A8: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xB3A9: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xB3AA: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xB3AB: 0x91E9, //CJK UNIFIED IDEOGRAPH + 0xB3AC: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xB3AD: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xB3AE: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xB3AF: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xB3B0: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xB3B1: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xB3B2: 0x9674, //CJK UNIFIED IDEOGRAPH + 0xB3B3: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xB3B4: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xB3B5: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xB3B6: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xB3B7: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xB3B8: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xB3B9: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xB3BA: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xB3BB: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xB3BC: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xB3BD: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xB3BE: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xB3BF: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xB3C0: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xB3C1: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xB3C2: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xB3C3: 0x50A2, //CJK UNIFIED IDEOGRAPH + 0xB3C4: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xB3C5: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xB3C6: 0x5099, //CJK UNIFIED IDEOGRAPH + 0xB3C7: 0x5091, //CJK UNIFIED IDEOGRAPH + 0xB3C8: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xB3C9: 0x5096, //CJK UNIFIED IDEOGRAPH + 0xB3CA: 0x5098, //CJK UNIFIED IDEOGRAPH + 0xB3CB: 0x509A, //CJK UNIFIED IDEOGRAPH + 0xB3CC: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xB3CD: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0xB3CE: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xB3CF: 0x5274, //CJK UNIFIED IDEOGRAPH + 0xB3D0: 0x5275, //CJK UNIFIED IDEOGRAPH + 0xB3D1: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xB3D2: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0xB3D3: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0xB3D4: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xB3D5: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xB3D6: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xB3D7: 0x557B, //CJK UNIFIED IDEOGRAPH + 0xB3D8: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xB3D9: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xB3DA: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xB3DB: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xB3DC: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xB3DD: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xB3DE: 0x5582, //CJK UNIFIED IDEOGRAPH + 0xB3DF: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xB3E0: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0xB3E1: 0x5594, //CJK UNIFIED IDEOGRAPH + 0xB3E2: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xB3E3: 0x558B, //CJK UNIFIED IDEOGRAPH + 0xB3E4: 0x5583, //CJK UNIFIED IDEOGRAPH + 0xB3E5: 0x55B3, //CJK UNIFIED IDEOGRAPH + 0xB3E6: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0xB3E7: 0x559F, //CJK UNIFIED IDEOGRAPH + 0xB3E8: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xB3E9: 0x55B2, //CJK UNIFIED IDEOGRAPH + 0xB3EA: 0x559A, //CJK UNIFIED IDEOGRAPH + 0xB3EB: 0x55BB, //CJK UNIFIED IDEOGRAPH + 0xB3EC: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0xB3ED: 0x55B1, //CJK UNIFIED IDEOGRAPH + 0xB3EE: 0x557E, //CJK UNIFIED IDEOGRAPH + 0xB3EF: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xB3F0: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0xB3F1: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xB3F2: 0x570D, //CJK UNIFIED IDEOGRAPH + 0xB3F3: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xB3F4: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xB3F5: 0x5834, //CJK UNIFIED IDEOGRAPH + 0xB3F6: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xB3F7: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xB3F8: 0x5831, //CJK UNIFIED IDEOGRAPH + 0xB3F9: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xB3FA: 0x581D, //CJK UNIFIED IDEOGRAPH + 0xB3FB: 0x5820, //CJK UNIFIED IDEOGRAPH + 0xB3FC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xB3FD: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0xB3FE: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xB440: 0x5A77, //CJK UNIFIED IDEOGRAPH + 0xB441: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xB442: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0xB443: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xB444: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xB445: 0x5AA7, //CJK UNIFIED IDEOGRAPH + 0xB446: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0xB447: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xB448: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xB449: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xB44A: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xB44B: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xB44C: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xB44D: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0xB44E: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xB44F: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xB450: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0xB451: 0x5D34, //CJK UNIFIED IDEOGRAPH + 0xB452: 0x5D47, //CJK UNIFIED IDEOGRAPH + 0xB453: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xB454: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xB455: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xB456: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0xB457: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0xB458: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0xB459: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xB45A: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0xB45B: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0xB45C: 0x5EC4, //CJK UNIFIED IDEOGRAPH + 0xB45D: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xB45E: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xB45F: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0xB460: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xB461: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xB462: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xB463: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0xB464: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xB465: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0xB466: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xB467: 0x611C, //CJK UNIFIED IDEOGRAPH + 0xB468: 0x6123, //CJK UNIFIED IDEOGRAPH + 0xB469: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xB46A: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xB46B: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xB46C: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0xB46D: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0xB46E: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xB46F: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0xB470: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xB471: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xB472: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xB473: 0x6100, //CJK UNIFIED IDEOGRAPH + 0xB474: 0x6112, //CJK UNIFIED IDEOGRAPH + 0xB475: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xB476: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xB477: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0xB478: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xB479: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xB47A: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0xB47B: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0xB47C: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0xB47D: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xB47E: 0x63CD, //CJK UNIFIED IDEOGRAPH + 0xB4A1: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0xB4A2: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0xB4A3: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xB4A4: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xB4A5: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xB4A6: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xB4A7: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0xB4A8: 0x6376, //CJK UNIFIED IDEOGRAPH + 0xB4A9: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xB4AA: 0x63EA, //CJK UNIFIED IDEOGRAPH + 0xB4AB: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0xB4AC: 0x6452, //CJK UNIFIED IDEOGRAPH + 0xB4AD: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0xB4AE: 0x63F9, //CJK UNIFIED IDEOGRAPH + 0xB4AF: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xB4B0: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xB4B1: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xB4B2: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xB4B3: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xB4B4: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xB4B5: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xB4B6: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xB4B7: 0x6670, //CJK UNIFIED IDEOGRAPH + 0xB4B8: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xB4B9: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xB4BA: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xB4BB: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xB4BC: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xB4BD: 0x667E, //CJK UNIFIED IDEOGRAPH + 0xB4BE: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xB4BF: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xB4C0: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xB4C1: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xB4C2: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xB4C3: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xB4C4: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xB4C5: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xB4C6: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xB4C7: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0xB4C8: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xB4C9: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0xB4CA: 0x68F5, //CJK UNIFIED IDEOGRAPH + 0xB4CB: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xB4CC: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0xB4CD: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xB4CE: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xB4CF: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0xB4D0: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0xB4D1: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xB4D2: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xB4D3: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xB4D4: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xB4D5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xB4D6: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xB4D7: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xB4D8: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xB4D9: 0x68FB, //CJK UNIFIED IDEOGRAPH + 0xB4DA: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xB4DB: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xB4DC: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0xB4DD: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0xB4DE: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xB4DF: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0xB4E0: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0xB4E1: 0x6C2E, //CJK UNIFIED IDEOGRAPH + 0xB4E2: 0x6C2F, //CJK UNIFIED IDEOGRAPH + 0xB4E3: 0x6C2C, //CJK UNIFIED IDEOGRAPH + 0xB4E4: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xB4E5: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xB4E6: 0x6E54, //CJK UNIFIED IDEOGRAPH + 0xB4E7: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xB4E8: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xB4E9: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0xB4EA: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0xB4EB: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xB4EC: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xB4ED: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xB4EE: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0xB4EF: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xB4F0: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xB4F1: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xB4F2: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xB4F3: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xB4F4: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xB4F5: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0xB4F6: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0xB4F7: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xB4F8: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xB4F9: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xB4FA: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0xB4FB: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xB4FC: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0xB4FD: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0xB4FE: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xB540: 0x6E89, //CJK UNIFIED IDEOGRAPH + 0xB541: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0xB542: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0xB543: 0x6E63, //CJK UNIFIED IDEOGRAPH + 0xB544: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xB545: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0xB546: 0x6E69, //CJK UNIFIED IDEOGRAPH + 0xB547: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xB548: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xB549: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xB54A: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xB54B: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xB54C: 0x7121, //CJK UNIFIED IDEOGRAPH + 0xB54D: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xB54E: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xB54F: 0x711C, //CJK UNIFIED IDEOGRAPH + 0xB550: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xB551: 0x7284, //CJK UNIFIED IDEOGRAPH + 0xB552: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xB553: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xB554: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xB555: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xB556: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xB557: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xB558: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xB559: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xB55A: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xB55B: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xB55C: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xB55D: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xB55E: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xB55F: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xB560: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xB561: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xB562: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xB563: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xB564: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xB565: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xB566: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xB567: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xB568: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xB569: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xB56A: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xB56B: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xB56C: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xB56D: 0x75E0, //CJK UNIFIED IDEOGRAPH + 0xB56E: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xB56F: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xB570: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xB571: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xB572: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xB573: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xB574: 0x774F, //CJK UNIFIED IDEOGRAPH + 0xB575: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xB576: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xB577: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xB578: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xB579: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xB57A: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xB57B: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xB57C: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xB57D: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xB57E: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xB5A1: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xB5A2: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xB5A3: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xB5A4: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xB5A5: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xB5A6: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xB5A7: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xB5A8: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xB5A9: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xB5AA: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xB5AB: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xB5AC: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xB5AD: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xB5AE: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xB5AF: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xB5B0: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xB5B1: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xB5B2: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xB5B3: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xB5B4: 0x7D55, //CJK UNIFIED IDEOGRAPH + 0xB5B5: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xB5B6: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xB5B7: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xB5B8: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xB5B9: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xB5BA: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xB5BB: 0x7D70, //CJK UNIFIED IDEOGRAPH + 0xB5BC: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xB5BD: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xB5BE: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xB5BF: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xB5C0: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xB5C1: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xB5C2: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xB5C3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xB5C4: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xB5C5: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xB5C6: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xB5C7: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xB5C8: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xB5C9: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xB5CA: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xB5CB: 0x814C, //CJK UNIFIED IDEOGRAPH + 0xB5CC: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xB5CD: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xB5CE: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xB5CF: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xB5D0: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xB5D1: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xB5D2: 0x83F8, //CJK UNIFIED IDEOGRAPH + 0xB5D3: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xB5D4: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xB5D5: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xB5D6: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xB5D7: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xB5D8: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xB5D9: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xB5DA: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xB5DB: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xB5DC: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xB5DD: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xB5DE: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xB5DF: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xB5E0: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xB5E1: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xB5E2: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xB5E3: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xB5E4: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xB5E5: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xB5E6: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xB5E7: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xB5E8: 0x83D4, //CJK UNIFIED IDEOGRAPH + 0xB5E9: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0xB5EA: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xB5EB: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xB5EC: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xB5ED: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xB5EE: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xB5EF: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xB5F0: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xB5F1: 0x86D0, //CJK UNIFIED IDEOGRAPH + 0xB5F2: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xB5F3: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xB5F4: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xB5F5: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xB5F6: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xB5F7: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xB5F8: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xB5F9: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xB5FA: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xB5FB: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xB5FC: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xB5FD: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0xB5FE: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xB640: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xB641: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xB642: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xB643: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xB644: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xB645: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xB646: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xB647: 0x8A56, //CJK UNIFIED IDEOGRAPH + 0xB648: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xB649: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xB64A: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xB64B: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xB64C: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xB64D: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xB64E: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xB64F: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xB650: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xB651: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xB652: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xB653: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xB654: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xB655: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xB656: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xB657: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xB658: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xB659: 0x8DCE, //CJK UNIFIED IDEOGRAPH + 0xB65A: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xB65B: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xB65C: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xB65D: 0x8DD1, //CJK UNIFIED IDEOGRAPH + 0xB65E: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xB65F: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xB660: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xB661: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xB662: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xB663: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xB664: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xB665: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xB666: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xB667: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xB668: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xB669: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xB66A: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xB66B: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xB66C: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xB66D: 0x9109, //CJK UNIFIED IDEOGRAPH + 0xB66E: 0x90FE, //CJK UNIFIED IDEOGRAPH + 0xB66F: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xB670: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xB671: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xB672: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xB673: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xB674: 0x9223, //CJK UNIFIED IDEOGRAPH + 0xB675: 0x9209, //CJK UNIFIED IDEOGRAPH + 0xB676: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xB677: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xB678: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xB679: 0x9207, //CJK UNIFIED IDEOGRAPH + 0xB67A: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xB67B: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xB67C: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xB67D: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xB67E: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xB6A1: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xB6A2: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xB6A3: 0x958E, //CJK UNIFIED IDEOGRAPH + 0xB6A4: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xB6A5: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xB6A6: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xB6A7: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xB6A8: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xB6A9: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xB6AA: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xB6AB: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xB6AC: 0x9684, //CJK UNIFIED IDEOGRAPH + 0xB6AD: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xB6AE: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xB6AF: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xB6B0: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xB6B1: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xB6B2: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xB6B3: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xB6B4: 0x97CC, //CJK UNIFIED IDEOGRAPH + 0xB6B5: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xB6B6: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xB6B7: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xB6B8: 0x98E7, //CJK UNIFIED IDEOGRAPH + 0xB6B9: 0x98EA, //CJK UNIFIED IDEOGRAPH + 0xB6BA: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xB6BB: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xB6BC: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0xB6BD: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xB6BE: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xB6BF: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xB6C0: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xB6C1: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xB6C2: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xB6C3: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0xB6C4: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0xB6C5: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0xB6C6: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xB6C7: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0xB6C8: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0xB6C9: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0xB6CA: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xB6CB: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0xB6CC: 0x50BB, //CJK UNIFIED IDEOGRAPH + 0xB6CD: 0x50AF, //CJK UNIFIED IDEOGRAPH + 0xB6CE: 0x50C7, //CJK UNIFIED IDEOGRAPH + 0xB6CF: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xB6D0: 0x5277, //CJK UNIFIED IDEOGRAPH + 0xB6D1: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xB6D2: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xB6D3: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0xB6D4: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xB6D5: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0xB6D6: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0xB6D7: 0x532F, //CJK UNIFIED IDEOGRAPH + 0xB6D8: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xB6D9: 0x55E8, //CJK UNIFIED IDEOGRAPH + 0xB6DA: 0x55D3, //CJK UNIFIED IDEOGRAPH + 0xB6DB: 0x55E6, //CJK UNIFIED IDEOGRAPH + 0xB6DC: 0x55CE, //CJK UNIFIED IDEOGRAPH + 0xB6DD: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xB6DE: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0xB6DF: 0x55D1, //CJK UNIFIED IDEOGRAPH + 0xB6E0: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xB6E1: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xB6E2: 0x55EF, //CJK UNIFIED IDEOGRAPH + 0xB6E3: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0xB6E4: 0x55E1, //CJK UNIFIED IDEOGRAPH + 0xB6E5: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xB6E6: 0x55C6, //CJK UNIFIED IDEOGRAPH + 0xB6E7: 0x55E5, //CJK UNIFIED IDEOGRAPH + 0xB6E8: 0x55C9, //CJK UNIFIED IDEOGRAPH + 0xB6E9: 0x5712, //CJK UNIFIED IDEOGRAPH + 0xB6EA: 0x5713, //CJK UNIFIED IDEOGRAPH + 0xB6EB: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xB6EC: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xB6ED: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xB6EE: 0x5857, //CJK UNIFIED IDEOGRAPH + 0xB6EF: 0x585A, //CJK UNIFIED IDEOGRAPH + 0xB6F0: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xB6F1: 0x586B, //CJK UNIFIED IDEOGRAPH + 0xB6F2: 0x584C, //CJK UNIFIED IDEOGRAPH + 0xB6F3: 0x586D, //CJK UNIFIED IDEOGRAPH + 0xB6F4: 0x584A, //CJK UNIFIED IDEOGRAPH + 0xB6F5: 0x5862, //CJK UNIFIED IDEOGRAPH + 0xB6F6: 0x5852, //CJK UNIFIED IDEOGRAPH + 0xB6F7: 0x584B, //CJK UNIFIED IDEOGRAPH + 0xB6F8: 0x5967, //CJK UNIFIED IDEOGRAPH + 0xB6F9: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xB6FA: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xB6FB: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xB6FC: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0xB6FD: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0xB6FE: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0xB740: 0x5AB3, //CJK UNIFIED IDEOGRAPH + 0xB741: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xB742: 0x5AB2, //CJK UNIFIED IDEOGRAPH + 0xB743: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xB744: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xB745: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xB746: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0xB747: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xB748: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0xB749: 0x5F12, //CJK UNIFIED IDEOGRAPH + 0xB74A: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0xB74B: 0x5FAC, //CJK UNIFIED IDEOGRAPH + 0xB74C: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xB74D: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xB74E: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xB74F: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xB750: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xB751: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xB752: 0x611B, //CJK UNIFIED IDEOGRAPH + 0xB753: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xB754: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xB755: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xB756: 0x614E, //CJK UNIFIED IDEOGRAPH + 0xB757: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xB758: 0x6144, //CJK UNIFIED IDEOGRAPH + 0xB759: 0x614D, //CJK UNIFIED IDEOGRAPH + 0xB75A: 0x613E, //CJK UNIFIED IDEOGRAPH + 0xB75B: 0x6134, //CJK UNIFIED IDEOGRAPH + 0xB75C: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xB75D: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xB75E: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xB75F: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xB760: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xB761: 0x6222, //CJK UNIFIED IDEOGRAPH + 0xB762: 0x6413, //CJK UNIFIED IDEOGRAPH + 0xB763: 0x643E, //CJK UNIFIED IDEOGRAPH + 0xB764: 0x641E, //CJK UNIFIED IDEOGRAPH + 0xB765: 0x642A, //CJK UNIFIED IDEOGRAPH + 0xB766: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xB767: 0x643D, //CJK UNIFIED IDEOGRAPH + 0xB768: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xB769: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xB76A: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xB76B: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xB76C: 0x640D, //CJK UNIFIED IDEOGRAPH + 0xB76D: 0x6436, //CJK UNIFIED IDEOGRAPH + 0xB76E: 0x6416, //CJK UNIFIED IDEOGRAPH + 0xB76F: 0x6417, //CJK UNIFIED IDEOGRAPH + 0xB770: 0x6406, //CJK UNIFIED IDEOGRAPH + 0xB771: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xB772: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xB773: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xB774: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xB775: 0x6689, //CJK UNIFIED IDEOGRAPH + 0xB776: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xB777: 0x6688, //CJK UNIFIED IDEOGRAPH + 0xB778: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xB779: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xB77A: 0x6698, //CJK UNIFIED IDEOGRAPH + 0xB77B: 0x668D, //CJK UNIFIED IDEOGRAPH + 0xB77C: 0x6703, //CJK UNIFIED IDEOGRAPH + 0xB77D: 0x6994, //CJK UNIFIED IDEOGRAPH + 0xB77E: 0x696D, //CJK UNIFIED IDEOGRAPH + 0xB7A1: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xB7A2: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xB7A3: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xB7A4: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xB7A5: 0x6975, //CJK UNIFIED IDEOGRAPH + 0xB7A6: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xB7A7: 0x6982, //CJK UNIFIED IDEOGRAPH + 0xB7A8: 0x694A, //CJK UNIFIED IDEOGRAPH + 0xB7A9: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xB7AA: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xB7AB: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xB7AC: 0x6953, //CJK UNIFIED IDEOGRAPH + 0xB7AD: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xB7AE: 0x6986, //CJK UNIFIED IDEOGRAPH + 0xB7AF: 0x695D, //CJK UNIFIED IDEOGRAPH + 0xB7B0: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xB7B1: 0x695B, //CJK UNIFIED IDEOGRAPH + 0xB7B2: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xB7B3: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0xB7B4: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0xB7B5: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xB7B6: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xB7B7: 0x6BFD, //CJK UNIFIED IDEOGRAPH + 0xB7B8: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xB7B9: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xB7BA: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xB7BB: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xB7BC: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xB7BD: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xB7BE: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0xB7BF: 0x6EC7, //CJK UNIFIED IDEOGRAPH + 0xB7C0: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0xB7C1: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xB7C2: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0xB7C3: 0x6EBC, //CJK UNIFIED IDEOGRAPH + 0xB7C4: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xB7C5: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0xB7C6: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xB7C7: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0xB7C8: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xB7C9: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0xB7CA: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xB7CB: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xB7CC: 0x6EA7, //CJK UNIFIED IDEOGRAPH + 0xB7CD: 0x6EB4, //CJK UNIFIED IDEOGRAPH + 0xB7CE: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xB7CF: 0x7159, //CJK UNIFIED IDEOGRAPH + 0xB7D0: 0x7169, //CJK UNIFIED IDEOGRAPH + 0xB7D1: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xB7D2: 0x7149, //CJK UNIFIED IDEOGRAPH + 0xB7D3: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xB7D4: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xB7D5: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xB7D6: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xB7D7: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xB7D8: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xB7D9: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xB7DA: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xB7DB: 0x7168, //CJK UNIFIED IDEOGRAPH + 0xB7DC: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xB7DD: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xB7DE: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xB7DF: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xB7E0: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xB7E1: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xB7E2: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xB7E3: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xB7E4: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xB7E5: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xB7E6: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xB7E7: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xB7E8: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xB7E9: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xB7EA: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xB7EB: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xB7EC: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xB7ED: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xB7EE: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xB7EF: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xB7F0: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xB7F1: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xB7F2: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xB7F3: 0x75F1, //CJK UNIFIED IDEOGRAPH + 0xB7F4: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xB7F5: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xB7F6: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xB7F7: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xB7F8: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xB7F9: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xB7FA: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xB7FB: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xB7FC: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xB7FD: 0x775E, //CJK UNIFIED IDEOGRAPH + 0xB7FE: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xB840: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xB841: 0x776A, //CJK UNIFIED IDEOGRAPH + 0xB842: 0x776C, //CJK UNIFIED IDEOGRAPH + 0xB843: 0x775C, //CJK UNIFIED IDEOGRAPH + 0xB844: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xB845: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xB846: 0x7762, //CJK UNIFIED IDEOGRAPH + 0xB847: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xB848: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xB849: 0x78B0, //CJK UNIFIED IDEOGRAPH + 0xB84A: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xB84B: 0x7898, //CJK UNIFIED IDEOGRAPH + 0xB84C: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xB84D: 0x7889, //CJK UNIFIED IDEOGRAPH + 0xB84E: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xB84F: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xB850: 0x7893, //CJK UNIFIED IDEOGRAPH + 0xB851: 0x787F, //CJK UNIFIED IDEOGRAPH + 0xB852: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xB853: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xB854: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xB855: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xB856: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xB857: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xB858: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xB859: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xB85A: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xB85B: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xB85C: 0x7A1E, //CJK UNIFIED IDEOGRAPH + 0xB85D: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xB85E: 0x7AA0, //CJK UNIFIED IDEOGRAPH + 0xB85F: 0x7B77, //CJK UNIFIED IDEOGRAPH + 0xB860: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xB861: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xB862: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xB863: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xB864: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xB865: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xB866: 0x7CB5, //CJK UNIFIED IDEOGRAPH + 0xB867: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xB868: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xB869: 0x7D91, //CJK UNIFIED IDEOGRAPH + 0xB86A: 0x7D81, //CJK UNIFIED IDEOGRAPH + 0xB86B: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xB86C: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xB86D: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xB86E: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xB86F: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xB870: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xB871: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xB872: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xB873: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xB874: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xB875: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xB876: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xB877: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xB878: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xB879: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xB87A: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xB87B: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xB87C: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xB87D: 0x8173, //CJK UNIFIED IDEOGRAPH + 0xB87E: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xB8A1: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xB8A2: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xB8A3: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xB8A4: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xB8A5: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xB8A6: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xB8A7: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xB8A8: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xB8A9: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xB8AA: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xB8AB: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xB8AC: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xB8AD: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xB8AE: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xB8AF: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xB8B0: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xB8B1: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xB8B2: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xB8B3: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xB8B4: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xB8B5: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xB8B6: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xB8B7: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xB8B8: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xB8B9: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xB8BA: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xB8BB: 0x8713, //CJK UNIFIED IDEOGRAPH + 0xB8BC: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xB8BD: 0x8707, //CJK UNIFIED IDEOGRAPH + 0xB8BE: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xB8BF: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xB8C0: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xB8C1: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xB8C2: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xB8C3: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xB8C4: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xB8C5: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xB8C6: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xB8C7: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xB8C8: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xB8C9: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xB8CA: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xB8CB: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xB8CC: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xB8CD: 0x88CA, //CJK UNIFIED IDEOGRAPH + 0xB8CE: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xB8CF: 0x88D2, //CJK UNIFIED IDEOGRAPH + 0xB8D0: 0x899C, //CJK UNIFIED IDEOGRAPH + 0xB8D1: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xB8D2: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0xB8D3: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xB8D4: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xB8D5: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xB8D6: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xB8D7: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0xB8D8: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xB8D9: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xB8DA: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xB8DB: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xB8DC: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xB8DD: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xB8DE: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xB8DF: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xB8E0: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xB8E1: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xB8E2: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xB8E3: 0x8A7B, //CJK UNIFIED IDEOGRAPH + 0xB8E4: 0x8A3E, //CJK UNIFIED IDEOGRAPH + 0xB8E5: 0x8A68, //CJK UNIFIED IDEOGRAPH + 0xB8E6: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xB8E7: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xB8E8: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xB8E9: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xB8EA: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xB8EB: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xB8EC: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xB8ED: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xB8EE: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xB8EF: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xB8F0: 0x8CC5, //CJK UNIFIED IDEOGRAPH + 0xB8F1: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xB8F2: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xB8F3: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xB8F4: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xB8F5: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xB8F6: 0x8DFA, //CJK UNIFIED IDEOGRAPH + 0xB8F7: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xB8F8: 0x8DE4, //CJK UNIFIED IDEOGRAPH + 0xB8F9: 0x8DE6, //CJK UNIFIED IDEOGRAPH + 0xB8FA: 0x8EB2, //CJK UNIFIED IDEOGRAPH + 0xB8FB: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xB8FC: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xB8FD: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xB8FE: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xB940: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xB941: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xB942: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xB943: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xB944: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xB945: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xB946: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xB947: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xB948: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xB949: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xB94A: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xB94B: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xB94C: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xB94D: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xB94E: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xB94F: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xB950: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xB951: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xB952: 0x9117, //CJK UNIFIED IDEOGRAPH + 0xB953: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xB954: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xB955: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xB956: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xB957: 0x9237, //CJK UNIFIED IDEOGRAPH + 0xB958: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xB959: 0x9238, //CJK UNIFIED IDEOGRAPH + 0xB95A: 0x923D, //CJK UNIFIED IDEOGRAPH + 0xB95B: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xB95C: 0x923E, //CJK UNIFIED IDEOGRAPH + 0xB95D: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xB95E: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xB95F: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xB960: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xB961: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xB962: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xB963: 0x924D, //CJK UNIFIED IDEOGRAPH + 0xB964: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xB965: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xB966: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xB967: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xB968: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xB969: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xB96A: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xB96B: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xB96C: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xB96D: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xB96E: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xB96F: 0x96CA, //CJK UNIFIED IDEOGRAPH + 0xB970: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xB971: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xB972: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xB973: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xB974: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xB975: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xB976: 0x9776, //CJK UNIFIED IDEOGRAPH + 0xB977: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xB978: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xB979: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xB97A: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xB97B: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xB97C: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xB97D: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xB97E: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xB9A1: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xB9A2: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xB9A3: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xB9A4: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xB9A5: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xB9A6: 0x9AE1, //CJK UNIFIED IDEOGRAPH + 0xB9A7: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xB9A8: 0x9E82, //CJK UNIFIED IDEOGRAPH + 0xB9A9: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xB9AA: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xB9AB: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xB9AC: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xB9AD: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0xB9AE: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0xB9AF: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xB9B0: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xB9B1: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xB9B2: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0xB9B3: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xB9B4: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0xB9B5: 0x50F1, //CJK UNIFIED IDEOGRAPH + 0xB9B6: 0x50CE, //CJK UNIFIED IDEOGRAPH + 0xB9B7: 0x50E9, //CJK UNIFIED IDEOGRAPH + 0xB9B8: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xB9B9: 0x51F3, //CJK UNIFIED IDEOGRAPH + 0xB9BA: 0x5283, //CJK UNIFIED IDEOGRAPH + 0xB9BB: 0x5282, //CJK UNIFIED IDEOGRAPH + 0xB9BC: 0x5331, //CJK UNIFIED IDEOGRAPH + 0xB9BD: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0xB9BE: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xB9BF: 0x5600, //CJK UNIFIED IDEOGRAPH + 0xB9C0: 0x561B, //CJK UNIFIED IDEOGRAPH + 0xB9C1: 0x5617, //CJK UNIFIED IDEOGRAPH + 0xB9C2: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xB9C3: 0x5614, //CJK UNIFIED IDEOGRAPH + 0xB9C4: 0x5606, //CJK UNIFIED IDEOGRAPH + 0xB9C5: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xB9C6: 0x560D, //CJK UNIFIED IDEOGRAPH + 0xB9C7: 0x560E, //CJK UNIFIED IDEOGRAPH + 0xB9C8: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0xB9C9: 0x5616, //CJK UNIFIED IDEOGRAPH + 0xB9CA: 0x561F, //CJK UNIFIED IDEOGRAPH + 0xB9CB: 0x5608, //CJK UNIFIED IDEOGRAPH + 0xB9CC: 0x5610, //CJK UNIFIED IDEOGRAPH + 0xB9CD: 0x55F6, //CJK UNIFIED IDEOGRAPH + 0xB9CE: 0x5718, //CJK UNIFIED IDEOGRAPH + 0xB9CF: 0x5716, //CJK UNIFIED IDEOGRAPH + 0xB9D0: 0x5875, //CJK UNIFIED IDEOGRAPH + 0xB9D1: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xB9D2: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xB9D3: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xB9D4: 0x588A, //CJK UNIFIED IDEOGRAPH + 0xB9D5: 0x5879, //CJK UNIFIED IDEOGRAPH + 0xB9D6: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xB9D7: 0x587D, //CJK UNIFIED IDEOGRAPH + 0xB9D8: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0xB9D9: 0x5925, //CJK UNIFIED IDEOGRAPH + 0xB9DA: 0x5922, //CJK UNIFIED IDEOGRAPH + 0xB9DB: 0x5924, //CJK UNIFIED IDEOGRAPH + 0xB9DC: 0x596A, //CJK UNIFIED IDEOGRAPH + 0xB9DD: 0x5969, //CJK UNIFIED IDEOGRAPH + 0xB9DE: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xB9DF: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xB9E0: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xB9E1: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0xB9E2: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0xB9E3: 0x5AD8, //CJK UNIFIED IDEOGRAPH + 0xB9E4: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0xB9E5: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xB9E6: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xB9E7: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0xB9E8: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xB9E9: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xB9EA: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0xB9EB: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xB9EC: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0xB9ED: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xB9EE: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xB9EF: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0xB9F0: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0xB9F1: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0xB9F2: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0xB9F3: 0x5E5B, //CJK UNIFIED IDEOGRAPH + 0xB9F4: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0xB9F5: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xB9F6: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0xB9F7: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0xB9F8: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xB9F9: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xB9FA: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xB9FB: 0x5F46, //CJK UNIFIED IDEOGRAPH + 0xB9FC: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xB9FD: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0xB9FE: 0x6147, //CJK UNIFIED IDEOGRAPH + 0xBA40: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xBA41: 0x614B, //CJK UNIFIED IDEOGRAPH + 0xBA42: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xBA43: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xBA44: 0x6163, //CJK UNIFIED IDEOGRAPH + 0xBA45: 0x615F, //CJK UNIFIED IDEOGRAPH + 0xBA46: 0x615A, //CJK UNIFIED IDEOGRAPH + 0xBA47: 0x6158, //CJK UNIFIED IDEOGRAPH + 0xBA48: 0x6175, //CJK UNIFIED IDEOGRAPH + 0xBA49: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xBA4A: 0x6487, //CJK UNIFIED IDEOGRAPH + 0xBA4B: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xBA4C: 0x6454, //CJK UNIFIED IDEOGRAPH + 0xBA4D: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xBA4E: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xBA4F: 0x645F, //CJK UNIFIED IDEOGRAPH + 0xBA50: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xBA51: 0x6451, //CJK UNIFIED IDEOGRAPH + 0xBA52: 0x6467, //CJK UNIFIED IDEOGRAPH + 0xBA53: 0x6434, //CJK UNIFIED IDEOGRAPH + 0xBA54: 0x646D, //CJK UNIFIED IDEOGRAPH + 0xBA55: 0x647B, //CJK UNIFIED IDEOGRAPH + 0xBA56: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xBA57: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xBA58: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xBA59: 0x65D6, //CJK UNIFIED IDEOGRAPH + 0xBA5A: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0xBA5B: 0x66A8, //CJK UNIFIED IDEOGRAPH + 0xBA5C: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xBA5D: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xBA5E: 0x69A8, //CJK UNIFIED IDEOGRAPH + 0xBA5F: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xBA60: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xBA61: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0xBA62: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0xBA63: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0xBA64: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xBA65: 0x69B7, //CJK UNIFIED IDEOGRAPH + 0xBA66: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xBA67: 0x69AB, //CJK UNIFIED IDEOGRAPH + 0xBA68: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xBA69: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xBA6A: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0xBA6B: 0x69AD, //CJK UNIFIED IDEOGRAPH + 0xBA6C: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xBA6D: 0x69A6, //CJK UNIFIED IDEOGRAPH + 0xBA6E: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0xBA6F: 0x69A3, //CJK UNIFIED IDEOGRAPH + 0xBA70: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0xBA71: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xBA72: 0x6C33, //CJK UNIFIED IDEOGRAPH + 0xBA73: 0x6F33, //CJK UNIFIED IDEOGRAPH + 0xBA74: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xBA75: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0xBA76: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xBA77: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xBA78: 0x6F29, //CJK UNIFIED IDEOGRAPH + 0xBA79: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xBA7A: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xBA7B: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0xBA7C: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xBA7D: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xBA7E: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0xBAA1: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0xBAA2: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0xBAA3: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xBAA4: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xBAA5: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0xBAA6: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0xBAA7: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0xBAA8: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xBAA9: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xBAAA: 0x6F2F, //CJK UNIFIED IDEOGRAPH + 0xBAAB: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xBAAC: 0x6F2A, //CJK UNIFIED IDEOGRAPH + 0xBAAD: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0xBAAE: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0xBAAF: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0xBAB0: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xBAB1: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0xBAB2: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xBAB3: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xBAB4: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xBAB5: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xBAB6: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xBAB7: 0x7192, //CJK UNIFIED IDEOGRAPH + 0xBAB8: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xBAB9: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xBABA: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xBABB: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xBABC: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xBABD: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xBABE: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xBABF: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xBAC0: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xBAC1: 0x746D, //CJK UNIFIED IDEOGRAPH + 0xBAC2: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xBAC3: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xBAC4: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xBAC5: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xBAC6: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xBAC7: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xBAC8: 0x7613, //CJK UNIFIED IDEOGRAPH + 0xBAC9: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xBACA: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xBACB: 0x7784, //CJK UNIFIED IDEOGRAPH + 0xBACC: 0x777D, //CJK UNIFIED IDEOGRAPH + 0xBACD: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xBACE: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xBACF: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xBAD0: 0x789F, //CJK UNIFIED IDEOGRAPH + 0xBAD1: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xBAD2: 0x78B3, //CJK UNIFIED IDEOGRAPH + 0xBAD3: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xBAD4: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xBAD5: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xBAD6: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xBAD7: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xBAD8: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xBAD9: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xBADA: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xBADB: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xBADC: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xBADD: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xBADE: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xBADF: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xBAE0: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xBAE1: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xBAE2: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xBAE3: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xBAE4: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xBAE5: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xBAE6: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xBAE7: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xBAE8: 0x7B84, //CJK UNIFIED IDEOGRAPH + 0xBAE9: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xBAEA: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xBAEB: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xBAEC: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xBAED: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xBAEE: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xBAEF: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xBAF0: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xBAF1: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xBAF2: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xBAF3: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xBAF4: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xBAF5: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xBAF6: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xBAF7: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xBAF8: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xBAF9: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xBAFA: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xBAFB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xBAFC: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0xBAFD: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xBAFE: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xBB40: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xBB41: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xBB42: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xBB43: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xBB44: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xBB45: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xBB46: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xBB47: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xBB48: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xBB49: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xBB4A: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xBB4B: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xBB4C: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xBB4D: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xBB4E: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xBB4F: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xBB50: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xBB51: 0x8214, //CJK UNIFIED IDEOGRAPH + 0xBB52: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xBB53: 0x824B, //CJK UNIFIED IDEOGRAPH + 0xBB54: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xBB55: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xBB56: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xBB57: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xBB58: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xBB59: 0x849E, //CJK UNIFIED IDEOGRAPH + 0xBB5A: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xBB5B: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xBB5C: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xBB5D: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xBB5E: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xBB5F: 0x84D3, //CJK UNIFIED IDEOGRAPH + 0xBB60: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xBB61: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xBB62: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xBB63: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xBB64: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xBB65: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xBB66: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xBB67: 0x8722, //CJK UNIFIED IDEOGRAPH + 0xBB68: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xBB69: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xBB6A: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xBB6B: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xBB6C: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xBB6D: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xBB6E: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xBB6F: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xBB70: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xBB71: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xBB72: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xBB73: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xBB74: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xBB75: 0x891A, //CJK UNIFIED IDEOGRAPH + 0xBB76: 0x88EF, //CJK UNIFIED IDEOGRAPH + 0xBB77: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xBB78: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xBB79: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xBB7A: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xBB7B: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xBB7C: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xBB7D: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xBB7E: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xBBA1: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xBBA2: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xBBA3: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xBBA4: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xBBA5: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xBBA6: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xBBA7: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xBBA8: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xBBA9: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xBBAA: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xBBAB: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xBBAC: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xBBAD: 0x8CD2, //CJK UNIFIED IDEOGRAPH + 0xBBAE: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xBBAF: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xBBB0: 0x8D95, //CJK UNIFIED IDEOGRAPH + 0xBBB1: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xBBB2: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xBBB3: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xBBB4: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xBBB5: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xBBB6: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xBBB7: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xBBB8: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xBBB9: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xBBBA: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xBBBB: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xBBBC: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xBBBD: 0x9062, //CJK UNIFIED IDEOGRAPH + 0xBBBE: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xBBBF: 0x905B, //CJK UNIFIED IDEOGRAPH + 0xBBC0: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xBBC1: 0x9118, //CJK UNIFIED IDEOGRAPH + 0xBBC2: 0x911E, //CJK UNIFIED IDEOGRAPH + 0xBBC3: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xBBC4: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xBBC5: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xBBC6: 0x9174, //CJK UNIFIED IDEOGRAPH + 0xBBC7: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xBBC8: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xBBC9: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xBBCA: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xBBCB: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xBBCC: 0x927B, //CJK UNIFIED IDEOGRAPH + 0xBBCD: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xBBCE: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xBBCF: 0x92A8, //CJK UNIFIED IDEOGRAPH + 0xBBD0: 0x927C, //CJK UNIFIED IDEOGRAPH + 0xBBD1: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xBBD2: 0x95A1, //CJK UNIFIED IDEOGRAPH + 0xBBD3: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xBBD4: 0x95A9, //CJK UNIFIED IDEOGRAPH + 0xBBD5: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xBBD6: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xBBD7: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xBBD8: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xBBD9: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xBBDA: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xBBDB: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xBBDC: 0x96D2, //CJK UNIFIED IDEOGRAPH + 0xBBDD: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xBBDE: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xBBDF: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xBBE0: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xBBE1: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xBBE2: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xBBE3: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xBBE4: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xBBE5: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xBBE6: 0x9905, //CJK UNIFIED IDEOGRAPH + 0xBBE7: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xBBE8: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xBBE9: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xBBEA: 0x9AAF, //CJK UNIFIED IDEOGRAPH + 0xBBEB: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xBBEC: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xBBED: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xBBEE: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xBBEF: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xBBF0: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xBBF1: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xBBF2: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0xBBF3: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xBBF4: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xBBF5: 0x5104, //CJK UNIFIED IDEOGRAPH + 0xBBF6: 0x5100, //CJK UNIFIED IDEOGRAPH + 0xBBF7: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xBBF8: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0xBBF9: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0xBBFA: 0x5102, //CJK UNIFIED IDEOGRAPH + 0xBBFB: 0x5108, //CJK UNIFIED IDEOGRAPH + 0xBBFC: 0x5109, //CJK UNIFIED IDEOGRAPH + 0xBBFD: 0x5105, //CJK UNIFIED IDEOGRAPH + 0xBBFE: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xBC40: 0x5287, //CJK UNIFIED IDEOGRAPH + 0xBC41: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xBC42: 0x5289, //CJK UNIFIED IDEOGRAPH + 0xBC43: 0x528D, //CJK UNIFIED IDEOGRAPH + 0xBC44: 0x528A, //CJK UNIFIED IDEOGRAPH + 0xBC45: 0x52F0, //CJK UNIFIED IDEOGRAPH + 0xBC46: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xBC47: 0x562E, //CJK UNIFIED IDEOGRAPH + 0xBC48: 0x563B, //CJK UNIFIED IDEOGRAPH + 0xBC49: 0x5639, //CJK UNIFIED IDEOGRAPH + 0xBC4A: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xBC4B: 0x563F, //CJK UNIFIED IDEOGRAPH + 0xBC4C: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xBC4D: 0x5629, //CJK UNIFIED IDEOGRAPH + 0xBC4E: 0x5653, //CJK UNIFIED IDEOGRAPH + 0xBC4F: 0x564E, //CJK UNIFIED IDEOGRAPH + 0xBC50: 0x5657, //CJK UNIFIED IDEOGRAPH + 0xBC51: 0x5674, //CJK UNIFIED IDEOGRAPH + 0xBC52: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xBC53: 0x562F, //CJK UNIFIED IDEOGRAPH + 0xBC54: 0x5630, //CJK UNIFIED IDEOGRAPH + 0xBC55: 0x5880, //CJK UNIFIED IDEOGRAPH + 0xBC56: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xBC57: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xBC58: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0xBC59: 0x589C, //CJK UNIFIED IDEOGRAPH + 0xBC5A: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0xBC5B: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xBC5C: 0x58A6, //CJK UNIFIED IDEOGRAPH + 0xBC5D: 0x596D, //CJK UNIFIED IDEOGRAPH + 0xBC5E: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xBC5F: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0xBC60: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0xBC61: 0x5AF5, //CJK UNIFIED IDEOGRAPH + 0xBC62: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0xBC63: 0x5B08, //CJK UNIFIED IDEOGRAPH + 0xBC64: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xBC65: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xBC66: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0xBC67: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0xBC68: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0xBC69: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xBC6A: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xBC6B: 0x5D94, //CJK UNIFIED IDEOGRAPH + 0xBC6C: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xBC6D: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0xBC6E: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xBC6F: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0xBC70: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0xBC71: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0xBC72: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0xBC73: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0xBC74: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0xBC75: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0xBC76: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xBC77: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xBC78: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xBC79: 0x6176, //CJK UNIFIED IDEOGRAPH + 0xBC7A: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xBC7B: 0x616E, //CJK UNIFIED IDEOGRAPH + 0xBC7C: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xBC7D: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xBC7E: 0x6182, //CJK UNIFIED IDEOGRAPH + 0xBCA1: 0x617C, //CJK UNIFIED IDEOGRAPH + 0xBCA2: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xBCA3: 0x616B, //CJK UNIFIED IDEOGRAPH + 0xBCA4: 0x617E, //CJK UNIFIED IDEOGRAPH + 0xBCA5: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xBCA6: 0x6190, //CJK UNIFIED IDEOGRAPH + 0xBCA7: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0xBCA8: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xBCA9: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xBCAA: 0x619A, //CJK UNIFIED IDEOGRAPH + 0xBCAB: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0xBCAC: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xBCAD: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0xBCAE: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xBCAF: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xBCB0: 0x646F, //CJK UNIFIED IDEOGRAPH + 0xBCB1: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xBCB2: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xBCB3: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0xBCB4: 0x6488, //CJK UNIFIED IDEOGRAPH + 0xBCB5: 0x6490, //CJK UNIFIED IDEOGRAPH + 0xBCB6: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xBCB7: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0xBCB8: 0x6493, //CJK UNIFIED IDEOGRAPH + 0xBCB9: 0x6495, //CJK UNIFIED IDEOGRAPH + 0xBCBA: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0xBCBB: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xBCBC: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xBCBD: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xBCBE: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0xBCBF: 0x649A, //CJK UNIFIED IDEOGRAPH + 0xBCC0: 0x64AC, //CJK UNIFIED IDEOGRAPH + 0xBCC1: 0x6499, //CJK UNIFIED IDEOGRAPH + 0xBCC2: 0x64A2, //CJK UNIFIED IDEOGRAPH + 0xBCC3: 0x64B3, //CJK UNIFIED IDEOGRAPH + 0xBCC4: 0x6575, //CJK UNIFIED IDEOGRAPH + 0xBCC5: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xBCC6: 0x6578, //CJK UNIFIED IDEOGRAPH + 0xBCC7: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xBCC8: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0xBCC9: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xBCCA: 0x66B1, //CJK UNIFIED IDEOGRAPH + 0xBCCB: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0xBCCC: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xBCCD: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0xBCCE: 0x6A01, //CJK UNIFIED IDEOGRAPH + 0xBCCF: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0xBCD0: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0xBCD1: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xBCD2: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xBCD3: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0xBCD4: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xBCD5: 0x69F3, //CJK UNIFIED IDEOGRAPH + 0xBCD6: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0xBCD7: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0xBCD8: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0xBCD9: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0xBCDA: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0xBCDB: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0xBCDC: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0xBCDD: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xBCDE: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0xBCDF: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0xBCE0: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xBCE1: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xBCE2: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0xBCE3: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xBCE4: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0xBCE5: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0xBCE6: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xBCE7: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xBCE8: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xBCE9: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xBCEA: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xBCEB: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xBCEC: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0xBCED: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0xBCEE: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0xBCEF: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xBCF0: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0xBCF1: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0xBCF2: 0x6F60, //CJK UNIFIED IDEOGRAPH + 0xBCF3: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0xBCF4: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xBCF5: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xBCF6: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0xBCF7: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xBCF8: 0x7256, //CJK UNIFIED IDEOGRAPH + 0xBCF9: 0x729B, //CJK UNIFIED IDEOGRAPH + 0xBCFA: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xBCFB: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xBCFC: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xBCFD: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xBCFE: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xBD40: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xBD41: 0x7480, //CJK UNIFIED IDEOGRAPH + 0xBD42: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xBD43: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xBD44: 0x7629, //CJK UNIFIED IDEOGRAPH + 0xBD45: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xBD46: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xBD47: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xBD48: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xBD49: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xBD4A: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xBD4B: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xBD4C: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xBD4D: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xBD4E: 0x7787, //CJK UNIFIED IDEOGRAPH + 0xBD4F: 0x778C, //CJK UNIFIED IDEOGRAPH + 0xBD50: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xBD51: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xBD52: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xBD53: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xBD54: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xBD55: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xBD56: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xBD57: 0x78D5, //CJK UNIFIED IDEOGRAPH + 0xBD58: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xBD59: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xBD5A: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xBD5B: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xBD5C: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xBD5D: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xBD5E: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xBD5F: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xBD60: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xBD61: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xBD62: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xBD63: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xBD64: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xBD65: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xBD66: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xBD67: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xBD68: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xBD69: 0x7BA0, //CJK UNIFIED IDEOGRAPH + 0xBD6A: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xBD6B: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xBD6C: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xBD6D: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xBD6E: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xBD6F: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xBD70: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xBD71: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xBD72: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xBD73: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xBD74: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xBD75: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xBD76: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xBD77: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xBD78: 0x7D9E, //CJK UNIFIED IDEOGRAPH + 0xBD79: 0x7DD9, //CJK UNIFIED IDEOGRAPH + 0xBD7A: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xBD7B: 0x7DF9, //CJK UNIFIED IDEOGRAPH + 0xBD7C: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xBD7D: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xBD7E: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xBDA1: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xBDA2: 0x8026, //CJK UNIFIED IDEOGRAPH + 0xBDA3: 0x819B, //CJK UNIFIED IDEOGRAPH + 0xBDA4: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xBDA5: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xBDA6: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xBDA7: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xBDA8: 0x8198, //CJK UNIFIED IDEOGRAPH + 0xBDA9: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xBDAA: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xBDAB: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xBDAC: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xBDAD: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xBDAE: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xBDAF: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xBDB0: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xBDB1: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xBDB2: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xBDB3: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xBDB4: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xBDB5: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xBDB6: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xBDB7: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xBDB8: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xBDB9: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xBDBA: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xBDBB: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xBDBC: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xBDBD: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xBDBE: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xBDBF: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xBDC0: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xBDC1: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xBDC2: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xBDC3: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xBDC4: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xBDC5: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xBDC6: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xBDC7: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xBDC8: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xBDC9: 0x8915, //CJK UNIFIED IDEOGRAPH + 0xBDCA: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xBDCB: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xBDCC: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xBDCD: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xBDCE: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xBDCF: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xBDD0: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xBDD1: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xBDD2: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xBDD3: 0x8AC9, //CJK UNIFIED IDEOGRAPH + 0xBDD4: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xBDD5: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xBDD6: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xBDD7: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xBDD8: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xBDD9: 0x8AB6, //CJK UNIFIED IDEOGRAPH + 0xBDDA: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xBDDB: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xBDDC: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xBDDD: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xBDDE: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xBDDF: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xBDE0: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xBDE1: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xBDE2: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xBDE3: 0x8CEC, //CJK UNIFIED IDEOGRAPH + 0xBDE4: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xBDE5: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xBDE6: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xBDE7: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xBDE8: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xBDE9: 0x8CE1, //CJK UNIFIED IDEOGRAPH + 0xBDEA: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xBDEB: 0x8D9F, //CJK UNIFIED IDEOGRAPH + 0xBDEC: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xBDED: 0x8E2B, //CJK UNIFIED IDEOGRAPH + 0xBDEE: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xBDEF: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xBDF0: 0x8E22, //CJK UNIFIED IDEOGRAPH + 0xBDF1: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xBDF2: 0x8E29, //CJK UNIFIED IDEOGRAPH + 0xBDF3: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xBDF4: 0x8E21, //CJK UNIFIED IDEOGRAPH + 0xBDF5: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xBDF6: 0x8EBA, //CJK UNIFIED IDEOGRAPH + 0xBDF7: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xBDF8: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xBDF9: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xBDFA: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xBDFB: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xBDFC: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xBDFD: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xBDFE: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xBE40: 0x8F25, //CJK UNIFIED IDEOGRAPH + 0xBE41: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xBE42: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xBE43: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xBE44: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xBE45: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xBE46: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xBE47: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xBE48: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xBE49: 0x9131, //CJK UNIFIED IDEOGRAPH + 0xBE4A: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xBE4B: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xBE4C: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xBE4D: 0x9183, //CJK UNIFIED IDEOGRAPH + 0xBE4E: 0x92C5, //CJK UNIFIED IDEOGRAPH + 0xBE4F: 0x92BB, //CJK UNIFIED IDEOGRAPH + 0xBE50: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xBE51: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xBE52: 0x92AC, //CJK UNIFIED IDEOGRAPH + 0xBE53: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xBE54: 0x92C1, //CJK UNIFIED IDEOGRAPH + 0xBE55: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xBE56: 0x92BC, //CJK UNIFIED IDEOGRAPH + 0xBE57: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xBE58: 0x92C7, //CJK UNIFIED IDEOGRAPH + 0xBE59: 0x92F0, //CJK UNIFIED IDEOGRAPH + 0xBE5A: 0x92B2, //CJK UNIFIED IDEOGRAPH + 0xBE5B: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xBE5C: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xBE5D: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xBE5E: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xBE5F: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xBE60: 0x9709, //CJK UNIFIED IDEOGRAPH + 0xBE61: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xBE62: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xBE63: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xBE64: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xBE65: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xBE66: 0x982B, //CJK UNIFIED IDEOGRAPH + 0xBE67: 0x981C, //CJK UNIFIED IDEOGRAPH + 0xBE68: 0x98B3, //CJK UNIFIED IDEOGRAPH + 0xBE69: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xBE6A: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xBE6B: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xBE6C: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xBE6D: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xBE6E: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xBE6F: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xBE70: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xBE71: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xBE72: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xBE73: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xBE74: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xBE75: 0x9AB7, //CJK UNIFIED IDEOGRAPH + 0xBE76: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xBE77: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xBE78: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xBE79: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xBE7A: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xBE7B: 0x9B77, //CJK UNIFIED IDEOGRAPH + 0xBE7C: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xBE7D: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xBE7E: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xBEA1: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xBEA2: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xBEA3: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xBEA4: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xBEA5: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xBEA6: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xBEA7: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xBEA8: 0x5118, //CJK UNIFIED IDEOGRAPH + 0xBEA9: 0x5114, //CJK UNIFIED IDEOGRAPH + 0xBEAA: 0x5110, //CJK UNIFIED IDEOGRAPH + 0xBEAB: 0x5115, //CJK UNIFIED IDEOGRAPH + 0xBEAC: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xBEAD: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0xBEAE: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xBEAF: 0x5291, //CJK UNIFIED IDEOGRAPH + 0xBEB0: 0x5293, //CJK UNIFIED IDEOGRAPH + 0xBEB1: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0xBEB2: 0x5659, //CJK UNIFIED IDEOGRAPH + 0xBEB3: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xBEB4: 0x5679, //CJK UNIFIED IDEOGRAPH + 0xBEB5: 0x5669, //CJK UNIFIED IDEOGRAPH + 0xBEB6: 0x5664, //CJK UNIFIED IDEOGRAPH + 0xBEB7: 0x5678, //CJK UNIFIED IDEOGRAPH + 0xBEB8: 0x566A, //CJK UNIFIED IDEOGRAPH + 0xBEB9: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xBEBA: 0x5665, //CJK UNIFIED IDEOGRAPH + 0xBEBB: 0x5671, //CJK UNIFIED IDEOGRAPH + 0xBEBC: 0x566F, //CJK UNIFIED IDEOGRAPH + 0xBEBD: 0x566C, //CJK UNIFIED IDEOGRAPH + 0xBEBE: 0x5662, //CJK UNIFIED IDEOGRAPH + 0xBEBF: 0x5676, //CJK UNIFIED IDEOGRAPH + 0xBEC0: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xBEC1: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0xBEC2: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0xBEC3: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xBEC4: 0x596E, //CJK UNIFIED IDEOGRAPH + 0xBEC5: 0x5B1D, //CJK UNIFIED IDEOGRAPH + 0xBEC6: 0x5B34, //CJK UNIFIED IDEOGRAPH + 0xBEC7: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0xBEC8: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0xBEC9: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0xBECA: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0xBECB: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0xBECC: 0x6191, //CJK UNIFIED IDEOGRAPH + 0xBECD: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xBECE: 0x618A, //CJK UNIFIED IDEOGRAPH + 0xBECF: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0xBED0: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0xBED1: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xBED2: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xBED3: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xBED4: 0x6230, //CJK UNIFIED IDEOGRAPH + 0xBED5: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xBED6: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0xBED7: 0x64CB, //CJK UNIFIED IDEOGRAPH + 0xBED8: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0xBED9: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0xBEDA: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0xBEDB: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0xBEDC: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0xBEDD: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0xBEDE: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xBEDF: 0x64BF, //CJK UNIFIED IDEOGRAPH + 0xBEE0: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xBEE1: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0xBEE2: 0x64BE, //CJK UNIFIED IDEOGRAPH + 0xBEE3: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xBEE4: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0xBEE5: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0xBEE6: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xBEE7: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0xBEE8: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0xBEE9: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0xBEEA: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xBEEB: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0xBEEC: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0xBEED: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xBEEE: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xBEEF: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xBEF0: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0xBEF1: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xBEF2: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0xBEF3: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xBEF4: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0xBEF5: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0xBEF6: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xBEF7: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0xBEF8: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0xBEF9: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0xBEFA: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0xBEFB: 0x6C05, //CJK UNIFIED IDEOGRAPH + 0xBEFC: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xBEFD: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0xBEFE: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xBF40: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0xBF41: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xBF42: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0xBF43: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xBF44: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xBF45: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xBF46: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xBF47: 0x6FB6, //CJK UNIFIED IDEOGRAPH + 0xBF48: 0x6FA6, //CJK UNIFIED IDEOGRAPH + 0xBF49: 0x6FA0, //CJK UNIFIED IDEOGRAPH + 0xBF4A: 0x6FB4, //CJK UNIFIED IDEOGRAPH + 0xBF4B: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xBF4C: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xBF4D: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0xBF4E: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xBF4F: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0xBF50: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xBF51: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xBF52: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xBF53: 0x71D9, //CJK UNIFIED IDEOGRAPH + 0xBF54: 0x71DC, //CJK UNIFIED IDEOGRAPH + 0xBF55: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xBF56: 0x71C4, //CJK UNIFIED IDEOGRAPH + 0xBF57: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xBF58: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xBF59: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xBF5A: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xBF5B: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xBF5C: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xBF5D: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xBF5E: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xBF5F: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xBF60: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xBF61: 0x7638, //CJK UNIFIED IDEOGRAPH + 0xBF62: 0x763A, //CJK UNIFIED IDEOGRAPH + 0xBF63: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xBF64: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xBF65: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xBF66: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xBF67: 0x779F, //CJK UNIFIED IDEOGRAPH + 0xBF68: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xBF69: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xBF6A: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xBF6B: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xBF6C: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xBF6D: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xBF6E: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xBF6F: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xBF70: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xBF71: 0x7A4C, //CJK UNIFIED IDEOGRAPH + 0xBF72: 0x7A4B, //CJK UNIFIED IDEOGRAPH + 0xBF73: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xBF74: 0x7BD9, //CJK UNIFIED IDEOGRAPH + 0xBF75: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xBF76: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xBF77: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xBF78: 0x7BDB, //CJK UNIFIED IDEOGRAPH + 0xBF79: 0x7BE1, //CJK UNIFIED IDEOGRAPH + 0xBF7A: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xBF7B: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xBF7C: 0x7CD5, //CJK UNIFIED IDEOGRAPH + 0xBF7D: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xBF7E: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xBFA1: 0x7E11, //CJK UNIFIED IDEOGRAPH + 0xBFA2: 0x7E08, //CJK UNIFIED IDEOGRAPH + 0xBFA3: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xBFA4: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xBFA5: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xBFA6: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xBFA7: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xBFA8: 0x7E10, //CJK UNIFIED IDEOGRAPH + 0xBFA9: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xBFAA: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xBFAB: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xBFAC: 0x7FF1, //CJK UNIFIED IDEOGRAPH + 0xBFAD: 0x7FEE, //CJK UNIFIED IDEOGRAPH + 0xBFAE: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xBFAF: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xBFB0: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xBFB1: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xBFB2: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xBFB3: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xBFB4: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xBFB5: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xBFB6: 0x854A, //CJK UNIFIED IDEOGRAPH + 0xBFB7: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xBFB8: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xBFB9: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xBFBA: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xBFBB: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xBFBC: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xBFBD: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xBFBE: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xBFBF: 0x855E, //CJK UNIFIED IDEOGRAPH + 0xBFC0: 0x8783, //CJK UNIFIED IDEOGRAPH + 0xBFC1: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xBFC2: 0x879E, //CJK UNIFIED IDEOGRAPH + 0xBFC3: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xBFC4: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xBFC5: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xBFC6: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xBFC7: 0x8932, //CJK UNIFIED IDEOGRAPH + 0xBFC8: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xBFC9: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xBFCA: 0x8921, //CJK UNIFIED IDEOGRAPH + 0xBFCB: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xBFCC: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xBFCD: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xBFCE: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xBFCF: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xBFD0: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xBFD1: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xBFD2: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xBFD3: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xBFD4: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xBFD5: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xBFD6: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xBFD7: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xBFD8: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xBFD9: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xBFDA: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xBFDB: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xBFDC: 0x8AFC, //CJK UNIFIED IDEOGRAPH + 0xBFDD: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xBFDE: 0x8C6D, //CJK UNIFIED IDEOGRAPH + 0xBFDF: 0x8C93, //CJK UNIFIED IDEOGRAPH + 0xBFE0: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xBFE1: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xBFE2: 0x8E31, //CJK UNIFIED IDEOGRAPH + 0xBFE3: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xBFE4: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xBFE5: 0x8E39, //CJK UNIFIED IDEOGRAPH + 0xBFE6: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xBFE7: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xBFE8: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xBFE9: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xBFEA: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xBFEB: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xBFEC: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xBFED: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xBFEE: 0x9074, //CJK UNIFIED IDEOGRAPH + 0xBFEF: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xBFF0: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xBFF1: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xBFF2: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xBFF3: 0x9134, //CJK UNIFIED IDEOGRAPH + 0xBFF4: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xBFF5: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xBFF6: 0x9336, //CJK UNIFIED IDEOGRAPH + 0xBFF7: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xBFF8: 0x9333, //CJK UNIFIED IDEOGRAPH + 0xBFF9: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xBFFA: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xBFFB: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xBFFC: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xBFFD: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xBFFE: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xC040: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xC041: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xC042: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xC043: 0x9315, //CJK UNIFIED IDEOGRAPH + 0xC044: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xC045: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xC046: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xC047: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xC048: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xC049: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xC04A: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xC04B: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xC04C: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xC04D: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xC04E: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xC04F: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xC050: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xC051: 0x975B, //CJK UNIFIED IDEOGRAPH + 0xC052: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xC053: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xC054: 0x9798, //CJK UNIFIED IDEOGRAPH + 0xC055: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xC056: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xC057: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xC058: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xC059: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xC05A: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xC05B: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xC05C: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xC05D: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xC05E: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xC05F: 0x991B, //CJK UNIFIED IDEOGRAPH + 0xC060: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xC061: 0x991A, //CJK UNIFIED IDEOGRAPH + 0xC062: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xC063: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xC064: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xC065: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xC066: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xC067: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xC068: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0xC069: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xC06A: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xC06B: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xC06C: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xC06D: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xC06E: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xC06F: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xC070: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xC071: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xC072: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xC073: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xC074: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xC075: 0x512A, //CJK UNIFIED IDEOGRAPH + 0xC076: 0x511F, //CJK UNIFIED IDEOGRAPH + 0xC077: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xC078: 0x5132, //CJK UNIFIED IDEOGRAPH + 0xC079: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0xC07A: 0x568E, //CJK UNIFIED IDEOGRAPH + 0xC07B: 0x5680, //CJK UNIFIED IDEOGRAPH + 0xC07C: 0x5690, //CJK UNIFIED IDEOGRAPH + 0xC07D: 0x5685, //CJK UNIFIED IDEOGRAPH + 0xC07E: 0x5687, //CJK UNIFIED IDEOGRAPH + 0xC0A1: 0x568F, //CJK UNIFIED IDEOGRAPH + 0xC0A2: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xC0A3: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0xC0A4: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xC0A5: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0xC0A6: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0xC0A7: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0xC0A8: 0x5B24, //CJK UNIFIED IDEOGRAPH + 0xC0A9: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xC0AA: 0x5C37, //CJK UNIFIED IDEOGRAPH + 0xC0AB: 0x5C68, //CJK UNIFIED IDEOGRAPH + 0xC0AC: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0xC0AD: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0xC0AE: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0xC0AF: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xC0B0: 0x5E6B, //CJK UNIFIED IDEOGRAPH + 0xC0B1: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0xC0B2: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xC0B3: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0xC0B4: 0x61C2, //CJK UNIFIED IDEOGRAPH + 0xC0B5: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0xC0B6: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xC0B7: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xC0B8: 0x6232, //CJK UNIFIED IDEOGRAPH + 0xC0B9: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xC0BA: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xC0BB: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0xC0BC: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xC0BD: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0xC0BE: 0x64F0, //CJK UNIFIED IDEOGRAPH + 0xC0BF: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xC0C0: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0xC0C1: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0xC0C2: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xC0C3: 0x64ED, //CJK UNIFIED IDEOGRAPH + 0xC0C4: 0x6582, //CJK UNIFIED IDEOGRAPH + 0xC0C5: 0x6583, //CJK UNIFIED IDEOGRAPH + 0xC0C6: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xC0C7: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0xC0C8: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xC0C9: 0x6A94, //CJK UNIFIED IDEOGRAPH + 0xC0CA: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xC0CB: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0xC0CC: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0xC0CD: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0xC0CE: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0xC0CF: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xC0D0: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xC0D1: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0xC0D2: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0xC0D3: 0x6B5C, //CJK UNIFIED IDEOGRAPH + 0xC0D4: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0xC0D5: 0x6BDA, //CJK UNIFIED IDEOGRAPH + 0xC0D6: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0xC0D7: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0xC0D8: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xC0D9: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xC0DA: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xC0DB: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0xC0DC: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0xC0DD: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0xC0DE: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xC0DF: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0xC0E0: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xC0E1: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xC0E2: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0xC0E3: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xC0E4: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xC0E5: 0x6FF0, //CJK UNIFIED IDEOGRAPH + 0xC0E6: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xC0E7: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xC0E8: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xC0E9: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xC0EA: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xC0EB: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xC0EC: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xC0ED: 0x71F4, //CJK UNIFIED IDEOGRAPH + 0xC0EE: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xC0EF: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xC0F0: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xC0F1: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xC0F2: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xC0F3: 0x74A9, //CJK UNIFIED IDEOGRAPH + 0xC0F4: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xC0F5: 0x74A6, //CJK UNIFIED IDEOGRAPH + 0xC0F6: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xC0F7: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xC0F8: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xC0F9: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xC0FA: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xC0FB: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xC0FC: 0x77AA, //CJK UNIFIED IDEOGRAPH + 0xC0FD: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xC0FE: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xC140: 0x77A7, //CJK UNIFIED IDEOGRAPH + 0xC141: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xC142: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xC143: 0x78F7, //CJK UNIFIED IDEOGRAPH + 0xC144: 0x78FA, //CJK UNIFIED IDEOGRAPH + 0xC145: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xC146: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xC147: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xC148: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xC149: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xC14A: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xC14B: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xC14C: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xC14D: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xC14E: 0x7BFE, //CJK UNIFIED IDEOGRAPH + 0xC14F: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xC150: 0x7C0C, //CJK UNIFIED IDEOGRAPH + 0xC151: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xC152: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xC153: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xC154: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xC155: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xC156: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xC157: 0x7CD9, //CJK UNIFIED IDEOGRAPH + 0xC158: 0x7CDD, //CJK UNIFIED IDEOGRAPH + 0xC159: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xC15A: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xC15B: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xC15C: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xC15D: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xC15E: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xC15F: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xC160: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xC161: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xC162: 0x7E45, //CJK UNIFIED IDEOGRAPH + 0xC163: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xC164: 0x7E34, //CJK UNIFIED IDEOGRAPH + 0xC165: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xC166: 0x7E48, //CJK UNIFIED IDEOGRAPH + 0xC167: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xC168: 0x7E3F, //CJK UNIFIED IDEOGRAPH + 0xC169: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xC16A: 0x7F44, //CJK UNIFIED IDEOGRAPH + 0xC16B: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xC16C: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xC16D: 0x8071, //CJK UNIFIED IDEOGRAPH + 0xC16E: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xC16F: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xC170: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xC171: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xC172: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xC173: 0x81C3, //CJK UNIFIED IDEOGRAPH + 0xC174: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xC175: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xC176: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xC177: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xC178: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xC179: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xC17A: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xC17B: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xC17C: 0x8209, //CJK UNIFIED IDEOGRAPH + 0xC17D: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xC17E: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xC1A1: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xC1A2: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xC1A3: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xC1A4: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xC1A5: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xC1A6: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xC1A7: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xC1A8: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xC1A9: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xC1AA: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xC1AB: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xC1AC: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xC1AD: 0x87D1, //CJK UNIFIED IDEOGRAPH + 0xC1AE: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xC1AF: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xC1B0: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xC1B1: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xC1B2: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xC1B3: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xC1B4: 0x87C8, //CJK UNIFIED IDEOGRAPH + 0xC1B5: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xC1B6: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xC1B7: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xC1B8: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xC1B9: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xC1BA: 0x893D, //CJK UNIFIED IDEOGRAPH + 0xC1BB: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xC1BC: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xC1BD: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xC1BE: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xC1BF: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xC1C0: 0x8B0A, //CJK UNIFIED IDEOGRAPH + 0xC1C1: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xC1C2: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xC1C3: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xC1C4: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xC1C5: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xC1C6: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xC1C7: 0x8C73, //CJK UNIFIED IDEOGRAPH + 0xC1C8: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xC1C9: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xC1CA: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xC1CB: 0x8CF8, //CJK UNIFIED IDEOGRAPH + 0xC1CC: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xC1CD: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xC1CE: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xC1CF: 0x8E4B, //CJK UNIFIED IDEOGRAPH + 0xC1D0: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xC1D1: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xC1D2: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xC1D3: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xC1D4: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xC1D5: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xC1D6: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xC1D7: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xC1D8: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xC1D9: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xC1DA: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xC1DB: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xC1DC: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xC1DD: 0x9139, //CJK UNIFIED IDEOGRAPH + 0xC1DE: 0x91A3, //CJK UNIFIED IDEOGRAPH + 0xC1DF: 0x919E, //CJK UNIFIED IDEOGRAPH + 0xC1E0: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xC1E1: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xC1E2: 0x9382, //CJK UNIFIED IDEOGRAPH + 0xC1E3: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xC1E4: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xC1E5: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xC1E6: 0x9365, //CJK UNIFIED IDEOGRAPH + 0xC1E7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xC1E8: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xC1E9: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xC1EA: 0x936C, //CJK UNIFIED IDEOGRAPH + 0xC1EB: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xC1EC: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xC1ED: 0x935A, //CJK UNIFIED IDEOGRAPH + 0xC1EE: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xC1EF: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xC1F0: 0x95CB, //CJK UNIFIED IDEOGRAPH + 0xC1F1: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xC1F2: 0x95C8, //CJK UNIFIED IDEOGRAPH + 0xC1F3: 0x95C6, //CJK UNIFIED IDEOGRAPH + 0xC1F4: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xC1F5: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xC1F6: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xC1F7: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xC1F8: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xC1F9: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xC1FA: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xC1FB: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xC1FC: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xC1FD: 0x9935, //CJK UNIFIED IDEOGRAPH + 0xC1FE: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xC240: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xC241: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xC242: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xC243: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0xC244: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0xC245: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xC246: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xC247: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xC248: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xC249: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xC24A: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xC24B: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xC24C: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xC24D: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xC24E: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xC24F: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0xC250: 0x5695, //CJK UNIFIED IDEOGRAPH + 0xC251: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0xC252: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0xC253: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0xC254: 0x5B38, //CJK UNIFIED IDEOGRAPH + 0xC255: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0xC256: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0xC257: 0x6233, //CJK UNIFIED IDEOGRAPH + 0xC258: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0xC259: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0xC25A: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0xC25B: 0x6506, //CJK UNIFIED IDEOGRAPH + 0xC25C: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0xC25D: 0x64FB, //CJK UNIFIED IDEOGRAPH + 0xC25E: 0x64F7, //CJK UNIFIED IDEOGRAPH + 0xC25F: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0xC260: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xC261: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xC262: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0xC263: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0xC264: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0xC265: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0xC266: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0xC267: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0xC268: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0xC269: 0x6AAF, //CJK UNIFIED IDEOGRAPH + 0xC26A: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0xC26B: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0xC26C: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0xC26D: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xC26E: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xC26F: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xC270: 0x7006, //CJK UNIFIED IDEOGRAPH + 0xC271: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0xC272: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xC273: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xC274: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xC275: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xC276: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xC277: 0x71F8, //CJK UNIFIED IDEOGRAPH + 0xC278: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xC279: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xC27A: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xC27B: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xC27C: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xC27D: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xC27E: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xC2A1: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xC2A2: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xC2A3: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xC2A4: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xC2A5: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xC2A6: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xC2A7: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xC2A8: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xC2A9: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xC2AA: 0x7A60, //CJK UNIFIED IDEOGRAPH + 0xC2AB: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xC2AC: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xC2AD: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xC2AE: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xC2AF: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xC2B0: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xC2B1: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xC2B2: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xC2B3: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xC2B4: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xC2B5: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xC2B6: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xC2B7: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xC2B8: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xC2B9: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xC2BA: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xC2BB: 0x7F48, //CJK UNIFIED IDEOGRAPH + 0xC2BC: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xC2BD: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0xC2BE: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xC2BF: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xC2C0: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xC2C1: 0x81CF, //CJK UNIFIED IDEOGRAPH + 0xC2C2: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xC2C3: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xC2C4: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xC2C5: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xC2C6: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xC2C7: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xC2C8: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xC2C9: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xC2CA: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xC2CB: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xC2CC: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xC2CD: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xC2CE: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xC2CF: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xC2D0: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xC2D1: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xC2D2: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xC2D3: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xC2D4: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xC2D5: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xC2D6: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xC2D7: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xC2D8: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xC2D9: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xC2DA: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xC2DB: 0x8E66, //CJK UNIFIED IDEOGRAPH + 0xC2DC: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xC2DD: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xC2DE: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xC2DF: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xC2E0: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xC2E1: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xC2E2: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xC2E3: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xC2E4: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xC2E5: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xC2E6: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xC2E7: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xC2E8: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xC2E9: 0x938A, //CJK UNIFIED IDEOGRAPH + 0xC2EA: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xC2EB: 0x93A2, //CJK UNIFIED IDEOGRAPH + 0xC2EC: 0x93B3, //CJK UNIFIED IDEOGRAPH + 0xC2ED: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0xC2EE: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xC2EF: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xC2F0: 0x9398, //CJK UNIFIED IDEOGRAPH + 0xC2F1: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xC2F2: 0x9397, //CJK UNIFIED IDEOGRAPH + 0xC2F3: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xC2F4: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xC2F5: 0x95D0, //CJK UNIFIED IDEOGRAPH + 0xC2F6: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xC2F7: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xC2F8: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xC2F9: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xC2FA: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xC2FB: 0x96DE, //CJK UNIFIED IDEOGRAPH + 0xC2FC: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xC2FD: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xC2FE: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xC340: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xC341: 0x97F9, //CJK UNIFIED IDEOGRAPH + 0xC342: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xC343: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xC344: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xC345: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xC346: 0x9853, //CJK UNIFIED IDEOGRAPH + 0xC347: 0x98BA, //CJK UNIFIED IDEOGRAPH + 0xC348: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xC349: 0x993F, //CJK UNIFIED IDEOGRAPH + 0xC34A: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xC34B: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xC34C: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xC34D: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xC34E: 0x9AC1, //CJK UNIFIED IDEOGRAPH + 0xC34F: 0x9B03, //CJK UNIFIED IDEOGRAPH + 0xC350: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xC351: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xC352: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xC353: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xC354: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xC355: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xC356: 0x9BFD, //CJK UNIFIED IDEOGRAPH + 0xC357: 0x9BC8, //CJK UNIFIED IDEOGRAPH + 0xC358: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xC359: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xC35A: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xC35B: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xC35C: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xC35D: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xC35E: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xC35F: 0x5133, //CJK UNIFIED IDEOGRAPH + 0xC360: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0xC361: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0xC362: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0xC363: 0x58E2, //CJK UNIFIED IDEOGRAPH + 0xC364: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0xC365: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xC366: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0xC367: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0xC368: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0xC369: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0xC36A: 0x61F5, //CJK UNIFIED IDEOGRAPH + 0xC36B: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xC36C: 0x650F, //CJK UNIFIED IDEOGRAPH + 0xC36D: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0xC36E: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xC36F: 0x6AE5, //CJK UNIFIED IDEOGRAPH + 0xC370: 0x6ADD, //CJK UNIFIED IDEOGRAPH + 0xC371: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0xC372: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0xC373: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xC374: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xC375: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xC376: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xC377: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xC378: 0x7015, //CJK UNIFIED IDEOGRAPH + 0xC379: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xC37A: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xC37B: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xC37C: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xC37D: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xC37E: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xC3A1: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xC3A2: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xC3A3: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xC3A4: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xC3A5: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xC3A6: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xC3A7: 0x765F, //CJK UNIFIED IDEOGRAPH + 0xC3A8: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xC3A9: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xC3AA: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xC3AB: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xC3AC: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xC3AD: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xC3AE: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xC3AF: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xC3B0: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0xC3B1: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xC3B2: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xC3B3: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xC3B4: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xC3B5: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xC3B6: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xC3B7: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xC3B8: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xC3B9: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xC3BA: 0x7E73, //CJK UNIFIED IDEOGRAPH + 0xC3BB: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xC3BC: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xC3BD: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xC3BE: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xC3BF: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xC3C0: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xC3C1: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xC3C2: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xC3C3: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xC3C4: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xC3C5: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xC3C6: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xC3C7: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xC3C8: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xC3C9: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xC3CA: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xC3CB: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xC3CC: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xC3CD: 0x8956, //CJK UNIFIED IDEOGRAPH + 0xC3CE: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xC3CF: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xC3D0: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xC3D1: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xC3D2: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xC3D3: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xC3D4: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xC3D5: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xC3D6: 0x8B46, //CJK UNIFIED IDEOGRAPH + 0xC3D7: 0x8B59, //CJK UNIFIED IDEOGRAPH + 0xC3D8: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xC3D9: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xC3DA: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xC3DB: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xC3DC: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xC3DD: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xC3DE: 0x8E6C, //CJK UNIFIED IDEOGRAPH + 0xC3DF: 0x8E7A, //CJK UNIFIED IDEOGRAPH + 0xC3E0: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xC3E1: 0x8F54, //CJK UNIFIED IDEOGRAPH + 0xC3E2: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xC3E3: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xC3E4: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xC3E5: 0x908B, //CJK UNIFIED IDEOGRAPH + 0xC3E6: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xC3E7: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xC3E8: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xC3E9: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xC3EA: 0x93DF, //CJK UNIFIED IDEOGRAPH + 0xC3EB: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xC3EC: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xC3ED: 0x93DC, //CJK UNIFIED IDEOGRAPH + 0xC3EE: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xC3EF: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xC3F0: 0x93E2, //CJK UNIFIED IDEOGRAPH + 0xC3F1: 0x93CD, //CJK UNIFIED IDEOGRAPH + 0xC3F2: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xC3F3: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xC3F4: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xC3F5: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xC3F6: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xC3F7: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xC3F8: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xC3F9: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xC3FA: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xC3FB: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xC3FC: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xC3FD: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xC3FE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xC440: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xC441: 0x985B, //CJK UNIFIED IDEOGRAPH + 0xC442: 0x98BC, //CJK UNIFIED IDEOGRAPH + 0xC443: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xC444: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xC445: 0x9A16, //CJK UNIFIED IDEOGRAPH + 0xC446: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xC447: 0x9B0D, //CJK UNIFIED IDEOGRAPH + 0xC448: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xC449: 0x9BE7, //CJK UNIFIED IDEOGRAPH + 0xC44A: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xC44B: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0xC44C: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xC44D: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xC44E: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xC44F: 0x9D6A, //CJK UNIFIED IDEOGRAPH + 0xC450: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xC451: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xC452: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xC453: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xC454: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xC455: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0xC456: 0x56A8, //CJK UNIFIED IDEOGRAPH + 0xC457: 0x56B7, //CJK UNIFIED IDEOGRAPH + 0xC458: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0xC459: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0xC45A: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xC45B: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xC45C: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xC45D: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0xC45E: 0x5B7D, //CJK UNIFIED IDEOGRAPH + 0xC45F: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0xC460: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0xC461: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0xC462: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0xC463: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xC464: 0x6514, //CJK UNIFIED IDEOGRAPH + 0xC465: 0x6519, //CJK UNIFIED IDEOGRAPH + 0xC466: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xC467: 0x6727, //CJK UNIFIED IDEOGRAPH + 0xC468: 0x6AEC, //CJK UNIFIED IDEOGRAPH + 0xC469: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xC46A: 0x7030, //CJK UNIFIED IDEOGRAPH + 0xC46B: 0x7032, //CJK UNIFIED IDEOGRAPH + 0xC46C: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xC46D: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xC46E: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xC46F: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xC470: 0x7665, //CJK UNIFIED IDEOGRAPH + 0xC471: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xC472: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xC473: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xC474: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xC475: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xC476: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xC477: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xC478: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xC479: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xC47A: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xC47B: 0x7CF0, //CJK UNIFIED IDEOGRAPH + 0xC47C: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xC47D: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xC47E: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xC4A1: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xC4A2: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xC4A3: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xC4A4: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xC4A5: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xC4A6: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xC4A7: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xC4A8: 0x8611, //CJK UNIFIED IDEOGRAPH + 0xC4A9: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xC4AA: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xC4AB: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xC4AC: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xC4AD: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xC4AE: 0x8814, //CJK UNIFIED IDEOGRAPH + 0xC4AF: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xC4B0: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xC4B1: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xC4B2: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xC4B3: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xC4B4: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xC4B5: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xC4B6: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xC4B7: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xC4B8: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xC4B9: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xC4BA: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xC4BB: 0x8E89, //CJK UNIFIED IDEOGRAPH + 0xC4BC: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xC4BD: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xC4BE: 0x8E82, //CJK UNIFIED IDEOGRAPH + 0xC4BF: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xC4C0: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xC4C1: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xC4C2: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xC4C3: 0x93FD, //CJK UNIFIED IDEOGRAPH + 0xC4C4: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xC4C5: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xC4C6: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xC4C7: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xC4C8: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xC4C9: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xC4CA: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xC4CB: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xC4CC: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xC4CD: 0x9A35, //CJK UNIFIED IDEOGRAPH + 0xC4CE: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xC4CF: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xC4D0: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xC4D1: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xC4D2: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xC4D3: 0x9F2F, //CJK UNIFIED IDEOGRAPH + 0xC4D4: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xC4D5: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xC4D6: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xC4D7: 0x5137, //CJK UNIFIED IDEOGRAPH + 0xC4D8: 0x5138, //CJK UNIFIED IDEOGRAPH + 0xC4D9: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0xC4DA: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0xC4DB: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0xC4DC: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xC4DD: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0xC4DE: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xC4DF: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0xC4E0: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0xC4E1: 0x651D, //CJK UNIFIED IDEOGRAPH + 0xC4E2: 0x651C, //CJK UNIFIED IDEOGRAPH + 0xC4E3: 0x6595, //CJK UNIFIED IDEOGRAPH + 0xC4E4: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0xC4E5: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0xC4E6: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0xC4E7: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0xC4E8: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0xC4E9: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xC4EA: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xC4EB: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xC4EC: 0x74D6, //CJK UNIFIED IDEOGRAPH + 0xC4ED: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xC4EE: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xC4EF: 0x77D3, //CJK UNIFIED IDEOGRAPH + 0xC4F0: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xC4F1: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xC4F2: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xC4F3: 0x7FBC, //CJK UNIFIED IDEOGRAPH + 0xC4F4: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xC4F5: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xC4F6: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xC4F7: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xC4F8: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xC4F9: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xC4FA: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xC4FB: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xC4FC: 0x896C, //CJK UNIFIED IDEOGRAPH + 0xC4FD: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xC4FE: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xC540: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xC541: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xC542: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xC543: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xC544: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xC545: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xC546: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xC547: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xC548: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xC549: 0x942E, //CJK UNIFIED IDEOGRAPH + 0xC54A: 0x9433, //CJK UNIFIED IDEOGRAPH + 0xC54B: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xC54C: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xC54D: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xC54E: 0x9432, //CJK UNIFIED IDEOGRAPH + 0xC54F: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xC550: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xC551: 0x9738, //CJK UNIFIED IDEOGRAPH + 0xC552: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xC553: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xC554: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xC555: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xC556: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xC557: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xC558: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xC559: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xC55A: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xC55B: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xC55C: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xC55D: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xC55E: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xC55F: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0xC560: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xC561: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xC562: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xC563: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xC564: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xC565: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xC566: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xC567: 0x9F19, //CJK UNIFIED IDEOGRAPH + 0xC568: 0x9F5C, //CJK UNIFIED IDEOGRAPH + 0xC569: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xC56A: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xC56B: 0x513C, //CJK UNIFIED IDEOGRAPH + 0xC56C: 0x513B, //CJK UNIFIED IDEOGRAPH + 0xC56D: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0xC56E: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xC56F: 0x56C9, //CJK UNIFIED IDEOGRAPH + 0xC570: 0x5B7F, //CJK UNIFIED IDEOGRAPH + 0xC571: 0x5DD4, //CJK UNIFIED IDEOGRAPH + 0xC572: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0xC573: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0xC574: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xC575: 0x6524, //CJK UNIFIED IDEOGRAPH + 0xC576: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0xC577: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0xC578: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xC579: 0x7058, //CJK UNIFIED IDEOGRAPH + 0xC57A: 0x7380, //CJK UNIFIED IDEOGRAPH + 0xC57B: 0x74E4, //CJK UNIFIED IDEOGRAPH + 0xC57C: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xC57D: 0x766E, //CJK UNIFIED IDEOGRAPH + 0xC57E: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xC5A1: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xC5A2: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xC5A3: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xC5A4: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xC5A5: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xC5A6: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xC5A7: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xC5A8: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xC5A9: 0x89FC, //CJK UNIFIED IDEOGRAPH + 0xC5AA: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xC5AB: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xC5AC: 0x8D17, //CJK UNIFIED IDEOGRAPH + 0xC5AD: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xC5AE: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xC5AF: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0xC5B0: 0x9148, //CJK UNIFIED IDEOGRAPH + 0xC5B1: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xC5B2: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xC5B3: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xC5B4: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xC5B5: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xC5B6: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xC5B7: 0x97C1, //CJK UNIFIED IDEOGRAPH + 0xC5B8: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xC5B9: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xC5BA: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xC5BB: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xC5BC: 0x9AD2, //CJK UNIFIED IDEOGRAPH + 0xC5BD: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xC5BE: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xC5BF: 0x9C31, //CJK UNIFIED IDEOGRAPH + 0xC5C0: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xC5C1: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xC5C2: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xC5C3: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xC5C4: 0x9F34, //CJK UNIFIED IDEOGRAPH + 0xC5C5: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xC5C6: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xC5C7: 0x9F94, //CJK UNIFIED IDEOGRAPH + 0xC5C8: 0x56CC, //CJK UNIFIED IDEOGRAPH + 0xC5C9: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0xC5CA: 0x6200, //CJK UNIFIED IDEOGRAPH + 0xC5CB: 0x6523, //CJK UNIFIED IDEOGRAPH + 0xC5CC: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xC5CD: 0x652A, //CJK UNIFIED IDEOGRAPH + 0xC5CE: 0x66EC, //CJK UNIFIED IDEOGRAPH + 0xC5CF: 0x6B10, //CJK UNIFIED IDEOGRAPH + 0xC5D0: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xC5D1: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xC5D2: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xC5D3: 0x7C63, //CJK UNIFIED IDEOGRAPH + 0xC5D4: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xC5D5: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xC5D6: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xC5D7: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xC5D8: 0x81E2, //CJK UNIFIED IDEOGRAPH + 0xC5D9: 0x8638, //CJK UNIFIED IDEOGRAPH + 0xC5DA: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xC5DB: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xC5DC: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xC5DD: 0x9090, //CJK UNIFIED IDEOGRAPH + 0xC5DE: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xC5DF: 0x9463, //CJK UNIFIED IDEOGRAPH + 0xC5E0: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xC5E1: 0x9464, //CJK UNIFIED IDEOGRAPH + 0xC5E2: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xC5E3: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xC5E4: 0x995C, //CJK UNIFIED IDEOGRAPH + 0xC5E5: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xC5E6: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xC5E7: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xC5E8: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xC5E9: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xC5EA: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xC5EB: 0x9C54, //CJK UNIFIED IDEOGRAPH + 0xC5EC: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xC5ED: 0x9C56, //CJK UNIFIED IDEOGRAPH + 0xC5EE: 0x9DE5, //CJK UNIFIED IDEOGRAPH + 0xC5EF: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xC5F0: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xC5F1: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0xC5F2: 0x58E9, //CJK UNIFIED IDEOGRAPH + 0xC5F3: 0x652C, //CJK UNIFIED IDEOGRAPH + 0xC5F4: 0x705E, //CJK UNIFIED IDEOGRAPH + 0xC5F5: 0x7671, //CJK UNIFIED IDEOGRAPH + 0xC5F6: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xC5F7: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xC5F8: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xC5F9: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xC5FA: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xC5FB: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xC5FC: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xC5FD: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xC5FE: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xC640: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xC641: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xC642: 0x8D1B, //CJK UNIFIED IDEOGRAPH + 0xC643: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xC644: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xC645: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xC646: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xC647: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xC648: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xC649: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xC64A: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xC64B: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xC64C: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xC64D: 0x9C5F, //CJK UNIFIED IDEOGRAPH + 0xC64E: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xC64F: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xC650: 0x9E7C, //CJK UNIFIED IDEOGRAPH + 0xC651: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xC652: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xC653: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xC654: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xC655: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0xC656: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0xC657: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xC658: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xC659: 0x7C6E, //CJK UNIFIED IDEOGRAPH + 0xC65A: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xC65B: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xC65C: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xC65D: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xC65E: 0x9472, //CJK UNIFIED IDEOGRAPH + 0xC65F: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xC660: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xC661: 0x995E, //CJK UNIFIED IDEOGRAPH + 0xC662: 0x9AD6, //CJK UNIFIED IDEOGRAPH + 0xC663: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xC664: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xC665: 0x7064, //CJK UNIFIED IDEOGRAPH + 0xC666: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xC667: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xC668: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xC669: 0x97C9, //CJK UNIFIED IDEOGRAPH + 0xC66A: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xC66B: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xC66C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xC66D: 0x8B9C, //CJK UNIFIED IDEOGRAPH + 0xC66E: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xC66F: 0x91C5, //CJK UNIFIED IDEOGRAPH + 0xC670: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xC671: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xC672: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xC673: 0x9C77, //CJK UNIFIED IDEOGRAPH + 0xC674: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xC675: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xC676: 0x8C54, //CJK UNIFIED IDEOGRAPH + 0xC677: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xC678: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xC679: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xC67A: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xC67B: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xC67C: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xC67D: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xC67E: 0x7C72, //CJK UNIFIED IDEOGRAPH + 0xC940: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0xC941: 0x4E5C, //CJK UNIFIED IDEOGRAPH + 0xC942: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0xC943: 0x531A, //CJK UNIFIED IDEOGRAPH + 0xC944: 0x5382, //CJK UNIFIED IDEOGRAPH + 0xC945: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xC946: 0x4E0C, //CJK UNIFIED IDEOGRAPH + 0xC947: 0x4E47, //CJK UNIFIED IDEOGRAPH + 0xC948: 0x4E8D, //CJK UNIFIED IDEOGRAPH + 0xC949: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0xC94A: 0xFA0C, //CJK COMPATIBILITY IDEOGRAPH + 0xC94B: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0xC94C: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0xC94D: 0x4E0F, //CJK UNIFIED IDEOGRAPH + 0xC94E: 0x5187, //CJK UNIFIED IDEOGRAPH + 0xC94F: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0xC950: 0x4E2E, //CJK UNIFIED IDEOGRAPH + 0xC951: 0x4E93, //CJK UNIFIED IDEOGRAPH + 0xC952: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0xC953: 0x4EC9, //CJK UNIFIED IDEOGRAPH + 0xC954: 0x4EC8, //CJK UNIFIED IDEOGRAPH + 0xC955: 0x5198, //CJK UNIFIED IDEOGRAPH + 0xC956: 0x52FC, //CJK UNIFIED IDEOGRAPH + 0xC957: 0x536C, //CJK UNIFIED IDEOGRAPH + 0xC958: 0x53B9, //CJK UNIFIED IDEOGRAPH + 0xC959: 0x5720, //CJK UNIFIED IDEOGRAPH + 0xC95A: 0x5903, //CJK UNIFIED IDEOGRAPH + 0xC95B: 0x592C, //CJK UNIFIED IDEOGRAPH + 0xC95C: 0x5C10, //CJK UNIFIED IDEOGRAPH + 0xC95D: 0x5DFF, //CJK UNIFIED IDEOGRAPH + 0xC95E: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0xC95F: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0xC960: 0x6BCC, //CJK UNIFIED IDEOGRAPH + 0xC961: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0xC962: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xC963: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0xC964: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0xC965: 0x4EE8, //CJK UNIFIED IDEOGRAPH + 0xC966: 0x4EDC, //CJK UNIFIED IDEOGRAPH + 0xC967: 0x4EE9, //CJK UNIFIED IDEOGRAPH + 0xC968: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xC969: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xC96A: 0x4EDA, //CJK UNIFIED IDEOGRAPH + 0xC96B: 0x520C, //CJK UNIFIED IDEOGRAPH + 0xC96C: 0x531C, //CJK UNIFIED IDEOGRAPH + 0xC96D: 0x534C, //CJK UNIFIED IDEOGRAPH + 0xC96E: 0x5722, //CJK UNIFIED IDEOGRAPH + 0xC96F: 0x5723, //CJK UNIFIED IDEOGRAPH + 0xC970: 0x5917, //CJK UNIFIED IDEOGRAPH + 0xC971: 0x592F, //CJK UNIFIED IDEOGRAPH + 0xC972: 0x5B81, //CJK UNIFIED IDEOGRAPH + 0xC973: 0x5B84, //CJK UNIFIED IDEOGRAPH + 0xC974: 0x5C12, //CJK UNIFIED IDEOGRAPH + 0xC975: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xC976: 0x5C74, //CJK UNIFIED IDEOGRAPH + 0xC977: 0x5C73, //CJK UNIFIED IDEOGRAPH + 0xC978: 0x5E04, //CJK UNIFIED IDEOGRAPH + 0xC979: 0x5E80, //CJK UNIFIED IDEOGRAPH + 0xC97A: 0x5E82, //CJK UNIFIED IDEOGRAPH + 0xC97B: 0x5FC9, //CJK UNIFIED IDEOGRAPH + 0xC97C: 0x6209, //CJK UNIFIED IDEOGRAPH + 0xC97D: 0x6250, //CJK UNIFIED IDEOGRAPH + 0xC97E: 0x6C15, //CJK UNIFIED IDEOGRAPH + 0xC9A1: 0x6C36, //CJK UNIFIED IDEOGRAPH + 0xC9A2: 0x6C43, //CJK UNIFIED IDEOGRAPH + 0xC9A3: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xC9A4: 0x6C3B, //CJK UNIFIED IDEOGRAPH + 0xC9A5: 0x72AE, //CJK UNIFIED IDEOGRAPH + 0xC9A6: 0x72B0, //CJK UNIFIED IDEOGRAPH + 0xC9A7: 0x738A, //CJK UNIFIED IDEOGRAPH + 0xC9A8: 0x79B8, //CJK UNIFIED IDEOGRAPH + 0xC9A9: 0x808A, //CJK UNIFIED IDEOGRAPH + 0xC9AA: 0x961E, //CJK UNIFIED IDEOGRAPH + 0xC9AB: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xC9AC: 0x4F18, //CJK UNIFIED IDEOGRAPH + 0xC9AD: 0x4F2C, //CJK UNIFIED IDEOGRAPH + 0xC9AE: 0x4EF5, //CJK UNIFIED IDEOGRAPH + 0xC9AF: 0x4F14, //CJK UNIFIED IDEOGRAPH + 0xC9B0: 0x4EF1, //CJK UNIFIED IDEOGRAPH + 0xC9B1: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xC9B2: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xC9B3: 0x4F08, //CJK UNIFIED IDEOGRAPH + 0xC9B4: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0xC9B5: 0x4F02, //CJK UNIFIED IDEOGRAPH + 0xC9B6: 0x4F05, //CJK UNIFIED IDEOGRAPH + 0xC9B7: 0x4F22, //CJK UNIFIED IDEOGRAPH + 0xC9B8: 0x4F13, //CJK UNIFIED IDEOGRAPH + 0xC9B9: 0x4F04, //CJK UNIFIED IDEOGRAPH + 0xC9BA: 0x4EF4, //CJK UNIFIED IDEOGRAPH + 0xC9BB: 0x4F12, //CJK UNIFIED IDEOGRAPH + 0xC9BC: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0xC9BD: 0x5213, //CJK UNIFIED IDEOGRAPH + 0xC9BE: 0x5209, //CJK UNIFIED IDEOGRAPH + 0xC9BF: 0x5210, //CJK UNIFIED IDEOGRAPH + 0xC9C0: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xC9C1: 0x5322, //CJK UNIFIED IDEOGRAPH + 0xC9C2: 0x531F, //CJK UNIFIED IDEOGRAPH + 0xC9C3: 0x534D, //CJK UNIFIED IDEOGRAPH + 0xC9C4: 0x538A, //CJK UNIFIED IDEOGRAPH + 0xC9C5: 0x5407, //CJK UNIFIED IDEOGRAPH + 0xC9C6: 0x56E1, //CJK UNIFIED IDEOGRAPH + 0xC9C7: 0x56DF, //CJK UNIFIED IDEOGRAPH + 0xC9C8: 0x572E, //CJK UNIFIED IDEOGRAPH + 0xC9C9: 0x572A, //CJK UNIFIED IDEOGRAPH + 0xC9CA: 0x5734, //CJK UNIFIED IDEOGRAPH + 0xC9CB: 0x593C, //CJK UNIFIED IDEOGRAPH + 0xC9CC: 0x5980, //CJK UNIFIED IDEOGRAPH + 0xC9CD: 0x597C, //CJK UNIFIED IDEOGRAPH + 0xC9CE: 0x5985, //CJK UNIFIED IDEOGRAPH + 0xC9CF: 0x597B, //CJK UNIFIED IDEOGRAPH + 0xC9D0: 0x597E, //CJK UNIFIED IDEOGRAPH + 0xC9D1: 0x5977, //CJK UNIFIED IDEOGRAPH + 0xC9D2: 0x597F, //CJK UNIFIED IDEOGRAPH + 0xC9D3: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xC9D4: 0x5C15, //CJK UNIFIED IDEOGRAPH + 0xC9D5: 0x5C25, //CJK UNIFIED IDEOGRAPH + 0xC9D6: 0x5C7C, //CJK UNIFIED IDEOGRAPH + 0xC9D7: 0x5C7A, //CJK UNIFIED IDEOGRAPH + 0xC9D8: 0x5C7B, //CJK UNIFIED IDEOGRAPH + 0xC9D9: 0x5C7E, //CJK UNIFIED IDEOGRAPH + 0xC9DA: 0x5DDF, //CJK UNIFIED IDEOGRAPH + 0xC9DB: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0xC9DC: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xC9DD: 0x5F02, //CJK UNIFIED IDEOGRAPH + 0xC9DE: 0x5F1A, //CJK UNIFIED IDEOGRAPH + 0xC9DF: 0x5F74, //CJK UNIFIED IDEOGRAPH + 0xC9E0: 0x5FD5, //CJK UNIFIED IDEOGRAPH + 0xC9E1: 0x5FD4, //CJK UNIFIED IDEOGRAPH + 0xC9E2: 0x5FCF, //CJK UNIFIED IDEOGRAPH + 0xC9E3: 0x625C, //CJK UNIFIED IDEOGRAPH + 0xC9E4: 0x625E, //CJK UNIFIED IDEOGRAPH + 0xC9E5: 0x6264, //CJK UNIFIED IDEOGRAPH + 0xC9E6: 0x6261, //CJK UNIFIED IDEOGRAPH + 0xC9E7: 0x6266, //CJK UNIFIED IDEOGRAPH + 0xC9E8: 0x6262, //CJK UNIFIED IDEOGRAPH + 0xC9E9: 0x6259, //CJK UNIFIED IDEOGRAPH + 0xC9EA: 0x6260, //CJK UNIFIED IDEOGRAPH + 0xC9EB: 0x625A, //CJK UNIFIED IDEOGRAPH + 0xC9EC: 0x6265, //CJK UNIFIED IDEOGRAPH + 0xC9ED: 0x65EF, //CJK UNIFIED IDEOGRAPH + 0xC9EE: 0x65EE, //CJK UNIFIED IDEOGRAPH + 0xC9EF: 0x673E, //CJK UNIFIED IDEOGRAPH + 0xC9F0: 0x6739, //CJK UNIFIED IDEOGRAPH + 0xC9F1: 0x6738, //CJK UNIFIED IDEOGRAPH + 0xC9F2: 0x673B, //CJK UNIFIED IDEOGRAPH + 0xC9F3: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xC9F4: 0x673F, //CJK UNIFIED IDEOGRAPH + 0xC9F5: 0x673C, //CJK UNIFIED IDEOGRAPH + 0xC9F6: 0x6733, //CJK UNIFIED IDEOGRAPH + 0xC9F7: 0x6C18, //CJK UNIFIED IDEOGRAPH + 0xC9F8: 0x6C46, //CJK UNIFIED IDEOGRAPH + 0xC9F9: 0x6C52, //CJK UNIFIED IDEOGRAPH + 0xC9FA: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xC9FB: 0x6C4F, //CJK UNIFIED IDEOGRAPH + 0xC9FC: 0x6C4A, //CJK UNIFIED IDEOGRAPH + 0xC9FD: 0x6C54, //CJK UNIFIED IDEOGRAPH + 0xC9FE: 0x6C4B, //CJK UNIFIED IDEOGRAPH + 0xCA40: 0x6C4C, //CJK UNIFIED IDEOGRAPH + 0xCA41: 0x7071, //CJK UNIFIED IDEOGRAPH + 0xCA42: 0x725E, //CJK UNIFIED IDEOGRAPH + 0xCA43: 0x72B4, //CJK UNIFIED IDEOGRAPH + 0xCA44: 0x72B5, //CJK UNIFIED IDEOGRAPH + 0xCA45: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xCA46: 0x752A, //CJK UNIFIED IDEOGRAPH + 0xCA47: 0x767F, //CJK UNIFIED IDEOGRAPH + 0xCA48: 0x7A75, //CJK UNIFIED IDEOGRAPH + 0xCA49: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xCA4A: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xCA4B: 0x827C, //CJK UNIFIED IDEOGRAPH + 0xCA4C: 0x8280, //CJK UNIFIED IDEOGRAPH + 0xCA4D: 0x827D, //CJK UNIFIED IDEOGRAPH + 0xCA4E: 0x827F, //CJK UNIFIED IDEOGRAPH + 0xCA4F: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xCA50: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xCA51: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xCA52: 0x9097, //CJK UNIFIED IDEOGRAPH + 0xCA53: 0x9098, //CJK UNIFIED IDEOGRAPH + 0xCA54: 0x909B, //CJK UNIFIED IDEOGRAPH + 0xCA55: 0x9094, //CJK UNIFIED IDEOGRAPH + 0xCA56: 0x9622, //CJK UNIFIED IDEOGRAPH + 0xCA57: 0x9624, //CJK UNIFIED IDEOGRAPH + 0xCA58: 0x9620, //CJK UNIFIED IDEOGRAPH + 0xCA59: 0x9623, //CJK UNIFIED IDEOGRAPH + 0xCA5A: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xCA5B: 0x4F3B, //CJK UNIFIED IDEOGRAPH + 0xCA5C: 0x4F62, //CJK UNIFIED IDEOGRAPH + 0xCA5D: 0x4F49, //CJK UNIFIED IDEOGRAPH + 0xCA5E: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0xCA5F: 0x4F64, //CJK UNIFIED IDEOGRAPH + 0xCA60: 0x4F3E, //CJK UNIFIED IDEOGRAPH + 0xCA61: 0x4F67, //CJK UNIFIED IDEOGRAPH + 0xCA62: 0x4F52, //CJK UNIFIED IDEOGRAPH + 0xCA63: 0x4F5F, //CJK UNIFIED IDEOGRAPH + 0xCA64: 0x4F41, //CJK UNIFIED IDEOGRAPH + 0xCA65: 0x4F58, //CJK UNIFIED IDEOGRAPH + 0xCA66: 0x4F2D, //CJK UNIFIED IDEOGRAPH + 0xCA67: 0x4F33, //CJK UNIFIED IDEOGRAPH + 0xCA68: 0x4F3F, //CJK UNIFIED IDEOGRAPH + 0xCA69: 0x4F61, //CJK UNIFIED IDEOGRAPH + 0xCA6A: 0x518F, //CJK UNIFIED IDEOGRAPH + 0xCA6B: 0x51B9, //CJK UNIFIED IDEOGRAPH + 0xCA6C: 0x521C, //CJK UNIFIED IDEOGRAPH + 0xCA6D: 0x521E, //CJK UNIFIED IDEOGRAPH + 0xCA6E: 0x5221, //CJK UNIFIED IDEOGRAPH + 0xCA6F: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0xCA70: 0x52AE, //CJK UNIFIED IDEOGRAPH + 0xCA71: 0x5309, //CJK UNIFIED IDEOGRAPH + 0xCA72: 0x5363, //CJK UNIFIED IDEOGRAPH + 0xCA73: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xCA74: 0x538E, //CJK UNIFIED IDEOGRAPH + 0xCA75: 0x538F, //CJK UNIFIED IDEOGRAPH + 0xCA76: 0x5430, //CJK UNIFIED IDEOGRAPH + 0xCA77: 0x5437, //CJK UNIFIED IDEOGRAPH + 0xCA78: 0x542A, //CJK UNIFIED IDEOGRAPH + 0xCA79: 0x5454, //CJK UNIFIED IDEOGRAPH + 0xCA7A: 0x5445, //CJK UNIFIED IDEOGRAPH + 0xCA7B: 0x5419, //CJK UNIFIED IDEOGRAPH + 0xCA7C: 0x541C, //CJK UNIFIED IDEOGRAPH + 0xCA7D: 0x5425, //CJK UNIFIED IDEOGRAPH + 0xCA7E: 0x5418, //CJK UNIFIED IDEOGRAPH + 0xCAA1: 0x543D, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x544F, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5441, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x5428, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x5424, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x5447, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x56E7, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x56E5, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x5741, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x5745, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x574C, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x5749, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x574B, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x5752, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x5906, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x5940, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x59A6, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x5998, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x59A0, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x598E, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x59A2, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x5990, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x598F, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x59A7, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x59A1, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x5B8E, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x5B92, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x5C2A, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x5C8D, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x5C8F, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x5C88, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x5C8B, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x5C89, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x5C92, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x5C8A, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x5C86, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x5C93, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x5C95, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x5DE0, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x5E0A, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x5E0E, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x5E8B, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x5E89, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x5E8C, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x5E88, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x5E8D, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x5F05, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x5F1D, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x5F78, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x5F76, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x5FD2, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x5FD1, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x5FD0, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x5FED, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x5FE8, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x5FEE, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x5FF3, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x5FE1, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x5FE3, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x5FFA, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x5FEF, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x5FF7, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x6000, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x5FF4, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x623A, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x6283, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x628C, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x628E, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x628F, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x6294, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x6287, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x6271, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x627B, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x627A, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x6270, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x6281, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x6288, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x6277, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x627D, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x6272, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x6274, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x6537, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x65F0, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x65F3, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x65F2, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x65F5, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x6745, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x6747, //CJK UNIFIED IDEOGRAPH + 0xCB40: 0x6759, //CJK UNIFIED IDEOGRAPH + 0xCB41: 0x6755, //CJK UNIFIED IDEOGRAPH + 0xCB42: 0x674C, //CJK UNIFIED IDEOGRAPH + 0xCB43: 0x6748, //CJK UNIFIED IDEOGRAPH + 0xCB44: 0x675D, //CJK UNIFIED IDEOGRAPH + 0xCB45: 0x674D, //CJK UNIFIED IDEOGRAPH + 0xCB46: 0x675A, //CJK UNIFIED IDEOGRAPH + 0xCB47: 0x674B, //CJK UNIFIED IDEOGRAPH + 0xCB48: 0x6BD0, //CJK UNIFIED IDEOGRAPH + 0xCB49: 0x6C19, //CJK UNIFIED IDEOGRAPH + 0xCB4A: 0x6C1A, //CJK UNIFIED IDEOGRAPH + 0xCB4B: 0x6C78, //CJK UNIFIED IDEOGRAPH + 0xCB4C: 0x6C67, //CJK UNIFIED IDEOGRAPH + 0xCB4D: 0x6C6B, //CJK UNIFIED IDEOGRAPH + 0xCB4E: 0x6C84, //CJK UNIFIED IDEOGRAPH + 0xCB4F: 0x6C8B, //CJK UNIFIED IDEOGRAPH + 0xCB50: 0x6C8F, //CJK UNIFIED IDEOGRAPH + 0xCB51: 0x6C71, //CJK UNIFIED IDEOGRAPH + 0xCB52: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xCB53: 0x6C69, //CJK UNIFIED IDEOGRAPH + 0xCB54: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0xCB55: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0xCB56: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0xCB57: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0xCB58: 0x6C9C, //CJK UNIFIED IDEOGRAPH + 0xCB59: 0x6C66, //CJK UNIFIED IDEOGRAPH + 0xCB5A: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0xCB5B: 0x6C65, //CJK UNIFIED IDEOGRAPH + 0xCB5C: 0x6C7B, //CJK UNIFIED IDEOGRAPH + 0xCB5D: 0x6C8E, //CJK UNIFIED IDEOGRAPH + 0xCB5E: 0x7074, //CJK UNIFIED IDEOGRAPH + 0xCB5F: 0x707A, //CJK UNIFIED IDEOGRAPH + 0xCB60: 0x7263, //CJK UNIFIED IDEOGRAPH + 0xCB61: 0x72BF, //CJK UNIFIED IDEOGRAPH + 0xCB62: 0x72BD, //CJK UNIFIED IDEOGRAPH + 0xCB63: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xCB64: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xCB65: 0x72C1, //CJK UNIFIED IDEOGRAPH + 0xCB66: 0x72BA, //CJK UNIFIED IDEOGRAPH + 0xCB67: 0x72C5, //CJK UNIFIED IDEOGRAPH + 0xCB68: 0x7395, //CJK UNIFIED IDEOGRAPH + 0xCB69: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xCB6A: 0x7393, //CJK UNIFIED IDEOGRAPH + 0xCB6B: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xCB6C: 0x7392, //CJK UNIFIED IDEOGRAPH + 0xCB6D: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xCB6E: 0x7539, //CJK UNIFIED IDEOGRAPH + 0xCB6F: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xCB70: 0x7595, //CJK UNIFIED IDEOGRAPH + 0xCB71: 0x7681, //CJK UNIFIED IDEOGRAPH + 0xCB72: 0x793D, //CJK UNIFIED IDEOGRAPH + 0xCB73: 0x8034, //CJK UNIFIED IDEOGRAPH + 0xCB74: 0x8095, //CJK UNIFIED IDEOGRAPH + 0xCB75: 0x8099, //CJK UNIFIED IDEOGRAPH + 0xCB76: 0x8090, //CJK UNIFIED IDEOGRAPH + 0xCB77: 0x8092, //CJK UNIFIED IDEOGRAPH + 0xCB78: 0x809C, //CJK UNIFIED IDEOGRAPH + 0xCB79: 0x8290, //CJK UNIFIED IDEOGRAPH + 0xCB7A: 0x828F, //CJK UNIFIED IDEOGRAPH + 0xCB7B: 0x8285, //CJK UNIFIED IDEOGRAPH + 0xCB7C: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xCB7D: 0x8291, //CJK UNIFIED IDEOGRAPH + 0xCB7E: 0x8293, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x828A, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x8283, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x8284, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x8FC9, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x909F, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x90A1, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x90A5, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x909E, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x90A7, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x90A0, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x9630, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x962D, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x4E33, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x4F85, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x4F7D, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x4F80, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x4F87, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x4F74, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x4F89, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x4F77, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x4F4C, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x4F97, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4F6A, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x4F79, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x4F78, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x4F90, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x4F9C, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x4F9E, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x4F82, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x4F95, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x4F6B, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x4F6E, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x519E, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x51BC, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0x5235, //CJK UNIFIED IDEOGRAPH + 0xCBD1: 0x5232, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x5233, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x5246, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x5231, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0x530A, //CJK UNIFIED IDEOGRAPH + 0xCBD7: 0x530B, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x533C, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x5392, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x5394, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x5487, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x547F, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x5481, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x5491, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x5482, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x5488, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x546B, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x547A, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x547E, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x5465, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x546C, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x5474, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0x5466, //CJK UNIFIED IDEOGRAPH + 0xCBE8: 0x548D, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x546F, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x5461, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x5460, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x5498, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x5463, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x5467, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5464, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x56F7, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x576F, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x5772, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x576D, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x576B, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x5771, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x5770, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x5776, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x5780, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x5775, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x577B, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x5773, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5774, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x5762, //CJK UNIFIED IDEOGRAPH + 0xCC40: 0x5768, //CJK UNIFIED IDEOGRAPH + 0xCC41: 0x577D, //CJK UNIFIED IDEOGRAPH + 0xCC42: 0x590C, //CJK UNIFIED IDEOGRAPH + 0xCC43: 0x5945, //CJK UNIFIED IDEOGRAPH + 0xCC44: 0x59B5, //CJK UNIFIED IDEOGRAPH + 0xCC45: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xCC46: 0x59CF, //CJK UNIFIED IDEOGRAPH + 0xCC47: 0x59CE, //CJK UNIFIED IDEOGRAPH + 0xCC48: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0xCC49: 0x59CC, //CJK UNIFIED IDEOGRAPH + 0xCC4A: 0x59C1, //CJK UNIFIED IDEOGRAPH + 0xCC4B: 0x59B6, //CJK UNIFIED IDEOGRAPH + 0xCC4C: 0x59BC, //CJK UNIFIED IDEOGRAPH + 0xCC4D: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0xCC4E: 0x59D6, //CJK UNIFIED IDEOGRAPH + 0xCC4F: 0x59B1, //CJK UNIFIED IDEOGRAPH + 0xCC50: 0x59BD, //CJK UNIFIED IDEOGRAPH + 0xCC51: 0x59C0, //CJK UNIFIED IDEOGRAPH + 0xCC52: 0x59C8, //CJK UNIFIED IDEOGRAPH + 0xCC53: 0x59B4, //CJK UNIFIED IDEOGRAPH + 0xCC54: 0x59C7, //CJK UNIFIED IDEOGRAPH + 0xCC55: 0x5B62, //CJK UNIFIED IDEOGRAPH + 0xCC56: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0xCC57: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xCC58: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xCC59: 0x5C44, //CJK UNIFIED IDEOGRAPH + 0xCC5A: 0x5C47, //CJK UNIFIED IDEOGRAPH + 0xCC5B: 0x5CAE, //CJK UNIFIED IDEOGRAPH + 0xCC5C: 0x5CA4, //CJK UNIFIED IDEOGRAPH + 0xCC5D: 0x5CA0, //CJK UNIFIED IDEOGRAPH + 0xCC5E: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xCC5F: 0x5CAF, //CJK UNIFIED IDEOGRAPH + 0xCC60: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0xCC61: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xCC62: 0x5C9F, //CJK UNIFIED IDEOGRAPH + 0xCC63: 0x5CA3, //CJK UNIFIED IDEOGRAPH + 0xCC64: 0x5CAD, //CJK UNIFIED IDEOGRAPH + 0xCC65: 0x5CA2, //CJK UNIFIED IDEOGRAPH + 0xCC66: 0x5CAA, //CJK UNIFIED IDEOGRAPH + 0xCC67: 0x5CA7, //CJK UNIFIED IDEOGRAPH + 0xCC68: 0x5C9D, //CJK UNIFIED IDEOGRAPH + 0xCC69: 0x5CA5, //CJK UNIFIED IDEOGRAPH + 0xCC6A: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0xCC6B: 0x5CB0, //CJK UNIFIED IDEOGRAPH + 0xCC6C: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xCC6D: 0x5E17, //CJK UNIFIED IDEOGRAPH + 0xCC6E: 0x5E14, //CJK UNIFIED IDEOGRAPH + 0xCC6F: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xCC70: 0x5F28, //CJK UNIFIED IDEOGRAPH + 0xCC71: 0x5F22, //CJK UNIFIED IDEOGRAPH + 0xCC72: 0x5F23, //CJK UNIFIED IDEOGRAPH + 0xCC73: 0x5F24, //CJK UNIFIED IDEOGRAPH + 0xCC74: 0x5F54, //CJK UNIFIED IDEOGRAPH + 0xCC75: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0xCC76: 0x5F7E, //CJK UNIFIED IDEOGRAPH + 0xCC77: 0x5F7D, //CJK UNIFIED IDEOGRAPH + 0xCC78: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xCC79: 0x5FE5, //CJK UNIFIED IDEOGRAPH + 0xCC7A: 0x602D, //CJK UNIFIED IDEOGRAPH + 0xCC7B: 0x6026, //CJK UNIFIED IDEOGRAPH + 0xCC7C: 0x6019, //CJK UNIFIED IDEOGRAPH + 0xCC7D: 0x6032, //CJK UNIFIED IDEOGRAPH + 0xCC7E: 0x600B, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x6034, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x600A, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x6017, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x6033, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x601A, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x601E, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x602C, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x6022, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x600D, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x6010, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x602E, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6013, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6011, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x600C, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x6009, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x6214, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x623D, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x62AD, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x62B4, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x62BE, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x62AA, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x62B6, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x62AE, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x62B3, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x62AF, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x62A9, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x62B0, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x62B8, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x653D, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x65A8, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x65BB, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x6604, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x6612, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x6608, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x6603, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x660B, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x660D, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x6605, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x6611, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x6610, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x66F6, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x670A, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x6785, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x676C, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x678E, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x6792, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x6776, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x677B, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x6798, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x6786, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x6784, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x6774, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x678D, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x678C, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x677A, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x679F, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x6791, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x6799, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x6783, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x677D, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x6781, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x6778, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x6779, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x6794, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x6B25, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x6B7E, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x6BDE, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x6C1D, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x6CEC, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x6CB6, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x6CD4, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x6CAD, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x6CE7, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x6CB7, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x6CD0, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x6CC3, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x6CC6, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x6CED, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x6CF2, //CJK UNIFIED IDEOGRAPH + 0xCD40: 0x6CD2, //CJK UNIFIED IDEOGRAPH + 0xCD41: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0xCD42: 0x6CB4, //CJK UNIFIED IDEOGRAPH + 0xCD43: 0x6C8A, //CJK UNIFIED IDEOGRAPH + 0xCD44: 0x6C9D, //CJK UNIFIED IDEOGRAPH + 0xCD45: 0x6C80, //CJK UNIFIED IDEOGRAPH + 0xCD46: 0x6CDE, //CJK UNIFIED IDEOGRAPH + 0xCD47: 0x6CC0, //CJK UNIFIED IDEOGRAPH + 0xCD48: 0x6D30, //CJK UNIFIED IDEOGRAPH + 0xCD49: 0x6CCD, //CJK UNIFIED IDEOGRAPH + 0xCD4A: 0x6CC7, //CJK UNIFIED IDEOGRAPH + 0xCD4B: 0x6CB0, //CJK UNIFIED IDEOGRAPH + 0xCD4C: 0x6CF9, //CJK UNIFIED IDEOGRAPH + 0xCD4D: 0x6CCF, //CJK UNIFIED IDEOGRAPH + 0xCD4E: 0x6CE9, //CJK UNIFIED IDEOGRAPH + 0xCD4F: 0x6CD1, //CJK UNIFIED IDEOGRAPH + 0xCD50: 0x7094, //CJK UNIFIED IDEOGRAPH + 0xCD51: 0x7098, //CJK UNIFIED IDEOGRAPH + 0xCD52: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xCD53: 0x7093, //CJK UNIFIED IDEOGRAPH + 0xCD54: 0x7086, //CJK UNIFIED IDEOGRAPH + 0xCD55: 0x7084, //CJK UNIFIED IDEOGRAPH + 0xCD56: 0x7091, //CJK UNIFIED IDEOGRAPH + 0xCD57: 0x7096, //CJK UNIFIED IDEOGRAPH + 0xCD58: 0x7082, //CJK UNIFIED IDEOGRAPH + 0xCD59: 0x709A, //CJK UNIFIED IDEOGRAPH + 0xCD5A: 0x7083, //CJK UNIFIED IDEOGRAPH + 0xCD5B: 0x726A, //CJK UNIFIED IDEOGRAPH + 0xCD5C: 0x72D6, //CJK UNIFIED IDEOGRAPH + 0xCD5D: 0x72CB, //CJK UNIFIED IDEOGRAPH + 0xCD5E: 0x72D8, //CJK UNIFIED IDEOGRAPH + 0xCD5F: 0x72C9, //CJK UNIFIED IDEOGRAPH + 0xCD60: 0x72DC, //CJK UNIFIED IDEOGRAPH + 0xCD61: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xCD62: 0x72D4, //CJK UNIFIED IDEOGRAPH + 0xCD63: 0x72DA, //CJK UNIFIED IDEOGRAPH + 0xCD64: 0x72CC, //CJK UNIFIED IDEOGRAPH + 0xCD65: 0x72D1, //CJK UNIFIED IDEOGRAPH + 0xCD66: 0x73A4, //CJK UNIFIED IDEOGRAPH + 0xCD67: 0x73A1, //CJK UNIFIED IDEOGRAPH + 0xCD68: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xCD69: 0x73A6, //CJK UNIFIED IDEOGRAPH + 0xCD6A: 0x73A2, //CJK UNIFIED IDEOGRAPH + 0xCD6B: 0x73A0, //CJK UNIFIED IDEOGRAPH + 0xCD6C: 0x73AC, //CJK UNIFIED IDEOGRAPH + 0xCD6D: 0x739D, //CJK UNIFIED IDEOGRAPH + 0xCD6E: 0x74DD, //CJK UNIFIED IDEOGRAPH + 0xCD6F: 0x74E8, //CJK UNIFIED IDEOGRAPH + 0xCD70: 0x753F, //CJK UNIFIED IDEOGRAPH + 0xCD71: 0x7540, //CJK UNIFIED IDEOGRAPH + 0xCD72: 0x753E, //CJK UNIFIED IDEOGRAPH + 0xCD73: 0x758C, //CJK UNIFIED IDEOGRAPH + 0xCD74: 0x7598, //CJK UNIFIED IDEOGRAPH + 0xCD75: 0x76AF, //CJK UNIFIED IDEOGRAPH + 0xCD76: 0x76F3, //CJK UNIFIED IDEOGRAPH + 0xCD77: 0x76F1, //CJK UNIFIED IDEOGRAPH + 0xCD78: 0x76F0, //CJK UNIFIED IDEOGRAPH + 0xCD79: 0x76F5, //CJK UNIFIED IDEOGRAPH + 0xCD7A: 0x77F8, //CJK UNIFIED IDEOGRAPH + 0xCD7B: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xCD7C: 0x77F9, //CJK UNIFIED IDEOGRAPH + 0xCD7D: 0x77FB, //CJK UNIFIED IDEOGRAPH + 0xCD7E: 0x77FA, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x77F7, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x7942, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x793F, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x79C5, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x7A78, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x7A7B, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x7AFB, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x7CFD, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x8035, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x808F, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x80AE, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x80A3, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x80B8, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x80B5, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x8220, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x82A0, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x82C0, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x8298, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x829B, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x82B5, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x82A7, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x829E, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x82BA, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x82B4, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x82A8, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x82A1, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x82C2, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x82A4, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x82C3, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x82B6, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x82A2, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x8670, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x866F, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x866D, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x866E, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x8C56, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x8FD2, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x8FCB, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x8FD3, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0x8FCD, //CJK UNIFIED IDEOGRAPH + 0xCDD0: 0x8FD6, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x8FD5, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x8FD7, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x90B2, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x90B4, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x90B3, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x9639, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x963D, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x963C, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x963A, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x9643, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x4FC5, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x4FB2, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x4FCB, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x4FC1, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x4FDC, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x4FD9, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x4FBB, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0x4FB3, //CJK UNIFIED IDEOGRAPH + 0xCDE9: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x4FC7, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x4FD6, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x4FBA, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x4FC0, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x4FB9, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x4FEC, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x5244, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x5249, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x52C2, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x533D, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x537C, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x5397, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x5396, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x5399, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x54BA, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x54A1, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x54AD, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x54CF, //CJK UNIFIED IDEOGRAPH + 0xCE40: 0x54C3, //CJK UNIFIED IDEOGRAPH + 0xCE41: 0x830D, //CJK UNIFIED IDEOGRAPH + 0xCE42: 0x54B7, //CJK UNIFIED IDEOGRAPH + 0xCE43: 0x54AE, //CJK UNIFIED IDEOGRAPH + 0xCE44: 0x54D6, //CJK UNIFIED IDEOGRAPH + 0xCE45: 0x54B6, //CJK UNIFIED IDEOGRAPH + 0xCE46: 0x54C5, //CJK UNIFIED IDEOGRAPH + 0xCE47: 0x54C6, //CJK UNIFIED IDEOGRAPH + 0xCE48: 0x54A0, //CJK UNIFIED IDEOGRAPH + 0xCE49: 0x5470, //CJK UNIFIED IDEOGRAPH + 0xCE4A: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0xCE4B: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0xCE4C: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0xCE4D: 0x5472, //CJK UNIFIED IDEOGRAPH + 0xCE4E: 0x54DE, //CJK UNIFIED IDEOGRAPH + 0xCE4F: 0x54B0, //CJK UNIFIED IDEOGRAPH + 0xCE50: 0x57B5, //CJK UNIFIED IDEOGRAPH + 0xCE51: 0x579E, //CJK UNIFIED IDEOGRAPH + 0xCE52: 0x579F, //CJK UNIFIED IDEOGRAPH + 0xCE53: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0xCE54: 0x578C, //CJK UNIFIED IDEOGRAPH + 0xCE55: 0x5797, //CJK UNIFIED IDEOGRAPH + 0xCE56: 0x579D, //CJK UNIFIED IDEOGRAPH + 0xCE57: 0x579B, //CJK UNIFIED IDEOGRAPH + 0xCE58: 0x5794, //CJK UNIFIED IDEOGRAPH + 0xCE59: 0x5798, //CJK UNIFIED IDEOGRAPH + 0xCE5A: 0x578F, //CJK UNIFIED IDEOGRAPH + 0xCE5B: 0x5799, //CJK UNIFIED IDEOGRAPH + 0xCE5C: 0x57A5, //CJK UNIFIED IDEOGRAPH + 0xCE5D: 0x579A, //CJK UNIFIED IDEOGRAPH + 0xCE5E: 0x5795, //CJK UNIFIED IDEOGRAPH + 0xCE5F: 0x58F4, //CJK UNIFIED IDEOGRAPH + 0xCE60: 0x590D, //CJK UNIFIED IDEOGRAPH + 0xCE61: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xCE62: 0x59E1, //CJK UNIFIED IDEOGRAPH + 0xCE63: 0x59DE, //CJK UNIFIED IDEOGRAPH + 0xCE64: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0xCE65: 0x5A00, //CJK UNIFIED IDEOGRAPH + 0xCE66: 0x59F1, //CJK UNIFIED IDEOGRAPH + 0xCE67: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xCE68: 0x59FA, //CJK UNIFIED IDEOGRAPH + 0xCE69: 0x59FD, //CJK UNIFIED IDEOGRAPH + 0xCE6A: 0x59FC, //CJK UNIFIED IDEOGRAPH + 0xCE6B: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0xCE6C: 0x59E4, //CJK UNIFIED IDEOGRAPH + 0xCE6D: 0x59F2, //CJK UNIFIED IDEOGRAPH + 0xCE6E: 0x59F7, //CJK UNIFIED IDEOGRAPH + 0xCE6F: 0x59DB, //CJK UNIFIED IDEOGRAPH + 0xCE70: 0x59E9, //CJK UNIFIED IDEOGRAPH + 0xCE71: 0x59F3, //CJK UNIFIED IDEOGRAPH + 0xCE72: 0x59F5, //CJK UNIFIED IDEOGRAPH + 0xCE73: 0x59E0, //CJK UNIFIED IDEOGRAPH + 0xCE74: 0x59FE, //CJK UNIFIED IDEOGRAPH + 0xCE75: 0x59F4, //CJK UNIFIED IDEOGRAPH + 0xCE76: 0x59ED, //CJK UNIFIED IDEOGRAPH + 0xCE77: 0x5BA8, //CJK UNIFIED IDEOGRAPH + 0xCE78: 0x5C4C, //CJK UNIFIED IDEOGRAPH + 0xCE79: 0x5CD0, //CJK UNIFIED IDEOGRAPH + 0xCE7A: 0x5CD8, //CJK UNIFIED IDEOGRAPH + 0xCE7B: 0x5CCC, //CJK UNIFIED IDEOGRAPH + 0xCE7C: 0x5CD7, //CJK UNIFIED IDEOGRAPH + 0xCE7D: 0x5CCB, //CJK UNIFIED IDEOGRAPH + 0xCE7E: 0x5CDB, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x5CDE, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x5CDA, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x5CC9, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x5CCA, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x5CD6, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x5CD3, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x5CD4, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x5CCF, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x5CC8, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x5CC6, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x5CCE, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0x5CDF, //CJK UNIFIED IDEOGRAPH + 0xCEAE: 0x5CF8, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x5DF9, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x5E21, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x5E22, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x5E23, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x5E20, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x5E24, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x5EB0, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x5EA4, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x5EA2, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x5E9B, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x5EA3, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x5EA5, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x5F07, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x5F2E, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x5F86, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x6037, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x6039, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x6054, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x6072, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x605E, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x6045, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x6053, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x6047, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x6049, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x605B, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x604C, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x6040, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x605F, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x6024, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x6044, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x6058, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x6066, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x606E, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x6242, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x6243, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x630D, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x630B, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x630E, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x6303, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x62EB, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x62F9, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x630F, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x630C, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x62F8, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x6300, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x6313, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x6314, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x62FA, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x6315, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x62FB, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x62F0, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x6541, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x6543, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x65AA, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x65BF, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x6621, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x6632, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x6635, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x661C, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x6626, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x6622, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x6633, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x662B, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x663A, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x661D, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x6639, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x670F, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x6710, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x67F2, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x67C8, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x67BA, //CJK UNIFIED IDEOGRAPH + 0xCF40: 0x67DC, //CJK UNIFIED IDEOGRAPH + 0xCF41: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xCF42: 0x67F8, //CJK UNIFIED IDEOGRAPH + 0xCF43: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0xCF44: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xCF45: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xCF46: 0x67C5, //CJK UNIFIED IDEOGRAPH + 0xCF47: 0x67EB, //CJK UNIFIED IDEOGRAPH + 0xCF48: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0xCF49: 0x67DF, //CJK UNIFIED IDEOGRAPH + 0xCF4A: 0x67B5, //CJK UNIFIED IDEOGRAPH + 0xCF4B: 0x67CD, //CJK UNIFIED IDEOGRAPH + 0xCF4C: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xCF4D: 0x67F7, //CJK UNIFIED IDEOGRAPH + 0xCF4E: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0xCF4F: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0xCF50: 0x67E3, //CJK UNIFIED IDEOGRAPH + 0xCF51: 0x67C2, //CJK UNIFIED IDEOGRAPH + 0xCF52: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0xCF53: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0xCF54: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0xCF55: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xCF56: 0x67B2, //CJK UNIFIED IDEOGRAPH + 0xCF57: 0x67FC, //CJK UNIFIED IDEOGRAPH + 0xCF58: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0xCF59: 0x67ED, //CJK UNIFIED IDEOGRAPH + 0xCF5A: 0x67CC, //CJK UNIFIED IDEOGRAPH + 0xCF5B: 0x67AE, //CJK UNIFIED IDEOGRAPH + 0xCF5C: 0x67E6, //CJK UNIFIED IDEOGRAPH + 0xCF5D: 0x67DB, //CJK UNIFIED IDEOGRAPH + 0xCF5E: 0x67FA, //CJK UNIFIED IDEOGRAPH + 0xCF5F: 0x67C9, //CJK UNIFIED IDEOGRAPH + 0xCF60: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0xCF61: 0x67C3, //CJK UNIFIED IDEOGRAPH + 0xCF62: 0x67EA, //CJK UNIFIED IDEOGRAPH + 0xCF63: 0x67CB, //CJK UNIFIED IDEOGRAPH + 0xCF64: 0x6B28, //CJK UNIFIED IDEOGRAPH + 0xCF65: 0x6B82, //CJK UNIFIED IDEOGRAPH + 0xCF66: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xCF67: 0x6BB6, //CJK UNIFIED IDEOGRAPH + 0xCF68: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xCF69: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0xCF6A: 0x6BE0, //CJK UNIFIED IDEOGRAPH + 0xCF6B: 0x6C20, //CJK UNIFIED IDEOGRAPH + 0xCF6C: 0x6C21, //CJK UNIFIED IDEOGRAPH + 0xCF6D: 0x6D28, //CJK UNIFIED IDEOGRAPH + 0xCF6E: 0x6D34, //CJK UNIFIED IDEOGRAPH + 0xCF6F: 0x6D2D, //CJK UNIFIED IDEOGRAPH + 0xCF70: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0xCF71: 0x6D3C, //CJK UNIFIED IDEOGRAPH + 0xCF72: 0x6D3F, //CJK UNIFIED IDEOGRAPH + 0xCF73: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0xCF74: 0x6D0A, //CJK UNIFIED IDEOGRAPH + 0xCF75: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xCF76: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0xCF77: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xCF78: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xCF79: 0x6D3A, //CJK UNIFIED IDEOGRAPH + 0xCF7A: 0x6D1A, //CJK UNIFIED IDEOGRAPH + 0xCF7B: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0xCF7C: 0x6D00, //CJK UNIFIED IDEOGRAPH + 0xCF7D: 0x6D1D, //CJK UNIFIED IDEOGRAPH + 0xCF7E: 0x6D42, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x6D01, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x6D18, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x6D37, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x6D03, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x6D0F, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x6D40, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x6D07, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x6D20, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x6D2C, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x6D08, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x6D22, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x6D09, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6D10, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x709F, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x70BE, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x70B1, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x70B0, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x70B4, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x70B5, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x70A9, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x7241, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7249, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x724A, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x726C, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x7270, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x7273, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x726E, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x72CA, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x72E4, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x72E8, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x72EB, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x72DF, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x72EA, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x72E6, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x72E3, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x7385, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x73C5, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x73B6, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x73B5, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x73B4, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x73EB, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x73BF, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x73C7, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x73BE, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x73C3, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x73C6, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x73B8, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x73CB, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x74EC, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x752E, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x7548, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x75A7, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x75AA, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x7679, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x76C4, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x7703, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x7705, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x770A, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x76F7, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x76FA, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x77E8, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x7806, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x7811, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x7805, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x7810, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x780F, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x780E, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x7809, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x7803, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x7813, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x794A, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x794C, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x794B, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x7945, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x7944, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x79CD, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0x79CF, //CJK UNIFIED IDEOGRAPH + 0xCFFC: 0x79D6, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x79CE, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x7A80, //CJK UNIFIED IDEOGRAPH + 0xD040: 0x7A7E, //CJK UNIFIED IDEOGRAPH + 0xD041: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xD042: 0x7B00, //CJK UNIFIED IDEOGRAPH + 0xD043: 0x7B01, //CJK UNIFIED IDEOGRAPH + 0xD044: 0x7C7A, //CJK UNIFIED IDEOGRAPH + 0xD045: 0x7C78, //CJK UNIFIED IDEOGRAPH + 0xD046: 0x7C79, //CJK UNIFIED IDEOGRAPH + 0xD047: 0x7C7F, //CJK UNIFIED IDEOGRAPH + 0xD048: 0x7C80, //CJK UNIFIED IDEOGRAPH + 0xD049: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0xD04A: 0x7D03, //CJK UNIFIED IDEOGRAPH + 0xD04B: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xD04C: 0x7D01, //CJK UNIFIED IDEOGRAPH + 0xD04D: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xD04E: 0x7F91, //CJK UNIFIED IDEOGRAPH + 0xD04F: 0x7F8D, //CJK UNIFIED IDEOGRAPH + 0xD050: 0x7FBE, //CJK UNIFIED IDEOGRAPH + 0xD051: 0x8007, //CJK UNIFIED IDEOGRAPH + 0xD052: 0x800E, //CJK UNIFIED IDEOGRAPH + 0xD053: 0x800F, //CJK UNIFIED IDEOGRAPH + 0xD054: 0x8014, //CJK UNIFIED IDEOGRAPH + 0xD055: 0x8037, //CJK UNIFIED IDEOGRAPH + 0xD056: 0x80D8, //CJK UNIFIED IDEOGRAPH + 0xD057: 0x80C7, //CJK UNIFIED IDEOGRAPH + 0xD058: 0x80E0, //CJK UNIFIED IDEOGRAPH + 0xD059: 0x80D1, //CJK UNIFIED IDEOGRAPH + 0xD05A: 0x80C8, //CJK UNIFIED IDEOGRAPH + 0xD05B: 0x80C2, //CJK UNIFIED IDEOGRAPH + 0xD05C: 0x80D0, //CJK UNIFIED IDEOGRAPH + 0xD05D: 0x80C5, //CJK UNIFIED IDEOGRAPH + 0xD05E: 0x80E3, //CJK UNIFIED IDEOGRAPH + 0xD05F: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xD060: 0x80DC, //CJK UNIFIED IDEOGRAPH + 0xD061: 0x80CA, //CJK UNIFIED IDEOGRAPH + 0xD062: 0x80D5, //CJK UNIFIED IDEOGRAPH + 0xD063: 0x80C9, //CJK UNIFIED IDEOGRAPH + 0xD064: 0x80CF, //CJK UNIFIED IDEOGRAPH + 0xD065: 0x80D7, //CJK UNIFIED IDEOGRAPH + 0xD066: 0x80E6, //CJK UNIFIED IDEOGRAPH + 0xD067: 0x80CD, //CJK UNIFIED IDEOGRAPH + 0xD068: 0x81FF, //CJK UNIFIED IDEOGRAPH + 0xD069: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xD06A: 0x8294, //CJK UNIFIED IDEOGRAPH + 0xD06B: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xD06C: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xD06D: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xD06E: 0x8307, //CJK UNIFIED IDEOGRAPH + 0xD06F: 0x82E8, //CJK UNIFIED IDEOGRAPH + 0xD070: 0x8300, //CJK UNIFIED IDEOGRAPH + 0xD071: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xD072: 0x833A, //CJK UNIFIED IDEOGRAPH + 0xD073: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0xD074: 0x82D6, //CJK UNIFIED IDEOGRAPH + 0xD075: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xD076: 0x82EC, //CJK UNIFIED IDEOGRAPH + 0xD077: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xD078: 0x82F2, //CJK UNIFIED IDEOGRAPH + 0xD079: 0x82F5, //CJK UNIFIED IDEOGRAPH + 0xD07A: 0x830C, //CJK UNIFIED IDEOGRAPH + 0xD07B: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xD07C: 0x82F6, //CJK UNIFIED IDEOGRAPH + 0xD07D: 0x82F0, //CJK UNIFIED IDEOGRAPH + 0xD07E: 0x82EA, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x82E4, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0x82E0, //CJK UNIFIED IDEOGRAPH + 0xD0A3: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x82ED, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x8677, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x8674, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x867C, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x8673, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x8841, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x884E, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x8867, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x886A, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x8869, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x89D3, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x8A04, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x8A07, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x8D72, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x8FE3, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x8FE1, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x8FEE, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x8FE0, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x90F1, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0x90BD, //CJK UNIFIED IDEOGRAPH + 0xD0B9: 0x90BF, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x90D5, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x90C5, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x90BE, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x90C7, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x90CB, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x90C8, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x91D4, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x91D3, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x9654, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x9651, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x9653, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x964A, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x964E, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x5005, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x5007, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x5013, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x5030, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x501B, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0x4FF4, //CJK UNIFIED IDEOGRAPH + 0xD0D1: 0x5033, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5037, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x4FF7, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x5017, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x5020, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x5027, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x5035, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x502F, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x5031, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0x500E, //CJK UNIFIED IDEOGRAPH + 0xD0DE: 0x515A, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x5194, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x5193, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x51CA, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x51C8, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x51CE, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x525A, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x5252, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x525E, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x525F, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x5255, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5262, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x530E, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x539E, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x5526, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x5517, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x5512, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x54E7, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x54F3, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x54E4, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x551A, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x5504, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x5508, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x54EB, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x5511, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x5505, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x54F1, //CJK UNIFIED IDEOGRAPH + 0xD140: 0x550A, //CJK UNIFIED IDEOGRAPH + 0xD141: 0x54FB, //CJK UNIFIED IDEOGRAPH + 0xD142: 0x54F7, //CJK UNIFIED IDEOGRAPH + 0xD143: 0x54F8, //CJK UNIFIED IDEOGRAPH + 0xD144: 0x54E0, //CJK UNIFIED IDEOGRAPH + 0xD145: 0x550E, //CJK UNIFIED IDEOGRAPH + 0xD146: 0x5503, //CJK UNIFIED IDEOGRAPH + 0xD147: 0x550B, //CJK UNIFIED IDEOGRAPH + 0xD148: 0x5701, //CJK UNIFIED IDEOGRAPH + 0xD149: 0x5702, //CJK UNIFIED IDEOGRAPH + 0xD14A: 0x57CC, //CJK UNIFIED IDEOGRAPH + 0xD14B: 0x5832, //CJK UNIFIED IDEOGRAPH + 0xD14C: 0x57D5, //CJK UNIFIED IDEOGRAPH + 0xD14D: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0xD14E: 0x57BA, //CJK UNIFIED IDEOGRAPH + 0xD14F: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0xD150: 0x57BD, //CJK UNIFIED IDEOGRAPH + 0xD151: 0x57BC, //CJK UNIFIED IDEOGRAPH + 0xD152: 0x57B8, //CJK UNIFIED IDEOGRAPH + 0xD153: 0x57B6, //CJK UNIFIED IDEOGRAPH + 0xD154: 0x57BF, //CJK UNIFIED IDEOGRAPH + 0xD155: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xD156: 0x57D0, //CJK UNIFIED IDEOGRAPH + 0xD157: 0x57B9, //CJK UNIFIED IDEOGRAPH + 0xD158: 0x57C1, //CJK UNIFIED IDEOGRAPH + 0xD159: 0x590E, //CJK UNIFIED IDEOGRAPH + 0xD15A: 0x594A, //CJK UNIFIED IDEOGRAPH + 0xD15B: 0x5A19, //CJK UNIFIED IDEOGRAPH + 0xD15C: 0x5A16, //CJK UNIFIED IDEOGRAPH + 0xD15D: 0x5A2D, //CJK UNIFIED IDEOGRAPH + 0xD15E: 0x5A2E, //CJK UNIFIED IDEOGRAPH + 0xD15F: 0x5A15, //CJK UNIFIED IDEOGRAPH + 0xD160: 0x5A0F, //CJK UNIFIED IDEOGRAPH + 0xD161: 0x5A17, //CJK UNIFIED IDEOGRAPH + 0xD162: 0x5A0A, //CJK UNIFIED IDEOGRAPH + 0xD163: 0x5A1E, //CJK UNIFIED IDEOGRAPH + 0xD164: 0x5A33, //CJK UNIFIED IDEOGRAPH + 0xD165: 0x5B6C, //CJK UNIFIED IDEOGRAPH + 0xD166: 0x5BA7, //CJK UNIFIED IDEOGRAPH + 0xD167: 0x5BAD, //CJK UNIFIED IDEOGRAPH + 0xD168: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0xD169: 0x5C03, //CJK UNIFIED IDEOGRAPH + 0xD16A: 0x5C56, //CJK UNIFIED IDEOGRAPH + 0xD16B: 0x5C54, //CJK UNIFIED IDEOGRAPH + 0xD16C: 0x5CEC, //CJK UNIFIED IDEOGRAPH + 0xD16D: 0x5CFF, //CJK UNIFIED IDEOGRAPH + 0xD16E: 0x5CEE, //CJK UNIFIED IDEOGRAPH + 0xD16F: 0x5CF1, //CJK UNIFIED IDEOGRAPH + 0xD170: 0x5CF7, //CJK UNIFIED IDEOGRAPH + 0xD171: 0x5D00, //CJK UNIFIED IDEOGRAPH + 0xD172: 0x5CF9, //CJK UNIFIED IDEOGRAPH + 0xD173: 0x5E29, //CJK UNIFIED IDEOGRAPH + 0xD174: 0x5E28, //CJK UNIFIED IDEOGRAPH + 0xD175: 0x5EA8, //CJK UNIFIED IDEOGRAPH + 0xD176: 0x5EAE, //CJK UNIFIED IDEOGRAPH + 0xD177: 0x5EAA, //CJK UNIFIED IDEOGRAPH + 0xD178: 0x5EAC, //CJK UNIFIED IDEOGRAPH + 0xD179: 0x5F33, //CJK UNIFIED IDEOGRAPH + 0xD17A: 0x5F30, //CJK UNIFIED IDEOGRAPH + 0xD17B: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xD17C: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xD17D: 0x605A, //CJK UNIFIED IDEOGRAPH + 0xD17E: 0x6067, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x60A2, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x6088, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x6080, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x6092, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x6081, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x609D, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x6083, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x6095, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x6097, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x6087, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x609C, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x608E, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x6219, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x6246, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x62F2, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x6310, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x6356, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x632C, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x6344, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x6345, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x6336, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x6343, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x63E4, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x6339, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x634B, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x634A, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x633C, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x6329, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x6341, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x6334, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x6358, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x6354, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x6359, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x632D, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x6347, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x6333, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x635A, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x6351, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x6338, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x6357, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x6340, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x6348, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x654A, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x6546, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x65C2, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x664A, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xD1D5: 0x6647, //CJK UNIFIED IDEOGRAPH + 0xD1D6: 0x6651, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x6712, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0x6713, //CJK UNIFIED IDEOGRAPH + 0xD1D9: 0x681F, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x681A, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0x6849, //CJK UNIFIED IDEOGRAPH + 0xD1DC: 0x6832, //CJK UNIFIED IDEOGRAPH + 0xD1DD: 0x6833, //CJK UNIFIED IDEOGRAPH + 0xD1DE: 0x683B, //CJK UNIFIED IDEOGRAPH + 0xD1DF: 0x684B, //CJK UNIFIED IDEOGRAPH + 0xD1E0: 0x684F, //CJK UNIFIED IDEOGRAPH + 0xD1E1: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0x6831, //CJK UNIFIED IDEOGRAPH + 0xD1E3: 0x681C, //CJK UNIFIED IDEOGRAPH + 0xD1E4: 0x6835, //CJK UNIFIED IDEOGRAPH + 0xD1E5: 0x682B, //CJK UNIFIED IDEOGRAPH + 0xD1E6: 0x682D, //CJK UNIFIED IDEOGRAPH + 0xD1E7: 0x682F, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xD1E9: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xD1EA: 0x6834, //CJK UNIFIED IDEOGRAPH + 0xD1EB: 0x681D, //CJK UNIFIED IDEOGRAPH + 0xD1EC: 0x6812, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0x6814, //CJK UNIFIED IDEOGRAPH + 0xD1EE: 0x6826, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0x6828, //CJK UNIFIED IDEOGRAPH + 0xD1F0: 0x682E, //CJK UNIFIED IDEOGRAPH + 0xD1F1: 0x684D, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0x683A, //CJK UNIFIED IDEOGRAPH + 0xD1F3: 0x6825, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x6820, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x6B2C, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0x6B2F, //CJK UNIFIED IDEOGRAPH + 0xD1F7: 0x6B2D, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x6B31, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6B34, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0x6B6D, //CJK UNIFIED IDEOGRAPH + 0xD1FB: 0x8082, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0x6B88, //CJK UNIFIED IDEOGRAPH + 0xD1FD: 0x6BE6, //CJK UNIFIED IDEOGRAPH + 0xD1FE: 0x6BE4, //CJK UNIFIED IDEOGRAPH + 0xD240: 0x6BE8, //CJK UNIFIED IDEOGRAPH + 0xD241: 0x6BE3, //CJK UNIFIED IDEOGRAPH + 0xD242: 0x6BE2, //CJK UNIFIED IDEOGRAPH + 0xD243: 0x6BE7, //CJK UNIFIED IDEOGRAPH + 0xD244: 0x6C25, //CJK UNIFIED IDEOGRAPH + 0xD245: 0x6D7A, //CJK UNIFIED IDEOGRAPH + 0xD246: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xD247: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0xD248: 0x6D76, //CJK UNIFIED IDEOGRAPH + 0xD249: 0x6D0D, //CJK UNIFIED IDEOGRAPH + 0xD24A: 0x6D61, //CJK UNIFIED IDEOGRAPH + 0xD24B: 0x6D92, //CJK UNIFIED IDEOGRAPH + 0xD24C: 0x6D58, //CJK UNIFIED IDEOGRAPH + 0xD24D: 0x6D62, //CJK UNIFIED IDEOGRAPH + 0xD24E: 0x6D6D, //CJK UNIFIED IDEOGRAPH + 0xD24F: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xD250: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xD251: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0xD252: 0x6DEF, //CJK UNIFIED IDEOGRAPH + 0xD253: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0xD254: 0x6D86, //CJK UNIFIED IDEOGRAPH + 0xD255: 0x6D5E, //CJK UNIFIED IDEOGRAPH + 0xD256: 0x6D67, //CJK UNIFIED IDEOGRAPH + 0xD257: 0x6D60, //CJK UNIFIED IDEOGRAPH + 0xD258: 0x6D97, //CJK UNIFIED IDEOGRAPH + 0xD259: 0x6D70, //CJK UNIFIED IDEOGRAPH + 0xD25A: 0x6D7C, //CJK UNIFIED IDEOGRAPH + 0xD25B: 0x6D5F, //CJK UNIFIED IDEOGRAPH + 0xD25C: 0x6D82, //CJK UNIFIED IDEOGRAPH + 0xD25D: 0x6D98, //CJK UNIFIED IDEOGRAPH + 0xD25E: 0x6D2F, //CJK UNIFIED IDEOGRAPH + 0xD25F: 0x6D68, //CJK UNIFIED IDEOGRAPH + 0xD260: 0x6D8B, //CJK UNIFIED IDEOGRAPH + 0xD261: 0x6D7E, //CJK UNIFIED IDEOGRAPH + 0xD262: 0x6D80, //CJK UNIFIED IDEOGRAPH + 0xD263: 0x6D84, //CJK UNIFIED IDEOGRAPH + 0xD264: 0x6D16, //CJK UNIFIED IDEOGRAPH + 0xD265: 0x6D83, //CJK UNIFIED IDEOGRAPH + 0xD266: 0x6D7B, //CJK UNIFIED IDEOGRAPH + 0xD267: 0x6D7D, //CJK UNIFIED IDEOGRAPH + 0xD268: 0x6D75, //CJK UNIFIED IDEOGRAPH + 0xD269: 0x6D90, //CJK UNIFIED IDEOGRAPH + 0xD26A: 0x70DC, //CJK UNIFIED IDEOGRAPH + 0xD26B: 0x70D3, //CJK UNIFIED IDEOGRAPH + 0xD26C: 0x70D1, //CJK UNIFIED IDEOGRAPH + 0xD26D: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xD26E: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xD26F: 0x7F39, //CJK UNIFIED IDEOGRAPH + 0xD270: 0x70E2, //CJK UNIFIED IDEOGRAPH + 0xD271: 0x70D7, //CJK UNIFIED IDEOGRAPH + 0xD272: 0x70D2, //CJK UNIFIED IDEOGRAPH + 0xD273: 0x70DE, //CJK UNIFIED IDEOGRAPH + 0xD274: 0x70E0, //CJK UNIFIED IDEOGRAPH + 0xD275: 0x70D4, //CJK UNIFIED IDEOGRAPH + 0xD276: 0x70CD, //CJK UNIFIED IDEOGRAPH + 0xD277: 0x70C5, //CJK UNIFIED IDEOGRAPH + 0xD278: 0x70C6, //CJK UNIFIED IDEOGRAPH + 0xD279: 0x70C7, //CJK UNIFIED IDEOGRAPH + 0xD27A: 0x70DA, //CJK UNIFIED IDEOGRAPH + 0xD27B: 0x70CE, //CJK UNIFIED IDEOGRAPH + 0xD27C: 0x70E1, //CJK UNIFIED IDEOGRAPH + 0xD27D: 0x7242, //CJK UNIFIED IDEOGRAPH + 0xD27E: 0x7278, //CJK UNIFIED IDEOGRAPH + 0xD2A1: 0x7277, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0x7276, //CJK UNIFIED IDEOGRAPH + 0xD2A3: 0x7300, //CJK UNIFIED IDEOGRAPH + 0xD2A4: 0x72FA, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x72F4, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x72FE, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0x72F6, //CJK UNIFIED IDEOGRAPH + 0xD2A8: 0x72F3, //CJK UNIFIED IDEOGRAPH + 0xD2A9: 0x72FB, //CJK UNIFIED IDEOGRAPH + 0xD2AA: 0x7301, //CJK UNIFIED IDEOGRAPH + 0xD2AB: 0x73D3, //CJK UNIFIED IDEOGRAPH + 0xD2AC: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xD2AE: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x73BC, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x73E7, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xD2B3: 0x73DC, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x73DB, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x73D4, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x73DA, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x73D7, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x73D8, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x73E8, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x74DE, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x74DF, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0x74F4, //CJK UNIFIED IDEOGRAPH + 0xD2BF: 0x74F5, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x7521, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0x755F, //CJK UNIFIED IDEOGRAPH + 0xD2C3: 0x75B0, //CJK UNIFIED IDEOGRAPH + 0xD2C4: 0x75C1, //CJK UNIFIED IDEOGRAPH + 0xD2C5: 0x75BB, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0x75C4, //CJK UNIFIED IDEOGRAPH + 0xD2C7: 0x75C0, //CJK UNIFIED IDEOGRAPH + 0xD2C8: 0x75BF, //CJK UNIFIED IDEOGRAPH + 0xD2C9: 0x75B6, //CJK UNIFIED IDEOGRAPH + 0xD2CA: 0x75BA, //CJK UNIFIED IDEOGRAPH + 0xD2CB: 0x768A, //CJK UNIFIED IDEOGRAPH + 0xD2CC: 0x76C9, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0x771D, //CJK UNIFIED IDEOGRAPH + 0xD2CE: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xD2CF: 0x7710, //CJK UNIFIED IDEOGRAPH + 0xD2D0: 0x7713, //CJK UNIFIED IDEOGRAPH + 0xD2D1: 0x7712, //CJK UNIFIED IDEOGRAPH + 0xD2D2: 0x7723, //CJK UNIFIED IDEOGRAPH + 0xD2D3: 0x7711, //CJK UNIFIED IDEOGRAPH + 0xD2D4: 0x7715, //CJK UNIFIED IDEOGRAPH + 0xD2D5: 0x7719, //CJK UNIFIED IDEOGRAPH + 0xD2D6: 0x771A, //CJK UNIFIED IDEOGRAPH + 0xD2D7: 0x7722, //CJK UNIFIED IDEOGRAPH + 0xD2D8: 0x7727, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0x7823, //CJK UNIFIED IDEOGRAPH + 0xD2DA: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xD2DB: 0x7822, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x7835, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x782F, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0x7828, //CJK UNIFIED IDEOGRAPH + 0xD2DF: 0x782E, //CJK UNIFIED IDEOGRAPH + 0xD2E0: 0x782B, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xD2E2: 0x7829, //CJK UNIFIED IDEOGRAPH + 0xD2E3: 0x7833, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0x782A, //CJK UNIFIED IDEOGRAPH + 0xD2E5: 0x7831, //CJK UNIFIED IDEOGRAPH + 0xD2E6: 0x7954, //CJK UNIFIED IDEOGRAPH + 0xD2E7: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xD2E8: 0x794F, //CJK UNIFIED IDEOGRAPH + 0xD2E9: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xD2EA: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xD2EB: 0x7952, //CJK UNIFIED IDEOGRAPH + 0xD2EC: 0x7951, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x79EB, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x79E0, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0x79EE, //CJK UNIFIED IDEOGRAPH + 0xD2F1: 0x79ED, //CJK UNIFIED IDEOGRAPH + 0xD2F2: 0x79EA, //CJK UNIFIED IDEOGRAPH + 0xD2F3: 0x79DC, //CJK UNIFIED IDEOGRAPH + 0xD2F4: 0x79DE, //CJK UNIFIED IDEOGRAPH + 0xD2F5: 0x79DD, //CJK UNIFIED IDEOGRAPH + 0xD2F6: 0x7A86, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0x7A89, //CJK UNIFIED IDEOGRAPH + 0xD2F8: 0x7A85, //CJK UNIFIED IDEOGRAPH + 0xD2F9: 0x7A8B, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x7A8C, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x7A8A, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x7A87, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x7AD8, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x7B10, //CJK UNIFIED IDEOGRAPH + 0xD340: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xD341: 0x7B13, //CJK UNIFIED IDEOGRAPH + 0xD342: 0x7B05, //CJK UNIFIED IDEOGRAPH + 0xD343: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xD344: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0xD345: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xD346: 0x7B0E, //CJK UNIFIED IDEOGRAPH + 0xD347: 0x7B09, //CJK UNIFIED IDEOGRAPH + 0xD348: 0x7B12, //CJK UNIFIED IDEOGRAPH + 0xD349: 0x7C84, //CJK UNIFIED IDEOGRAPH + 0xD34A: 0x7C91, //CJK UNIFIED IDEOGRAPH + 0xD34B: 0x7C8A, //CJK UNIFIED IDEOGRAPH + 0xD34C: 0x7C8C, //CJK UNIFIED IDEOGRAPH + 0xD34D: 0x7C88, //CJK UNIFIED IDEOGRAPH + 0xD34E: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0xD34F: 0x7C85, //CJK UNIFIED IDEOGRAPH + 0xD350: 0x7D1E, //CJK UNIFIED IDEOGRAPH + 0xD351: 0x7D1D, //CJK UNIFIED IDEOGRAPH + 0xD352: 0x7D11, //CJK UNIFIED IDEOGRAPH + 0xD353: 0x7D0E, //CJK UNIFIED IDEOGRAPH + 0xD354: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xD355: 0x7D16, //CJK UNIFIED IDEOGRAPH + 0xD356: 0x7D13, //CJK UNIFIED IDEOGRAPH + 0xD357: 0x7D1F, //CJK UNIFIED IDEOGRAPH + 0xD358: 0x7D12, //CJK UNIFIED IDEOGRAPH + 0xD359: 0x7D0F, //CJK UNIFIED IDEOGRAPH + 0xD35A: 0x7D0C, //CJK UNIFIED IDEOGRAPH + 0xD35B: 0x7F5C, //CJK UNIFIED IDEOGRAPH + 0xD35C: 0x7F61, //CJK UNIFIED IDEOGRAPH + 0xD35D: 0x7F5E, //CJK UNIFIED IDEOGRAPH + 0xD35E: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xD35F: 0x7F5D, //CJK UNIFIED IDEOGRAPH + 0xD360: 0x7F5B, //CJK UNIFIED IDEOGRAPH + 0xD361: 0x7F96, //CJK UNIFIED IDEOGRAPH + 0xD362: 0x7F92, //CJK UNIFIED IDEOGRAPH + 0xD363: 0x7FC3, //CJK UNIFIED IDEOGRAPH + 0xD364: 0x7FC2, //CJK UNIFIED IDEOGRAPH + 0xD365: 0x7FC0, //CJK UNIFIED IDEOGRAPH + 0xD366: 0x8016, //CJK UNIFIED IDEOGRAPH + 0xD367: 0x803E, //CJK UNIFIED IDEOGRAPH + 0xD368: 0x8039, //CJK UNIFIED IDEOGRAPH + 0xD369: 0x80FA, //CJK UNIFIED IDEOGRAPH + 0xD36A: 0x80F2, //CJK UNIFIED IDEOGRAPH + 0xD36B: 0x80F9, //CJK UNIFIED IDEOGRAPH + 0xD36C: 0x80F5, //CJK UNIFIED IDEOGRAPH + 0xD36D: 0x8101, //CJK UNIFIED IDEOGRAPH + 0xD36E: 0x80FB, //CJK UNIFIED IDEOGRAPH + 0xD36F: 0x8100, //CJK UNIFIED IDEOGRAPH + 0xD370: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xD371: 0x822F, //CJK UNIFIED IDEOGRAPH + 0xD372: 0x8225, //CJK UNIFIED IDEOGRAPH + 0xD373: 0x8333, //CJK UNIFIED IDEOGRAPH + 0xD374: 0x832D, //CJK UNIFIED IDEOGRAPH + 0xD375: 0x8344, //CJK UNIFIED IDEOGRAPH + 0xD376: 0x8319, //CJK UNIFIED IDEOGRAPH + 0xD377: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xD378: 0x8325, //CJK UNIFIED IDEOGRAPH + 0xD379: 0x8356, //CJK UNIFIED IDEOGRAPH + 0xD37A: 0x833F, //CJK UNIFIED IDEOGRAPH + 0xD37B: 0x8341, //CJK UNIFIED IDEOGRAPH + 0xD37C: 0x8326, //CJK UNIFIED IDEOGRAPH + 0xD37D: 0x831C, //CJK UNIFIED IDEOGRAPH + 0xD37E: 0x8322, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x8342, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x834E, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x831B, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x832A, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x8308, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x833C, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x834D, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x8324, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x8320, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x8337, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x8329, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x834C, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x8353, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x831E, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x832C, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x834B, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x8327, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x8348, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x8653, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x8652, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x86A2, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x86A8, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x8696, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x868D, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x8691, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x869E, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x8687, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x8697, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x8686, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x869A, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x8685, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x86A5, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x8699, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x86A1, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x86A7, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x8695, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x8698, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x868E, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x869D, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x8690, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x8694, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x8843, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x886D, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x8876, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x8880, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x8871, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x886F, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x8883, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x8874, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x887C, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x8C47, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x8C57, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x8C7B, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x8CA4, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x8CA3, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x8D78, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x8DB5, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x8DB7, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x8DB6, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x8ED1, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x8ED3, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x8FFE, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x8FF5, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x8FFF, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x8FFB, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x9004, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x8FFC, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x8FF6, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x90D6, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x90E0, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x90D9, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x90DA, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x90E3, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x90DF, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x90E5, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x90D8, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x90D7, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x90DC, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x9150, //CJK UNIFIED IDEOGRAPH + 0xD440: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xD441: 0x914F, //CJK UNIFIED IDEOGRAPH + 0xD442: 0x91D5, //CJK UNIFIED IDEOGRAPH + 0xD443: 0x91E2, //CJK UNIFIED IDEOGRAPH + 0xD444: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xD445: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xD446: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xD447: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0xD448: 0x98E3, //CJK UNIFIED IDEOGRAPH + 0xD449: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xD44A: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xD44B: 0x4E7F, //CJK UNIFIED IDEOGRAPH + 0xD44C: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xD44D: 0x506A, //CJK UNIFIED IDEOGRAPH + 0xD44E: 0x5061, //CJK UNIFIED IDEOGRAPH + 0xD44F: 0x505E, //CJK UNIFIED IDEOGRAPH + 0xD450: 0x5060, //CJK UNIFIED IDEOGRAPH + 0xD451: 0x5053, //CJK UNIFIED IDEOGRAPH + 0xD452: 0x504B, //CJK UNIFIED IDEOGRAPH + 0xD453: 0x505D, //CJK UNIFIED IDEOGRAPH + 0xD454: 0x5072, //CJK UNIFIED IDEOGRAPH + 0xD455: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xD456: 0x504D, //CJK UNIFIED IDEOGRAPH + 0xD457: 0x5041, //CJK UNIFIED IDEOGRAPH + 0xD458: 0x505B, //CJK UNIFIED IDEOGRAPH + 0xD459: 0x504A, //CJK UNIFIED IDEOGRAPH + 0xD45A: 0x5062, //CJK UNIFIED IDEOGRAPH + 0xD45B: 0x5015, //CJK UNIFIED IDEOGRAPH + 0xD45C: 0x5045, //CJK UNIFIED IDEOGRAPH + 0xD45D: 0x505F, //CJK UNIFIED IDEOGRAPH + 0xD45E: 0x5069, //CJK UNIFIED IDEOGRAPH + 0xD45F: 0x506B, //CJK UNIFIED IDEOGRAPH + 0xD460: 0x5063, //CJK UNIFIED IDEOGRAPH + 0xD461: 0x5064, //CJK UNIFIED IDEOGRAPH + 0xD462: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xD463: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xD464: 0x506E, //CJK UNIFIED IDEOGRAPH + 0xD465: 0x5073, //CJK UNIFIED IDEOGRAPH + 0xD466: 0x5057, //CJK UNIFIED IDEOGRAPH + 0xD467: 0x5051, //CJK UNIFIED IDEOGRAPH + 0xD468: 0x51D0, //CJK UNIFIED IDEOGRAPH + 0xD469: 0x526B, //CJK UNIFIED IDEOGRAPH + 0xD46A: 0x526D, //CJK UNIFIED IDEOGRAPH + 0xD46B: 0x526C, //CJK UNIFIED IDEOGRAPH + 0xD46C: 0x526E, //CJK UNIFIED IDEOGRAPH + 0xD46D: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xD46E: 0x52D3, //CJK UNIFIED IDEOGRAPH + 0xD46F: 0x532D, //CJK UNIFIED IDEOGRAPH + 0xD470: 0x539C, //CJK UNIFIED IDEOGRAPH + 0xD471: 0x5575, //CJK UNIFIED IDEOGRAPH + 0xD472: 0x5576, //CJK UNIFIED IDEOGRAPH + 0xD473: 0x553C, //CJK UNIFIED IDEOGRAPH + 0xD474: 0x554D, //CJK UNIFIED IDEOGRAPH + 0xD475: 0x5550, //CJK UNIFIED IDEOGRAPH + 0xD476: 0x5534, //CJK UNIFIED IDEOGRAPH + 0xD477: 0x552A, //CJK UNIFIED IDEOGRAPH + 0xD478: 0x5551, //CJK UNIFIED IDEOGRAPH + 0xD479: 0x5562, //CJK UNIFIED IDEOGRAPH + 0xD47A: 0x5536, //CJK UNIFIED IDEOGRAPH + 0xD47B: 0x5535, //CJK UNIFIED IDEOGRAPH + 0xD47C: 0x5530, //CJK UNIFIED IDEOGRAPH + 0xD47D: 0x5552, //CJK UNIFIED IDEOGRAPH + 0xD47E: 0x5545, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x550C, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x5532, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x5565, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x554E, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x5539, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x5548, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x552D, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x553B, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x5540, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x554B, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x570A, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x5707, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x57FB, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x5814, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x57E2, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x57F6, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x57ED, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x57FD, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x5808, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x57F8, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x580B, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x57F3, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x57CF, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x5807, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x57EE, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x57F2, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x57E5, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x57EC, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x57E1, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x580E, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x5810, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x57E7, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x5801, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x580C, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x57F1, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x57E9, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x580D, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x5804, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x595C, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x5A60, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x5A58, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x5A55, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x5A67, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x5A5E, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x5A38, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x5A6D, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x5A50, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x5A5F, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x5A65, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x5A53, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x5A64, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x5A57, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x5A43, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x5A5D, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x5A52, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x5A44, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x5A5B, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x5A48, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x5A8E, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x5A3E, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x5A4D, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0x5A39, //CJK UNIFIED IDEOGRAPH + 0xD4E7: 0x5A4C, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x5A70, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x5A69, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x5A47, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x5A51, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x5A56, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x5A42, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x5A5C, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x5B72, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x5B6E, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x5BC1, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x5C59, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x5D1E, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x5D1D, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x5D20, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x5D0C, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x5D28, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0x5D26, //CJK UNIFIED IDEOGRAPH + 0xD4FD: 0x5D25, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x5D0F, //CJK UNIFIED IDEOGRAPH + 0xD540: 0x5D30, //CJK UNIFIED IDEOGRAPH + 0xD541: 0x5D12, //CJK UNIFIED IDEOGRAPH + 0xD542: 0x5D23, //CJK UNIFIED IDEOGRAPH + 0xD543: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0xD544: 0x5D2E, //CJK UNIFIED IDEOGRAPH + 0xD545: 0x5E3E, //CJK UNIFIED IDEOGRAPH + 0xD546: 0x5E34, //CJK UNIFIED IDEOGRAPH + 0xD547: 0x5EB1, //CJK UNIFIED IDEOGRAPH + 0xD548: 0x5EB4, //CJK UNIFIED IDEOGRAPH + 0xD549: 0x5EB9, //CJK UNIFIED IDEOGRAPH + 0xD54A: 0x5EB2, //CJK UNIFIED IDEOGRAPH + 0xD54B: 0x5EB3, //CJK UNIFIED IDEOGRAPH + 0xD54C: 0x5F36, //CJK UNIFIED IDEOGRAPH + 0xD54D: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0xD54E: 0x5F9B, //CJK UNIFIED IDEOGRAPH + 0xD54F: 0x5F96, //CJK UNIFIED IDEOGRAPH + 0xD550: 0x5F9F, //CJK UNIFIED IDEOGRAPH + 0xD551: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xD552: 0x6090, //CJK UNIFIED IDEOGRAPH + 0xD553: 0x6086, //CJK UNIFIED IDEOGRAPH + 0xD554: 0x60BE, //CJK UNIFIED IDEOGRAPH + 0xD555: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0xD556: 0x60BA, //CJK UNIFIED IDEOGRAPH + 0xD557: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0xD558: 0x60D4, //CJK UNIFIED IDEOGRAPH + 0xD559: 0x60CF, //CJK UNIFIED IDEOGRAPH + 0xD55A: 0x60E4, //CJK UNIFIED IDEOGRAPH + 0xD55B: 0x60D9, //CJK UNIFIED IDEOGRAPH + 0xD55C: 0x60DD, //CJK UNIFIED IDEOGRAPH + 0xD55D: 0x60C8, //CJK UNIFIED IDEOGRAPH + 0xD55E: 0x60B1, //CJK UNIFIED IDEOGRAPH + 0xD55F: 0x60DB, //CJK UNIFIED IDEOGRAPH + 0xD560: 0x60B7, //CJK UNIFIED IDEOGRAPH + 0xD561: 0x60CA, //CJK UNIFIED IDEOGRAPH + 0xD562: 0x60BF, //CJK UNIFIED IDEOGRAPH + 0xD563: 0x60C3, //CJK UNIFIED IDEOGRAPH + 0xD564: 0x60CD, //CJK UNIFIED IDEOGRAPH + 0xD565: 0x60C0, //CJK UNIFIED IDEOGRAPH + 0xD566: 0x6332, //CJK UNIFIED IDEOGRAPH + 0xD567: 0x6365, //CJK UNIFIED IDEOGRAPH + 0xD568: 0x638A, //CJK UNIFIED IDEOGRAPH + 0xD569: 0x6382, //CJK UNIFIED IDEOGRAPH + 0xD56A: 0x637D, //CJK UNIFIED IDEOGRAPH + 0xD56B: 0x63BD, //CJK UNIFIED IDEOGRAPH + 0xD56C: 0x639E, //CJK UNIFIED IDEOGRAPH + 0xD56D: 0x63AD, //CJK UNIFIED IDEOGRAPH + 0xD56E: 0x639D, //CJK UNIFIED IDEOGRAPH + 0xD56F: 0x6397, //CJK UNIFIED IDEOGRAPH + 0xD570: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0xD571: 0x638E, //CJK UNIFIED IDEOGRAPH + 0xD572: 0x636F, //CJK UNIFIED IDEOGRAPH + 0xD573: 0x6387, //CJK UNIFIED IDEOGRAPH + 0xD574: 0x6390, //CJK UNIFIED IDEOGRAPH + 0xD575: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xD576: 0x63AF, //CJK UNIFIED IDEOGRAPH + 0xD577: 0x6375, //CJK UNIFIED IDEOGRAPH + 0xD578: 0x639C, //CJK UNIFIED IDEOGRAPH + 0xD579: 0x636D, //CJK UNIFIED IDEOGRAPH + 0xD57A: 0x63AE, //CJK UNIFIED IDEOGRAPH + 0xD57B: 0x637C, //CJK UNIFIED IDEOGRAPH + 0xD57C: 0x63A4, //CJK UNIFIED IDEOGRAPH + 0xD57D: 0x633B, //CJK UNIFIED IDEOGRAPH + 0xD57E: 0x639F, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x6378, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x6385, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x6381, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x6391, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0x638D, //CJK UNIFIED IDEOGRAPH + 0xD5A6: 0x6370, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x6553, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x65CD, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x6661, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0x665B, //CJK UNIFIED IDEOGRAPH + 0xD5AC: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x665C, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0x6662, //CJK UNIFIED IDEOGRAPH + 0xD5AF: 0x6718, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x6879, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6887, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x6890, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x689C, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x686D, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x686E, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x68AE, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x68AB, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x6956, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x686F, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x68A3, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x68AC, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x68A9, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6875, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x6874, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x68B2, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x6877, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x6892, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x687C, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x686B, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x6872, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x68AA, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6880, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6871, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x687E, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x689B, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x6896, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x688B, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x6889, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x68A4, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x6878, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x687B, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x6891, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x688C, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x688A, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x687D, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x6B36, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x6B33, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x6B91, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x6B8F, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x6B8E, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x6B8C, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x6C2A, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x6DAB, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x6DB4, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x6DB3, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x6E74, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x6DE9, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x6DE2, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x6DB7, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x6DF6, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x6DD4, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x6E00, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x6DC8, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x6DE0, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x6DDF, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x6DD6, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x6DBE, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x6DE5, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x6DDC, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x6DDD, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x6DDB, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x6DF4, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x6DCA, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x6DBD, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x6DED, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x6DF0, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x6DBA, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x6DC2, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x6DC9, //CJK UNIFIED IDEOGRAPH + 0xD640: 0x6DD0, //CJK UNIFIED IDEOGRAPH + 0xD641: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xD642: 0x6DD3, //CJK UNIFIED IDEOGRAPH + 0xD643: 0x6DFD, //CJK UNIFIED IDEOGRAPH + 0xD644: 0x6DD7, //CJK UNIFIED IDEOGRAPH + 0xD645: 0x6DCD, //CJK UNIFIED IDEOGRAPH + 0xD646: 0x6DE3, //CJK UNIFIED IDEOGRAPH + 0xD647: 0x6DBB, //CJK UNIFIED IDEOGRAPH + 0xD648: 0x70FA, //CJK UNIFIED IDEOGRAPH + 0xD649: 0x710D, //CJK UNIFIED IDEOGRAPH + 0xD64A: 0x70F7, //CJK UNIFIED IDEOGRAPH + 0xD64B: 0x7117, //CJK UNIFIED IDEOGRAPH + 0xD64C: 0x70F4, //CJK UNIFIED IDEOGRAPH + 0xD64D: 0x710C, //CJK UNIFIED IDEOGRAPH + 0xD64E: 0x70F0, //CJK UNIFIED IDEOGRAPH + 0xD64F: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xD650: 0x70F3, //CJK UNIFIED IDEOGRAPH + 0xD651: 0x7110, //CJK UNIFIED IDEOGRAPH + 0xD652: 0x70FC, //CJK UNIFIED IDEOGRAPH + 0xD653: 0x70FF, //CJK UNIFIED IDEOGRAPH + 0xD654: 0x7106, //CJK UNIFIED IDEOGRAPH + 0xD655: 0x7113, //CJK UNIFIED IDEOGRAPH + 0xD656: 0x7100, //CJK UNIFIED IDEOGRAPH + 0xD657: 0x70F8, //CJK UNIFIED IDEOGRAPH + 0xD658: 0x70F6, //CJK UNIFIED IDEOGRAPH + 0xD659: 0x710B, //CJK UNIFIED IDEOGRAPH + 0xD65A: 0x7102, //CJK UNIFIED IDEOGRAPH + 0xD65B: 0x710E, //CJK UNIFIED IDEOGRAPH + 0xD65C: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xD65D: 0x727B, //CJK UNIFIED IDEOGRAPH + 0xD65E: 0x727C, //CJK UNIFIED IDEOGRAPH + 0xD65F: 0x727F, //CJK UNIFIED IDEOGRAPH + 0xD660: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xD661: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xD662: 0x7307, //CJK UNIFIED IDEOGRAPH + 0xD663: 0x7311, //CJK UNIFIED IDEOGRAPH + 0xD664: 0x7318, //CJK UNIFIED IDEOGRAPH + 0xD665: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xD666: 0x7308, //CJK UNIFIED IDEOGRAPH + 0xD667: 0x72FF, //CJK UNIFIED IDEOGRAPH + 0xD668: 0x730F, //CJK UNIFIED IDEOGRAPH + 0xD669: 0x731E, //CJK UNIFIED IDEOGRAPH + 0xD66A: 0x7388, //CJK UNIFIED IDEOGRAPH + 0xD66B: 0x73F6, //CJK UNIFIED IDEOGRAPH + 0xD66C: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xD66D: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xD66E: 0x7404, //CJK UNIFIED IDEOGRAPH + 0xD66F: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xD670: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xD671: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xD672: 0x7400, //CJK UNIFIED IDEOGRAPH + 0xD673: 0x73FA, //CJK UNIFIED IDEOGRAPH + 0xD674: 0x73FC, //CJK UNIFIED IDEOGRAPH + 0xD675: 0x73FF, //CJK UNIFIED IDEOGRAPH + 0xD676: 0x740C, //CJK UNIFIED IDEOGRAPH + 0xD677: 0x740B, //CJK UNIFIED IDEOGRAPH + 0xD678: 0x73F4, //CJK UNIFIED IDEOGRAPH + 0xD679: 0x7408, //CJK UNIFIED IDEOGRAPH + 0xD67A: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xD67B: 0x7563, //CJK UNIFIED IDEOGRAPH + 0xD67C: 0x75CE, //CJK UNIFIED IDEOGRAPH + 0xD67D: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xD67E: 0x75CF, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x75CB, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x75CC, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x75D1, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x75D0, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x768F, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x7689, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x76D3, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x7739, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x772F, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x772D, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x7731, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x7732, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x7734, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x7733, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x773D, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x773B, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x7735, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x7848, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x7852, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x7849, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x784D, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x784A, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0x784C, //CJK UNIFIED IDEOGRAPH + 0xD6B9: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x7850, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x7964, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7967, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x7969, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x796A, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x7963, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x796B, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x7961, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x79BB, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x79FA, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x79F8, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x79F6, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x79F7, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x7A8F, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x7A94, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x7A90, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x7B47, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0x7B34, //CJK UNIFIED IDEOGRAPH + 0xD6CE: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x7B30, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x7B22, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x7B24, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x7B2A, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x7B1D, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x7B31, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x7B2B, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x7B2F, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x7B32, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x7B38, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x7B1A, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x7B23, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x7C94, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7C96, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x7CA3, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x7D3D, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x7D38, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x7D36, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x7D29, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x7D41, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x7D47, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x7D3E, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x7D4A, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x7D3B, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x7D28, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x7F63, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x7F95, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x7F9C, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x7F9B, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x7FCB, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x7FCD, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x7FD0, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x7FD1, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x7FC7, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x7FCF, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x7FC9, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x801F, //CJK UNIFIED IDEOGRAPH + 0xD740: 0x801E, //CJK UNIFIED IDEOGRAPH + 0xD741: 0x801B, //CJK UNIFIED IDEOGRAPH + 0xD742: 0x8047, //CJK UNIFIED IDEOGRAPH + 0xD743: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xD744: 0x8048, //CJK UNIFIED IDEOGRAPH + 0xD745: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xD746: 0x8125, //CJK UNIFIED IDEOGRAPH + 0xD747: 0x8119, //CJK UNIFIED IDEOGRAPH + 0xD748: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xD749: 0x812D, //CJK UNIFIED IDEOGRAPH + 0xD74A: 0x811F, //CJK UNIFIED IDEOGRAPH + 0xD74B: 0x812C, //CJK UNIFIED IDEOGRAPH + 0xD74C: 0x811E, //CJK UNIFIED IDEOGRAPH + 0xD74D: 0x8121, //CJK UNIFIED IDEOGRAPH + 0xD74E: 0x8115, //CJK UNIFIED IDEOGRAPH + 0xD74F: 0x8127, //CJK UNIFIED IDEOGRAPH + 0xD750: 0x811D, //CJK UNIFIED IDEOGRAPH + 0xD751: 0x8122, //CJK UNIFIED IDEOGRAPH + 0xD752: 0x8211, //CJK UNIFIED IDEOGRAPH + 0xD753: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xD754: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xD755: 0x823A, //CJK UNIFIED IDEOGRAPH + 0xD756: 0x8234, //CJK UNIFIED IDEOGRAPH + 0xD757: 0x8232, //CJK UNIFIED IDEOGRAPH + 0xD758: 0x8274, //CJK UNIFIED IDEOGRAPH + 0xD759: 0x8390, //CJK UNIFIED IDEOGRAPH + 0xD75A: 0x83A3, //CJK UNIFIED IDEOGRAPH + 0xD75B: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xD75C: 0x838D, //CJK UNIFIED IDEOGRAPH + 0xD75D: 0x837A, //CJK UNIFIED IDEOGRAPH + 0xD75E: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xD75F: 0x83A4, //CJK UNIFIED IDEOGRAPH + 0xD760: 0x8374, //CJK UNIFIED IDEOGRAPH + 0xD761: 0x838F, //CJK UNIFIED IDEOGRAPH + 0xD762: 0x8381, //CJK UNIFIED IDEOGRAPH + 0xD763: 0x8395, //CJK UNIFIED IDEOGRAPH + 0xD764: 0x8399, //CJK UNIFIED IDEOGRAPH + 0xD765: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xD766: 0x8394, //CJK UNIFIED IDEOGRAPH + 0xD767: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xD768: 0x837D, //CJK UNIFIED IDEOGRAPH + 0xD769: 0x8383, //CJK UNIFIED IDEOGRAPH + 0xD76A: 0x838C, //CJK UNIFIED IDEOGRAPH + 0xD76B: 0x839D, //CJK UNIFIED IDEOGRAPH + 0xD76C: 0x839B, //CJK UNIFIED IDEOGRAPH + 0xD76D: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xD76E: 0x838B, //CJK UNIFIED IDEOGRAPH + 0xD76F: 0x837E, //CJK UNIFIED IDEOGRAPH + 0xD770: 0x83A5, //CJK UNIFIED IDEOGRAPH + 0xD771: 0x83AF, //CJK UNIFIED IDEOGRAPH + 0xD772: 0x8388, //CJK UNIFIED IDEOGRAPH + 0xD773: 0x8397, //CJK UNIFIED IDEOGRAPH + 0xD774: 0x83B0, //CJK UNIFIED IDEOGRAPH + 0xD775: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xD776: 0x83A6, //CJK UNIFIED IDEOGRAPH + 0xD777: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xD778: 0x83AE, //CJK UNIFIED IDEOGRAPH + 0xD779: 0x8376, //CJK UNIFIED IDEOGRAPH + 0xD77A: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xD77B: 0x8659, //CJK UNIFIED IDEOGRAPH + 0xD77C: 0x8656, //CJK UNIFIED IDEOGRAPH + 0xD77D: 0x86BF, //CJK UNIFIED IDEOGRAPH + 0xD77E: 0x86B7, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x86C2, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x86C1, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x86C5, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x86BA, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x86C8, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x86B9, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x86B3, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x86B8, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x86CC, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x86B4, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x86BB, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x86BC, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x86C3, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x86BD, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x86BE, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x8889, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x8895, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x88A8, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x88AA, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x889A, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x8891, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x88A1, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x889F, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x8898, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x88A7, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x889B, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x88AC, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x888C, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x8893, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x888E, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x8982, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x89D6, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x89D9, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x89D5, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x8A30, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x8A27, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0x8A2C, //CJK UNIFIED IDEOGRAPH + 0xD7CC: 0x8A1E, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x8C39, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x8C3B, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x8C5C, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x8C5D, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x8C7D, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x8CA5, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x8D7D, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x8D7B, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x8D79, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x8DBC, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x8DB9, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x8DBF, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x8DC1, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x8ED8, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x8EDE, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x8EDD, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x8EDC, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x8ED7, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x8EE0, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x8EE1, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x9024, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xD7E5: 0x901C, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x900C, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x90EF, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x90EA, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x90F0, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x90F4, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x90F2, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x90F3, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x90D4, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x90EB, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x90EC, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x90E9, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x915A, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x9153, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x9155, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x91EC, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x91F4, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x91F1, //CJK UNIFIED IDEOGRAPH + 0xD7FA: 0x91F3, //CJK UNIFIED IDEOGRAPH + 0xD7FB: 0x91F8, //CJK UNIFIED IDEOGRAPH + 0xD7FC: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xD7FD: 0x91F9, //CJK UNIFIED IDEOGRAPH + 0xD7FE: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xD840: 0x91EB, //CJK UNIFIED IDEOGRAPH + 0xD841: 0x91F7, //CJK UNIFIED IDEOGRAPH + 0xD842: 0x91E8, //CJK UNIFIED IDEOGRAPH + 0xD843: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xD844: 0x957A, //CJK UNIFIED IDEOGRAPH + 0xD845: 0x9586, //CJK UNIFIED IDEOGRAPH + 0xD846: 0x9588, //CJK UNIFIED IDEOGRAPH + 0xD847: 0x967C, //CJK UNIFIED IDEOGRAPH + 0xD848: 0x966D, //CJK UNIFIED IDEOGRAPH + 0xD849: 0x966B, //CJK UNIFIED IDEOGRAPH + 0xD84A: 0x9671, //CJK UNIFIED IDEOGRAPH + 0xD84B: 0x966F, //CJK UNIFIED IDEOGRAPH + 0xD84C: 0x96BF, //CJK UNIFIED IDEOGRAPH + 0xD84D: 0x976A, //CJK UNIFIED IDEOGRAPH + 0xD84E: 0x9804, //CJK UNIFIED IDEOGRAPH + 0xD84F: 0x98E5, //CJK UNIFIED IDEOGRAPH + 0xD850: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xD851: 0x509B, //CJK UNIFIED IDEOGRAPH + 0xD852: 0x5095, //CJK UNIFIED IDEOGRAPH + 0xD853: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xD854: 0x509E, //CJK UNIFIED IDEOGRAPH + 0xD855: 0x508B, //CJK UNIFIED IDEOGRAPH + 0xD856: 0x50A3, //CJK UNIFIED IDEOGRAPH + 0xD857: 0x5083, //CJK UNIFIED IDEOGRAPH + 0xD858: 0x508C, //CJK UNIFIED IDEOGRAPH + 0xD859: 0x508E, //CJK UNIFIED IDEOGRAPH + 0xD85A: 0x509D, //CJK UNIFIED IDEOGRAPH + 0xD85B: 0x5068, //CJK UNIFIED IDEOGRAPH + 0xD85C: 0x509C, //CJK UNIFIED IDEOGRAPH + 0xD85D: 0x5092, //CJK UNIFIED IDEOGRAPH + 0xD85E: 0x5082, //CJK UNIFIED IDEOGRAPH + 0xD85F: 0x5087, //CJK UNIFIED IDEOGRAPH + 0xD860: 0x515F, //CJK UNIFIED IDEOGRAPH + 0xD861: 0x51D4, //CJK UNIFIED IDEOGRAPH + 0xD862: 0x5312, //CJK UNIFIED IDEOGRAPH + 0xD863: 0x5311, //CJK UNIFIED IDEOGRAPH + 0xD864: 0x53A4, //CJK UNIFIED IDEOGRAPH + 0xD865: 0x53A7, //CJK UNIFIED IDEOGRAPH + 0xD866: 0x5591, //CJK UNIFIED IDEOGRAPH + 0xD867: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0xD868: 0x55A5, //CJK UNIFIED IDEOGRAPH + 0xD869: 0x55AD, //CJK UNIFIED IDEOGRAPH + 0xD86A: 0x5577, //CJK UNIFIED IDEOGRAPH + 0xD86B: 0x5645, //CJK UNIFIED IDEOGRAPH + 0xD86C: 0x55A2, //CJK UNIFIED IDEOGRAPH + 0xD86D: 0x5593, //CJK UNIFIED IDEOGRAPH + 0xD86E: 0x5588, //CJK UNIFIED IDEOGRAPH + 0xD86F: 0x558F, //CJK UNIFIED IDEOGRAPH + 0xD870: 0x55B5, //CJK UNIFIED IDEOGRAPH + 0xD871: 0x5581, //CJK UNIFIED IDEOGRAPH + 0xD872: 0x55A3, //CJK UNIFIED IDEOGRAPH + 0xD873: 0x5592, //CJK UNIFIED IDEOGRAPH + 0xD874: 0x55A4, //CJK UNIFIED IDEOGRAPH + 0xD875: 0x557D, //CJK UNIFIED IDEOGRAPH + 0xD876: 0x558C, //CJK UNIFIED IDEOGRAPH + 0xD877: 0x55A6, //CJK UNIFIED IDEOGRAPH + 0xD878: 0x557F, //CJK UNIFIED IDEOGRAPH + 0xD879: 0x5595, //CJK UNIFIED IDEOGRAPH + 0xD87A: 0x55A1, //CJK UNIFIED IDEOGRAPH + 0xD87B: 0x558E, //CJK UNIFIED IDEOGRAPH + 0xD87C: 0x570C, //CJK UNIFIED IDEOGRAPH + 0xD87D: 0x5829, //CJK UNIFIED IDEOGRAPH + 0xD87E: 0x5837, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x5819, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x5827, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x5823, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x5828, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x57F5, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x5848, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x5825, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x581C, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x581B, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x5833, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x583F, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x5836, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x582E, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x5839, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x5838, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x582D, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x582C, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x583B, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x5961, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x5AAF, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x5A94, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x5A9F, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x5A7A, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x5AA2, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x5A9E, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x5A78, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x5AA6, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x5A7C, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x5AA5, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x5AAC, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x5A95, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x5AAE, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x5A37, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x5A84, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x5A8A, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x5A97, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x5A83, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x5A8B, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x5AA9, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x5A7B, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x5A7D, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x5A8C, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x5A9C, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x5A8F, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x5A93, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x5A9D, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x5BEA, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x5BCD, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x5BCB, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x5BD1, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x5BCA, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x5BCE, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x5C0C, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x5C30, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x5D37, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5D43, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x5D6B, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x5D41, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x5D3F, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x5D35, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x5D51, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x5D55, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x5D33, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x5D3A, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x5D3D, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x5D31, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x5D59, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x5D39, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x5D49, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x5D38, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x5D3C, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x5D32, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x5D36, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x5D40, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x5D45, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x5E41, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x5F58, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x5FA6, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x5FA5, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x5FAB, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x60C9, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x60B9, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x60CC, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x60E2, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x60CE, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x60C4, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x6114, //CJK UNIFIED IDEOGRAPH + 0xD940: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xD941: 0x610A, //CJK UNIFIED IDEOGRAPH + 0xD942: 0x6116, //CJK UNIFIED IDEOGRAPH + 0xD943: 0x6105, //CJK UNIFIED IDEOGRAPH + 0xD944: 0x60F5, //CJK UNIFIED IDEOGRAPH + 0xD945: 0x6113, //CJK UNIFIED IDEOGRAPH + 0xD946: 0x60F8, //CJK UNIFIED IDEOGRAPH + 0xD947: 0x60FC, //CJK UNIFIED IDEOGRAPH + 0xD948: 0x60FE, //CJK UNIFIED IDEOGRAPH + 0xD949: 0x60C1, //CJK UNIFIED IDEOGRAPH + 0xD94A: 0x6103, //CJK UNIFIED IDEOGRAPH + 0xD94B: 0x6118, //CJK UNIFIED IDEOGRAPH + 0xD94C: 0x611D, //CJK UNIFIED IDEOGRAPH + 0xD94D: 0x6110, //CJK UNIFIED IDEOGRAPH + 0xD94E: 0x60FF, //CJK UNIFIED IDEOGRAPH + 0xD94F: 0x6104, //CJK UNIFIED IDEOGRAPH + 0xD950: 0x610B, //CJK UNIFIED IDEOGRAPH + 0xD951: 0x624A, //CJK UNIFIED IDEOGRAPH + 0xD952: 0x6394, //CJK UNIFIED IDEOGRAPH + 0xD953: 0x63B1, //CJK UNIFIED IDEOGRAPH + 0xD954: 0x63B0, //CJK UNIFIED IDEOGRAPH + 0xD955: 0x63CE, //CJK UNIFIED IDEOGRAPH + 0xD956: 0x63E5, //CJK UNIFIED IDEOGRAPH + 0xD957: 0x63E8, //CJK UNIFIED IDEOGRAPH + 0xD958: 0x63EF, //CJK UNIFIED IDEOGRAPH + 0xD959: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0xD95A: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xD95B: 0x63F3, //CJK UNIFIED IDEOGRAPH + 0xD95C: 0x63CA, //CJK UNIFIED IDEOGRAPH + 0xD95D: 0x63E0, //CJK UNIFIED IDEOGRAPH + 0xD95E: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xD95F: 0x63D5, //CJK UNIFIED IDEOGRAPH + 0xD960: 0x63F2, //CJK UNIFIED IDEOGRAPH + 0xD961: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xD962: 0x6461, //CJK UNIFIED IDEOGRAPH + 0xD963: 0x63DF, //CJK UNIFIED IDEOGRAPH + 0xD964: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0xD965: 0x63DD, //CJK UNIFIED IDEOGRAPH + 0xD966: 0x63DC, //CJK UNIFIED IDEOGRAPH + 0xD967: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xD968: 0x63D8, //CJK UNIFIED IDEOGRAPH + 0xD969: 0x63D3, //CJK UNIFIED IDEOGRAPH + 0xD96A: 0x63C2, //CJK UNIFIED IDEOGRAPH + 0xD96B: 0x63C7, //CJK UNIFIED IDEOGRAPH + 0xD96C: 0x63CC, //CJK UNIFIED IDEOGRAPH + 0xD96D: 0x63CB, //CJK UNIFIED IDEOGRAPH + 0xD96E: 0x63C8, //CJK UNIFIED IDEOGRAPH + 0xD96F: 0x63F0, //CJK UNIFIED IDEOGRAPH + 0xD970: 0x63D7, //CJK UNIFIED IDEOGRAPH + 0xD971: 0x63D9, //CJK UNIFIED IDEOGRAPH + 0xD972: 0x6532, //CJK UNIFIED IDEOGRAPH + 0xD973: 0x6567, //CJK UNIFIED IDEOGRAPH + 0xD974: 0x656A, //CJK UNIFIED IDEOGRAPH + 0xD975: 0x6564, //CJK UNIFIED IDEOGRAPH + 0xD976: 0x655C, //CJK UNIFIED IDEOGRAPH + 0xD977: 0x6568, //CJK UNIFIED IDEOGRAPH + 0xD978: 0x6565, //CJK UNIFIED IDEOGRAPH + 0xD979: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xD97A: 0x659D, //CJK UNIFIED IDEOGRAPH + 0xD97B: 0x659E, //CJK UNIFIED IDEOGRAPH + 0xD97C: 0x65AE, //CJK UNIFIED IDEOGRAPH + 0xD97D: 0x65D0, //CJK UNIFIED IDEOGRAPH + 0xD97E: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x667C, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x666C, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x667B, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x6680, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x6671, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x6679, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x666A, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x6672, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x6701, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x690C, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x68D3, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x6904, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x68DC, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x692A, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x68EC, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x68EA, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x68F1, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x690F, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x68D6, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x68F7, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x68EB, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x68E4, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x68F6, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x6913, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x6910, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x68F3, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x6907, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x68CC, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x6908, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x6970, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x68B4, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x6911, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x6914, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x68F8, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x68D0, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x68FD, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x68FC, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x690B, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x690A, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x6917, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x68CE, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x68DD, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x68DE, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x68E6, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x68F4, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x68D1, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x6906, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x68E9, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x6915, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x6925, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x68C7, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6B3B, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x6B3F, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x6B3C, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x6B94, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x6B97, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x6B99, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x6BBD, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x6BF0, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x6BF2, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x6C30, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x6E46, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x6E47, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x6E49, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x6E88, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x6E45, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x6E62, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x6E3F, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x6E41, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x6E5D, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x6E1C, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x6E33, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x6E4B, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x6E40, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x6E51, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x6E3B, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x6E03, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0xDA40: 0x6E68, //CJK UNIFIED IDEOGRAPH + 0xDA41: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xDA42: 0x6E61, //CJK UNIFIED IDEOGRAPH + 0xDA43: 0x6E31, //CJK UNIFIED IDEOGRAPH + 0xDA44: 0x6E28, //CJK UNIFIED IDEOGRAPH + 0xDA45: 0x6E60, //CJK UNIFIED IDEOGRAPH + 0xDA46: 0x6E71, //CJK UNIFIED IDEOGRAPH + 0xDA47: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xDA48: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xDA49: 0x6E22, //CJK UNIFIED IDEOGRAPH + 0xDA4A: 0x6E30, //CJK UNIFIED IDEOGRAPH + 0xDA4B: 0x6E53, //CJK UNIFIED IDEOGRAPH + 0xDA4C: 0x6E65, //CJK UNIFIED IDEOGRAPH + 0xDA4D: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xDA4E: 0x6E78, //CJK UNIFIED IDEOGRAPH + 0xDA4F: 0x6E64, //CJK UNIFIED IDEOGRAPH + 0xDA50: 0x6E77, //CJK UNIFIED IDEOGRAPH + 0xDA51: 0x6E55, //CJK UNIFIED IDEOGRAPH + 0xDA52: 0x6E79, //CJK UNIFIED IDEOGRAPH + 0xDA53: 0x6E52, //CJK UNIFIED IDEOGRAPH + 0xDA54: 0x6E66, //CJK UNIFIED IDEOGRAPH + 0xDA55: 0x6E35, //CJK UNIFIED IDEOGRAPH + 0xDA56: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0xDA57: 0x6E5A, //CJK UNIFIED IDEOGRAPH + 0xDA58: 0x7120, //CJK UNIFIED IDEOGRAPH + 0xDA59: 0x711E, //CJK UNIFIED IDEOGRAPH + 0xDA5A: 0x712F, //CJK UNIFIED IDEOGRAPH + 0xDA5B: 0x70FB, //CJK UNIFIED IDEOGRAPH + 0xDA5C: 0x712E, //CJK UNIFIED IDEOGRAPH + 0xDA5D: 0x7131, //CJK UNIFIED IDEOGRAPH + 0xDA5E: 0x7123, //CJK UNIFIED IDEOGRAPH + 0xDA5F: 0x7125, //CJK UNIFIED IDEOGRAPH + 0xDA60: 0x7122, //CJK UNIFIED IDEOGRAPH + 0xDA61: 0x7132, //CJK UNIFIED IDEOGRAPH + 0xDA62: 0x711F, //CJK UNIFIED IDEOGRAPH + 0xDA63: 0x7128, //CJK UNIFIED IDEOGRAPH + 0xDA64: 0x713A, //CJK UNIFIED IDEOGRAPH + 0xDA65: 0x711B, //CJK UNIFIED IDEOGRAPH + 0xDA66: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xDA67: 0x725A, //CJK UNIFIED IDEOGRAPH + 0xDA68: 0x7288, //CJK UNIFIED IDEOGRAPH + 0xDA69: 0x7289, //CJK UNIFIED IDEOGRAPH + 0xDA6A: 0x7286, //CJK UNIFIED IDEOGRAPH + 0xDA6B: 0x7285, //CJK UNIFIED IDEOGRAPH + 0xDA6C: 0x728B, //CJK UNIFIED IDEOGRAPH + 0xDA6D: 0x7312, //CJK UNIFIED IDEOGRAPH + 0xDA6E: 0x730B, //CJK UNIFIED IDEOGRAPH + 0xDA6F: 0x7330, //CJK UNIFIED IDEOGRAPH + 0xDA70: 0x7322, //CJK UNIFIED IDEOGRAPH + 0xDA71: 0x7331, //CJK UNIFIED IDEOGRAPH + 0xDA72: 0x7333, //CJK UNIFIED IDEOGRAPH + 0xDA73: 0x7327, //CJK UNIFIED IDEOGRAPH + 0xDA74: 0x7332, //CJK UNIFIED IDEOGRAPH + 0xDA75: 0x732D, //CJK UNIFIED IDEOGRAPH + 0xDA76: 0x7326, //CJK UNIFIED IDEOGRAPH + 0xDA77: 0x7323, //CJK UNIFIED IDEOGRAPH + 0xDA78: 0x7335, //CJK UNIFIED IDEOGRAPH + 0xDA79: 0x730C, //CJK UNIFIED IDEOGRAPH + 0xDA7A: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xDA7B: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xDA7C: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xDA7D: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xDA7E: 0x7416, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x741A, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x742D, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x7431, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x7424, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x7423, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x741D, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x74FB, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x756C, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x75E7, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x75DA, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x75E1, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x75E6, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x75DD, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x75DF, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x75E4, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x75D7, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x7695, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x7692, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x76DA, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x7744, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x7745, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x774A, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x774E, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x774B, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x774C, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x77DE, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x77EC, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x7860, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x7865, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x785C, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x786D, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x7871, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x786A, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x786E, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x7870, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x7869, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x7868, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x785E, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x7862, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x7974, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x7973, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x7972, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x7970, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x7A02, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x7A0A, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x7A03, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x7A0C, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x7A04, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x7A99, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x7AE4, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x7B4A, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x7B3B, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x7B44, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x7B4E, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x7B40, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x7B58, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x7C9E, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x7D58, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x7D6F, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x7D53, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x7D67, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x7D6D, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x7D6B, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x7D52, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x7D54, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x7D69, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x7D51, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x7D5F, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x7F3E, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x7F3F, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x7F65, //CJK UNIFIED IDEOGRAPH + 0xDB40: 0x7F66, //CJK UNIFIED IDEOGRAPH + 0xDB41: 0x7FA2, //CJK UNIFIED IDEOGRAPH + 0xDB42: 0x7FA0, //CJK UNIFIED IDEOGRAPH + 0xDB43: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xDB44: 0x7FD7, //CJK UNIFIED IDEOGRAPH + 0xDB45: 0x8051, //CJK UNIFIED IDEOGRAPH + 0xDB46: 0x804F, //CJK UNIFIED IDEOGRAPH + 0xDB47: 0x8050, //CJK UNIFIED IDEOGRAPH + 0xDB48: 0x80FE, //CJK UNIFIED IDEOGRAPH + 0xDB49: 0x80D4, //CJK UNIFIED IDEOGRAPH + 0xDB4A: 0x8143, //CJK UNIFIED IDEOGRAPH + 0xDB4B: 0x814A, //CJK UNIFIED IDEOGRAPH + 0xDB4C: 0x8152, //CJK UNIFIED IDEOGRAPH + 0xDB4D: 0x814F, //CJK UNIFIED IDEOGRAPH + 0xDB4E: 0x8147, //CJK UNIFIED IDEOGRAPH + 0xDB4F: 0x813D, //CJK UNIFIED IDEOGRAPH + 0xDB50: 0x814D, //CJK UNIFIED IDEOGRAPH + 0xDB51: 0x813A, //CJK UNIFIED IDEOGRAPH + 0xDB52: 0x81E6, //CJK UNIFIED IDEOGRAPH + 0xDB53: 0x81EE, //CJK UNIFIED IDEOGRAPH + 0xDB54: 0x81F7, //CJK UNIFIED IDEOGRAPH + 0xDB55: 0x81F8, //CJK UNIFIED IDEOGRAPH + 0xDB56: 0x81F9, //CJK UNIFIED IDEOGRAPH + 0xDB57: 0x8204, //CJK UNIFIED IDEOGRAPH + 0xDB58: 0x823C, //CJK UNIFIED IDEOGRAPH + 0xDB59: 0x823D, //CJK UNIFIED IDEOGRAPH + 0xDB5A: 0x823F, //CJK UNIFIED IDEOGRAPH + 0xDB5B: 0x8275, //CJK UNIFIED IDEOGRAPH + 0xDB5C: 0x833B, //CJK UNIFIED IDEOGRAPH + 0xDB5D: 0x83CF, //CJK UNIFIED IDEOGRAPH + 0xDB5E: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xDB5F: 0x8423, //CJK UNIFIED IDEOGRAPH + 0xDB60: 0x83C0, //CJK UNIFIED IDEOGRAPH + 0xDB61: 0x83E8, //CJK UNIFIED IDEOGRAPH + 0xDB62: 0x8412, //CJK UNIFIED IDEOGRAPH + 0xDB63: 0x83E7, //CJK UNIFIED IDEOGRAPH + 0xDB64: 0x83E4, //CJK UNIFIED IDEOGRAPH + 0xDB65: 0x83FC, //CJK UNIFIED IDEOGRAPH + 0xDB66: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xDB67: 0x8410, //CJK UNIFIED IDEOGRAPH + 0xDB68: 0x83C6, //CJK UNIFIED IDEOGRAPH + 0xDB69: 0x83C8, //CJK UNIFIED IDEOGRAPH + 0xDB6A: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xDB6B: 0x83E3, //CJK UNIFIED IDEOGRAPH + 0xDB6C: 0x83BF, //CJK UNIFIED IDEOGRAPH + 0xDB6D: 0x8401, //CJK UNIFIED IDEOGRAPH + 0xDB6E: 0x83DD, //CJK UNIFIED IDEOGRAPH + 0xDB6F: 0x83E5, //CJK UNIFIED IDEOGRAPH + 0xDB70: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xDB71: 0x83FF, //CJK UNIFIED IDEOGRAPH + 0xDB72: 0x83E1, //CJK UNIFIED IDEOGRAPH + 0xDB73: 0x83CB, //CJK UNIFIED IDEOGRAPH + 0xDB74: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xDB75: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xDB76: 0x83F5, //CJK UNIFIED IDEOGRAPH + 0xDB77: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xDB78: 0x8409, //CJK UNIFIED IDEOGRAPH + 0xDB79: 0x840F, //CJK UNIFIED IDEOGRAPH + 0xDB7A: 0x83DE, //CJK UNIFIED IDEOGRAPH + 0xDB7B: 0x8411, //CJK UNIFIED IDEOGRAPH + 0xDB7C: 0x8406, //CJK UNIFIED IDEOGRAPH + 0xDB7D: 0x83C2, //CJK UNIFIED IDEOGRAPH + 0xDB7E: 0x83F3, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x83D5, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x83FA, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x83D1, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x83EA, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x83C3, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x83EC, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x83EE, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x83C4, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x83D7, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x83E2, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x841B, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x83DB, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x83FE, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x86D8, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x86E2, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x86E6, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x86D3, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x86E3, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x86DA, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x86EA, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x86DD, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x86EB, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x86DC, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x86D7, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x86E8, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x86D1, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x8848, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x8856, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x8855, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x88BA, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x88D7, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0x88B9, //CJK UNIFIED IDEOGRAPH + 0xDBC6: 0x88B8, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x88C0, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x88BE, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x88B6, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x88BC, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x88BD, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x88B2, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x8901, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x88C9, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x8995, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x8997, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x89DB, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x8A4E, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x8A4D, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x8A39, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x8A59, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x8A40, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x8A57, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x8A58, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x8A44, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x8A45, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x8A4A, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x8A4C, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0x8A4F, //CJK UNIFIED IDEOGRAPH + 0xDBE5: 0x8C5F, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x8C81, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x8C80, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x8CBA, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x8CBE, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x8CB9, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x8CB5, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x8D84, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x8D80, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x8D89, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x8DD8, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x8DD3, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x8DCD, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x8DC7, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x8DDC, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x8DD5, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x8DD9, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x8DC8, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x8DD7, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x8DC5, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x8EEF, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x8EF7, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x8EFA, //CJK UNIFIED IDEOGRAPH + 0xDC40: 0x8EF9, //CJK UNIFIED IDEOGRAPH + 0xDC41: 0x8EE6, //CJK UNIFIED IDEOGRAPH + 0xDC42: 0x8EEE, //CJK UNIFIED IDEOGRAPH + 0xDC43: 0x8EE5, //CJK UNIFIED IDEOGRAPH + 0xDC44: 0x8EF5, //CJK UNIFIED IDEOGRAPH + 0xDC45: 0x8EE7, //CJK UNIFIED IDEOGRAPH + 0xDC46: 0x8EE8, //CJK UNIFIED IDEOGRAPH + 0xDC47: 0x8EF6, //CJK UNIFIED IDEOGRAPH + 0xDC48: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xDC49: 0x8EF1, //CJK UNIFIED IDEOGRAPH + 0xDC4A: 0x8EEC, //CJK UNIFIED IDEOGRAPH + 0xDC4B: 0x8EF4, //CJK UNIFIED IDEOGRAPH + 0xDC4C: 0x8EE9, //CJK UNIFIED IDEOGRAPH + 0xDC4D: 0x902D, //CJK UNIFIED IDEOGRAPH + 0xDC4E: 0x9034, //CJK UNIFIED IDEOGRAPH + 0xDC4F: 0x902F, //CJK UNIFIED IDEOGRAPH + 0xDC50: 0x9106, //CJK UNIFIED IDEOGRAPH + 0xDC51: 0x912C, //CJK UNIFIED IDEOGRAPH + 0xDC52: 0x9104, //CJK UNIFIED IDEOGRAPH + 0xDC53: 0x90FF, //CJK UNIFIED IDEOGRAPH + 0xDC54: 0x90FC, //CJK UNIFIED IDEOGRAPH + 0xDC55: 0x9108, //CJK UNIFIED IDEOGRAPH + 0xDC56: 0x90F9, //CJK UNIFIED IDEOGRAPH + 0xDC57: 0x90FB, //CJK UNIFIED IDEOGRAPH + 0xDC58: 0x9101, //CJK UNIFIED IDEOGRAPH + 0xDC59: 0x9100, //CJK UNIFIED IDEOGRAPH + 0xDC5A: 0x9107, //CJK UNIFIED IDEOGRAPH + 0xDC5B: 0x9105, //CJK UNIFIED IDEOGRAPH + 0xDC5C: 0x9103, //CJK UNIFIED IDEOGRAPH + 0xDC5D: 0x9161, //CJK UNIFIED IDEOGRAPH + 0xDC5E: 0x9164, //CJK UNIFIED IDEOGRAPH + 0xDC5F: 0x915F, //CJK UNIFIED IDEOGRAPH + 0xDC60: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xDC61: 0x9160, //CJK UNIFIED IDEOGRAPH + 0xDC62: 0x9201, //CJK UNIFIED IDEOGRAPH + 0xDC63: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xDC64: 0x9225, //CJK UNIFIED IDEOGRAPH + 0xDC65: 0x9203, //CJK UNIFIED IDEOGRAPH + 0xDC66: 0x921A, //CJK UNIFIED IDEOGRAPH + 0xDC67: 0x9226, //CJK UNIFIED IDEOGRAPH + 0xDC68: 0x920F, //CJK UNIFIED IDEOGRAPH + 0xDC69: 0x920C, //CJK UNIFIED IDEOGRAPH + 0xDC6A: 0x9200, //CJK UNIFIED IDEOGRAPH + 0xDC6B: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xDC6C: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xDC6D: 0x91FD, //CJK UNIFIED IDEOGRAPH + 0xDC6E: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xDC6F: 0x9204, //CJK UNIFIED IDEOGRAPH + 0xDC70: 0x9227, //CJK UNIFIED IDEOGRAPH + 0xDC71: 0x9202, //CJK UNIFIED IDEOGRAPH + 0xDC72: 0x921C, //CJK UNIFIED IDEOGRAPH + 0xDC73: 0x9224, //CJK UNIFIED IDEOGRAPH + 0xDC74: 0x9219, //CJK UNIFIED IDEOGRAPH + 0xDC75: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xDC76: 0x9205, //CJK UNIFIED IDEOGRAPH + 0xDC77: 0x9216, //CJK UNIFIED IDEOGRAPH + 0xDC78: 0x957B, //CJK UNIFIED IDEOGRAPH + 0xDC79: 0x958D, //CJK UNIFIED IDEOGRAPH + 0xDC7A: 0x958C, //CJK UNIFIED IDEOGRAPH + 0xDC7B: 0x9590, //CJK UNIFIED IDEOGRAPH + 0xDC7C: 0x9687, //CJK UNIFIED IDEOGRAPH + 0xDC7D: 0x967E, //CJK UNIFIED IDEOGRAPH + 0xDC7E: 0x9688, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x9689, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x9683, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x9680, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x96C2, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0x96C8, //CJK UNIFIED IDEOGRAPH + 0xDCA6: 0x96C3, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x96F1, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x976C, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x9770, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x976E, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x9807, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x98A9, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x9CE6, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x4E83, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x4E84, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x50BD, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x50BF, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x50C6, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x50AE, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x50C4, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x50C8, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x50B0, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x50C1, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x50BA, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x50B1, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x50CB, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x50B6, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x50B8, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x51D7, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x527A, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x5278, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x527B, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x527C, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x55C3, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x55DB, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x55CC, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x55D0, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x55CB, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x55CA, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x55DD, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x55C0, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x55E9, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x55BF, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x55D2, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x558D, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x55CF, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x55D5, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x55E2, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x55D6, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x55C8, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x55F2, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x55CD, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x55D9, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x55C2, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x5714, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x5853, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x5868, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x5864, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x584F, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x584D, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x5849, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x586F, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x5855, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x584E, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x585D, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x5859, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x5865, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x585B, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x583D, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x5863, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x5871, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x5AC7, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x5ABA, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x5AB8, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x5AB1, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x5AB5, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x5AB0, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x5ABF, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x5AC8, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x5ABB, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x5AC6, //CJK UNIFIED IDEOGRAPH + 0xDD40: 0x5AB7, //CJK UNIFIED IDEOGRAPH + 0xDD41: 0x5AC0, //CJK UNIFIED IDEOGRAPH + 0xDD42: 0x5ACA, //CJK UNIFIED IDEOGRAPH + 0xDD43: 0x5AB4, //CJK UNIFIED IDEOGRAPH + 0xDD44: 0x5AB6, //CJK UNIFIED IDEOGRAPH + 0xDD45: 0x5ACD, //CJK UNIFIED IDEOGRAPH + 0xDD46: 0x5AB9, //CJK UNIFIED IDEOGRAPH + 0xDD47: 0x5A90, //CJK UNIFIED IDEOGRAPH + 0xDD48: 0x5BD6, //CJK UNIFIED IDEOGRAPH + 0xDD49: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xDD4A: 0x5BD9, //CJK UNIFIED IDEOGRAPH + 0xDD4B: 0x5C1F, //CJK UNIFIED IDEOGRAPH + 0xDD4C: 0x5C33, //CJK UNIFIED IDEOGRAPH + 0xDD4D: 0x5D71, //CJK UNIFIED IDEOGRAPH + 0xDD4E: 0x5D63, //CJK UNIFIED IDEOGRAPH + 0xDD4F: 0x5D4A, //CJK UNIFIED IDEOGRAPH + 0xDD50: 0x5D65, //CJK UNIFIED IDEOGRAPH + 0xDD51: 0x5D72, //CJK UNIFIED IDEOGRAPH + 0xDD52: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xDD53: 0x5D5E, //CJK UNIFIED IDEOGRAPH + 0xDD54: 0x5D68, //CJK UNIFIED IDEOGRAPH + 0xDD55: 0x5D67, //CJK UNIFIED IDEOGRAPH + 0xDD56: 0x5D62, //CJK UNIFIED IDEOGRAPH + 0xDD57: 0x5DF0, //CJK UNIFIED IDEOGRAPH + 0xDD58: 0x5E4F, //CJK UNIFIED IDEOGRAPH + 0xDD59: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0xDD5A: 0x5E4A, //CJK UNIFIED IDEOGRAPH + 0xDD5B: 0x5E4D, //CJK UNIFIED IDEOGRAPH + 0xDD5C: 0x5E4B, //CJK UNIFIED IDEOGRAPH + 0xDD5D: 0x5EC5, //CJK UNIFIED IDEOGRAPH + 0xDD5E: 0x5ECC, //CJK UNIFIED IDEOGRAPH + 0xDD5F: 0x5EC6, //CJK UNIFIED IDEOGRAPH + 0xDD60: 0x5ECB, //CJK UNIFIED IDEOGRAPH + 0xDD61: 0x5EC7, //CJK UNIFIED IDEOGRAPH + 0xDD62: 0x5F40, //CJK UNIFIED IDEOGRAPH + 0xDD63: 0x5FAF, //CJK UNIFIED IDEOGRAPH + 0xDD64: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0xDD65: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0xDD66: 0x6149, //CJK UNIFIED IDEOGRAPH + 0xDD67: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xDD68: 0x612B, //CJK UNIFIED IDEOGRAPH + 0xDD69: 0x6145, //CJK UNIFIED IDEOGRAPH + 0xDD6A: 0x6136, //CJK UNIFIED IDEOGRAPH + 0xDD6B: 0x6132, //CJK UNIFIED IDEOGRAPH + 0xDD6C: 0x612E, //CJK UNIFIED IDEOGRAPH + 0xDD6D: 0x6146, //CJK UNIFIED IDEOGRAPH + 0xDD6E: 0x612F, //CJK UNIFIED IDEOGRAPH + 0xDD6F: 0x614F, //CJK UNIFIED IDEOGRAPH + 0xDD70: 0x6129, //CJK UNIFIED IDEOGRAPH + 0xDD71: 0x6140, //CJK UNIFIED IDEOGRAPH + 0xDD72: 0x6220, //CJK UNIFIED IDEOGRAPH + 0xDD73: 0x9168, //CJK UNIFIED IDEOGRAPH + 0xDD74: 0x6223, //CJK UNIFIED IDEOGRAPH + 0xDD75: 0x6225, //CJK UNIFIED IDEOGRAPH + 0xDD76: 0x6224, //CJK UNIFIED IDEOGRAPH + 0xDD77: 0x63C5, //CJK UNIFIED IDEOGRAPH + 0xDD78: 0x63F1, //CJK UNIFIED IDEOGRAPH + 0xDD79: 0x63EB, //CJK UNIFIED IDEOGRAPH + 0xDD7A: 0x6410, //CJK UNIFIED IDEOGRAPH + 0xDD7B: 0x6412, //CJK UNIFIED IDEOGRAPH + 0xDD7C: 0x6409, //CJK UNIFIED IDEOGRAPH + 0xDD7D: 0x6420, //CJK UNIFIED IDEOGRAPH + 0xDD7E: 0x6424, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x6433, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x6443, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x641F, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x6415, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0x6418, //CJK UNIFIED IDEOGRAPH + 0xDDA6: 0x6439, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x6437, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x6422, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x6423, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x640C, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x6426, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x6430, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x6428, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x6441, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x6435, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x642F, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x640A, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x641A, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x6440, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x6425, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x6427, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x640B, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x63E7, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x641B, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x642E, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x6421, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x640E, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x656F, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x6592, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x65D3, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x6686, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x668C, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x6695, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x6690, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x668B, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x668A, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x6694, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x6678, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x6720, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x6966, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x695F, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x6938, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x694E, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x6962, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x6971, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x6945, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x696A, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x6939, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x6942, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0x6959, //CJK UNIFIED IDEOGRAPH + 0xDDD6: 0x697A, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x6948, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x6949, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x6935, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x696C, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x6933, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x6965, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x68F0, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x6934, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x6969, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x6940, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x696F, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x6944, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x6976, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x6958, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x6941, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x6974, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x694C, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x693B, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x694B, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x6937, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x695C, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x694F, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x6951, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x6932, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x6952, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x692F, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x697B, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0x693C, //CJK UNIFIED IDEOGRAPH + 0xDDF5: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x6B45, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x6B42, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x6B48, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x6B41, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x6B9B, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0xFA0D, //CJK COMPATIBILITY IDEOGRAPH + 0xDDFD: 0x6BFB, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x6BFC, //CJK UNIFIED IDEOGRAPH + 0xDE40: 0x6BF9, //CJK UNIFIED IDEOGRAPH + 0xDE41: 0x6BF7, //CJK UNIFIED IDEOGRAPH + 0xDE42: 0x6BF8, //CJK UNIFIED IDEOGRAPH + 0xDE43: 0x6E9B, //CJK UNIFIED IDEOGRAPH + 0xDE44: 0x6ED6, //CJK UNIFIED IDEOGRAPH + 0xDE45: 0x6EC8, //CJK UNIFIED IDEOGRAPH + 0xDE46: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0xDE47: 0x6EC0, //CJK UNIFIED IDEOGRAPH + 0xDE48: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xDE49: 0x6E93, //CJK UNIFIED IDEOGRAPH + 0xDE4A: 0x6E94, //CJK UNIFIED IDEOGRAPH + 0xDE4B: 0x6EA0, //CJK UNIFIED IDEOGRAPH + 0xDE4C: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xDE4D: 0x6EB9, //CJK UNIFIED IDEOGRAPH + 0xDE4E: 0x6EC6, //CJK UNIFIED IDEOGRAPH + 0xDE4F: 0x6ED2, //CJK UNIFIED IDEOGRAPH + 0xDE50: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0xDE51: 0x6EC1, //CJK UNIFIED IDEOGRAPH + 0xDE52: 0x6E9E, //CJK UNIFIED IDEOGRAPH + 0xDE53: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0xDE54: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0xDE55: 0x6EB0, //CJK UNIFIED IDEOGRAPH + 0xDE56: 0x6ECD, //CJK UNIFIED IDEOGRAPH + 0xDE57: 0x6EA6, //CJK UNIFIED IDEOGRAPH + 0xDE58: 0x6ECF, //CJK UNIFIED IDEOGRAPH + 0xDE59: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0xDE5A: 0x6EBE, //CJK UNIFIED IDEOGRAPH + 0xDE5B: 0x6EC3, //CJK UNIFIED IDEOGRAPH + 0xDE5C: 0x6EDC, //CJK UNIFIED IDEOGRAPH + 0xDE5D: 0x6ED8, //CJK UNIFIED IDEOGRAPH + 0xDE5E: 0x6E99, //CJK UNIFIED IDEOGRAPH + 0xDE5F: 0x6E92, //CJK UNIFIED IDEOGRAPH + 0xDE60: 0x6E8E, //CJK UNIFIED IDEOGRAPH + 0xDE61: 0x6E8D, //CJK UNIFIED IDEOGRAPH + 0xDE62: 0x6EA4, //CJK UNIFIED IDEOGRAPH + 0xDE63: 0x6EA1, //CJK UNIFIED IDEOGRAPH + 0xDE64: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xDE65: 0x6EB3, //CJK UNIFIED IDEOGRAPH + 0xDE66: 0x6ED0, //CJK UNIFIED IDEOGRAPH + 0xDE67: 0x6ECA, //CJK UNIFIED IDEOGRAPH + 0xDE68: 0x6E97, //CJK UNIFIED IDEOGRAPH + 0xDE69: 0x6EAE, //CJK UNIFIED IDEOGRAPH + 0xDE6A: 0x6EA3, //CJK UNIFIED IDEOGRAPH + 0xDE6B: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xDE6C: 0x7154, //CJK UNIFIED IDEOGRAPH + 0xDE6D: 0x7152, //CJK UNIFIED IDEOGRAPH + 0xDE6E: 0x7163, //CJK UNIFIED IDEOGRAPH + 0xDE6F: 0x7160, //CJK UNIFIED IDEOGRAPH + 0xDE70: 0x7141, //CJK UNIFIED IDEOGRAPH + 0xDE71: 0x715D, //CJK UNIFIED IDEOGRAPH + 0xDE72: 0x7162, //CJK UNIFIED IDEOGRAPH + 0xDE73: 0x7172, //CJK UNIFIED IDEOGRAPH + 0xDE74: 0x7178, //CJK UNIFIED IDEOGRAPH + 0xDE75: 0x716A, //CJK UNIFIED IDEOGRAPH + 0xDE76: 0x7161, //CJK UNIFIED IDEOGRAPH + 0xDE77: 0x7142, //CJK UNIFIED IDEOGRAPH + 0xDE78: 0x7158, //CJK UNIFIED IDEOGRAPH + 0xDE79: 0x7143, //CJK UNIFIED IDEOGRAPH + 0xDE7A: 0x714B, //CJK UNIFIED IDEOGRAPH + 0xDE7B: 0x7170, //CJK UNIFIED IDEOGRAPH + 0xDE7C: 0x715F, //CJK UNIFIED IDEOGRAPH + 0xDE7D: 0x7150, //CJK UNIFIED IDEOGRAPH + 0xDE7E: 0x7153, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x7144, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x714D, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x715A, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x724F, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x728D, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x728C, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x7291, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x7290, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x728E, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x733C, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x7342, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x733B, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x733A, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x7340, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x734A, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x7349, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x744A, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x7452, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x7451, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x744F, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x7450, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x744E, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x7442, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x7446, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x744D, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x7454, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x74E1, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x74FF, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x74FE, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x74FD, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x751D, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x7579, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x7577, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x6983, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x75EF, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x760F, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x7603, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x75F7, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x75F9, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x75F8, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x7610, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x75FB, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x75F6, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x75ED, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x75F5, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x75FD, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x76B5, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x76DD, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x7755, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x775F, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x7760, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x7752, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x7756, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x7769, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x7767, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x7754, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x7759, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x776D, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x77E0, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x7894, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x788F, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x7884, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x7895, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x7885, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x78A1, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x7883, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x7879, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x7899, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x7880, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x7896, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x787B, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x797C, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x7982, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x797D, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x7979, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x7A11, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x7A12, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0x7A15, //CJK UNIFIED IDEOGRAPH + 0xDEFD: 0x7A22, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0x7A13, //CJK UNIFIED IDEOGRAPH + 0xDF40: 0x7A1B, //CJK UNIFIED IDEOGRAPH + 0xDF41: 0x7A10, //CJK UNIFIED IDEOGRAPH + 0xDF42: 0x7AA3, //CJK UNIFIED IDEOGRAPH + 0xDF43: 0x7AA2, //CJK UNIFIED IDEOGRAPH + 0xDF44: 0x7A9E, //CJK UNIFIED IDEOGRAPH + 0xDF45: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xDF46: 0x7B66, //CJK UNIFIED IDEOGRAPH + 0xDF47: 0x7B64, //CJK UNIFIED IDEOGRAPH + 0xDF48: 0x7B6D, //CJK UNIFIED IDEOGRAPH + 0xDF49: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xDF4A: 0x7B69, //CJK UNIFIED IDEOGRAPH + 0xDF4B: 0x7B72, //CJK UNIFIED IDEOGRAPH + 0xDF4C: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xDF4D: 0x7B73, //CJK UNIFIED IDEOGRAPH + 0xDF4E: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xDF4F: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xDF50: 0x7B61, //CJK UNIFIED IDEOGRAPH + 0xDF51: 0x7B78, //CJK UNIFIED IDEOGRAPH + 0xDF52: 0x7B76, //CJK UNIFIED IDEOGRAPH + 0xDF53: 0x7B63, //CJK UNIFIED IDEOGRAPH + 0xDF54: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xDF55: 0x7CB4, //CJK UNIFIED IDEOGRAPH + 0xDF56: 0x7CAF, //CJK UNIFIED IDEOGRAPH + 0xDF57: 0x7D88, //CJK UNIFIED IDEOGRAPH + 0xDF58: 0x7D86, //CJK UNIFIED IDEOGRAPH + 0xDF59: 0x7D80, //CJK UNIFIED IDEOGRAPH + 0xDF5A: 0x7D8D, //CJK UNIFIED IDEOGRAPH + 0xDF5B: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xDF5C: 0x7D85, //CJK UNIFIED IDEOGRAPH + 0xDF5D: 0x7D7A, //CJK UNIFIED IDEOGRAPH + 0xDF5E: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xDF5F: 0x7D7B, //CJK UNIFIED IDEOGRAPH + 0xDF60: 0x7D83, //CJK UNIFIED IDEOGRAPH + 0xDF61: 0x7D7C, //CJK UNIFIED IDEOGRAPH + 0xDF62: 0x7D8C, //CJK UNIFIED IDEOGRAPH + 0xDF63: 0x7D94, //CJK UNIFIED IDEOGRAPH + 0xDF64: 0x7D84, //CJK UNIFIED IDEOGRAPH + 0xDF65: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xDF66: 0x7D92, //CJK UNIFIED IDEOGRAPH + 0xDF67: 0x7F6D, //CJK UNIFIED IDEOGRAPH + 0xDF68: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xDF69: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xDF6A: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xDF6B: 0x7F6C, //CJK UNIFIED IDEOGRAPH + 0xDF6C: 0x7FA6, //CJK UNIFIED IDEOGRAPH + 0xDF6D: 0x7FA5, //CJK UNIFIED IDEOGRAPH + 0xDF6E: 0x7FA7, //CJK UNIFIED IDEOGRAPH + 0xDF6F: 0x7FDB, //CJK UNIFIED IDEOGRAPH + 0xDF70: 0x7FDC, //CJK UNIFIED IDEOGRAPH + 0xDF71: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xDF72: 0x8164, //CJK UNIFIED IDEOGRAPH + 0xDF73: 0x8160, //CJK UNIFIED IDEOGRAPH + 0xDF74: 0x8177, //CJK UNIFIED IDEOGRAPH + 0xDF75: 0x815C, //CJK UNIFIED IDEOGRAPH + 0xDF76: 0x8169, //CJK UNIFIED IDEOGRAPH + 0xDF77: 0x815B, //CJK UNIFIED IDEOGRAPH + 0xDF78: 0x8162, //CJK UNIFIED IDEOGRAPH + 0xDF79: 0x8172, //CJK UNIFIED IDEOGRAPH + 0xDF7A: 0x6721, //CJK UNIFIED IDEOGRAPH + 0xDF7B: 0x815E, //CJK UNIFIED IDEOGRAPH + 0xDF7C: 0x8176, //CJK UNIFIED IDEOGRAPH + 0xDF7D: 0x8167, //CJK UNIFIED IDEOGRAPH + 0xDF7E: 0x816F, //CJK UNIFIED IDEOGRAPH + 0xDFA1: 0x8144, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x8161, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x821D, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x8249, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x8244, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x8242, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x84F1, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x843F, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x8456, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x8476, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x848F, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x848D, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x8465, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x8451, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x8440, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0x8486, //CJK UNIFIED IDEOGRAPH + 0xDFB4: 0x8467, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x8430, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x844D, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x847D, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x845A, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x8459, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x8474, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x8473, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x845D, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x8507, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x845E, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x8437, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x843A, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x8434, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x8443, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x8478, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x8432, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x8445, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x83D9, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x844B, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x842F, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x8442, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x842D, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x845F, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x8470, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x8439, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x844E, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x844C, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x8452, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x84C5, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x848E, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x843B, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x8447, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x8436, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x8433, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x8468, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x847E, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x8444, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x842B, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x8460, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x8454, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0x8450, //CJK UNIFIED IDEOGRAPH + 0xDFE2: 0x870B, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x8704, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x86F7, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x870C, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x86FA, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x86D6, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0x86F5, //CJK UNIFIED IDEOGRAPH + 0xDFE9: 0x874D, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x870E, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x8701, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x86F6, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x8705, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x88D6, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x88CB, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x88CD, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x88CE, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x88DE, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x88DB, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x88DA, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x88CC, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x88D0, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x8985, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x899B, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x89DF, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x89E5, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x89E4, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x89E1, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x89E0, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x89E2, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x8A76, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x8A86, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x8A7F, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x8A61, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x8A3F, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x8A77, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x8A83, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x8A81, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x8A74, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x8A7A, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x8C3C, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x8C4B, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x8C65, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x8C64, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x8C66, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x8C86, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x8C84, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x8CCC, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x8D68, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x8D69, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x8D91, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x8D8C, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x8D8E, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x8D8F, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x8D8D, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x8D93, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x8D94, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x8D90, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x8D92, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x8DF0, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x8DE0, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x8DEC, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x8DF1, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x8DEE, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x8DD0, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x8DE9, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x8DE2, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x8DE7, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x8DF2, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x8DF4, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x8F06, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x8EFF, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x8F01, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x8F00, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x8F07, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x8F08, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x8F02, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x8F0B, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x903F, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x9044, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x903D, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x9110, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x910D, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x910F, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x9111, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x9116, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x9114, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x910B, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x910E, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x916E, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x916F, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x9252, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x9230, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x9233, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x922E, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x924A, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x9246, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x926D, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x926C, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x924F, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x9260, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x926F, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x9236, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x9261, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x9270, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x9231, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x9254, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x9263, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x9272, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x9253, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x924C, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x9256, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x9232, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x959F, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x959C, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x959E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x959B, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x9692, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x9693, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x9691, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x96FA, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x96FD, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x96F8, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x96F5, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x9773, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x9778, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x9772, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x980D, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x980E, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x98AC, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x98F6, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x98F9, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x99AF, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x99B2, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x99B0, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x99B5, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x9AAB, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x9B5B, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x9CEA, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x9CED, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x9E80, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x50E6, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x50D4, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x50D7, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x50E8, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x50F3, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x50DB, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x50EA, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x50DD, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x50E4, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x50D3, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x50EC, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x50F0, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x50EF, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x50E0, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x51D8, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x5280, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x5281, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x52E9, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x52EB, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x5330, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x53AC, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x5627, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x5615, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x560C, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x5612, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x55FC, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x560F, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x561C, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x5601, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x5613, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x5602, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x55FA, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x561D, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x5604, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x55FF, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x587C, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x5890, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x5898, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x5886, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x5881, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x587F, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x5874, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x588B, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x587A, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x5887, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x5891, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x588E, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x5876, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x5882, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x5888, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x587B, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x5894, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x588F, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x58FE, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x596B, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x5ADC, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x5AEE, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x5AE5, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x5AD5, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x5AEA, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x5ADA, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x5AED, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x5AEB, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x5AF3, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x5AE2, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x5AE0, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x5ADB, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x5AEC, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x5ADE, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x5ADD, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x5AD9, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x5AE8, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x5ADF, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x5B77, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x5BE0, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x5BE3, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x5C63, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x5D80, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x5D7D, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x5D86, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x5D7A, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x5D81, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x5D77, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x5D8A, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x5D89, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x5D88, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x5D7E, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x5D7C, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x5D8D, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x5D79, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5D7F, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5E58, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5E59, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5E53, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5ED8, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x5ED1, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x5ED7, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x5ECE, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x5EDC, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x5ED5, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x5ED9, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x5ED2, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x5ED4, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x5F44, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x5F43, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x5F6F, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x5FB6, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x612C, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x6128, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x6141, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x615E, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x6171, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x6173, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x6152, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x6153, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x6172, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x616C, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x6180, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x6174, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x6154, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x617A, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x615B, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x6165, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x613B, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x616A, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x6161, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x6156, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x6229, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x6227, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x622B, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x642B, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x644D, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x645B, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x645D, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x6474, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x6476, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x6472, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x6473, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x647D, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x6475, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x6466, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x64A6, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x644E, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x6482, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x645E, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x645C, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x644B, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x6453, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x6450, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x647F, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x643F, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x646C, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x646B, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x6459, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x6465, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x6477, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x6573, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x65A0, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x66A1, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x669F, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x6705, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x6704, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x6722, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x69B6, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x69C9, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x6996, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x69B0, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x69AC, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x69BC, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x6991, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x6999, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x698E, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x698D, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x69A9, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x69AF, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x69C4, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x69BD, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x69A4, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x69D4, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x69B9, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x699A, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x69CF, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x69B3, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x6993, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x69AA, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x69A1, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x699E, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x6997, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x6990, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x69C2, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x69B5, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x69C6, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x6B4A, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x6B4D, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x6B4B, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x6B9F, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x6BA0, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x6BC3, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x6BC4, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x6BFE, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x6EF5, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x6EF1, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x6F03, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x6F25, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x6F37, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x6EFB, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x6F2E, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x6F4E, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x6F19, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x6F1A, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x6F27, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x6F18, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x6F3B, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x6F12, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x6EED, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x6F0A, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x6F36, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x6F73, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x6EF9, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x6EEE, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x6F2D, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x6F40, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x6F30, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x6F3C, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x6F35, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x6EEB, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x6F07, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x6F0E, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x6F43, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x6F05, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x6EFD, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x6EF6, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x6F39, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x6F1C, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x6EFC, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x6F3A, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x6F1F, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x6F0D, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x6F1E, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x6F08, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x6F21, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7187, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x7190, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x7189, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x7180, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x7185, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x7182, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x717B, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x7186, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x7181, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x7197, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x7244, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x7253, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x7297, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x7295, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x7293, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x7343, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x734D, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x7351, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x734C, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x7473, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x7471, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x7475, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x7472, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x7467, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x746E, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x7500, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x7502, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x757D, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x7590, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7616, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x7608, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x760C, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x7615, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x7611, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x760A, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x7614, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x7781, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x777C, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x7785, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x7782, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x776E, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x7780, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x776F, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x7783, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x78B2, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x78B4, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x78AD, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x78A8, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x787E, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x78AB, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x789E, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x78A5, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x78A0, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x78AC, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x78A2, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x78A4, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x7998, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x798B, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x7996, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x7995, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x7993, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x7997, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x7988, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x7992, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x7990, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x7A2B, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x7A4A, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x7A30, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x7A2F, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x7A28, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x7A26, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x7AA8, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x7AAB, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x7AAC, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x7AEE, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x7B88, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x7B8A, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x7B91, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x7B90, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x7B96, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x7B8C, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x7B9B, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x7B8E, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x7B85, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x5284, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x7BA4, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x7B82, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x7CBB, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x7CBF, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x7CBC, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x7CBA, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x7DA7, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x7DC2, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x7DAA, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x7DC1, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x7DC0, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x7DC5, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x7D9D, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x7DCE, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x7DC4, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x7DC6, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x7DCC, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x7DB9, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x7D96, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x7DBC, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x7DA6, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x7DA9, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x7DA1, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x7DC9, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x7F73, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x7FE2, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x7FE3, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x7FE5, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x7FDE, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x8024, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x805D, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x805C, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x8189, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x8186, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x8187, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x818D, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x818C, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x818B, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x8215, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x8497, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x84A4, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x84BA, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x84CE, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x84AC, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x84AE, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x84AB, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x84AA, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x849A, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x84B1, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x849D, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x84A7, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x84A2, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x84C7, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x84CC, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x849B, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x84A9, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x84AF, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x84A8, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x8498, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x84B6, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x84CF, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x84A0, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x84D7, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x84D4, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x84D2, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x84DB, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x84B0, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x8491, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x8661, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x8733, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x8723, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x8728, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x876B, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x8740, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x872E, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x871E, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8721, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x8719, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x871B, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x8743, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x872C, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x8741, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x873E, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x8746, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x8720, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x8732, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x872A, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x872D, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x873C, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x873A, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x8731, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x8735, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x8742, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x8726, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x8727, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x8738, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x8724, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x8730, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x88F7, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x88E7, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x88F1, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x88FA, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x88EE, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x88F6, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x88FB, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x88F0, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x88EC, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x88EB, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x899D, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x899F, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x899E, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x89E9, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x89EB, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x89E8, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x8AAB, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x8A99, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x8A8B, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x8A92, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x8A8F, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x8A96, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x8C3D, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x8C68, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x8C69, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x8CD5, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x8CCF, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x8CD7, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x8D96, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x8E02, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x8E0D, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x8DFD, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x8E03, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x8E07, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x8E06, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x8E05, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x8DFE, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x8E00, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x8E04, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x8F10, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x8F11, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x8F0E, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x8F0D, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x9123, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x911C, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x9120, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x9122, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x911F, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x911D, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x911A, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x9124, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x9121, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x911B, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x917A, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x9179, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x92A5, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x92A4, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x9276, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x927A, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x92A0, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x9294, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x92AA, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x928D, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x92A6, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x929A, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x92AB, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x9279, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x9297, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x927F, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x92A3, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x92EE, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x928E, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x9282, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x92A2, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x927D, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x92A1, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x928A, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x9286, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x928C, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x9299, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x927E, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x9287, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x92A9, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x929D, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x928B, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x922D, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x969E, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x96A1, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x96FF, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x9758, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x977D, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x977E, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x9783, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x9780, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x9782, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x977B, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x9784, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x977F, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x97CE, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x97CD, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x9816, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x98AD, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x98AE, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x9902, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x9900, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x9907, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x999C, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x99C3, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x99BB, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x99BA, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x99C2, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x99BD, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x99C7, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x9AB1, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x9AE7, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x9B3E, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x9B3F, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x9B60, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x9B61, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x9B5F, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x9CF1, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x9CF2, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x9CF5, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x9EA7, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x5103, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x5130, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x50F8, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x5107, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x50F6, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x50FE, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x510B, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x510C, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x50FD, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x510A, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x528B, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x528C, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x52F1, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x52EF, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x5648, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x5642, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x564C, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x5635, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x5641, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x564A, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x5649, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x5646, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x5658, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x565A, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x5640, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x5633, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x563D, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x562C, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x563E, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x5638, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x562A, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x563A, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x571A, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x589D, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x58B1, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x58A0, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x58A3, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x58AF, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x58AC, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x58A5, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x58A1, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x58FF, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x5AFF, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x5AF4, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x5AFD, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x5AF7, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x5AF6, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x5B03, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x5AF8, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x5B02, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x5AF9, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x5B01, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x5B07, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x5B0F, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x5C67, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x5D99, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x5D97, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x5D9F, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x5D92, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x5D93, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x5D95, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x5D9C, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x5DA1, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x5D9A, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x5D9E, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x5E69, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x5E5D, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x5E60, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x5E5C, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x7DF3, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x5EDE, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x5F49, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x5FB2, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x618B, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x6183, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x6179, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x61B1, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x61B0, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x61A2, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x6189, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x619B, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x6193, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x61AF, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x61AD, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x619F, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x6192, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x61AA, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x61A1, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x618D, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x6166, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x61B3, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x622D, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x646E, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x6470, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x6496, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x64A0, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x6485, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x6497, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x649C, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x648F, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x648B, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x648A, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x648C, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x64A3, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x649F, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x6468, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x64B1, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x6498, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x6576, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x657A, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x6579, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x657B, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x65B2, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x65B3, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x66B5, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x66B0, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x66A9, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x66B7, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x66AA, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x66AF, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x6A00, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x6A06, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x69E5, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x69F8, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x6A15, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x69F1, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x69E4, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x6A20, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x69EC, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x6A1D, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x69FE, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x6A27, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x69EE, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x69F7, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x6A40, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x6A08, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x69E6, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x6A0D, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x69FC, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x6A09, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x6A04, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x6A18, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x6A25, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x6A0F, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x69F6, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x6A26, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x6A07, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x69F4, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x6A16, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x6B51, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x6BA5, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x6BA3, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x6BA2, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x6BA6, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x6C01, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x6C00, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x6BFF, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x6C02, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x6F26, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x6F87, //CJK UNIFIED IDEOGRAPH + 0xE5FD: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0x6F92, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x6F89, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x6F8C, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x6F4F, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x6F85, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x6F96, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x6F76, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x6F6C, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x6F55, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x6F72, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x6F52, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x6F50, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x6F93, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x6F5D, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x6F00, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x6F61, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x6F6B, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x6F67, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x6F53, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x6F8B, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x6F69, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x6F7F, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x6F95, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x6F63, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x6F77, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x6F6A, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x6F7B, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x71B2, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x71AF, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x719B, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x71B0, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x71A0, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x719A, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x71A9, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x71B5, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x719D, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x71A5, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x719E, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x71A4, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x71A1, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x71AA, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x719C, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x71A7, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x71B3, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x7298, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x729A, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x7358, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x735E, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x735F, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x7360, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x735D, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x735B, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x7361, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x735A, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x7359, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x7362, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x748A, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x7486, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x7481, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x747D, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x7485, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x7488, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x747C, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x7479, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x7508, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x7507, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x757E, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x7625, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x761E, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x761D, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x761C, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x7623, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x761A, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x7628, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x761B, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x769D, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x778D, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x778F, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x7789, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x7788, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x78CD, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x78CF, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x78CC, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x78C8, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x78C3, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x78C4, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x78C9, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x799A, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x79A1, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x79A0, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x799C, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x79A2, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x6B76, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x7A39, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x7AB2, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x7AB4, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x7AB3, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x7BB7, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x7BBE, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x7BAC, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x7BCE, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x7BAF, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x7BB9, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x7BCA, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x7BB5, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x7CC8, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x7CCC, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x7CCB, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x7DF7, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x7DDB, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x7DEA, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x7DE7, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x7DD7, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x7E03, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x7DFA, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x7DE6, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x7DF6, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x7DF1, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x7DF0, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x7DEE, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x7DDF, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x7F76, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x7FAC, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x7FB0, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x7FAD, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x7FED, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x7FEA, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x7FEC, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x7FE8, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x8064, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x8067, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x819F, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x819E, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x81A2, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x8199, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x8197, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x824F, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x8253, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x8252, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x8250, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x824E, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x8251, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x8524, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x853B, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x850F, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x8500, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x8529, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x850E, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x8509, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x850D, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x850A, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x8527, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x851C, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x84FB, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x852B, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x84FA, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x8508, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x850C, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x852A, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x84F2, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x84F7, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x84EB, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x84F3, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x8512, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x84EA, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x84E9, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x8516, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x84FE, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x8528, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x851D, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x852E, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x8502, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x84FD, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x84F6, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x8531, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x8526, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x84E7, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x84E8, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x84F0, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x84EF, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x84F9, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x8520, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x8530, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x850B, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x8519, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x8662, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x8756, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x8764, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x8777, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x87E1, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x8773, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x8758, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x8754, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x875B, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x8752, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x8761, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x875A, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x8751, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x875E, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x876D, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x8750, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x875D, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x876F, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x876C, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x877A, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x875C, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x8765, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x874F, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x877B, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x8775, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x8762, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x8767, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x8769, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x885A, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x8905, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x8914, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x890B, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x8917, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x8906, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x8916, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x8911, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x890E, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x8909, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x89A2, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x89A4, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x89A3, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x89ED, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x89F0, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x89EC, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x8AC6, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x8AB8, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x8AD3, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x8AD1, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x8AD4, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x8AD5, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x8ABB, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x8AD7, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x8AC0, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x8AC5, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x8AD8, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x8AC3, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x8ABA, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x8ABD, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x8AD9, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x8C3E, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x8C4D, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x8C8F, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x8CE5, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x8CDF, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x8CD9, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x8CE8, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x8CDD, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x8CE7, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x8DA0, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x8D9C, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x8DA1, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x8D9B, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x8E20, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x8E23, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x8E25, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x8E24, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x8E2E, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x8E15, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x8E1B, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x8E16, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x8E11, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x8E19, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x8E26, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x8E27, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x8E14, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x8E12, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x8E18, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x8E13, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x8E1C, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x8E17, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x8E1A, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x8F2C, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x8F24, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x8F18, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x8F1A, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x8F20, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x8F23, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x8F16, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x8F17, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x9073, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x9070, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x906B, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x912F, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x912B, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x9129, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x912A, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x9126, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x912E, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x9185, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x9186, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x918A, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x9181, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9184, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9180, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x92C3, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x92C4, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x92C0, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x92F1, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x92DF, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x92D8, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x92DD, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x92EF, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x92C2, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x92E8, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x92CA, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x92C8, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x92CE, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x92E6, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x92CD, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x92C9, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x92DE, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x92D1, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x92B5, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x92E1, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x92C6, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x92B4, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x957C, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x95AC, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x95AB, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x95AE, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x95B0, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x96A4, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x96A2, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x96D3, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x9705, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x9702, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x975A, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x978A, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x978E, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x9788, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x97D0, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x97CF, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x981E, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x981D, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x9826, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x9829, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x9828, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9820, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x981B, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9827, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x98B2, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x9908, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x98FA, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x9911, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x9916, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x9917, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x9915, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x99DC, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x99CD, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x99CF, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x99D3, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x99D4, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x99CE, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x99C9, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x99D6, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x99CB, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x99D7, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x99CC, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x9AB3, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x9AEC, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x9AF3, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x9AF2, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x9B46, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x9B67, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x9B71, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x9B66, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x9B76, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x9B70, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x9B68, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x9B64, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x9B6C, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x9CFC, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x9CFA, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x9CFD, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x9CFF, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x9CF7, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x9D00, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x9CF9, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x9CFB, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x9D05, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x9D04, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x9E83, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x9ED3, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x9F0F, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x9F10, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x511C, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x5113, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x5117, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x511A, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x5111, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x5334, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x5670, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x5660, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0x566E, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x5673, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x5666, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x5663, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x566D, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x5672, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x565E, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x5677, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x571C, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x571B, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x58C8, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x58BD, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x58C9, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x58BF, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x58C2, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x58BC, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x58C6, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x5B17, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x5B19, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x5B1B, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x5B21, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x5B14, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x5B13, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x5B10, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x5B28, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x5B1A, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x5B20, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x5B1E, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x5DB1, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x5DA9, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x5DA7, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x5DB5, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x5DB0, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x5DA8, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x5DB2, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x5DAD, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x5DAF, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x5DB4, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x5E67, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x5E68, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x5E66, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x5E6F, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x5EE7, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x5EE6, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x5EE5, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x5F4B, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x619D, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x61A8, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x6196, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x61C5, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x61B4, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x61C1, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x61BF, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x61B8, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x618C, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x64D7, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x64D6, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x64D0, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x64CF, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x64C9, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x64BD, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x6489, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x64C3, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x64DB, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x64F3, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x64D9, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x6533, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x657F, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x657C, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x65A2, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x66C8, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x66C0, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x66CA, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x66CB, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x66CF, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x66BD, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x66BA, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x66CC, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x6723, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x6A34, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x6A49, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x6A67, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x6A32, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x6A68, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x6A3E, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x6A5D, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x6A6D, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x6A76, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x6A5B, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x6A51, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x6A28, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x6A5A, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x6A3B, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x6A3F, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x6A41, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x6A6A, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x6A64, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x6A50, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x6A4F, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x6A54, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x6A6F, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x6A69, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x6A60, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x6A3C, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6A5E, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x6A56, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x6A55, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x6A4D, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x6A4E, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x6B55, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x6B56, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x6BA7, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x6BC8, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x6BC7, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x6C04, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x6C03, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x6C06, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x6FAD, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x6FCB, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x6FC7, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x6FBC, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x6FCE, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x6FC8, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x6FC4, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x6FBD, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x6F9E, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x6FA8, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x7004, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x6FA5, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x6FBA, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x6FAC, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x6FCF, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x6FBF, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x6FB8, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x6FA2, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x6FC9, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x6FAB, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x6FCD, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x6FB2, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x6FB0, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x71C5, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x71C2, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x71BF, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x71B8, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x71D6, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x71C0, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x71CB, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x71CA, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x71C7, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x71CF, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x71BD, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x71D8, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x71BC, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x71C6, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x71DA, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x71DB, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x729D, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x729E, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x7369, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x7366, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x7367, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x736C, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x7365, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x736B, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x747F, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x749A, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x74A0, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x7494, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x7492, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x7495, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x750B, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x7580, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x762F, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x762D, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x7631, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x763D, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x7633, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x763C, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x7635, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x7632, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x76BB, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x76E6, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x779A, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x779D, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x77A1, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x779C, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x779B, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x77A2, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x77A3, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x7795, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x7799, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x7797, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x78DD, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x78E9, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x78E5, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x78EA, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x78DE, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x78E3, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x78DB, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x78E1, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x78E2, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x78ED, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x78DF, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x78E0, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x79A4, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x7A44, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x7A48, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x7A47, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x7AB8, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x7AB5, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x7AB1, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x7AB7, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x7BDE, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x7BE3, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x7BE7, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x7BD5, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x7BDA, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x7BE8, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x7BF9, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x7BD4, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0x7BEA, //CJK UNIFIED IDEOGRAPH + 0xEAC2: 0x7BE2, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x7BDC, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x7BEB, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x7BD8, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x7BDF, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x7CD4, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x7CD7, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x7CD0, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x7CD1, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x7E17, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x7E0C, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x7E20, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x7E13, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x7E0E, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x7E1C, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x7E1A, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x7E0F, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x7E16, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x7E0D, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x7E14, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x7E25, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x7E24, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x7F43, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x7F7B, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x7F7C, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x7F7A, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x7FB1, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x7FEF, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0x802A, //CJK UNIFIED IDEOGRAPH + 0xEAE6: 0x8029, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x806C, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x81B1, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x81A6, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x81AE, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x81B9, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x81AB, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x81AC, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x81B4, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x81B2, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x81B7, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x81A7, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0x81F2, //CJK UNIFIED IDEOGRAPH + 0xEAF5: 0x8255, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x8256, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0x8257, //CJK UNIFIED IDEOGRAPH + 0xEAF8: 0x8556, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x8545, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x854D, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEAFD: 0x8561, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xEB40: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xEB41: 0x8546, //CJK UNIFIED IDEOGRAPH + 0xEB42: 0x8564, //CJK UNIFIED IDEOGRAPH + 0xEB43: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xEB44: 0x8562, //CJK UNIFIED IDEOGRAPH + 0xEB45: 0x8544, //CJK UNIFIED IDEOGRAPH + 0xEB46: 0x8551, //CJK UNIFIED IDEOGRAPH + 0xEB47: 0x8547, //CJK UNIFIED IDEOGRAPH + 0xEB48: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xEB49: 0x853E, //CJK UNIFIED IDEOGRAPH + 0xEB4A: 0x855B, //CJK UNIFIED IDEOGRAPH + 0xEB4B: 0x8571, //CJK UNIFIED IDEOGRAPH + 0xEB4C: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xEB4D: 0x856E, //CJK UNIFIED IDEOGRAPH + 0xEB4E: 0x8575, //CJK UNIFIED IDEOGRAPH + 0xEB4F: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xEB50: 0x8567, //CJK UNIFIED IDEOGRAPH + 0xEB51: 0x8560, //CJK UNIFIED IDEOGRAPH + 0xEB52: 0x858C, //CJK UNIFIED IDEOGRAPH + 0xEB53: 0x8566, //CJK UNIFIED IDEOGRAPH + 0xEB54: 0x855D, //CJK UNIFIED IDEOGRAPH + 0xEB55: 0x8554, //CJK UNIFIED IDEOGRAPH + 0xEB56: 0x8565, //CJK UNIFIED IDEOGRAPH + 0xEB57: 0x856C, //CJK UNIFIED IDEOGRAPH + 0xEB58: 0x8663, //CJK UNIFIED IDEOGRAPH + 0xEB59: 0x8665, //CJK UNIFIED IDEOGRAPH + 0xEB5A: 0x8664, //CJK UNIFIED IDEOGRAPH + 0xEB5B: 0x879B, //CJK UNIFIED IDEOGRAPH + 0xEB5C: 0x878F, //CJK UNIFIED IDEOGRAPH + 0xEB5D: 0x8797, //CJK UNIFIED IDEOGRAPH + 0xEB5E: 0x8793, //CJK UNIFIED IDEOGRAPH + 0xEB5F: 0x8792, //CJK UNIFIED IDEOGRAPH + 0xEB60: 0x8788, //CJK UNIFIED IDEOGRAPH + 0xEB61: 0x8781, //CJK UNIFIED IDEOGRAPH + 0xEB62: 0x8796, //CJK UNIFIED IDEOGRAPH + 0xEB63: 0x8798, //CJK UNIFIED IDEOGRAPH + 0xEB64: 0x8779, //CJK UNIFIED IDEOGRAPH + 0xEB65: 0x8787, //CJK UNIFIED IDEOGRAPH + 0xEB66: 0x87A3, //CJK UNIFIED IDEOGRAPH + 0xEB67: 0x8785, //CJK UNIFIED IDEOGRAPH + 0xEB68: 0x8790, //CJK UNIFIED IDEOGRAPH + 0xEB69: 0x8791, //CJK UNIFIED IDEOGRAPH + 0xEB6A: 0x879D, //CJK UNIFIED IDEOGRAPH + 0xEB6B: 0x8784, //CJK UNIFIED IDEOGRAPH + 0xEB6C: 0x8794, //CJK UNIFIED IDEOGRAPH + 0xEB6D: 0x879C, //CJK UNIFIED IDEOGRAPH + 0xEB6E: 0x879A, //CJK UNIFIED IDEOGRAPH + 0xEB6F: 0x8789, //CJK UNIFIED IDEOGRAPH + 0xEB70: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xEB71: 0x8926, //CJK UNIFIED IDEOGRAPH + 0xEB72: 0x8930, //CJK UNIFIED IDEOGRAPH + 0xEB73: 0x892D, //CJK UNIFIED IDEOGRAPH + 0xEB74: 0x892E, //CJK UNIFIED IDEOGRAPH + 0xEB75: 0x8927, //CJK UNIFIED IDEOGRAPH + 0xEB76: 0x8931, //CJK UNIFIED IDEOGRAPH + 0xEB77: 0x8922, //CJK UNIFIED IDEOGRAPH + 0xEB78: 0x8929, //CJK UNIFIED IDEOGRAPH + 0xEB79: 0x8923, //CJK UNIFIED IDEOGRAPH + 0xEB7A: 0x892F, //CJK UNIFIED IDEOGRAPH + 0xEB7B: 0x892C, //CJK UNIFIED IDEOGRAPH + 0xEB7C: 0x891F, //CJK UNIFIED IDEOGRAPH + 0xEB7D: 0x89F1, //CJK UNIFIED IDEOGRAPH + 0xEB7E: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xEBA1: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x8AF2, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x8AF4, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0x8AF5, //CJK UNIFIED IDEOGRAPH + 0xEBA5: 0x8ADD, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xEBA8: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0x8AF0, //CJK UNIFIED IDEOGRAPH + 0xEBAA: 0x8AC8, //CJK UNIFIED IDEOGRAPH + 0xEBAB: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x8AE8, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x8AFF, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x8AEF, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x8AFB, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x8C91, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x8C92, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x8C90, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x8CF5, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x8CEE, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x8CF1, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x8CF3, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x8D6C, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0x8D6E, //CJK UNIFIED IDEOGRAPH + 0xEBBB: 0x8DA5, //CJK UNIFIED IDEOGRAPH + 0xEBBC: 0x8DA7, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0x8E33, //CJK UNIFIED IDEOGRAPH + 0xEBBE: 0x8E3E, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x8E38, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x8E40, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0x8E45, //CJK UNIFIED IDEOGRAPH + 0xEBC2: 0x8E36, //CJK UNIFIED IDEOGRAPH + 0xEBC3: 0x8E3C, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x8E3D, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x8E41, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xEBC7: 0x8E3F, //CJK UNIFIED IDEOGRAPH + 0xEBC8: 0x8EBD, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x8F36, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x8F2E, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x8F35, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0x8F32, //CJK UNIFIED IDEOGRAPH + 0xEBCD: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x8F37, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0x8F34, //CJK UNIFIED IDEOGRAPH + 0xEBD0: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xEBD1: 0x9079, //CJK UNIFIED IDEOGRAPH + 0xEBD2: 0x907B, //CJK UNIFIED IDEOGRAPH + 0xEBD3: 0x9086, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x90FA, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x9133, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x9135, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x9136, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0x9193, //CJK UNIFIED IDEOGRAPH + 0xEBD9: 0x9190, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x9191, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x918F, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x9327, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x9308, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x9306, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x937A, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x9338, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x933C, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x931B, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x9312, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x9301, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x9346, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x932D, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x930E, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x930D, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x92CB, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x9313, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x92F7, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x9334, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x9329, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x9339, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x932A, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x9314, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x930C, //CJK UNIFIED IDEOGRAPH + 0xEC40: 0x930B, //CJK UNIFIED IDEOGRAPH + 0xEC41: 0x92FE, //CJK UNIFIED IDEOGRAPH + 0xEC42: 0x9309, //CJK UNIFIED IDEOGRAPH + 0xEC43: 0x9300, //CJK UNIFIED IDEOGRAPH + 0xEC44: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xEC45: 0x9316, //CJK UNIFIED IDEOGRAPH + 0xEC46: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xEC47: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xEC48: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xEC49: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xEC4A: 0x95BA, //CJK UNIFIED IDEOGRAPH + 0xEC4B: 0x95B6, //CJK UNIFIED IDEOGRAPH + 0xEC4C: 0x95BF, //CJK UNIFIED IDEOGRAPH + 0xEC4D: 0x95B5, //CJK UNIFIED IDEOGRAPH + 0xEC4E: 0x95BD, //CJK UNIFIED IDEOGRAPH + 0xEC4F: 0x96A9, //CJK UNIFIED IDEOGRAPH + 0xEC50: 0x96D4, //CJK UNIFIED IDEOGRAPH + 0xEC51: 0x970B, //CJK UNIFIED IDEOGRAPH + 0xEC52: 0x9712, //CJK UNIFIED IDEOGRAPH + 0xEC53: 0x9710, //CJK UNIFIED IDEOGRAPH + 0xEC54: 0x9799, //CJK UNIFIED IDEOGRAPH + 0xEC55: 0x9797, //CJK UNIFIED IDEOGRAPH + 0xEC56: 0x9794, //CJK UNIFIED IDEOGRAPH + 0xEC57: 0x97F0, //CJK UNIFIED IDEOGRAPH + 0xEC58: 0x97F8, //CJK UNIFIED IDEOGRAPH + 0xEC59: 0x9835, //CJK UNIFIED IDEOGRAPH + 0xEC5A: 0x982F, //CJK UNIFIED IDEOGRAPH + 0xEC5B: 0x9832, //CJK UNIFIED IDEOGRAPH + 0xEC5C: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xEC5D: 0x991F, //CJK UNIFIED IDEOGRAPH + 0xEC5E: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xEC5F: 0x9929, //CJK UNIFIED IDEOGRAPH + 0xEC60: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xEC61: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xEC62: 0x99EC, //CJK UNIFIED IDEOGRAPH + 0xEC63: 0x99E5, //CJK UNIFIED IDEOGRAPH + 0xEC64: 0x99E4, //CJK UNIFIED IDEOGRAPH + 0xEC65: 0x99F0, //CJK UNIFIED IDEOGRAPH + 0xEC66: 0x99E3, //CJK UNIFIED IDEOGRAPH + 0xEC67: 0x99EA, //CJK UNIFIED IDEOGRAPH + 0xEC68: 0x99E9, //CJK UNIFIED IDEOGRAPH + 0xEC69: 0x99E7, //CJK UNIFIED IDEOGRAPH + 0xEC6A: 0x9AB9, //CJK UNIFIED IDEOGRAPH + 0xEC6B: 0x9ABF, //CJK UNIFIED IDEOGRAPH + 0xEC6C: 0x9AB4, //CJK UNIFIED IDEOGRAPH + 0xEC6D: 0x9ABB, //CJK UNIFIED IDEOGRAPH + 0xEC6E: 0x9AF6, //CJK UNIFIED IDEOGRAPH + 0xEC6F: 0x9AFA, //CJK UNIFIED IDEOGRAPH + 0xEC70: 0x9AF9, //CJK UNIFIED IDEOGRAPH + 0xEC71: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xEC72: 0x9B33, //CJK UNIFIED IDEOGRAPH + 0xEC73: 0x9B80, //CJK UNIFIED IDEOGRAPH + 0xEC74: 0x9B85, //CJK UNIFIED IDEOGRAPH + 0xEC75: 0x9B87, //CJK UNIFIED IDEOGRAPH + 0xEC76: 0x9B7C, //CJK UNIFIED IDEOGRAPH + 0xEC77: 0x9B7E, //CJK UNIFIED IDEOGRAPH + 0xEC78: 0x9B7B, //CJK UNIFIED IDEOGRAPH + 0xEC79: 0x9B82, //CJK UNIFIED IDEOGRAPH + 0xEC7A: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xEC7B: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0xEC7C: 0x9B90, //CJK UNIFIED IDEOGRAPH + 0xEC7D: 0x9B7A, //CJK UNIFIED IDEOGRAPH + 0xEC7E: 0x9B95, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x9B7D, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x9B88, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x9D25, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x9D17, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x9D20, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0x9D1E, //CJK UNIFIED IDEOGRAPH + 0xECA7: 0x9D14, //CJK UNIFIED IDEOGRAPH + 0xECA8: 0x9D29, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x9D1D, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0x9D18, //CJK UNIFIED IDEOGRAPH + 0xECAB: 0x9D22, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x9D10, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x9D19, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xECB0: 0x9E86, //CJK UNIFIED IDEOGRAPH + 0xECB1: 0x9E87, //CJK UNIFIED IDEOGRAPH + 0xECB2: 0x9EAE, //CJK UNIFIED IDEOGRAPH + 0xECB3: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x9ED5, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0x9ED6, //CJK UNIFIED IDEOGRAPH + 0xECB6: 0x9EFA, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x9F12, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0x9F3D, //CJK UNIFIED IDEOGRAPH + 0xECB9: 0x5126, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0x5125, //CJK UNIFIED IDEOGRAPH + 0xECBB: 0x5122, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x5124, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x5120, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x5129, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x52F4, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0x5693, //CJK UNIFIED IDEOGRAPH + 0xECC1: 0x568C, //CJK UNIFIED IDEOGRAPH + 0xECC2: 0x568D, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x5684, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0x5683, //CJK UNIFIED IDEOGRAPH + 0xECC6: 0x567E, //CJK UNIFIED IDEOGRAPH + 0xECC7: 0x5682, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x567F, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0x5681, //CJK UNIFIED IDEOGRAPH + 0xECCA: 0x58D6, //CJK UNIFIED IDEOGRAPH + 0xECCB: 0x58D4, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x58CF, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x58D2, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x5B2D, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x5B25, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x5B23, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x5B27, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x5B26, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0x5B2F, //CJK UNIFIED IDEOGRAPH + 0xECD6: 0x5B2E, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x5B7B, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x5BF1, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x5BF2, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x5E6C, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x5E6A, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0x5FBE, //CJK UNIFIED IDEOGRAPH + 0xECDE: 0x5FBB, //CJK UNIFIED IDEOGRAPH + 0xECDF: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x61B5, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0x61BC, //CJK UNIFIED IDEOGRAPH + 0xECE2: 0x61E7, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x61E0, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0x61E5, //CJK UNIFIED IDEOGRAPH + 0xECE5: 0x61E4, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x61E8, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0x61DE, //CJK UNIFIED IDEOGRAPH + 0xECE8: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0xECE9: 0x64E9, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x64EB, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x64E4, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x64E8, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x6581, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x6580, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x65B6, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x65DA, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x66D2, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x6A96, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x6A81, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x6AA5, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0xECF8: 0x6A9F, //CJK UNIFIED IDEOGRAPH + 0xECF9: 0x6A9B, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0x6AA1, //CJK UNIFIED IDEOGRAPH + 0xECFB: 0x6A9E, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x6A87, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x6A93, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x6A95, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x6A83, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x6AA8, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x6AA4, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x6A91, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x6AA6, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x6A9A, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x6A85, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x6A8C, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x6A92, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x6BAD, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x6C09, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x6FCC, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x6FA9, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x6FF4, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x6FE3, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x6FDC, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x6FED, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x6FE7, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x6FE6, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x6FDE, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x6FF2, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x6FDD, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x6FE2, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x6FE8, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x71E1, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x71F1, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x71E8, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x71F2, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x71E4, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x71F0, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x71E2, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x7373, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x736E, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x736F, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x7497, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x74AB, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x7490, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x74AD, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x74B1, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x74AF, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x7510, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x7512, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x750F, //CJK UNIFIED IDEOGRAPH + 0xED73: 0x7584, //CJK UNIFIED IDEOGRAPH + 0xED74: 0x7643, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x7649, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x76A4, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x76E9, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x77B5, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x77AB, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x77B2, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x77B7, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x77B4, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x77B1, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x77A8, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x77F0, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x78F3, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x7902, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x78FC, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x78F2, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x7905, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x78F9, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x78FE, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x7904, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x79AB, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x79A8, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x7A5C, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x7A5B, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x7A56, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x7A58, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x7A54, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x7A5A, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x7ABE, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x7AC0, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7AC1, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x7C05, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x7C0F, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x7BF2, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x7BFF, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x7BFB, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x7C0E, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x7BF4, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x7C0B, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x7C02, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x7C09, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x7C03, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x7C01, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x7BF8, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7BFD, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x7C06, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x7BF0, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x7BF1, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x7C10, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x7C0A, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x7CE8, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x7E2D, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x7E3C, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x7E42, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x7E33, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x9848, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x7E38, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x7E2A, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x7E49, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x7E40, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x7E29, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x7E4C, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x7E30, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x7E36, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x7E44, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x7F7F, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x7F7E, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x7F7D, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x7FF4, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x7FF2, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x802C, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x81BB, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x81C4, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x81CC, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x81CA, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x81C5, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x81C7, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x81BC, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x81E9, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x825B, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x825C, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x8583, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x85A7, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x8595, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x85A0, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x858B, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x85A3, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x857B, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x859A, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x859E, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x857C, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0x8589, //CJK UNIFIED IDEOGRAPH + 0xEE43: 0x85A1, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x857A, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x8578, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x8557, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x858E, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x8596, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x8586, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x858D, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x8599, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x859D, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x8581, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x85A2, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x8582, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x8585, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x8579, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x8576, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x8598, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x859F, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x8668, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x87BE, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0x87AA, //CJK UNIFIED IDEOGRAPH + 0xEE5A: 0x87AD, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x87C5, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x87B0, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x87AC, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x87B9, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x87B5, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x87BC, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0x87AE, //CJK UNIFIED IDEOGRAPH + 0xEE62: 0x87C9, //CJK UNIFIED IDEOGRAPH + 0xEE63: 0x87C3, //CJK UNIFIED IDEOGRAPH + 0xEE64: 0x87C2, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0x87CC, //CJK UNIFIED IDEOGRAPH + 0xEE66: 0x87B7, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0x87CA, //CJK UNIFIED IDEOGRAPH + 0xEE6A: 0x87B4, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x87B6, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0x87BF, //CJK UNIFIED IDEOGRAPH + 0xEE6D: 0x87B8, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x87DE, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x87B2, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x8935, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x8933, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x893C, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x893E, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xEE76: 0x8952, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x8937, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x8942, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x89AD, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x89AE, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x89F2, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x89F3, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x8B1E, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x8B18, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x8B11, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x8B05, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x8B0B, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x8B22, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x8B0F, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x8B12, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x8B15, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x8B0D, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x8B08, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x8B06, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x8B1C, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x8B13, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x8C4F, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x8C70, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x8C72, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x8C71, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x8C6F, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x8C95, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x8CF9, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x8D6F, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x8E4E, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x8E4D, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x8E53, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x8F43, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x8F40, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x9085, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x907E, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9138, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x919A, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x919B, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x9199, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x919F, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x91A1, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x919D, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x91A0, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x93A1, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x9383, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x93AF, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x9364, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x9347, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x9358, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x9376, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x9349, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x9350, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x9351, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0x936D, //CJK UNIFIED IDEOGRAPH + 0xEEDC: 0x938F, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x934C, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x936A, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x9379, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x9355, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x9352, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x934F, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x9371, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x9377, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x937B, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x9361, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x935E, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x9363, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x9367, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x9380, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x934E, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x9359, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x95C0, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x95C9, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x95C5, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x95B7, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x96AE, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x96AC, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x9720, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x971F, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x9718, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x971D, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x979A, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x97A1, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xEF40: 0x979E, //CJK UNIFIED IDEOGRAPH + 0xEF41: 0x979D, //CJK UNIFIED IDEOGRAPH + 0xEF42: 0x97D5, //CJK UNIFIED IDEOGRAPH + 0xEF43: 0x97D4, //CJK UNIFIED IDEOGRAPH + 0xEF44: 0x97F1, //CJK UNIFIED IDEOGRAPH + 0xEF45: 0x9841, //CJK UNIFIED IDEOGRAPH + 0xEF46: 0x9844, //CJK UNIFIED IDEOGRAPH + 0xEF47: 0x984A, //CJK UNIFIED IDEOGRAPH + 0xEF48: 0x9849, //CJK UNIFIED IDEOGRAPH + 0xEF49: 0x9845, //CJK UNIFIED IDEOGRAPH + 0xEF4A: 0x9843, //CJK UNIFIED IDEOGRAPH + 0xEF4B: 0x9925, //CJK UNIFIED IDEOGRAPH + 0xEF4C: 0x992B, //CJK UNIFIED IDEOGRAPH + 0xEF4D: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xEF4E: 0x992A, //CJK UNIFIED IDEOGRAPH + 0xEF4F: 0x9933, //CJK UNIFIED IDEOGRAPH + 0xEF50: 0x9932, //CJK UNIFIED IDEOGRAPH + 0xEF51: 0x992F, //CJK UNIFIED IDEOGRAPH + 0xEF52: 0x992D, //CJK UNIFIED IDEOGRAPH + 0xEF53: 0x9931, //CJK UNIFIED IDEOGRAPH + 0xEF54: 0x9930, //CJK UNIFIED IDEOGRAPH + 0xEF55: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xEF56: 0x99A3, //CJK UNIFIED IDEOGRAPH + 0xEF57: 0x99A1, //CJK UNIFIED IDEOGRAPH + 0xEF58: 0x9A02, //CJK UNIFIED IDEOGRAPH + 0xEF59: 0x99FA, //CJK UNIFIED IDEOGRAPH + 0xEF5A: 0x99F4, //CJK UNIFIED IDEOGRAPH + 0xEF5B: 0x99F7, //CJK UNIFIED IDEOGRAPH + 0xEF5C: 0x99F9, //CJK UNIFIED IDEOGRAPH + 0xEF5D: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xEF5E: 0x99F6, //CJK UNIFIED IDEOGRAPH + 0xEF5F: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xEF60: 0x99FD, //CJK UNIFIED IDEOGRAPH + 0xEF61: 0x99FE, //CJK UNIFIED IDEOGRAPH + 0xEF62: 0x99FC, //CJK UNIFIED IDEOGRAPH + 0xEF63: 0x9A03, //CJK UNIFIED IDEOGRAPH + 0xEF64: 0x9ABE, //CJK UNIFIED IDEOGRAPH + 0xEF65: 0x9AFE, //CJK UNIFIED IDEOGRAPH + 0xEF66: 0x9AFD, //CJK UNIFIED IDEOGRAPH + 0xEF67: 0x9B01, //CJK UNIFIED IDEOGRAPH + 0xEF68: 0x9AFC, //CJK UNIFIED IDEOGRAPH + 0xEF69: 0x9B48, //CJK UNIFIED IDEOGRAPH + 0xEF6A: 0x9B9A, //CJK UNIFIED IDEOGRAPH + 0xEF6B: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xEF6C: 0x9B9E, //CJK UNIFIED IDEOGRAPH + 0xEF6D: 0x9B9B, //CJK UNIFIED IDEOGRAPH + 0xEF6E: 0x9BA6, //CJK UNIFIED IDEOGRAPH + 0xEF6F: 0x9BA1, //CJK UNIFIED IDEOGRAPH + 0xEF70: 0x9BA5, //CJK UNIFIED IDEOGRAPH + 0xEF71: 0x9BA4, //CJK UNIFIED IDEOGRAPH + 0xEF72: 0x9B86, //CJK UNIFIED IDEOGRAPH + 0xEF73: 0x9BA2, //CJK UNIFIED IDEOGRAPH + 0xEF74: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xEF75: 0x9BAF, //CJK UNIFIED IDEOGRAPH + 0xEF76: 0x9D33, //CJK UNIFIED IDEOGRAPH + 0xEF77: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xEF78: 0x9D67, //CJK UNIFIED IDEOGRAPH + 0xEF79: 0x9D36, //CJK UNIFIED IDEOGRAPH + 0xEF7A: 0x9D2E, //CJK UNIFIED IDEOGRAPH + 0xEF7B: 0x9D2F, //CJK UNIFIED IDEOGRAPH + 0xEF7C: 0x9D31, //CJK UNIFIED IDEOGRAPH + 0xEF7D: 0x9D38, //CJK UNIFIED IDEOGRAPH + 0xEF7E: 0x9D30, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x9D45, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x9D42, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x9D43, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x9D37, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x9D40, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x9D3D, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x7FF5, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x9D2D, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x9E8A, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x9E89, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x9E8D, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x9EB0, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x9EC8, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x9EDA, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9EFF, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x9F24, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x9F23, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x9F22, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x5131, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x512D, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x512E, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x5698, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x569C, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x5697, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x569A, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x569D, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x5699, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x5970, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x5B3C, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x5C69, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x5C6A, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x5DC0, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x5E6D, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x5E6E, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x61D8, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x61DF, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x61ED, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x61EE, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x61F1, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x61EA, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x61F0, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x61EB, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x61D6, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x61E9, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x64FF, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x6504, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x64F8, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x6501, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x6503, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x64FC, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x6594, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x66DB, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x66D8, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x6AC5, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x6AB9, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x6ABD, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x6AE1, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x6AC6, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x6ABA, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x6AB6, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x6AB7, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x6AC7, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x6AB4, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x6AAD, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x6B5E, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x6BC9, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x6C0B, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x700C, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x700D, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x7014, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x700E, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x6FFF, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x7000, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x6FFB, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x7026, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x6FFC, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x6FF7, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x700A, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x7201, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x7203, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x71FD, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x7376, //CJK UNIFIED IDEOGRAPH + 0xF040: 0x74B8, //CJK UNIFIED IDEOGRAPH + 0xF041: 0x74C0, //CJK UNIFIED IDEOGRAPH + 0xF042: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xF043: 0x74C1, //CJK UNIFIED IDEOGRAPH + 0xF044: 0x74BE, //CJK UNIFIED IDEOGRAPH + 0xF045: 0x74B6, //CJK UNIFIED IDEOGRAPH + 0xF046: 0x74BB, //CJK UNIFIED IDEOGRAPH + 0xF047: 0x74C2, //CJK UNIFIED IDEOGRAPH + 0xF048: 0x7514, //CJK UNIFIED IDEOGRAPH + 0xF049: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xF04A: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xF04B: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xF04C: 0x7659, //CJK UNIFIED IDEOGRAPH + 0xF04D: 0x7650, //CJK UNIFIED IDEOGRAPH + 0xF04E: 0x7653, //CJK UNIFIED IDEOGRAPH + 0xF04F: 0x7657, //CJK UNIFIED IDEOGRAPH + 0xF050: 0x765A, //CJK UNIFIED IDEOGRAPH + 0xF051: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xF052: 0x76BD, //CJK UNIFIED IDEOGRAPH + 0xF053: 0x76EC, //CJK UNIFIED IDEOGRAPH + 0xF054: 0x77C2, //CJK UNIFIED IDEOGRAPH + 0xF055: 0x77BA, //CJK UNIFIED IDEOGRAPH + 0xF056: 0x78FF, //CJK UNIFIED IDEOGRAPH + 0xF057: 0x790C, //CJK UNIFIED IDEOGRAPH + 0xF058: 0x7913, //CJK UNIFIED IDEOGRAPH + 0xF059: 0x7914, //CJK UNIFIED IDEOGRAPH + 0xF05A: 0x7909, //CJK UNIFIED IDEOGRAPH + 0xF05B: 0x7910, //CJK UNIFIED IDEOGRAPH + 0xF05C: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xF05D: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xF05E: 0x79AD, //CJK UNIFIED IDEOGRAPH + 0xF05F: 0x79AC, //CJK UNIFIED IDEOGRAPH + 0xF060: 0x7A5F, //CJK UNIFIED IDEOGRAPH + 0xF061: 0x7C1C, //CJK UNIFIED IDEOGRAPH + 0xF062: 0x7C29, //CJK UNIFIED IDEOGRAPH + 0xF063: 0x7C19, //CJK UNIFIED IDEOGRAPH + 0xF064: 0x7C20, //CJK UNIFIED IDEOGRAPH + 0xF065: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xF066: 0x7C2D, //CJK UNIFIED IDEOGRAPH + 0xF067: 0x7C1D, //CJK UNIFIED IDEOGRAPH + 0xF068: 0x7C26, //CJK UNIFIED IDEOGRAPH + 0xF069: 0x7C28, //CJK UNIFIED IDEOGRAPH + 0xF06A: 0x7C22, //CJK UNIFIED IDEOGRAPH + 0xF06B: 0x7C25, //CJK UNIFIED IDEOGRAPH + 0xF06C: 0x7C30, //CJK UNIFIED IDEOGRAPH + 0xF06D: 0x7E5C, //CJK UNIFIED IDEOGRAPH + 0xF06E: 0x7E50, //CJK UNIFIED IDEOGRAPH + 0xF06F: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xF070: 0x7E63, //CJK UNIFIED IDEOGRAPH + 0xF071: 0x7E58, //CJK UNIFIED IDEOGRAPH + 0xF072: 0x7E62, //CJK UNIFIED IDEOGRAPH + 0xF073: 0x7E5F, //CJK UNIFIED IDEOGRAPH + 0xF074: 0x7E51, //CJK UNIFIED IDEOGRAPH + 0xF075: 0x7E60, //CJK UNIFIED IDEOGRAPH + 0xF076: 0x7E57, //CJK UNIFIED IDEOGRAPH + 0xF077: 0x7E53, //CJK UNIFIED IDEOGRAPH + 0xF078: 0x7FB5, //CJK UNIFIED IDEOGRAPH + 0xF079: 0x7FB3, //CJK UNIFIED IDEOGRAPH + 0xF07A: 0x7FF7, //CJK UNIFIED IDEOGRAPH + 0xF07B: 0x7FF8, //CJK UNIFIED IDEOGRAPH + 0xF07C: 0x8075, //CJK UNIFIED IDEOGRAPH + 0xF07D: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xF07E: 0x81D2, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x81D0, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x825E, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x85B4, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x85C6, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x85C0, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x85C3, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x85C2, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x85B3, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x85B5, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x85BD, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x85C7, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x85C4, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x85BF, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x85CB, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x85C8, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x85C5, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x85B1, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x85B6, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x85D2, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x8624, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x85B8, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x85B7, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x85BE, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x8669, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x87E7, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x87E6, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x87E2, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x87DB, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x87EB, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x87EA, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x87E5, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x87DF, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x87F3, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x87E4, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x87D4, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x87DC, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x87D3, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x87ED, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x87D8, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x87E3, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x87A4, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x87D7, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x87D9, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x8801, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x87F4, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x87E8, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x87DD, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x8953, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x894B, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x894F, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x8946, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x8950, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x8951, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x8949, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x8B2A, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x8B27, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x8B23, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x8B30, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x8B35, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x8B47, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x8B2F, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x8B3C, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x8B31, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x8B25, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x8B37, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x8B36, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x8B2E, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x8B24, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x8B3B, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x8B3D, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x8B3A, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x8C42, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x8C75, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x8C99, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x8C97, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x8CFE, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x8D02, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x8D00, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x8E5C, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x8E62, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x8E57, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x8E56, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x8E5E, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x8E65, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x8E67, //CJK UNIFIED IDEOGRAPH + 0xF140: 0x8E5B, //CJK UNIFIED IDEOGRAPH + 0xF141: 0x8E5A, //CJK UNIFIED IDEOGRAPH + 0xF142: 0x8E61, //CJK UNIFIED IDEOGRAPH + 0xF143: 0x8E5D, //CJK UNIFIED IDEOGRAPH + 0xF144: 0x8E69, //CJK UNIFIED IDEOGRAPH + 0xF145: 0x8E54, //CJK UNIFIED IDEOGRAPH + 0xF146: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xF147: 0x8F47, //CJK UNIFIED IDEOGRAPH + 0xF148: 0x8F48, //CJK UNIFIED IDEOGRAPH + 0xF149: 0x8F4B, //CJK UNIFIED IDEOGRAPH + 0xF14A: 0x9128, //CJK UNIFIED IDEOGRAPH + 0xF14B: 0x913A, //CJK UNIFIED IDEOGRAPH + 0xF14C: 0x913B, //CJK UNIFIED IDEOGRAPH + 0xF14D: 0x913E, //CJK UNIFIED IDEOGRAPH + 0xF14E: 0x91A8, //CJK UNIFIED IDEOGRAPH + 0xF14F: 0x91A5, //CJK UNIFIED IDEOGRAPH + 0xF150: 0x91A7, //CJK UNIFIED IDEOGRAPH + 0xF151: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xF152: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xF153: 0x93B5, //CJK UNIFIED IDEOGRAPH + 0xF154: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xF155: 0x9392, //CJK UNIFIED IDEOGRAPH + 0xF156: 0x93B7, //CJK UNIFIED IDEOGRAPH + 0xF157: 0x939B, //CJK UNIFIED IDEOGRAPH + 0xF158: 0x939D, //CJK UNIFIED IDEOGRAPH + 0xF159: 0x9389, //CJK UNIFIED IDEOGRAPH + 0xF15A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xF15B: 0x938E, //CJK UNIFIED IDEOGRAPH + 0xF15C: 0x93AA, //CJK UNIFIED IDEOGRAPH + 0xF15D: 0x939E, //CJK UNIFIED IDEOGRAPH + 0xF15E: 0x93A6, //CJK UNIFIED IDEOGRAPH + 0xF15F: 0x9395, //CJK UNIFIED IDEOGRAPH + 0xF160: 0x9388, //CJK UNIFIED IDEOGRAPH + 0xF161: 0x9399, //CJK UNIFIED IDEOGRAPH + 0xF162: 0x939F, //CJK UNIFIED IDEOGRAPH + 0xF163: 0x938D, //CJK UNIFIED IDEOGRAPH + 0xF164: 0x93B1, //CJK UNIFIED IDEOGRAPH + 0xF165: 0x9391, //CJK UNIFIED IDEOGRAPH + 0xF166: 0x93B2, //CJK UNIFIED IDEOGRAPH + 0xF167: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xF168: 0x93A8, //CJK UNIFIED IDEOGRAPH + 0xF169: 0x93B4, //CJK UNIFIED IDEOGRAPH + 0xF16A: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xF16B: 0x93A5, //CJK UNIFIED IDEOGRAPH + 0xF16C: 0x95D2, //CJK UNIFIED IDEOGRAPH + 0xF16D: 0x95D3, //CJK UNIFIED IDEOGRAPH + 0xF16E: 0x95D1, //CJK UNIFIED IDEOGRAPH + 0xF16F: 0x96B3, //CJK UNIFIED IDEOGRAPH + 0xF170: 0x96D7, //CJK UNIFIED IDEOGRAPH + 0xF171: 0x96DA, //CJK UNIFIED IDEOGRAPH + 0xF172: 0x5DC2, //CJK UNIFIED IDEOGRAPH + 0xF173: 0x96DF, //CJK UNIFIED IDEOGRAPH + 0xF174: 0x96D8, //CJK UNIFIED IDEOGRAPH + 0xF175: 0x96DD, //CJK UNIFIED IDEOGRAPH + 0xF176: 0x9723, //CJK UNIFIED IDEOGRAPH + 0xF177: 0x9722, //CJK UNIFIED IDEOGRAPH + 0xF178: 0x9725, //CJK UNIFIED IDEOGRAPH + 0xF179: 0x97AC, //CJK UNIFIED IDEOGRAPH + 0xF17A: 0x97AE, //CJK UNIFIED IDEOGRAPH + 0xF17B: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xF17C: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xF17D: 0x97A4, //CJK UNIFIED IDEOGRAPH + 0xF17E: 0x97AA, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x97A2, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x97A5, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x97D7, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x97D9, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x97D6, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x97D8, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x97FA, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x9850, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x9851, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x9852, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x98B8, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x9941, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x993C, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x993A, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x9A0B, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x9A09, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x9A0D, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x9A04, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x9A11, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x9A0A, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x9A07, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x9A06, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x9B08, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x9B04, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x9B05, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x9B35, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x9B4A, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x9B4C, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x9B4B, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x9BC7, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x9BC3, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x9BBF, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x9BC1, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x9BB5, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x9BB8, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x9BD3, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x9BB6, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x9BC4, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x9BBD, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x9D53, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x9D4F, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x9D4A, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x9D5B, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x9D4B, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x9D56, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x9D4C, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x9D57, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x9D52, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x9D54, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x9D5F, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x9D58, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x9D5A, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x9E8E, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x9EDF, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x9F01, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x9F00, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x9F16, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x9F25, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x9F2B, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x9F2A, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x9F29, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x9F28, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x9F4C, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x9F55, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x5134, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x5135, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x5296, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x52F7, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x53B4, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x56AB, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x56AD, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x56A6, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x56A7, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x56AA, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x58DA, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x58DD, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x58DB, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x5912, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x5B3D, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x5B3F, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x5DC3, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x5E70, //CJK UNIFIED IDEOGRAPH + 0xF240: 0x5FBF, //CJK UNIFIED IDEOGRAPH + 0xF241: 0x61FB, //CJK UNIFIED IDEOGRAPH + 0xF242: 0x6507, //CJK UNIFIED IDEOGRAPH + 0xF243: 0x6510, //CJK UNIFIED IDEOGRAPH + 0xF244: 0x650D, //CJK UNIFIED IDEOGRAPH + 0xF245: 0x6509, //CJK UNIFIED IDEOGRAPH + 0xF246: 0x650C, //CJK UNIFIED IDEOGRAPH + 0xF247: 0x650E, //CJK UNIFIED IDEOGRAPH + 0xF248: 0x6584, //CJK UNIFIED IDEOGRAPH + 0xF249: 0x65DE, //CJK UNIFIED IDEOGRAPH + 0xF24A: 0x65DD, //CJK UNIFIED IDEOGRAPH + 0xF24B: 0x66DE, //CJK UNIFIED IDEOGRAPH + 0xF24C: 0x6AE7, //CJK UNIFIED IDEOGRAPH + 0xF24D: 0x6AE0, //CJK UNIFIED IDEOGRAPH + 0xF24E: 0x6ACC, //CJK UNIFIED IDEOGRAPH + 0xF24F: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0xF250: 0x6AD9, //CJK UNIFIED IDEOGRAPH + 0xF251: 0x6ACB, //CJK UNIFIED IDEOGRAPH + 0xF252: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0xF253: 0x6ADC, //CJK UNIFIED IDEOGRAPH + 0xF254: 0x6AD0, //CJK UNIFIED IDEOGRAPH + 0xF255: 0x6AEB, //CJK UNIFIED IDEOGRAPH + 0xF256: 0x6ACF, //CJK UNIFIED IDEOGRAPH + 0xF257: 0x6ACD, //CJK UNIFIED IDEOGRAPH + 0xF258: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0xF259: 0x6B60, //CJK UNIFIED IDEOGRAPH + 0xF25A: 0x6BB0, //CJK UNIFIED IDEOGRAPH + 0xF25B: 0x6C0C, //CJK UNIFIED IDEOGRAPH + 0xF25C: 0x7019, //CJK UNIFIED IDEOGRAPH + 0xF25D: 0x7027, //CJK UNIFIED IDEOGRAPH + 0xF25E: 0x7020, //CJK UNIFIED IDEOGRAPH + 0xF25F: 0x7016, //CJK UNIFIED IDEOGRAPH + 0xF260: 0x702B, //CJK UNIFIED IDEOGRAPH + 0xF261: 0x7021, //CJK UNIFIED IDEOGRAPH + 0xF262: 0x7022, //CJK UNIFIED IDEOGRAPH + 0xF263: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xF264: 0x7029, //CJK UNIFIED IDEOGRAPH + 0xF265: 0x7017, //CJK UNIFIED IDEOGRAPH + 0xF266: 0x7024, //CJK UNIFIED IDEOGRAPH + 0xF267: 0x701C, //CJK UNIFIED IDEOGRAPH + 0xF268: 0x702A, //CJK UNIFIED IDEOGRAPH + 0xF269: 0x720C, //CJK UNIFIED IDEOGRAPH + 0xF26A: 0x720A, //CJK UNIFIED IDEOGRAPH + 0xF26B: 0x7207, //CJK UNIFIED IDEOGRAPH + 0xF26C: 0x7202, //CJK UNIFIED IDEOGRAPH + 0xF26D: 0x7205, //CJK UNIFIED IDEOGRAPH + 0xF26E: 0x72A5, //CJK UNIFIED IDEOGRAPH + 0xF26F: 0x72A6, //CJK UNIFIED IDEOGRAPH + 0xF270: 0x72A4, //CJK UNIFIED IDEOGRAPH + 0xF271: 0x72A3, //CJK UNIFIED IDEOGRAPH + 0xF272: 0x72A1, //CJK UNIFIED IDEOGRAPH + 0xF273: 0x74CB, //CJK UNIFIED IDEOGRAPH + 0xF274: 0x74C5, //CJK UNIFIED IDEOGRAPH + 0xF275: 0x74B7, //CJK UNIFIED IDEOGRAPH + 0xF276: 0x74C3, //CJK UNIFIED IDEOGRAPH + 0xF277: 0x7516, //CJK UNIFIED IDEOGRAPH + 0xF278: 0x7660, //CJK UNIFIED IDEOGRAPH + 0xF279: 0x77C9, //CJK UNIFIED IDEOGRAPH + 0xF27A: 0x77CA, //CJK UNIFIED IDEOGRAPH + 0xF27B: 0x77C4, //CJK UNIFIED IDEOGRAPH + 0xF27C: 0x77F1, //CJK UNIFIED IDEOGRAPH + 0xF27D: 0x791D, //CJK UNIFIED IDEOGRAPH + 0xF27E: 0x791B, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x7921, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x791C, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x7917, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x791E, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x7A67, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x7A68, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x7C33, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x7C3C, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x7C39, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x7C2C, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x7C3B, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x7CEC, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x7CEA, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x7E76, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x7E75, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x7E78, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x7E77, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x7E6F, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x7E7A, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x7E72, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x7E74, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x7E68, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x7F4B, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x7F4A, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0x7FB7, //CJK UNIFIED IDEOGRAPH + 0xF2BE: 0x7FFD, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x7FFE, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x8078, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x81D7, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x81D5, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x8261, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x8263, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x85EB, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x85F1, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x85ED, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x85D9, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x85E1, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x85E8, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x85DA, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x85D7, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x85EC, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x85F2, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x85F8, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x85D8, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x85DF, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x85E3, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x85D1, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x85F0, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x85E6, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x85EF, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x85DE, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x85E2, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x8800, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x87FA, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x8803, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x8809, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x880C, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x880B, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x8806, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x87FC, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x8808, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x87FF, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x880A, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x8802, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x8962, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x895A, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x895B, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x8957, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x8961, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x895C, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x8958, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x895D, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x8959, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x89B7, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x89B6, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x89F6, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8B50, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x8B48, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x8B4A, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x8B40, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xF2FB: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x8B54, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x8B4B, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x8B55, //CJK UNIFIED IDEOGRAPH + 0xF340: 0x8B51, //CJK UNIFIED IDEOGRAPH + 0xF341: 0x8B42, //CJK UNIFIED IDEOGRAPH + 0xF342: 0x8B52, //CJK UNIFIED IDEOGRAPH + 0xF343: 0x8B57, //CJK UNIFIED IDEOGRAPH + 0xF344: 0x8C43, //CJK UNIFIED IDEOGRAPH + 0xF345: 0x8C77, //CJK UNIFIED IDEOGRAPH + 0xF346: 0x8C76, //CJK UNIFIED IDEOGRAPH + 0xF347: 0x8C9A, //CJK UNIFIED IDEOGRAPH + 0xF348: 0x8D06, //CJK UNIFIED IDEOGRAPH + 0xF349: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xF34A: 0x8D09, //CJK UNIFIED IDEOGRAPH + 0xF34B: 0x8DAC, //CJK UNIFIED IDEOGRAPH + 0xF34C: 0x8DAA, //CJK UNIFIED IDEOGRAPH + 0xF34D: 0x8DAD, //CJK UNIFIED IDEOGRAPH + 0xF34E: 0x8DAB, //CJK UNIFIED IDEOGRAPH + 0xF34F: 0x8E6D, //CJK UNIFIED IDEOGRAPH + 0xF350: 0x8E78, //CJK UNIFIED IDEOGRAPH + 0xF351: 0x8E73, //CJK UNIFIED IDEOGRAPH + 0xF352: 0x8E6A, //CJK UNIFIED IDEOGRAPH + 0xF353: 0x8E6F, //CJK UNIFIED IDEOGRAPH + 0xF354: 0x8E7B, //CJK UNIFIED IDEOGRAPH + 0xF355: 0x8EC2, //CJK UNIFIED IDEOGRAPH + 0xF356: 0x8F52, //CJK UNIFIED IDEOGRAPH + 0xF357: 0x8F51, //CJK UNIFIED IDEOGRAPH + 0xF358: 0x8F4F, //CJK UNIFIED IDEOGRAPH + 0xF359: 0x8F50, //CJK UNIFIED IDEOGRAPH + 0xF35A: 0x8F53, //CJK UNIFIED IDEOGRAPH + 0xF35B: 0x8FB4, //CJK UNIFIED IDEOGRAPH + 0xF35C: 0x9140, //CJK UNIFIED IDEOGRAPH + 0xF35D: 0x913F, //CJK UNIFIED IDEOGRAPH + 0xF35E: 0x91B0, //CJK UNIFIED IDEOGRAPH + 0xF35F: 0x91AD, //CJK UNIFIED IDEOGRAPH + 0xF360: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xF361: 0x93C7, //CJK UNIFIED IDEOGRAPH + 0xF362: 0x93CF, //CJK UNIFIED IDEOGRAPH + 0xF363: 0x93C2, //CJK UNIFIED IDEOGRAPH + 0xF364: 0x93DA, //CJK UNIFIED IDEOGRAPH + 0xF365: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xF366: 0x93F9, //CJK UNIFIED IDEOGRAPH + 0xF367: 0x93EC, //CJK UNIFIED IDEOGRAPH + 0xF368: 0x93CC, //CJK UNIFIED IDEOGRAPH + 0xF369: 0x93D9, //CJK UNIFIED IDEOGRAPH + 0xF36A: 0x93A9, //CJK UNIFIED IDEOGRAPH + 0xF36B: 0x93E6, //CJK UNIFIED IDEOGRAPH + 0xF36C: 0x93CA, //CJK UNIFIED IDEOGRAPH + 0xF36D: 0x93D4, //CJK UNIFIED IDEOGRAPH + 0xF36E: 0x93EE, //CJK UNIFIED IDEOGRAPH + 0xF36F: 0x93E3, //CJK UNIFIED IDEOGRAPH + 0xF370: 0x93D5, //CJK UNIFIED IDEOGRAPH + 0xF371: 0x93C4, //CJK UNIFIED IDEOGRAPH + 0xF372: 0x93CE, //CJK UNIFIED IDEOGRAPH + 0xF373: 0x93C0, //CJK UNIFIED IDEOGRAPH + 0xF374: 0x93D2, //CJK UNIFIED IDEOGRAPH + 0xF375: 0x93E7, //CJK UNIFIED IDEOGRAPH + 0xF376: 0x957D, //CJK UNIFIED IDEOGRAPH + 0xF377: 0x95DA, //CJK UNIFIED IDEOGRAPH + 0xF378: 0x95DB, //CJK UNIFIED IDEOGRAPH + 0xF379: 0x96E1, //CJK UNIFIED IDEOGRAPH + 0xF37A: 0x9729, //CJK UNIFIED IDEOGRAPH + 0xF37B: 0x972B, //CJK UNIFIED IDEOGRAPH + 0xF37C: 0x972C, //CJK UNIFIED IDEOGRAPH + 0xF37D: 0x9728, //CJK UNIFIED IDEOGRAPH + 0xF37E: 0x9726, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x97B7, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x97B6, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x97DD, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x97DE, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x97DF, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x985C, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x9859, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x985D, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x98BF, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x98BD, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x98BB, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x98BE, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x9948, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x9947, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0x9943, //CJK UNIFIED IDEOGRAPH + 0xF3B2: 0x99A6, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x99A7, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x9A1A, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x9A15, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x9A25, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x9A1D, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x9A24, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x9A1B, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x9A22, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x9A20, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x9A27, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x9A23, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x9A1E, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x9A1C, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x9A14, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x9AC2, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x9B0B, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x9B0A, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x9B0E, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x9B0C, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x9B37, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x9BEA, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x9BEB, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x9BE0, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x9BDE, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x9BE6, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x9BD7, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x9BEC, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x9BDC, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x9BD9, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x9BE5, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x9BD5, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x9BDA, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x9D77, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x9D81, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x9D8A, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x9D84, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x9D88, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x9D71, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x9D80, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x9D78, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x9D86, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x9D8B, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x9D8C, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x9D7D, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x9D74, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x9D75, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x9D69, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x9D85, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x9D73, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x9D7B, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x9D82, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x9D79, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x9D7F, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x9D68, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x9E94, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x9EC0, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x9F2D, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x9F40, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x9F41, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x9F4D, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x9F56, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x9F57, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x9F58, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x5337, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x56B2, //CJK UNIFIED IDEOGRAPH + 0xF440: 0x56B5, //CJK UNIFIED IDEOGRAPH + 0xF441: 0x56B3, //CJK UNIFIED IDEOGRAPH + 0xF442: 0x58E3, //CJK UNIFIED IDEOGRAPH + 0xF443: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0xF444: 0x5DC6, //CJK UNIFIED IDEOGRAPH + 0xF445: 0x5DC7, //CJK UNIFIED IDEOGRAPH + 0xF446: 0x5EEE, //CJK UNIFIED IDEOGRAPH + 0xF447: 0x5EEF, //CJK UNIFIED IDEOGRAPH + 0xF448: 0x5FC0, //CJK UNIFIED IDEOGRAPH + 0xF449: 0x5FC1, //CJK UNIFIED IDEOGRAPH + 0xF44A: 0x61F9, //CJK UNIFIED IDEOGRAPH + 0xF44B: 0x6517, //CJK UNIFIED IDEOGRAPH + 0xF44C: 0x6516, //CJK UNIFIED IDEOGRAPH + 0xF44D: 0x6515, //CJK UNIFIED IDEOGRAPH + 0xF44E: 0x6513, //CJK UNIFIED IDEOGRAPH + 0xF44F: 0x65DF, //CJK UNIFIED IDEOGRAPH + 0xF450: 0x66E8, //CJK UNIFIED IDEOGRAPH + 0xF451: 0x66E3, //CJK UNIFIED IDEOGRAPH + 0xF452: 0x66E4, //CJK UNIFIED IDEOGRAPH + 0xF453: 0x6AF3, //CJK UNIFIED IDEOGRAPH + 0xF454: 0x6AF0, //CJK UNIFIED IDEOGRAPH + 0xF455: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0xF456: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0xF457: 0x6AF9, //CJK UNIFIED IDEOGRAPH + 0xF458: 0x6AF1, //CJK UNIFIED IDEOGRAPH + 0xF459: 0x6AEE, //CJK UNIFIED IDEOGRAPH + 0xF45A: 0x6AEF, //CJK UNIFIED IDEOGRAPH + 0xF45B: 0x703C, //CJK UNIFIED IDEOGRAPH + 0xF45C: 0x7035, //CJK UNIFIED IDEOGRAPH + 0xF45D: 0x702F, //CJK UNIFIED IDEOGRAPH + 0xF45E: 0x7037, //CJK UNIFIED IDEOGRAPH + 0xF45F: 0x7034, //CJK UNIFIED IDEOGRAPH + 0xF460: 0x7031, //CJK UNIFIED IDEOGRAPH + 0xF461: 0x7042, //CJK UNIFIED IDEOGRAPH + 0xF462: 0x7038, //CJK UNIFIED IDEOGRAPH + 0xF463: 0x703F, //CJK UNIFIED IDEOGRAPH + 0xF464: 0x703A, //CJK UNIFIED IDEOGRAPH + 0xF465: 0x7039, //CJK UNIFIED IDEOGRAPH + 0xF466: 0x7040, //CJK UNIFIED IDEOGRAPH + 0xF467: 0x703B, //CJK UNIFIED IDEOGRAPH + 0xF468: 0x7033, //CJK UNIFIED IDEOGRAPH + 0xF469: 0x7041, //CJK UNIFIED IDEOGRAPH + 0xF46A: 0x7213, //CJK UNIFIED IDEOGRAPH + 0xF46B: 0x7214, //CJK UNIFIED IDEOGRAPH + 0xF46C: 0x72A8, //CJK UNIFIED IDEOGRAPH + 0xF46D: 0x737D, //CJK UNIFIED IDEOGRAPH + 0xF46E: 0x737C, //CJK UNIFIED IDEOGRAPH + 0xF46F: 0x74BA, //CJK UNIFIED IDEOGRAPH + 0xF470: 0x76AB, //CJK UNIFIED IDEOGRAPH + 0xF471: 0x76AA, //CJK UNIFIED IDEOGRAPH + 0xF472: 0x76BE, //CJK UNIFIED IDEOGRAPH + 0xF473: 0x76ED, //CJK UNIFIED IDEOGRAPH + 0xF474: 0x77CC, //CJK UNIFIED IDEOGRAPH + 0xF475: 0x77CE, //CJK UNIFIED IDEOGRAPH + 0xF476: 0x77CF, //CJK UNIFIED IDEOGRAPH + 0xF477: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xF478: 0x77F2, //CJK UNIFIED IDEOGRAPH + 0xF479: 0x7925, //CJK UNIFIED IDEOGRAPH + 0xF47A: 0x7923, //CJK UNIFIED IDEOGRAPH + 0xF47B: 0x7927, //CJK UNIFIED IDEOGRAPH + 0xF47C: 0x7928, //CJK UNIFIED IDEOGRAPH + 0xF47D: 0x7924, //CJK UNIFIED IDEOGRAPH + 0xF47E: 0x7929, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x79B2, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x7A6E, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x7A6C, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x7A6D, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x7AF7, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x7C49, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0x7C48, //CJK UNIFIED IDEOGRAPH + 0xF4A8: 0x7C4A, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x7C47, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x7C45, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x7CEE, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x7E7E, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x7E81, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x7E80, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x7FBA, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x7FFF, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x81DB, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x820B, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x8269, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x8601, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x861B, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x8600, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x85F6, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x8604, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x8609, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8605, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x860C, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x85FD, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x8819, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x8810, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x8817, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x8813, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x8963, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x89B9, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x89F7, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x8B60, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x8B6A, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x8B5D, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x8B68, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x8B63, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x8B65, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x8B67, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x8B6D, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x8DAE, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x8E86, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x8E88, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x8F59, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x8F56, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x8F55, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x8F58, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x8F5A, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x908D, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x9143, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x9141, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x91B7, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x91B2, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x91B3, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x940B, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x93FB, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x9420, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x940F, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x93FE, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0x9415, //CJK UNIFIED IDEOGRAPH + 0xF4EF: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x9428, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x9419, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x940D, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x93F5, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x9400, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x93F7, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x940E, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x9416, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x9412, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x93FA, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x9409, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x940A, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x93FF, //CJK UNIFIED IDEOGRAPH + 0xF540: 0x93FC, //CJK UNIFIED IDEOGRAPH + 0xF541: 0x940C, //CJK UNIFIED IDEOGRAPH + 0xF542: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xF543: 0x9411, //CJK UNIFIED IDEOGRAPH + 0xF544: 0x9406, //CJK UNIFIED IDEOGRAPH + 0xF545: 0x95DE, //CJK UNIFIED IDEOGRAPH + 0xF546: 0x95E0, //CJK UNIFIED IDEOGRAPH + 0xF547: 0x95DF, //CJK UNIFIED IDEOGRAPH + 0xF548: 0x972E, //CJK UNIFIED IDEOGRAPH + 0xF549: 0x972F, //CJK UNIFIED IDEOGRAPH + 0xF54A: 0x97B9, //CJK UNIFIED IDEOGRAPH + 0xF54B: 0x97BB, //CJK UNIFIED IDEOGRAPH + 0xF54C: 0x97FD, //CJK UNIFIED IDEOGRAPH + 0xF54D: 0x97FE, //CJK UNIFIED IDEOGRAPH + 0xF54E: 0x9860, //CJK UNIFIED IDEOGRAPH + 0xF54F: 0x9862, //CJK UNIFIED IDEOGRAPH + 0xF550: 0x9863, //CJK UNIFIED IDEOGRAPH + 0xF551: 0x985F, //CJK UNIFIED IDEOGRAPH + 0xF552: 0x98C1, //CJK UNIFIED IDEOGRAPH + 0xF553: 0x98C2, //CJK UNIFIED IDEOGRAPH + 0xF554: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xF555: 0x994E, //CJK UNIFIED IDEOGRAPH + 0xF556: 0x9959, //CJK UNIFIED IDEOGRAPH + 0xF557: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF558: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xF559: 0x9953, //CJK UNIFIED IDEOGRAPH + 0xF55A: 0x9A32, //CJK UNIFIED IDEOGRAPH + 0xF55B: 0x9A34, //CJK UNIFIED IDEOGRAPH + 0xF55C: 0x9A31, //CJK UNIFIED IDEOGRAPH + 0xF55D: 0x9A2C, //CJK UNIFIED IDEOGRAPH + 0xF55E: 0x9A2A, //CJK UNIFIED IDEOGRAPH + 0xF55F: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF560: 0x9A29, //CJK UNIFIED IDEOGRAPH + 0xF561: 0x9A2E, //CJK UNIFIED IDEOGRAPH + 0xF562: 0x9A38, //CJK UNIFIED IDEOGRAPH + 0xF563: 0x9A2D, //CJK UNIFIED IDEOGRAPH + 0xF564: 0x9AC7, //CJK UNIFIED IDEOGRAPH + 0xF565: 0x9ACA, //CJK UNIFIED IDEOGRAPH + 0xF566: 0x9AC6, //CJK UNIFIED IDEOGRAPH + 0xF567: 0x9B10, //CJK UNIFIED IDEOGRAPH + 0xF568: 0x9B12, //CJK UNIFIED IDEOGRAPH + 0xF569: 0x9B11, //CJK UNIFIED IDEOGRAPH + 0xF56A: 0x9C0B, //CJK UNIFIED IDEOGRAPH + 0xF56B: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xF56C: 0x9BF7, //CJK UNIFIED IDEOGRAPH + 0xF56D: 0x9C05, //CJK UNIFIED IDEOGRAPH + 0xF56E: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xF56F: 0x9BF8, //CJK UNIFIED IDEOGRAPH + 0xF570: 0x9C40, //CJK UNIFIED IDEOGRAPH + 0xF571: 0x9C07, //CJK UNIFIED IDEOGRAPH + 0xF572: 0x9C0E, //CJK UNIFIED IDEOGRAPH + 0xF573: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xF574: 0x9C17, //CJK UNIFIED IDEOGRAPH + 0xF575: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xF576: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xF577: 0x9D9F, //CJK UNIFIED IDEOGRAPH + 0xF578: 0x9D99, //CJK UNIFIED IDEOGRAPH + 0xF579: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xF57A: 0x9D9D, //CJK UNIFIED IDEOGRAPH + 0xF57B: 0x9D92, //CJK UNIFIED IDEOGRAPH + 0xF57C: 0x9D98, //CJK UNIFIED IDEOGRAPH + 0xF57D: 0x9D90, //CJK UNIFIED IDEOGRAPH + 0xF57E: 0x9D9B, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x9DA0, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x9D94, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x9D9C, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x9DAA, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x9D97, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x9DA1, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x9DA2, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x9DA8, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x9D9E, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x9DA3, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x9DBF, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x9D96, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x9DA6, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x9DA7, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x9E99, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x9E9B, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x9E9A, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x9EE4, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x9EE7, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x9EE6, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x9F30, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x9F2E, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x9F5B, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x9F5E, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x9F5D, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x9F59, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x9F91, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x513A, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x5139, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x5298, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x5297, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x56BD, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x56BE, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x5B48, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x5B47, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x5DCB, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x5DCF, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x651B, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x6B02, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x6AFC, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x6B03, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x6AF8, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x6B00, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x7043, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x7044, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x704A, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x7048, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x7049, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x7045, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x7046, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x721D, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x721A, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x7219, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x737E, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x7517, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x77D0, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x792D, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x7931, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x792F, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x7C53, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x7E87, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x7E8B, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x7E86, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x7E8D, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x7FBB, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x8030, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x81DD, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x8618, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x862A, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x8626, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x861F, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x8623, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x861C, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x8619, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x8627, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x862E, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x8621, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x8620, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x8629, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x861E, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x8625, //CJK UNIFIED IDEOGRAPH + 0xF640: 0x8829, //CJK UNIFIED IDEOGRAPH + 0xF641: 0x881D, //CJK UNIFIED IDEOGRAPH + 0xF642: 0x881B, //CJK UNIFIED IDEOGRAPH + 0xF643: 0x8820, //CJK UNIFIED IDEOGRAPH + 0xF644: 0x8824, //CJK UNIFIED IDEOGRAPH + 0xF645: 0x881C, //CJK UNIFIED IDEOGRAPH + 0xF646: 0x882B, //CJK UNIFIED IDEOGRAPH + 0xF647: 0x884A, //CJK UNIFIED IDEOGRAPH + 0xF648: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xF649: 0x8969, //CJK UNIFIED IDEOGRAPH + 0xF64A: 0x896E, //CJK UNIFIED IDEOGRAPH + 0xF64B: 0x896B, //CJK UNIFIED IDEOGRAPH + 0xF64C: 0x89FA, //CJK UNIFIED IDEOGRAPH + 0xF64D: 0x8B79, //CJK UNIFIED IDEOGRAPH + 0xF64E: 0x8B78, //CJK UNIFIED IDEOGRAPH + 0xF64F: 0x8B45, //CJK UNIFIED IDEOGRAPH + 0xF650: 0x8B7A, //CJK UNIFIED IDEOGRAPH + 0xF651: 0x8B7B, //CJK UNIFIED IDEOGRAPH + 0xF652: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xF653: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xF654: 0x8DAF, //CJK UNIFIED IDEOGRAPH + 0xF655: 0x8E8E, //CJK UNIFIED IDEOGRAPH + 0xF656: 0x8E8C, //CJK UNIFIED IDEOGRAPH + 0xF657: 0x8F5E, //CJK UNIFIED IDEOGRAPH + 0xF658: 0x8F5B, //CJK UNIFIED IDEOGRAPH + 0xF659: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xF65A: 0x9146, //CJK UNIFIED IDEOGRAPH + 0xF65B: 0x9144, //CJK UNIFIED IDEOGRAPH + 0xF65C: 0x9145, //CJK UNIFIED IDEOGRAPH + 0xF65D: 0x91B9, //CJK UNIFIED IDEOGRAPH + 0xF65E: 0x943F, //CJK UNIFIED IDEOGRAPH + 0xF65F: 0x943B, //CJK UNIFIED IDEOGRAPH + 0xF660: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xF661: 0x9429, //CJK UNIFIED IDEOGRAPH + 0xF662: 0x943D, //CJK UNIFIED IDEOGRAPH + 0xF663: 0x943C, //CJK UNIFIED IDEOGRAPH + 0xF664: 0x9430, //CJK UNIFIED IDEOGRAPH + 0xF665: 0x9439, //CJK UNIFIED IDEOGRAPH + 0xF666: 0x942A, //CJK UNIFIED IDEOGRAPH + 0xF667: 0x9437, //CJK UNIFIED IDEOGRAPH + 0xF668: 0x942C, //CJK UNIFIED IDEOGRAPH + 0xF669: 0x9440, //CJK UNIFIED IDEOGRAPH + 0xF66A: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xF66B: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xF66C: 0x95E4, //CJK UNIFIED IDEOGRAPH + 0xF66D: 0x95E3, //CJK UNIFIED IDEOGRAPH + 0xF66E: 0x9735, //CJK UNIFIED IDEOGRAPH + 0xF66F: 0x973A, //CJK UNIFIED IDEOGRAPH + 0xF670: 0x97BF, //CJK UNIFIED IDEOGRAPH + 0xF671: 0x97E1, //CJK UNIFIED IDEOGRAPH + 0xF672: 0x9864, //CJK UNIFIED IDEOGRAPH + 0xF673: 0x98C9, //CJK UNIFIED IDEOGRAPH + 0xF674: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xF675: 0x98C0, //CJK UNIFIED IDEOGRAPH + 0xF676: 0x9958, //CJK UNIFIED IDEOGRAPH + 0xF677: 0x9956, //CJK UNIFIED IDEOGRAPH + 0xF678: 0x9A39, //CJK UNIFIED IDEOGRAPH + 0xF679: 0x9A3D, //CJK UNIFIED IDEOGRAPH + 0xF67A: 0x9A46, //CJK UNIFIED IDEOGRAPH + 0xF67B: 0x9A44, //CJK UNIFIED IDEOGRAPH + 0xF67C: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xF67D: 0x9A41, //CJK UNIFIED IDEOGRAPH + 0xF67E: 0x9A3A, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x9A3F, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x9ACD, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x9B15, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x9B17, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x9B16, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x9B3A, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x9B52, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x9C2B, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x9C1D, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x9C1C, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x9C2C, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x9C23, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x9C28, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x9C29, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x9DB7, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x9DB6, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x9DBC, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x9DC7, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x9DCA, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x9DBE, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x9DC5, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x9DC3, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x9DB5, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x9DCE, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x9DB9, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x9DAC, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x9DC8, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x9DB1, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x9DAD, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x9DCC, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x9DB3, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x9DCD, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x9E7A, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x9E9C, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x9EEB, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x9EEE, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x9EED, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x9F1B, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x9F18, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x9F1A, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x9F31, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x9F65, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x9F64, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x9F92, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x4EB9, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x56C6, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x56C5, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x56CB, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x5971, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x5B4B, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x5B4C, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x5DD5, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x5DD1, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x5EF2, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x6521, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x6520, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x6526, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x6522, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x6B0B, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x6B08, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x6B09, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x6C0D, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x7055, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x7056, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x7057, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x7052, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x721E, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x721F, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x72A9, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x737F, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x74D5, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x74D9, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x74D7, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0x766D, //CJK UNIFIED IDEOGRAPH + 0xF6F5: 0x76AD, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0x7935, //CJK UNIFIED IDEOGRAPH + 0xF6F7: 0x79B4, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x7A71, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x7C57, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x7C5C, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x7C59, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x7C5B, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x7C5A, //CJK UNIFIED IDEOGRAPH + 0xF740: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xF741: 0x7CF1, //CJK UNIFIED IDEOGRAPH + 0xF742: 0x7E91, //CJK UNIFIED IDEOGRAPH + 0xF743: 0x7F4F, //CJK UNIFIED IDEOGRAPH + 0xF744: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xF745: 0x81DE, //CJK UNIFIED IDEOGRAPH + 0xF746: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xF747: 0x8634, //CJK UNIFIED IDEOGRAPH + 0xF748: 0x8635, //CJK UNIFIED IDEOGRAPH + 0xF749: 0x8633, //CJK UNIFIED IDEOGRAPH + 0xF74A: 0x862C, //CJK UNIFIED IDEOGRAPH + 0xF74B: 0x8632, //CJK UNIFIED IDEOGRAPH + 0xF74C: 0x8636, //CJK UNIFIED IDEOGRAPH + 0xF74D: 0x882C, //CJK UNIFIED IDEOGRAPH + 0xF74E: 0x8828, //CJK UNIFIED IDEOGRAPH + 0xF74F: 0x8826, //CJK UNIFIED IDEOGRAPH + 0xF750: 0x882A, //CJK UNIFIED IDEOGRAPH + 0xF751: 0x8825, //CJK UNIFIED IDEOGRAPH + 0xF752: 0x8971, //CJK UNIFIED IDEOGRAPH + 0xF753: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xF754: 0x89BE, //CJK UNIFIED IDEOGRAPH + 0xF755: 0x89FB, //CJK UNIFIED IDEOGRAPH + 0xF756: 0x8B7E, //CJK UNIFIED IDEOGRAPH + 0xF757: 0x8B84, //CJK UNIFIED IDEOGRAPH + 0xF758: 0x8B82, //CJK UNIFIED IDEOGRAPH + 0xF759: 0x8B86, //CJK UNIFIED IDEOGRAPH + 0xF75A: 0x8B85, //CJK UNIFIED IDEOGRAPH + 0xF75B: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xF75C: 0x8D15, //CJK UNIFIED IDEOGRAPH + 0xF75D: 0x8E95, //CJK UNIFIED IDEOGRAPH + 0xF75E: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xF75F: 0x8E9A, //CJK UNIFIED IDEOGRAPH + 0xF760: 0x8E92, //CJK UNIFIED IDEOGRAPH + 0xF761: 0x8E90, //CJK UNIFIED IDEOGRAPH + 0xF762: 0x8E96, //CJK UNIFIED IDEOGRAPH + 0xF763: 0x8E97, //CJK UNIFIED IDEOGRAPH + 0xF764: 0x8F60, //CJK UNIFIED IDEOGRAPH + 0xF765: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xF766: 0x9147, //CJK UNIFIED IDEOGRAPH + 0xF767: 0x944C, //CJK UNIFIED IDEOGRAPH + 0xF768: 0x9450, //CJK UNIFIED IDEOGRAPH + 0xF769: 0x944A, //CJK UNIFIED IDEOGRAPH + 0xF76A: 0x944B, //CJK UNIFIED IDEOGRAPH + 0xF76B: 0x944F, //CJK UNIFIED IDEOGRAPH + 0xF76C: 0x9447, //CJK UNIFIED IDEOGRAPH + 0xF76D: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xF76E: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xF76F: 0x9449, //CJK UNIFIED IDEOGRAPH + 0xF770: 0x9446, //CJK UNIFIED IDEOGRAPH + 0xF771: 0x973F, //CJK UNIFIED IDEOGRAPH + 0xF772: 0x97E3, //CJK UNIFIED IDEOGRAPH + 0xF773: 0x986A, //CJK UNIFIED IDEOGRAPH + 0xF774: 0x9869, //CJK UNIFIED IDEOGRAPH + 0xF775: 0x98CB, //CJK UNIFIED IDEOGRAPH + 0xF776: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xF777: 0x995B, //CJK UNIFIED IDEOGRAPH + 0xF778: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xF779: 0x9A53, //CJK UNIFIED IDEOGRAPH + 0xF77A: 0x9A54, //CJK UNIFIED IDEOGRAPH + 0xF77B: 0x9A4C, //CJK UNIFIED IDEOGRAPH + 0xF77C: 0x9A4F, //CJK UNIFIED IDEOGRAPH + 0xF77D: 0x9A48, //CJK UNIFIED IDEOGRAPH + 0xF77E: 0x9A4A, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9A49, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x9A52, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x9A50, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x9AD0, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x9B19, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x9B2B, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x9B56, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x9B55, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x9C3F, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x9C44, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x9C33, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x9C41, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x9C3C, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x9C37, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x9C34, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x9C3D, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x9C36, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x9DDB, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0x9DD2, //CJK UNIFIED IDEOGRAPH + 0xF7B9: 0x9DDE, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x9DDA, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x9DCB, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x9DD0, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x9DDC, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x9DD1, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x9DDF, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x9DE9, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x9DD8, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x9DD6, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x9DF5, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x9DD5, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x9DDD, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x9EB6, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0x9EF0, //CJK UNIFIED IDEOGRAPH + 0xF7C9: 0x9F35, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x9F33, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x9F32, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x9F42, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x9F6B, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x9FA2, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x513D, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x5299, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x58E8, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0x58E7, //CJK UNIFIED IDEOGRAPH + 0xF7D4: 0x5972, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x5B4D, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x5DD8, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x882F, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x5F4F, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x6201, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x6203, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x6204, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x6529, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x6525, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x6596, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x66EB, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x6B11, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x6B0F, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x6BCA, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x705B, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x705A, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x7222, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x7382, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x7381, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x7383, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x77D4, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x7C67, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x7C66, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x7E95, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x826C, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x863A, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x8640, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x8639, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x863C, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x8631, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x863B, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x863E, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x8830, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x8832, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x882E, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x8833, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x8976, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x8973, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x89FE, //CJK UNIFIED IDEOGRAPH + 0xF840: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xF841: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xF842: 0x8B8B, //CJK UNIFIED IDEOGRAPH + 0xF843: 0x8B88, //CJK UNIFIED IDEOGRAPH + 0xF844: 0x8C45, //CJK UNIFIED IDEOGRAPH + 0xF845: 0x8D19, //CJK UNIFIED IDEOGRAPH + 0xF846: 0x8E98, //CJK UNIFIED IDEOGRAPH + 0xF847: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xF848: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xF849: 0x91BC, //CJK UNIFIED IDEOGRAPH + 0xF84A: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xF84B: 0x9455, //CJK UNIFIED IDEOGRAPH + 0xF84C: 0x945D, //CJK UNIFIED IDEOGRAPH + 0xF84D: 0x9457, //CJK UNIFIED IDEOGRAPH + 0xF84E: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xF84F: 0x97C4, //CJK UNIFIED IDEOGRAPH + 0xF850: 0x97C5, //CJK UNIFIED IDEOGRAPH + 0xF851: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xF852: 0x9A56, //CJK UNIFIED IDEOGRAPH + 0xF853: 0x9A59, //CJK UNIFIED IDEOGRAPH + 0xF854: 0x9B1E, //CJK UNIFIED IDEOGRAPH + 0xF855: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xF856: 0x9B20, //CJK UNIFIED IDEOGRAPH + 0xF857: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0xF858: 0x9C58, //CJK UNIFIED IDEOGRAPH + 0xF859: 0x9C50, //CJK UNIFIED IDEOGRAPH + 0xF85A: 0x9C4A, //CJK UNIFIED IDEOGRAPH + 0xF85B: 0x9C4D, //CJK UNIFIED IDEOGRAPH + 0xF85C: 0x9C4B, //CJK UNIFIED IDEOGRAPH + 0xF85D: 0x9C55, //CJK UNIFIED IDEOGRAPH + 0xF85E: 0x9C59, //CJK UNIFIED IDEOGRAPH + 0xF85F: 0x9C4C, //CJK UNIFIED IDEOGRAPH + 0xF860: 0x9C4E, //CJK UNIFIED IDEOGRAPH + 0xF861: 0x9DFB, //CJK UNIFIED IDEOGRAPH + 0xF862: 0x9DF7, //CJK UNIFIED IDEOGRAPH + 0xF863: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xF864: 0x9DE3, //CJK UNIFIED IDEOGRAPH + 0xF865: 0x9DEB, //CJK UNIFIED IDEOGRAPH + 0xF866: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xF867: 0x9DE4, //CJK UNIFIED IDEOGRAPH + 0xF868: 0x9DF6, //CJK UNIFIED IDEOGRAPH + 0xF869: 0x9DE1, //CJK UNIFIED IDEOGRAPH + 0xF86A: 0x9DEE, //CJK UNIFIED IDEOGRAPH + 0xF86B: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xF86C: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xF86D: 0x9DF0, //CJK UNIFIED IDEOGRAPH + 0xF86E: 0x9DE2, //CJK UNIFIED IDEOGRAPH + 0xF86F: 0x9DEC, //CJK UNIFIED IDEOGRAPH + 0xF870: 0x9DF4, //CJK UNIFIED IDEOGRAPH + 0xF871: 0x9DF3, //CJK UNIFIED IDEOGRAPH + 0xF872: 0x9DE8, //CJK UNIFIED IDEOGRAPH + 0xF873: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xF874: 0x9EC2, //CJK UNIFIED IDEOGRAPH + 0xF875: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xF876: 0x9EF2, //CJK UNIFIED IDEOGRAPH + 0xF877: 0x9EF3, //CJK UNIFIED IDEOGRAPH + 0xF878: 0x9F06, //CJK UNIFIED IDEOGRAPH + 0xF879: 0x9F1C, //CJK UNIFIED IDEOGRAPH + 0xF87A: 0x9F38, //CJK UNIFIED IDEOGRAPH + 0xF87B: 0x9F37, //CJK UNIFIED IDEOGRAPH + 0xF87C: 0x9F36, //CJK UNIFIED IDEOGRAPH + 0xF87D: 0x9F43, //CJK UNIFIED IDEOGRAPH + 0xF87E: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xF8A1: 0x9F71, //CJK UNIFIED IDEOGRAPH + 0xF8A2: 0x9F70, //CJK UNIFIED IDEOGRAPH + 0xF8A3: 0x9F6E, //CJK UNIFIED IDEOGRAPH + 0xF8A4: 0x9F6F, //CJK UNIFIED IDEOGRAPH + 0xF8A5: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0xF8A6: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0xF8A7: 0x5B4E, //CJK UNIFIED IDEOGRAPH + 0xF8A8: 0x5C6D, //CJK UNIFIED IDEOGRAPH + 0xF8A9: 0x652D, //CJK UNIFIED IDEOGRAPH + 0xF8AA: 0x66ED, //CJK UNIFIED IDEOGRAPH + 0xF8AB: 0x66EE, //CJK UNIFIED IDEOGRAPH + 0xF8AC: 0x6B13, //CJK UNIFIED IDEOGRAPH + 0xF8AD: 0x705F, //CJK UNIFIED IDEOGRAPH + 0xF8AE: 0x7061, //CJK UNIFIED IDEOGRAPH + 0xF8AF: 0x705D, //CJK UNIFIED IDEOGRAPH + 0xF8B0: 0x7060, //CJK UNIFIED IDEOGRAPH + 0xF8B1: 0x7223, //CJK UNIFIED IDEOGRAPH + 0xF8B2: 0x74DB, //CJK UNIFIED IDEOGRAPH + 0xF8B3: 0x74E5, //CJK UNIFIED IDEOGRAPH + 0xF8B4: 0x77D5, //CJK UNIFIED IDEOGRAPH + 0xF8B5: 0x7938, //CJK UNIFIED IDEOGRAPH + 0xF8B6: 0x79B7, //CJK UNIFIED IDEOGRAPH + 0xF8B7: 0x79B6, //CJK UNIFIED IDEOGRAPH + 0xF8B8: 0x7C6A, //CJK UNIFIED IDEOGRAPH + 0xF8B9: 0x7E97, //CJK UNIFIED IDEOGRAPH + 0xF8BA: 0x7F89, //CJK UNIFIED IDEOGRAPH + 0xF8BB: 0x826D, //CJK UNIFIED IDEOGRAPH + 0xF8BC: 0x8643, //CJK UNIFIED IDEOGRAPH + 0xF8BD: 0x8838, //CJK UNIFIED IDEOGRAPH + 0xF8BE: 0x8837, //CJK UNIFIED IDEOGRAPH + 0xF8BF: 0x8835, //CJK UNIFIED IDEOGRAPH + 0xF8C0: 0x884B, //CJK UNIFIED IDEOGRAPH + 0xF8C1: 0x8B94, //CJK UNIFIED IDEOGRAPH + 0xF8C2: 0x8B95, //CJK UNIFIED IDEOGRAPH + 0xF8C3: 0x8E9E, //CJK UNIFIED IDEOGRAPH + 0xF8C4: 0x8E9F, //CJK UNIFIED IDEOGRAPH + 0xF8C5: 0x8EA0, //CJK UNIFIED IDEOGRAPH + 0xF8C6: 0x8E9D, //CJK UNIFIED IDEOGRAPH + 0xF8C7: 0x91BE, //CJK UNIFIED IDEOGRAPH + 0xF8C8: 0x91BD, //CJK UNIFIED IDEOGRAPH + 0xF8C9: 0x91C2, //CJK UNIFIED IDEOGRAPH + 0xF8CA: 0x946B, //CJK UNIFIED IDEOGRAPH + 0xF8CB: 0x9468, //CJK UNIFIED IDEOGRAPH + 0xF8CC: 0x9469, //CJK UNIFIED IDEOGRAPH + 0xF8CD: 0x96E5, //CJK UNIFIED IDEOGRAPH + 0xF8CE: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xF8CF: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xF8D0: 0x9747, //CJK UNIFIED IDEOGRAPH + 0xF8D1: 0x97C7, //CJK UNIFIED IDEOGRAPH + 0xF8D2: 0x97E5, //CJK UNIFIED IDEOGRAPH + 0xF8D3: 0x9A5E, //CJK UNIFIED IDEOGRAPH + 0xF8D4: 0x9AD5, //CJK UNIFIED IDEOGRAPH + 0xF8D5: 0x9B59, //CJK UNIFIED IDEOGRAPH + 0xF8D6: 0x9C63, //CJK UNIFIED IDEOGRAPH + 0xF8D7: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xF8D8: 0x9C66, //CJK UNIFIED IDEOGRAPH + 0xF8D9: 0x9C62, //CJK UNIFIED IDEOGRAPH + 0xF8DA: 0x9C5E, //CJK UNIFIED IDEOGRAPH + 0xF8DB: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xF8DC: 0x9E02, //CJK UNIFIED IDEOGRAPH + 0xF8DD: 0x9DFE, //CJK UNIFIED IDEOGRAPH + 0xF8DE: 0x9E07, //CJK UNIFIED IDEOGRAPH + 0xF8DF: 0x9E03, //CJK UNIFIED IDEOGRAPH + 0xF8E0: 0x9E06, //CJK UNIFIED IDEOGRAPH + 0xF8E1: 0x9E05, //CJK UNIFIED IDEOGRAPH + 0xF8E2: 0x9E00, //CJK UNIFIED IDEOGRAPH + 0xF8E3: 0x9E01, //CJK UNIFIED IDEOGRAPH + 0xF8E4: 0x9E09, //CJK UNIFIED IDEOGRAPH + 0xF8E5: 0x9DFF, //CJK UNIFIED IDEOGRAPH + 0xF8E6: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xF8E7: 0x9E04, //CJK UNIFIED IDEOGRAPH + 0xF8E8: 0x9EA0, //CJK UNIFIED IDEOGRAPH + 0xF8E9: 0x9F1E, //CJK UNIFIED IDEOGRAPH + 0xF8EA: 0x9F46, //CJK UNIFIED IDEOGRAPH + 0xF8EB: 0x9F74, //CJK UNIFIED IDEOGRAPH + 0xF8EC: 0x9F75, //CJK UNIFIED IDEOGRAPH + 0xF8ED: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xF8EE: 0x56D4, //CJK UNIFIED IDEOGRAPH + 0xF8EF: 0x652E, //CJK UNIFIED IDEOGRAPH + 0xF8F0: 0x65B8, //CJK UNIFIED IDEOGRAPH + 0xF8F1: 0x6B18, //CJK UNIFIED IDEOGRAPH + 0xF8F2: 0x6B19, //CJK UNIFIED IDEOGRAPH + 0xF8F3: 0x6B17, //CJK UNIFIED IDEOGRAPH + 0xF8F4: 0x6B1A, //CJK UNIFIED IDEOGRAPH + 0xF8F5: 0x7062, //CJK UNIFIED IDEOGRAPH + 0xF8F6: 0x7226, //CJK UNIFIED IDEOGRAPH + 0xF8F7: 0x72AA, //CJK UNIFIED IDEOGRAPH + 0xF8F8: 0x77D8, //CJK UNIFIED IDEOGRAPH + 0xF8F9: 0x77D9, //CJK UNIFIED IDEOGRAPH + 0xF8FA: 0x7939, //CJK UNIFIED IDEOGRAPH + 0xF8FB: 0x7C69, //CJK UNIFIED IDEOGRAPH + 0xF8FC: 0x7C6B, //CJK UNIFIED IDEOGRAPH + 0xF8FD: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xF8FE: 0x7E9A, //CJK UNIFIED IDEOGRAPH + 0xF940: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xF941: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xF942: 0x7E99, //CJK UNIFIED IDEOGRAPH + 0xF943: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xF944: 0x81E1, //CJK UNIFIED IDEOGRAPH + 0xF945: 0x8646, //CJK UNIFIED IDEOGRAPH + 0xF946: 0x8647, //CJK UNIFIED IDEOGRAPH + 0xF947: 0x8648, //CJK UNIFIED IDEOGRAPH + 0xF948: 0x8979, //CJK UNIFIED IDEOGRAPH + 0xF949: 0x897A, //CJK UNIFIED IDEOGRAPH + 0xF94A: 0x897C, //CJK UNIFIED IDEOGRAPH + 0xF94B: 0x897B, //CJK UNIFIED IDEOGRAPH + 0xF94C: 0x89FF, //CJK UNIFIED IDEOGRAPH + 0xF94D: 0x8B98, //CJK UNIFIED IDEOGRAPH + 0xF94E: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xF94F: 0x8EA5, //CJK UNIFIED IDEOGRAPH + 0xF950: 0x8EA4, //CJK UNIFIED IDEOGRAPH + 0xF951: 0x8EA3, //CJK UNIFIED IDEOGRAPH + 0xF952: 0x946E, //CJK UNIFIED IDEOGRAPH + 0xF953: 0x946D, //CJK UNIFIED IDEOGRAPH + 0xF954: 0x946F, //CJK UNIFIED IDEOGRAPH + 0xF955: 0x9471, //CJK UNIFIED IDEOGRAPH + 0xF956: 0x9473, //CJK UNIFIED IDEOGRAPH + 0xF957: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xF958: 0x9872, //CJK UNIFIED IDEOGRAPH + 0xF959: 0x995F, //CJK UNIFIED IDEOGRAPH + 0xF95A: 0x9C68, //CJK UNIFIED IDEOGRAPH + 0xF95B: 0x9C6E, //CJK UNIFIED IDEOGRAPH + 0xF95C: 0x9C6D, //CJK UNIFIED IDEOGRAPH + 0xF95D: 0x9E0B, //CJK UNIFIED IDEOGRAPH + 0xF95E: 0x9E0D, //CJK UNIFIED IDEOGRAPH + 0xF95F: 0x9E10, //CJK UNIFIED IDEOGRAPH + 0xF960: 0x9E0F, //CJK UNIFIED IDEOGRAPH + 0xF961: 0x9E12, //CJK UNIFIED IDEOGRAPH + 0xF962: 0x9E11, //CJK UNIFIED IDEOGRAPH + 0xF963: 0x9EA1, //CJK UNIFIED IDEOGRAPH + 0xF964: 0x9EF5, //CJK UNIFIED IDEOGRAPH + 0xF965: 0x9F09, //CJK UNIFIED IDEOGRAPH + 0xF966: 0x9F47, //CJK UNIFIED IDEOGRAPH + 0xF967: 0x9F78, //CJK UNIFIED IDEOGRAPH + 0xF968: 0x9F7B, //CJK UNIFIED IDEOGRAPH + 0xF969: 0x9F7A, //CJK UNIFIED IDEOGRAPH + 0xF96A: 0x9F79, //CJK UNIFIED IDEOGRAPH + 0xF96B: 0x571E, //CJK UNIFIED IDEOGRAPH + 0xF96C: 0x7066, //CJK UNIFIED IDEOGRAPH + 0xF96D: 0x7C6F, //CJK UNIFIED IDEOGRAPH + 0xF96E: 0x883C, //CJK UNIFIED IDEOGRAPH + 0xF96F: 0x8DB2, //CJK UNIFIED IDEOGRAPH + 0xF970: 0x8EA6, //CJK UNIFIED IDEOGRAPH + 0xF971: 0x91C3, //CJK UNIFIED IDEOGRAPH + 0xF972: 0x9474, //CJK UNIFIED IDEOGRAPH + 0xF973: 0x9478, //CJK UNIFIED IDEOGRAPH + 0xF974: 0x9476, //CJK UNIFIED IDEOGRAPH + 0xF975: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xF976: 0x9A60, //CJK UNIFIED IDEOGRAPH + 0xF977: 0x9C74, //CJK UNIFIED IDEOGRAPH + 0xF978: 0x9C73, //CJK UNIFIED IDEOGRAPH + 0xF979: 0x9C71, //CJK UNIFIED IDEOGRAPH + 0xF97A: 0x9C75, //CJK UNIFIED IDEOGRAPH + 0xF97B: 0x9E14, //CJK UNIFIED IDEOGRAPH + 0xF97C: 0x9E13, //CJK UNIFIED IDEOGRAPH + 0xF97D: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xF97E: 0x9F0A, //CJK UNIFIED IDEOGRAPH + 0xF9A1: 0x9FA4, //CJK UNIFIED IDEOGRAPH + 0xF9A2: 0x7068, //CJK UNIFIED IDEOGRAPH + 0xF9A3: 0x7065, //CJK UNIFIED IDEOGRAPH + 0xF9A4: 0x7CF7, //CJK UNIFIED IDEOGRAPH + 0xF9A5: 0x866A, //CJK UNIFIED IDEOGRAPH + 0xF9A6: 0x883E, //CJK UNIFIED IDEOGRAPH + 0xF9A7: 0x883D, //CJK UNIFIED IDEOGRAPH + 0xF9A8: 0x883F, //CJK UNIFIED IDEOGRAPH + 0xF9A9: 0x8B9E, //CJK UNIFIED IDEOGRAPH + 0xF9AA: 0x8C9C, //CJK UNIFIED IDEOGRAPH + 0xF9AB: 0x8EA9, //CJK UNIFIED IDEOGRAPH + 0xF9AC: 0x8EC9, //CJK UNIFIED IDEOGRAPH + 0xF9AD: 0x974B, //CJK UNIFIED IDEOGRAPH + 0xF9AE: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xF9AF: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xF9B0: 0x98CC, //CJK UNIFIED IDEOGRAPH + 0xF9B1: 0x9961, //CJK UNIFIED IDEOGRAPH + 0xF9B2: 0x99AB, //CJK UNIFIED IDEOGRAPH + 0xF9B3: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xF9B4: 0x9A66, //CJK UNIFIED IDEOGRAPH + 0xF9B5: 0x9A67, //CJK UNIFIED IDEOGRAPH + 0xF9B6: 0x9B24, //CJK UNIFIED IDEOGRAPH + 0xF9B7: 0x9E15, //CJK UNIFIED IDEOGRAPH + 0xF9B8: 0x9E17, //CJK UNIFIED IDEOGRAPH + 0xF9B9: 0x9F48, //CJK UNIFIED IDEOGRAPH + 0xF9BA: 0x6207, //CJK UNIFIED IDEOGRAPH + 0xF9BB: 0x6B1E, //CJK UNIFIED IDEOGRAPH + 0xF9BC: 0x7227, //CJK UNIFIED IDEOGRAPH + 0xF9BD: 0x864C, //CJK UNIFIED IDEOGRAPH + 0xF9BE: 0x8EA8, //CJK UNIFIED IDEOGRAPH + 0xF9BF: 0x9482, //CJK UNIFIED IDEOGRAPH + 0xF9C0: 0x9480, //CJK UNIFIED IDEOGRAPH + 0xF9C1: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xF9C2: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xF9C3: 0x9A68, //CJK UNIFIED IDEOGRAPH + 0xF9C4: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xF9C5: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xF9C6: 0x7229, //CJK UNIFIED IDEOGRAPH + 0xF9C7: 0x864B, //CJK UNIFIED IDEOGRAPH + 0xF9C8: 0x8B9F, //CJK UNIFIED IDEOGRAPH + 0xF9C9: 0x9483, //CJK UNIFIED IDEOGRAPH + 0xF9CA: 0x9C79, //CJK UNIFIED IDEOGRAPH + 0xF9CB: 0x9EB7, //CJK UNIFIED IDEOGRAPH + 0xF9CC: 0x7675, //CJK UNIFIED IDEOGRAPH + 0xF9CD: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xF9CE: 0x9C7A, //CJK UNIFIED IDEOGRAPH + 0xF9CF: 0x9E1D, //CJK UNIFIED IDEOGRAPH + 0xF9D0: 0x7069, //CJK UNIFIED IDEOGRAPH + 0xF9D1: 0x706A, //CJK UNIFIED IDEOGRAPH + 0xF9D2: 0x9EA4, //CJK UNIFIED IDEOGRAPH + 0xF9D3: 0x9F7E, //CJK UNIFIED IDEOGRAPH + 0xF9D4: 0x9F49, //CJK UNIFIED IDEOGRAPH + 0xF9D5: 0x9F98, //CJK UNIFIED IDEOGRAPH + 0xF9D6: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xF9D7: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xF9D8: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xF9D9: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0xF9DA: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xF9DB: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xF9DC: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0xF9DD: 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0xF9DE: 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0xF9DF: 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0xF9E0: 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0xF9E1: 0x256C, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0xF9E2: 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0xF9E3: 0x255A, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0xF9E4: 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0xF9E5: 0x255D, //BOX DRAWINGS DOUBLE UP AND LEFT + 0xF9E6: 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0xF9E7: 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0xF9E8: 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0xF9E9: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xF9EA: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xF9EB: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xF9EC: 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0xF9ED: 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0xF9EE: 0x255B, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0xF9EF: 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0xF9F0: 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0xF9F1: 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0xF9F2: 0x255F, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0xF9F3: 0x256B, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0xF9F4: 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0xF9F5: 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0xF9F6: 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0xF9F7: 0x255C, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0xF9F8: 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0xF9F9: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xF9FA: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xF9FB: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xF9FC: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xF9FD: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xF9FE: 0x2593, //DARK SHADE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/log.go b/vendor/github.com/denisenkom/go-mssqldb/log.go new file mode 100644 index 0000000..9b8c551 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/log.go @@ -0,0 +1,30 @@ +package mssql + +import ( + "log" +) + +type Logger interface { + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} + +type optionalLogger struct { + logger Logger +} + +func (o optionalLogger) Printf(format string, v ...interface{}) { + if o.logger != nil { + o.logger.Printf(format, v...) + } else { + log.Printf(format, v...) + } +} + +func (o optionalLogger) Println(v ...interface{}) { + if o.logger != nil { + o.logger.Println(v...) + } else { + log.Println(v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql.go b/vendor/github.com/denisenkom/go-mssqldb/mssql.go new file mode 100644 index 0000000..dc60fd2 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go @@ -0,0 +1,815 @@ +package mssql + +import ( + "context" + "database/sql" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "net" + "reflect" + "strings" + "time" +) + +var driverInstance = &Driver{processQueryText: true} +var driverInstanceNoProcess = &Driver{processQueryText: false} + +func init() { + sql.Register("mssql", driverInstance) + sql.Register("sqlserver", driverInstanceNoProcess) + createDialer = func(p *connectParams) dialer { + return tcpDialer{&net.Dialer{KeepAlive: p.keepAlive}} + } +} + +// Abstract the dialer for testing and for non-TCP based connections. +type dialer interface { + Dial(ctx context.Context, addr string) (net.Conn, error) +} + +var createDialer func(p *connectParams) dialer + +type tcpDialer struct { + nd *net.Dialer +} + +func (d tcpDialer) Dial(ctx context.Context, addr string) (net.Conn, error) { + return d.nd.DialContext(ctx, "tcp", addr) +} + +type Driver struct { + log optionalLogger + + processQueryText bool +} + +// OpenConnector opens a new connector. Useful to dial with a context. +func (d *Driver) OpenConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + return &Connector{ + params: params, + driver: d, + }, nil +} + +func (d *Driver) Open(dsn string) (driver.Conn, error) { + return d.open(context.Background(), dsn) +} + +func SetLogger(logger Logger) { + driverInstance.SetLogger(logger) + driverInstanceNoProcess.SetLogger(logger) +} + +func (d *Driver) SetLogger(logger Logger) { + d.log = optionalLogger{logger} +} + +// NewConnector creates a new connector from a DSN. +// The returned connector may be used with sql.OpenDB. +func NewConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + c := &Connector{ + params: params, + driver: driverInstanceNoProcess, + } + return c, nil +} + +// Connector holds the parsed DSN and is ready to make a new connection +// at any time. +// +// In the future, settings that cannot be passed through a string DSN +// may be set directly on the connector. +type Connector struct { + params connectParams + driver *Driver + + // SessionInitSQL is executed after marking a given session to be reset. + // When not present, the next query will still reset the session to the + // database defaults. + // + // When present the connection will immediately mark the session to + // be reset, then execute the SessionInitSQL text to setup the session + // that may be different from the base database defaults. + // + // For Example, the application relies on the following defaults + // but is not allowed to set them at the database system level. + // + // SET XACT_ABORT ON; + // SET TEXTSIZE -1; + // SET ANSI_NULLS ON; + // SET LOCK_TIMEOUT 10000; + // + // SessionInitSQL should not attempt to manually call sp_reset_connection. + // This will happen at the TDS layer. + // + // SessionInitSQL is optional. The session will be reset even if + // SessionInitSQL is empty. + SessionInitSQL string +} + +type Conn struct { + connector *Connector + sess *tdsSession + transactionCtx context.Context + resetSession bool + + processQueryText bool + connectionGood bool + + outs map[string]interface{} +} + +func (c *Conn) checkBadConn(err error) error { + // this is a hack to address Issue #275 + // we set connectionGood flag to false if + // error indicates that connection is not usable + // but we return actual error instead of ErrBadConn + // this will cause connection to stay in a pool + // but next request to this connection will return ErrBadConn + + // it might be possible to revise this hack after + // https://github.com/golang/go/issues/20807 + // is implemented + switch err { + case nil: + return nil + case io.EOF: + c.connectionGood = false + return driver.ErrBadConn + case driver.ErrBadConn: + // It is an internal programming error if driver.ErrBadConn + // is ever passed to this function. driver.ErrBadConn should + // only ever be returned in response to a *mssql.Conn.connectionGood == false + // check in the external facing API. + panic("driver.ErrBadConn in checkBadConn. This should not happen.") + } + + switch err.(type) { + case net.Error: + c.connectionGood = false + return err + case StreamError: + c.connectionGood = false + return err + default: + return err + } +} + +func (c *Conn) clearOuts() { + c.outs = nil +} + +func (c *Conn) simpleProcessResp(ctx context.Context) error { + tokchan := make(chan tokenStruct, 5) + go processResponse(ctx, c.sess, tokchan, c.outs) + c.clearOuts() + for tok := range tokchan { + switch token := tok.(type) { + case doneStruct: + if token.isError() { + return c.checkBadConn(token.getError()) + } + case error: + return c.checkBadConn(token) + } + } + return nil +} + +func (c *Conn) Commit() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendCommitRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendCommitRequest() error { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{c.sess.tranid, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send CommitXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Faild to send CommitXact: %v", err) + } + return nil +} + +func (c *Conn) Rollback() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendRollbackRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendRollbackRequest() error { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{c.sess.tranid, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send RollbackXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Failed to send RollbackXact: %v", err) + } + return nil +} + +func (c *Conn) Begin() (driver.Tx, error) { + return c.begin(context.Background(), isolationUseCurrent) +} + +func (c *Conn) begin(ctx context.Context, tdsIsolation isoLevel) (tx driver.Tx, err error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + err = c.sendBeginRequest(ctx, tdsIsolation) + if err != nil { + return nil, c.checkBadConn(err) + } + tx, err = c.processBeginResponse(ctx) + if err != nil { + return nil, c.checkBadConn(err) + } + return +} + +func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) error { + c.transactionCtx = ctx + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{0, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendBeginXact(c.sess.buf, headers, tdsIsolation, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send BeginXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Failed to send BeginXact: %v", err) + } + return nil +} + +func (c *Conn) processBeginResponse(ctx context.Context) (driver.Tx, error) { + if err := c.simpleProcessResp(ctx); err != nil { + return nil, err + } + // successful BEGINXACT request will return sess.tranid + // for started transaction + return c, nil +} + +func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + return d.connect(ctx, params) +} + +// connect to the server, using the provided context for dialing only. +func (d *Driver) connect(ctx context.Context, params connectParams) (*Conn, error) { + sess, err := connect(ctx, d.log, params) + if err != nil { + // main server failed, try fail-over partner + if params.failOverPartner == "" { + return nil, err + } + + params.host = params.failOverPartner + if params.failOverPort != 0 { + params.port = params.failOverPort + } + + sess, err = connect(ctx, d.log, params) + if err != nil { + // fail-over partner also failed, now fail + return nil, err + } + } + + conn := &Conn{ + sess: sess, + transactionCtx: context.Background(), + processQueryText: d.processQueryText, + connectionGood: true, + } + conn.sess.log = d.log + + return conn, nil +} + +func (c *Conn) Close() error { + return c.sess.buf.transport.Close() +} + +type Stmt struct { + c *Conn + query string + paramCount int + notifSub *queryNotifSub +} + +type queryNotifSub struct { + msgText string + options string + timeout uint32 +} + +func (c *Conn) Prepare(query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(context.Background(), query) + } + return c.prepareContext(context.Background(), query) +} + +func (c *Conn) prepareContext(ctx context.Context, query string) (*Stmt, error) { + paramCount := -1 + if c.processQueryText { + query, paramCount = parseParams(query) + } + return &Stmt{c, query, paramCount, nil}, nil +} + +func (s *Stmt) Close() error { + return nil +} + +func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) { + to := uint32(timeout / time.Second) + if to < 1 { + to = 1 + } + s.notifSub = &queryNotifSub{id, options, to} +} + +func (s *Stmt) NumInput() int { + return s.paramCount +} + +func (s *Stmt) sendQuery(args []namedValue) (err error) { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{s.c.sess.tranid, 1}.pack()}, + } + + if s.notifSub != nil { + headers = append(headers, + headerStruct{ + hdrtype: dataStmHdrQueryNotif, + data: queryNotifHdr{ + s.notifSub.msgText, + s.notifSub.options, + s.notifSub.timeout, + }.pack(), + }) + } + + conn := s.c + + // no need to check number of parameters here, it is checked by database/sql + if conn.sess.logFlags&logSQL != 0 { + conn.sess.log.Println(s.query) + } + if conn.sess.logFlags&logParams != 0 && len(args) > 0 { + for i := 0; i < len(args); i++ { + if len(args[i].Name) > 0 { + s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value) + } else { + s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value) + } + } + } + + reset := conn.resetSession + conn.resetSession = false + if len(args) == 0 { + if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send SqlBatch with %v", err) + } + conn.connectionGood = false + return fmt.Errorf("failed to send SQL Batch: %v", err) + } + } else { + proc := sp_ExecuteSql + var params []param + if isProc(s.query) { + proc.name = s.query + params, _, err = s.makeRPCParams(args, 0) + } else { + var decls []string + params, decls, err = s.makeRPCParams(args, 2) + if err != nil { + return + } + params[0] = makeStrParam(s.query) + params[1] = makeStrParam(strings.Join(decls, ",")) + } + if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send Rpc with %v", err) + } + conn.connectionGood = false + return fmt.Errorf("Failed to send RPC: %v", err) + } + } + return +} + +// isProc takes the query text in s and determines if it is a stored proc name +// or SQL text. +func isProc(s string) bool { + if len(s) == 0 { + return false + } + if s[0] == '[' && s[len(s)-1] == ']' && strings.ContainsAny(s, "\n\r") == false { + return true + } + return !strings.ContainsAny(s, " \t\n\r;") +} + +func (s *Stmt) makeRPCParams(args []namedValue, offset int) ([]param, []string, error) { + var err error + params := make([]param, len(args)+offset) + decls := make([]string, len(args)) + for i, val := range args { + params[i+offset], err = s.makeParam(val.Value) + if err != nil { + return nil, nil, err + } + var name string + if len(val.Name) > 0 { + name = "@" + val.Name + } else { + name = fmt.Sprintf("@p%d", val.Ordinal) + } + params[i+offset].Name = name + decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti)) + } + return params, decls, nil +} + +type namedValue struct { + Name string + Ordinal int + Value driver.Value +} + +func convertOldArgs(args []driver.Value) []namedValue { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return list +} + +func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) { + return s.queryContext(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + return s.processQueryResponse(ctx) +} + +func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) { + tokchan := make(chan tokenStruct, 5) + ctx, cancel := context.WithCancel(ctx) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() + // process metadata + var cols []columnStruct +loop: + for tok := range tokchan { + switch token := tok.(type) { + // By ignoring DONE token we effectively + // skip empty result-sets. + // This improves results in queries like that: + // set nocount on; select 1 + // see TestIgnoreEmptyResults test + //case doneStruct: + //break loop + case []columnStruct: + cols = token + break loop + case doneStruct: + if token.isError() { + return nil, s.c.checkBadConn(token.getError()) + } + case error: + return nil, s.c.checkBadConn(token) + } + } + res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel} + return +} + +func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) { + return s.exec(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + if res, err = s.processExec(ctx); err != nil { + return nil, s.c.checkBadConn(err) + } + return +} + +func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) { + tokchan := make(chan tokenStruct, 5) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneInProcStruct: + if token.Status&doneCount != 0 { + rowCount += int64(token.RowCount) + } + case doneStruct: + if token.Status&doneCount != 0 { + rowCount += int64(token.RowCount) + } + if token.isError() { + return nil, token.getError() + } + case error: + return nil, token + } + } + return &Result{s.c, rowCount}, nil +} + +type Rows struct { + stmt *Stmt + cols []columnStruct + tokchan chan tokenStruct + + nextCols []columnStruct + + cancel func() +} + +func (rc *Rows) Close() error { + rc.cancel() + for _ = range rc.tokchan { + } + rc.tokchan = nil + return nil +} + +func (rc *Rows) Columns() (res []string) { + res = make([]string, len(rc.cols)) + for i, col := range rc.cols { + res[i] = col.ColName + } + return +} + +func (rc *Rows) Next(dest []driver.Value) error { + if !rc.stmt.c.connectionGood { + return driver.ErrBadConn + } + if rc.nextCols != nil { + return io.EOF + } + for tok := range rc.tokchan { + switch tokdata := tok.(type) { + case []columnStruct: + rc.nextCols = tokdata + return io.EOF + case []interface{}: + for i := range dest { + dest[i] = tokdata[i] + } + return nil + case doneStruct: + if tokdata.isError() { + return rc.stmt.c.checkBadConn(tokdata.getError()) + } + case error: + return rc.stmt.c.checkBadConn(tokdata) + } + } + return io.EOF +} + +func (rc *Rows) HasNextResultSet() bool { + return rc.nextCols != nil +} + +func (rc *Rows) NextResultSet() error { + rc.cols = rc.nextCols + rc.nextCols = nil + if rc.cols == nil { + return io.EOF + } + return nil +} + +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func (r *Rows) ColumnTypeScanType(index int) reflect.Type { + return makeGoLangScanType(r.cols[index].ti) +} + +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { + return makeGoLangTypeName(r.cols[index].ti) +} + +// RowsColumnTypeLength may be implemented by Rows. It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func (r *Rows) ColumnTypeLength(index int) (int64, bool) { + return makeGoLangTypeLength(r.cols[index].ti) +} + +// It should return +// the precision and scale for decimal types. If not applicable, ok should be false. +// The following are examples of returned values for various types: +// decimal(38, 4) (38, 4, true) +// int (0, 0, false) +// decimal (math.MaxInt64, math.MaxInt64, true) +func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) { + return makeGoLangTypePrecisionScale(r.cols[index].ti) +} + +// The nullable value should +// be true if it is known the column may be null, or false if the column is known +// to be not nullable. +// If the column nullability is unknown, ok should be false. +func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) { + nullable = r.cols[index].Flags&colFlagNullable != 0 + ok = true + return +} + +func makeStrParam(val string) (res param) { + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(val) + res.ti.Size = len(res.buffer) + return +} + +func (s *Stmt) makeParam(val driver.Value) (res param, err error) { + if val == nil { + res.ti.TypeId = typeNull + res.buffer = nil + res.ti.Size = 0 + return + } + switch val := val.(type) { + case int64: + res.ti.TypeId = typeIntN + res.buffer = make([]byte, 8) + res.ti.Size = 8 + binary.LittleEndian.PutUint64(res.buffer, uint64(val)) + case float64: + res.ti.TypeId = typeFltN + res.ti.Size = 8 + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val)) + case []byte: + res.ti.TypeId = typeBigVarBin + res.ti.Size = len(val) + res.buffer = val + case string: + res = makeStrParam(val) + case bool: + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val { + res.buffer[0] = 1 + } + case time.Time: + if s.c.sess.loginAck.TDSVersion >= verTDS73 { + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.ti.Size = 10 + buf := make([]byte, 10) + res.buffer = buf + days, ns := dateTime2(val) + ns /= 100 + buf[0] = byte(ns) + buf[1] = byte(ns >> 8) + buf[2] = byte(ns >> 16) + buf[3] = byte(ns >> 24) + buf[4] = byte(ns >> 32) + buf[5] = byte(days) + buf[6] = byte(days >> 8) + buf[7] = byte(days >> 16) + _, offset := val.Zone() + offset /= 60 + buf[8] = byte(offset) + buf[9] = byte(offset >> 8) + } else { + res.ti.TypeId = typeDateTimeN + res.ti.Size = 8 + res.buffer = make([]byte, 8) + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + tm := (300 * (dur % (24 * time.Hour))) / time.Second + binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) + } + default: + return s.makeParamExtra(val) + } + return +} + +type Result struct { + c *Conn + rowsAffected int64 +} + +func (r *Result) RowsAffected() (int64, error) { + return r.rowsAffected, nil +} + +func (r *Result) LastInsertId() (int64, error) { + s, err := r.c.Prepare("select cast(@@identity as bigint)") + if err != nil { + return 0, err + } + defer s.Close() + rows, err := s.Query(nil) + if err != nil { + return 0, err + } + defer rows.Close() + dest := make([]driver.Value, 1) + err = rows.Next(dest) + if err != nil { + return 0, err + } + if dest[0] == nil { + return -1, errors.New("There is no generated identity value") + } + lastInsertId := dest[0].(int64) + return lastInsertId, nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go new file mode 100644 index 0000000..3d5ab57 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go @@ -0,0 +1,50 @@ +// +build go1.10 + +package mssql + +import ( + "context" + "database/sql/driver" +) + +var _ driver.Connector = &Connector{} +var _ driver.SessionResetter = &Conn{} + +func (c *Conn) ResetSession(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + c.resetSession = true + + if c.connector == nil || len(c.connector.SessionInitSQL) == 0 { + return nil + } + + s, err := c.prepareContext(ctx, c.connector.SessionInitSQL) + if err != nil { + return driver.ErrBadConn + } + _, err = s.exec(ctx, nil) + if err != nil { + return driver.ErrBadConn + } + + return nil +} + +// Connect to the server and return a TDS connection. +func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { + conn, err := c.driver.connect(ctx, c.params) + if conn != nil { + conn.connector = c + } + if err == nil { + err = conn.ResetSession(ctx) + } + return conn, err +} + +// Driver underlying the Connector. +func (c *Connector) Driver() driver.Driver { + return c.driver +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go new file mode 100644 index 0000000..082a65e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go18.go @@ -0,0 +1,91 @@ +// +build go1.8 + +package mssql + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "strings" +) + +var _ driver.Pinger = &Conn{} + +// Ping is used to check if the remote server is available and satisfies the Pinger interface. +func (c *Conn) Ping(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + stmt := &Stmt{c, `select 1;`, 0, nil} + _, err := stmt.ExecContext(ctx, nil) + return err +} + +var _ driver.ConnBeginTx = &Conn{} + +// BeginTx satisfies ConnBeginTx. +func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if opts.ReadOnly { + return nil, errors.New("Read-only transactions are not supported") + } + + var tdsIsolation isoLevel + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + tdsIsolation = isolationUseCurrent + case sql.LevelReadUncommitted: + tdsIsolation = isolationReadUncommited + case sql.LevelReadCommitted: + tdsIsolation = isolationReadCommited + case sql.LevelWriteCommitted: + return nil, errors.New("LevelWriteCommitted isolation level is not supported") + case sql.LevelRepeatableRead: + tdsIsolation = isolationRepeatableRead + case sql.LevelSnapshot: + tdsIsolation = isolationSnapshot + case sql.LevelSerializable: + tdsIsolation = isolationSerializable + case sql.LevelLinearizable: + return nil, errors.New("LevelLinearizable isolation level is not supported") + default: + return nil, errors.New("Isolation level is not supported or unknown") + } + return c.begin(ctx, tdsIsolation) +} + +func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(ctx, query) + } + + return c.prepareContext(ctx, query) +} + +func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.queryContext(ctx, list) +} + +func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.exec(ctx, list) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go new file mode 100644 index 0000000..ec63c5f --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -0,0 +1,222 @@ +// +build go1.9 + +package mssql + +import ( + "database/sql" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "reflect" + "time" + + // "github.com/cockroachdb/apd" + "cloud.google.com/go/civil" +) + +// Type alias provided for compibility. + +type MssqlDriver = Driver // Deprecated: users should transition to the new name when possible. +type MssqlBulk = Bulk // Deprecated: users should transition to the new name when possible. +type MssqlBulkOptions = BulkOptions // Deprecated: users should transition to the new name when possible. +type MssqlConn = Conn // Deprecated: users should transition to the new name when possible. +type MssqlResult = Result // Deprecated: users should transition to the new name when possible. +type MssqlRows = Rows // Deprecated: users should transition to the new name when possible. +type MssqlStmt = Stmt // Deprecated: users should transition to the new name when possible. + +var _ driver.NamedValueChecker = &Conn{} + +// VarChar parameter types. +type VarChar string + +// DateTime1 encodes parameters to original DateTime SQL types. +type DateTime1 time.Time + +// DateTimeOffset encodes parameters to DateTimeOffset, preserving the UTC offset. +type DateTimeOffset time.Time + +func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error { + switch v := nv.Value.(type) { + case sql.Out: + if c.outs == nil { + c.outs = make(map[string]interface{}) + } + c.outs[nv.Name] = v.Dest + + // Unwrap the Out value and check the inner value. + lnv := *nv + lnv.Value = v.Dest + err := c.CheckNamedValue(&lnv) + if err != nil { + if err != driver.ErrSkip { + return err + } + lnv.Value, err = driver.DefaultParameterConverter.ConvertValue(lnv.Value) + if err != nil { + return err + } + } + nv.Value = sql.Out{Dest: lnv.Value} + return nil + case VarChar: + return nil + case DateTime1: + return nil + case DateTimeOffset: + return nil + case civil.Date: + return nil + case civil.DateTime: + return nil + case civil.Time: + return nil + // case *apd.Decimal: + // return nil + default: + return driver.ErrSkip + } +} + +func (s *Stmt) makeParamExtra(val driver.Value) (res param, err error) { + switch val := val.(type) { + case VarChar: + res.ti.TypeId = typeBigVarChar + res.buffer = []byte(val) + res.ti.Size = len(res.buffer) + case DateTime1: + t := time.Time(val) + res.ti.TypeId = typeDateTimeN + res.ti.Size = 8 + res.buffer = make([]byte, 8) + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, t.Location()) + dur := t.Sub(ref) + days := dur / (24 * time.Hour) + tm := (300 * (dur % (24 * time.Hour))) / time.Second + binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) + case DateTimeOffset: + t := time.Time(val) + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.ti.Size = 10 + buf := make([]byte, 10) + res.buffer = buf + days, ns := dateTime2(t) + ns /= 100 + buf[0] = byte(ns) + buf[1] = byte(ns >> 8) + buf[2] = byte(ns >> 16) + buf[3] = byte(ns >> 24) + buf[4] = byte(ns >> 32) + buf[5] = byte(days) + buf[6] = byte(days >> 8) + buf[7] = byte(days >> 16) + _, offset := t.Zone() + offset /= 60 + buf[8] = byte(offset) + buf[9] = byte(offset >> 8) + case civil.Date: + res.ti.TypeId = typeDateN + res.ti.Size = 3 + res.buffer = make([]byte, 3) + buf := res.buffer + days := val.DaysSince(civil.Date{Year: 1970, Month: time.January, Day: 1}) + // number of days since Jan 1 1 UTC + days = days + 1969*365 + 1969/4 - 1969/100 + 1969/400 + buf[0] = byte(days) + buf[1] = byte(days >> 8) + buf[2] = byte(days >> 16) + case civil.DateTime: + res.ti.TypeId = typeDateTime2N + res.ti.Scale = 7 + res.ti.Size = 8 + res.buffer = make([]byte, 8) + buf := res.buffer + + dur := time.Hour*time.Duration(val.Time.Hour) + + time.Minute*time.Duration(val.Time.Minute) + + time.Second*time.Duration(val.Time.Second) + + time.Duration(val.Time.Nanosecond) + + ns := int64(dur) + ns /= 100 + buf[0] = byte(ns) + buf[1] = byte(ns >> 8) + buf[2] = byte(ns >> 16) + buf[3] = byte(ns >> 24) + buf[4] = byte(ns >> 32) + + days := val.Date.DaysSince(civil.Date{Year: 1970, Month: time.January, Day: 1}) + // number of days since Jan 1 1 UTC + days = days + 1969*365 + 1969/4 - 1969/100 + 1969/400 + buf[5] = byte(days) + buf[6] = byte(days >> 8) + buf[7] = byte(days >> 16) + case civil.Time: + res.ti.TypeId = typeTimeN + res.ti.Scale = 7 + res.ti.Size = 5 + res.buffer = make([]byte, 5) + buf := res.buffer + dur := time.Hour*time.Duration(val.Hour) + + time.Minute*time.Duration(val.Minute) + + time.Second*time.Duration(val.Second) + + time.Duration(val.Nanosecond) + + ns := int64(dur) + ns /= 100 + buf[0] = byte(ns) + buf[1] = byte(ns >> 8) + buf[2] = byte(ns >> 16) + buf[3] = byte(ns >> 24) + buf[4] = byte(ns >> 32) + case sql.Out: + res, err = s.makeParam(val.Dest) + res.Flags = fByRevValue + default: + err = fmt.Errorf("mssql: unknown type for %T", val) + } + return +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + switch fs := fromServer.(type) { + case int64: + switch si := scanInto.(type) { + case *int64: + *si = fs + return nil + } + case string: + switch si := scanInto.(type) { + case *string: + *si = fs + return nil + case *VarChar: + *si = VarChar(fs) + return nil + } + } + + dpv := reflect.ValueOf(scanInto) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errors.New("destination is a nil pointer") + } + sv := reflect.ValueOf(fromServer) + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + dv.Set(sv) + return nil + } + + if sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + return fmt.Errorf("unsupported type for parameter %[3]q from server %[1]T=%[1]v into %[2]T=%[2]v ", fromServer, scanInto, name) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go new file mode 100644 index 0000000..9680f51 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go @@ -0,0 +1,16 @@ +// +build !go1.9 + +package mssql + +import ( + "database/sql/driver" + "fmt" +) + +func (s *Stmt) makeParamExtra(val driver.Value) (param, error) { + return param{}, fmt.Errorf("mssql: unknown type for %T", val) +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + return fmt.Errorf("mssql: unsupported OUTPUT type, use a newer Go version") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/net.go b/vendor/github.com/denisenkom/go-mssqldb/net.go new file mode 100644 index 0000000..e3864d1 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/net.go @@ -0,0 +1,103 @@ +package mssql + +import ( + "fmt" + "net" + "time" +) + +type timeoutConn struct { + c net.Conn + timeout time.Duration + buf *tdsBuffer + packetPending bool + continueRead bool +} + +func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { + return &timeoutConn{ + c: conn, + timeout: timeout, + } +} + +func (c *timeoutConn) Read(b []byte) (n int, err error) { + if c.buf != nil { + if c.packetPending { + c.packetPending = false + err = c.buf.FinishPacket() + if err != nil { + err = fmt.Errorf("Cannot send handshake packet: %s", err.Error()) + return + } + c.continueRead = false + } + if !c.continueRead { + var packet packetType + packet, err = c.buf.BeginRead() + if err != nil { + err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) + return + } + if packet != packPrelogin { + err = fmt.Errorf("unexpected packet %d, expecting prelogin", packet) + return + } + c.continueRead = true + } + n, err = c.buf.Read(b) + return + } + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } + } + return c.c.Read(b) +} + +func (c *timeoutConn) Write(b []byte) (n int, err error) { + if c.buf != nil { + if !c.packetPending { + c.buf.BeginPacket(packPrelogin, false) + c.packetPending = true + } + n, err = c.buf.Write(b) + if err != nil { + return + } + return + } + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } + } + return c.c.Write(b) +} + +func (c timeoutConn) Close() error { + return c.c.Close() +} + +func (c timeoutConn) LocalAddr() net.Addr { + return c.c.LocalAddr() +} + +func (c timeoutConn) RemoteAddr() net.Addr { + return c.c.RemoteAddr() +} + +func (c timeoutConn) SetDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c timeoutConn) SetReadDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c timeoutConn) SetWriteDeadline(t time.Time) error { + panic("Not implemented") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go new file mode 100644 index 0000000..7c0cc4f --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go @@ -0,0 +1,283 @@ +// +build !windows + +package mssql + +import ( + "crypto/des" + "crypto/md5" + "crypto/rand" + "encoding/binary" + "errors" + "strings" + "unicode/utf16" + + "golang.org/x/crypto/md4" +) + +const ( + _NEGOTIATE_MESSAGE = 1 + _CHALLENGE_MESSAGE = 2 + _AUTHENTICATE_MESSAGE = 3 +) + +const ( + _NEGOTIATE_UNICODE = 0x00000001 + _NEGOTIATE_OEM = 0x00000002 + _NEGOTIATE_TARGET = 0x00000004 + _NEGOTIATE_SIGN = 0x00000010 + _NEGOTIATE_SEAL = 0x00000020 + _NEGOTIATE_DATAGRAM = 0x00000040 + _NEGOTIATE_LMKEY = 0x00000080 + _NEGOTIATE_NTLM = 0x00000200 + _NEGOTIATE_ANONYMOUS = 0x00000800 + _NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000 + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000 + _NEGOTIATE_ALWAYS_SIGN = 0x00008000 + _NEGOTIATE_TARGET_TYPE_DOMAIN = 0x00010000 + _NEGOTIATE_TARGET_TYPE_SERVER = 0x00020000 + _NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000 + _NEGOTIATE_IDENTIFY = 0x00100000 + _REQUEST_NON_NT_SESSION_KEY = 0x00400000 + _NEGOTIATE_TARGET_INFO = 0x00800000 + _NEGOTIATE_VERSION = 0x02000000 + _NEGOTIATE_128 = 0x20000000 + _NEGOTIATE_KEY_EXCH = 0x40000000 + _NEGOTIATE_56 = 0x80000000 +) + +const _NEGOTIATE_FLAGS = _NEGOTIATE_UNICODE | + _NEGOTIATE_NTLM | + _NEGOTIATE_OEM_DOMAIN_SUPPLIED | + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED | + _NEGOTIATE_ALWAYS_SIGN | + _NEGOTIATE_EXTENDED_SESSIONSECURITY + +type ntlmAuth struct { + Domain string + UserName string + Password string + Workstation string +} + +func getAuth(user, password, service, workstation string) (auth, bool) { + if !strings.ContainsRune(user, '\\') { + return nil, false + } + domain_user := strings.SplitN(user, "\\", 2) + return &ntlmAuth{ + Domain: domain_user[0], + UserName: domain_user[1], + Password: password, + Workstation: workstation, + }, true +} + +func utf16le(val string) []byte { + var v []byte + for _, r := range val { + if utf16.IsSurrogate(r) { + r1, r2 := utf16.EncodeRune(r) + v = append(v, byte(r1), byte(r1>>8)) + v = append(v, byte(r2), byte(r2>>8)) + } else { + v = append(v, byte(r), byte(r>>8)) + } + } + return v +} + +func (auth *ntlmAuth) InitialBytes() ([]byte, error) { + domain_len := len(auth.Domain) + workstation_len := len(auth.Workstation) + msg := make([]byte, 40+domain_len+workstation_len) + copy(msg, []byte("NTLMSSP\x00")) + binary.LittleEndian.PutUint32(msg[8:], _NEGOTIATE_MESSAGE) + binary.LittleEndian.PutUint32(msg[12:], _NEGOTIATE_FLAGS) + // Domain Name Fields + binary.LittleEndian.PutUint16(msg[16:], uint16(domain_len)) + binary.LittleEndian.PutUint16(msg[18:], uint16(domain_len)) + binary.LittleEndian.PutUint32(msg[20:], 40) + // Workstation Fields + binary.LittleEndian.PutUint16(msg[24:], uint16(workstation_len)) + binary.LittleEndian.PutUint16(msg[26:], uint16(workstation_len)) + binary.LittleEndian.PutUint32(msg[28:], uint32(40+domain_len)) + // Version + binary.LittleEndian.PutUint32(msg[32:], 0) + binary.LittleEndian.PutUint32(msg[36:], 0) + // Payload + copy(msg[40:], auth.Domain) + copy(msg[40+domain_len:], auth.Workstation) + return msg, nil +} + +var errorNTLM = errors.New("NTLM protocol error") + +func createDesKey(bytes, material []byte) { + material[0] = bytes[0] + material[1] = (byte)(bytes[0]<<7 | (bytes[1]&0xff)>>1) + material[2] = (byte)(bytes[1]<<6 | (bytes[2]&0xff)>>2) + material[3] = (byte)(bytes[2]<<5 | (bytes[3]&0xff)>>3) + material[4] = (byte)(bytes[3]<<4 | (bytes[4]&0xff)>>4) + material[5] = (byte)(bytes[4]<<3 | (bytes[5]&0xff)>>5) + material[6] = (byte)(bytes[5]<<2 | (bytes[6]&0xff)>>6) + material[7] = (byte)(bytes[6] << 1) +} + +func oddParity(bytes []byte) { + for i := 0; i < len(bytes); i++ { + b := bytes[i] + needsParity := (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1)) & 0x01) == 0 + if needsParity { + bytes[i] = bytes[i] | byte(0x01) + } else { + bytes[i] = bytes[i] & byte(0xfe) + } + } +} + +func encryptDes(key []byte, cleartext []byte, ciphertext []byte) { + var desKey [8]byte + createDesKey(key, desKey[:]) + cipher, err := des.NewCipher(desKey[:]) + if err != nil { + panic(err) + } + cipher.Encrypt(ciphertext, cleartext) +} + +func response(challenge [8]byte, hash [21]byte) (ret [24]byte) { + encryptDes(hash[:7], challenge[:], ret[:8]) + encryptDes(hash[7:14], challenge[:], ret[8:16]) + encryptDes(hash[14:], challenge[:], ret[16:]) + return +} + +func lmHash(password string) (hash [21]byte) { + var lmpass [14]byte + copy(lmpass[:14], []byte(strings.ToUpper(password))) + magic := []byte("KGS!@#$%") + encryptDes(lmpass[:7], magic, hash[:8]) + encryptDes(lmpass[7:], magic, hash[8:]) + return +} + +func lmResponse(challenge [8]byte, password string) [24]byte { + hash := lmHash(password) + return response(challenge, hash) +} + +func ntlmHash(password string) (hash [21]byte) { + h := md4.New() + h.Write(utf16le(password)) + h.Sum(hash[:0]) + return +} + +func ntResponse(challenge [8]byte, password string) [24]byte { + hash := ntlmHash(password) + return response(challenge, hash) +} + +func clientChallenge() (nonce [8]byte) { + _, err := rand.Read(nonce[:]) + if err != nil { + panic(err) + } + return +} + +func ntlmSessionResponse(clientNonce [8]byte, serverChallenge [8]byte, password string) [24]byte { + var sessionHash [16]byte + h := md5.New() + h.Write(serverChallenge[:]) + h.Write(clientNonce[:]) + h.Sum(sessionHash[:0]) + var hash [8]byte + copy(hash[:], sessionHash[:8]) + passwordHash := ntlmHash(password) + return response(hash, passwordHash) +} + +func (auth *ntlmAuth) NextBytes(bytes []byte) ([]byte, error) { + if string(bytes[0:8]) != "NTLMSSP\x00" { + return nil, errorNTLM + } + if binary.LittleEndian.Uint32(bytes[8:12]) != _CHALLENGE_MESSAGE { + return nil, errorNTLM + } + flags := binary.LittleEndian.Uint32(bytes[20:24]) + var challenge [8]byte + copy(challenge[:], bytes[24:32]) + + var lm, nt []byte + if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 { + nonce := clientChallenge() + var lm_bytes [24]byte + copy(lm_bytes[:8], nonce[:]) + lm = lm_bytes[:] + nt_bytes := ntlmSessionResponse(nonce, challenge, auth.Password) + nt = nt_bytes[:] + } else { + lm_bytes := lmResponse(challenge, auth.Password) + lm = lm_bytes[:] + nt_bytes := ntResponse(challenge, auth.Password) + nt = nt_bytes[:] + } + lm_len := len(lm) + nt_len := len(nt) + + domain16 := utf16le(auth.Domain) + domain_len := len(domain16) + user16 := utf16le(auth.UserName) + user_len := len(user16) + workstation16 := utf16le(auth.Workstation) + workstation_len := len(workstation16) + + msg := make([]byte, 88+lm_len+nt_len+domain_len+user_len+workstation_len) + copy(msg, []byte("NTLMSSP\x00")) + binary.LittleEndian.PutUint32(msg[8:], _AUTHENTICATE_MESSAGE) + // Lm Challenge Response Fields + binary.LittleEndian.PutUint16(msg[12:], uint16(lm_len)) + binary.LittleEndian.PutUint16(msg[14:], uint16(lm_len)) + binary.LittleEndian.PutUint32(msg[16:], 88) + // Nt Challenge Response Fields + binary.LittleEndian.PutUint16(msg[20:], uint16(nt_len)) + binary.LittleEndian.PutUint16(msg[22:], uint16(nt_len)) + binary.LittleEndian.PutUint32(msg[24:], uint32(88+lm_len)) + // Domain Name Fields + binary.LittleEndian.PutUint16(msg[28:], uint16(domain_len)) + binary.LittleEndian.PutUint16(msg[30:], uint16(domain_len)) + binary.LittleEndian.PutUint32(msg[32:], uint32(88+lm_len+nt_len)) + // User Name Fields + binary.LittleEndian.PutUint16(msg[36:], uint16(user_len)) + binary.LittleEndian.PutUint16(msg[38:], uint16(user_len)) + binary.LittleEndian.PutUint32(msg[40:], uint32(88+lm_len+nt_len+domain_len)) + // Workstation Fields + binary.LittleEndian.PutUint16(msg[44:], uint16(workstation_len)) + binary.LittleEndian.PutUint16(msg[46:], uint16(workstation_len)) + binary.LittleEndian.PutUint32(msg[48:], uint32(88+lm_len+nt_len+domain_len+user_len)) + // Encrypted Random Session Key Fields + binary.LittleEndian.PutUint16(msg[52:], 0) + binary.LittleEndian.PutUint16(msg[54:], 0) + binary.LittleEndian.PutUint32(msg[56:], uint32(88+lm_len+nt_len+domain_len+user_len+workstation_len)) + // Negotiate Flags + binary.LittleEndian.PutUint32(msg[60:], flags) + // Version + binary.LittleEndian.PutUint32(msg[64:], 0) + binary.LittleEndian.PutUint32(msg[68:], 0) + // MIC + binary.LittleEndian.PutUint32(msg[72:], 0) + binary.LittleEndian.PutUint32(msg[76:], 0) + binary.LittleEndian.PutUint32(msg[88:], 0) + binary.LittleEndian.PutUint32(msg[84:], 0) + // Payload + copy(msg[88:], lm) + copy(msg[88+lm_len:], nt) + copy(msg[88+lm_len+nt_len:], domain16) + copy(msg[88+lm_len+nt_len+domain_len:], user16) + copy(msg[88+lm_len+nt_len+domain_len+user_len:], workstation16) + return msg, nil +} + +func (auth *ntlmAuth) Free() { +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/parser.go b/vendor/github.com/denisenkom/go-mssqldb/parser.go new file mode 100644 index 0000000..8021ca6 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/parser.go @@ -0,0 +1,257 @@ +package mssql + +import ( + "bytes" + "io" + "strconv" +) + +type parser struct { + r *bytes.Reader + w bytes.Buffer + paramCount int + paramMax int + + // using map as a set + namedParams map[string]bool +} + +func (p *parser) next() (rune, bool) { + ch, _, err := p.r.ReadRune() + if err != nil { + if err != io.EOF { + panic(err) + } + return 0, false + } + return ch, true +} + +func (p *parser) unread() { + err := p.r.UnreadRune() + if err != nil { + panic(err) + } +} + +func (p *parser) write(ch rune) { + p.w.WriteRune(ch) +} + +type stateFunc func(*parser) stateFunc + +func parseParams(query string) (string, int) { + p := &parser{ + r: bytes.NewReader([]byte(query)), + namedParams: map[string]bool{}, + } + state := parseNormal + for state != nil { + state = state(p) + } + return p.w.String(), p.paramMax + len(p.namedParams) +} + +func parseNormal(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + if ch == '?' { + return parseOrdinalParameter + } else if ch == '$' || ch == ':' { + ch2, ok := p.next() + if !ok { + p.write(ch) + return nil + } + p.unread() + if ch2 >= '0' && ch2 <= '9' { + return parseOrdinalParameter + } else if 'a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z' { + return parseNamedParameter + } + } + p.write(ch) + switch ch { + case '\'': + return parseQuote + case '"': + return parseDoubleQuote + case '[': + return parseBracket + case '-': + return parseLineComment + case '/': + return parseComment + } + } +} + +func parseOrdinalParameter(p *parser) stateFunc { + var paramN int + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && ch >= '0' && ch <= '9' { + paramN = paramN*10 + int(ch-'0') + } else { + break + } + } + if ok { + p.unread() + } + if paramN == 0 { + p.paramCount++ + paramN = p.paramCount + } + if paramN > p.paramMax { + p.paramMax = paramN + } + p.w.WriteString("@p") + p.w.WriteString(strconv.Itoa(paramN)) + if !ok { + return nil + } + return parseNormal +} + +func parseNamedParameter(p *parser) stateFunc { + var paramName string + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && (ch >= '0' && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') { + paramName = paramName + string(ch) + } else { + break + } + } + if ok { + p.unread() + } + p.namedParams[paramName] = true + p.w.WriteString("@") + p.w.WriteString(paramName) + if !ok { + return nil + } + return parseNormal +} + +func parseQuote(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '\'' { + return parseNormal + } + } +} + +func parseDoubleQuote(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '"' { + return parseNormal + } + } +} + +func parseBracket(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == ']' { + ch, ok = p.next() + if !ok { + return nil + } + if ch != ']' { + p.unread() + return parseNormal + } + p.write(ch) + } + } +} + +func parseLineComment(p *parser) stateFunc { + ch, ok := p.next() + if !ok { + return nil + } + if ch != '-' { + p.unread() + return parseNormal + } + p.write(ch) + for { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '\n' { + return parseNormal + } + } +} + +func parseComment(p *parser) stateFunc { + var nested int + ch, ok := p.next() + if !ok { + return nil + } + if ch != '*' { + p.unread() + return parseNormal + } + p.write(ch) + for { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + for ch == '*' { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '/' { + if nested == 0 { + return parseNormal + } else { + nested-- + } + } + } + for ch == '/' { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '*' { + nested++ + } + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/rpc.go b/vendor/github.com/denisenkom/go-mssqldb/rpc.go new file mode 100644 index 0000000..849fe3e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/rpc.go @@ -0,0 +1,100 @@ +package mssql + +import ( + "encoding/binary" +) + +type procId struct { + id uint16 + name string +} + +// parameter flags +const ( + fByRevValue = 1 + fDefaultValue = 2 +) + +type param struct { + Name string + Flags uint8 + ti typeInfo + buffer []byte +} + +func makeProcId(name string) (res procId) { + res.name = name + if len(name) == 0 { + panic("Proc name shouln't be empty") + } + if len(name) >= 0xffff { + panic("Invalid length of procedure name, should be less than 0xffff") + } + return res +} + +const ( + fWithRecomp = 1 + fNoMetaData = 2 + fReuseMetaData = 4 +) + +var ( + sp_Cursor = procId{1, ""} + sp_CursorOpen = procId{2, ""} + sp_CursorPrepare = procId{3, ""} + sp_CursorExecute = procId{4, ""} + sp_CursorPrepExec = procId{5, ""} + sp_CursorUnprepare = procId{6, ""} + sp_CursorFetch = procId{7, ""} + sp_CursorOption = procId{8, ""} + sp_CursorClose = procId{9, ""} + sp_ExecuteSql = procId{10, ""} + sp_Prepare = procId{11, ""} + sp_PrepExec = procId{13, ""} + sp_PrepExecRpc = procId{14, ""} + sp_Unprepare = procId{15, ""} +) + +// http://msdn.microsoft.com/en-us/library/dd357576.aspx +func sendRpc(buf *tdsBuffer, headers []headerStruct, proc procId, flags uint16, params []param, resetSession bool) (err error) { + buf.BeginPacket(packRPCRequest, resetSession) + writeAllHeaders(buf, headers) + if len(proc.name) == 0 { + var idswitch uint16 = 0xffff + err = binary.Write(buf, binary.LittleEndian, &idswitch) + if err != nil { + return + } + err = binary.Write(buf, binary.LittleEndian, &proc.id) + if err != nil { + return + } + } else { + err = writeUsVarChar(buf, proc.name) + if err != nil { + return + } + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return + } + for _, param := range params { + if err = writeBVarChar(buf, param.Name); err != nil { + return + } + if err = binary.Write(buf, binary.LittleEndian, param.Flags); err != nil { + return + } + err = writeTypeInfo(buf, ¶m.ti) + if err != nil { + return + } + err = param.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return + } + } + return buf.FinishPacket() +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go new file mode 100644 index 0000000..9b5bc68 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go @@ -0,0 +1,266 @@ +package mssql + +import ( + "fmt" + "strings" + "syscall" + "unsafe" +) + +var ( + secur32_dll = syscall.NewLazyDLL("secur32.dll") + initSecurityInterface = secur32_dll.NewProc("InitSecurityInterfaceW") + sec_fn *SecurityFunctionTable +) + +func init() { + ptr, _, _ := initSecurityInterface.Call() + sec_fn = (*SecurityFunctionTable)(unsafe.Pointer(ptr)) +} + +const ( + SEC_E_OK = 0 + SECPKG_CRED_OUTBOUND = 2 + SEC_WINNT_AUTH_IDENTITY_UNICODE = 2 + ISC_REQ_DELEGATE = 0x00000001 + ISC_REQ_REPLAY_DETECT = 0x00000004 + ISC_REQ_SEQUENCE_DETECT = 0x00000008 + ISC_REQ_CONFIDENTIALITY = 0x00000010 + ISC_REQ_CONNECTION = 0x00000800 + SECURITY_NETWORK_DREP = 0 + SEC_I_CONTINUE_NEEDED = 0x00090312 + SEC_I_COMPLETE_NEEDED = 0x00090313 + SEC_I_COMPLETE_AND_CONTINUE = 0x00090314 + SECBUFFER_VERSION = 0 + SECBUFFER_TOKEN = 2 + NTLMBUF_LEN = 12000 +) + +const ISC_REQ = ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_CONNECTION | + ISC_REQ_DELEGATE + +type SecurityFunctionTable struct { + dwVersion uint32 + EnumerateSecurityPackages uintptr + QueryCredentialsAttributes uintptr + AcquireCredentialsHandle uintptr + FreeCredentialsHandle uintptr + Reserved2 uintptr + InitializeSecurityContext uintptr + AcceptSecurityContext uintptr + CompleteAuthToken uintptr + DeleteSecurityContext uintptr + ApplyControlToken uintptr + QueryContextAttributes uintptr + ImpersonateSecurityContext uintptr + RevertSecurityContext uintptr + MakeSignature uintptr + VerifySignature uintptr + FreeContextBuffer uintptr + QuerySecurityPackageInfo uintptr + Reserved3 uintptr + Reserved4 uintptr + Reserved5 uintptr + Reserved6 uintptr + Reserved7 uintptr + Reserved8 uintptr + QuerySecurityContextToken uintptr + EncryptMessage uintptr + DecryptMessage uintptr +} + +type SEC_WINNT_AUTH_IDENTITY struct { + User *uint16 + UserLength uint32 + Domain *uint16 + DomainLength uint32 + Password *uint16 + PasswordLength uint32 + Flags uint32 +} + +type TimeStamp struct { + LowPart uint32 + HighPart int32 +} + +type SecHandle struct { + dwLower uintptr + dwUpper uintptr +} + +type SecBuffer struct { + cbBuffer uint32 + BufferType uint32 + pvBuffer *byte +} + +type SecBufferDesc struct { + ulVersion uint32 + cBuffers uint32 + pBuffers *SecBuffer +} + +type SSPIAuth struct { + Domain string + UserName string + Password string + Service string + cred SecHandle + ctxt SecHandle +} + +func getAuth(user, password, service, workstation string) (auth, bool) { + if user == "" { + return &SSPIAuth{Service: service}, true + } + if !strings.ContainsRune(user, '\\') { + return nil, false + } + domain_user := strings.SplitN(user, "\\", 2) + return &SSPIAuth{ + Domain: domain_user[0], + UserName: domain_user[1], + Password: password, + Service: service, + }, true +} + +func (auth *SSPIAuth) InitialBytes() ([]byte, error) { + var identity *SEC_WINNT_AUTH_IDENTITY + if auth.UserName != "" { + identity = &SEC_WINNT_AUTH_IDENTITY{ + Flags: SEC_WINNT_AUTH_IDENTITY_UNICODE, + Password: syscall.StringToUTF16Ptr(auth.Password), + PasswordLength: uint32(len(auth.Password)), + Domain: syscall.StringToUTF16Ptr(auth.Domain), + DomainLength: uint32(len(auth.Domain)), + User: syscall.StringToUTF16Ptr(auth.UserName), + UserLength: uint32(len(auth.UserName)), + } + } + var ts TimeStamp + sec_ok, _, _ := syscall.Syscall9(sec_fn.AcquireCredentialsHandle, + 9, + 0, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Negotiate"))), + SECPKG_CRED_OUTBOUND, + 0, + uintptr(unsafe.Pointer(identity)), + 0, + 0, + uintptr(unsafe.Pointer(&auth.cred)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok != SEC_E_OK { + return nil, fmt.Errorf("AcquireCredentialsHandle failed %x", sec_ok) + } + + var buf SecBuffer + var desc SecBufferDesc + desc.ulVersion = SECBUFFER_VERSION + desc.cBuffers = 1 + desc.pBuffers = &buf + + outbuf := make([]byte, NTLMBUF_LEN) + buf.cbBuffer = NTLMBUF_LEN + buf.BufferType = SECBUFFER_TOKEN + buf.pvBuffer = &outbuf[0] + + var attrs uint32 + sec_ok, _, _ = syscall.Syscall12(sec_fn.InitializeSecurityContext, + 12, + uintptr(unsafe.Pointer(&auth.cred)), + 0, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))), + ISC_REQ, + 0, + SECURITY_NETWORK_DREP, + 0, + 0, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&desc)), + uintptr(unsafe.Pointer(&attrs)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok == SEC_I_COMPLETE_AND_CONTINUE || + sec_ok == SEC_I_COMPLETE_NEEDED { + syscall.Syscall6(sec_fn.CompleteAuthToken, + 2, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&desc)), + 0, 0, 0, 0) + } else if sec_ok != SEC_E_OK && + sec_ok != SEC_I_CONTINUE_NEEDED { + syscall.Syscall6(sec_fn.FreeCredentialsHandle, + 1, + uintptr(unsafe.Pointer(&auth.cred)), + 0, 0, 0, 0, 0) + return nil, fmt.Errorf("InitialBytes InitializeSecurityContext failed %x", sec_ok) + } + return outbuf[:buf.cbBuffer], nil +} + +func (auth *SSPIAuth) NextBytes(bytes []byte) ([]byte, error) { + var in_buf, out_buf SecBuffer + var in_desc, out_desc SecBufferDesc + + in_desc.ulVersion = SECBUFFER_VERSION + in_desc.cBuffers = 1 + in_desc.pBuffers = &in_buf + + out_desc.ulVersion = SECBUFFER_VERSION + out_desc.cBuffers = 1 + out_desc.pBuffers = &out_buf + + in_buf.BufferType = SECBUFFER_TOKEN + in_buf.pvBuffer = &bytes[0] + in_buf.cbBuffer = uint32(len(bytes)) + + outbuf := make([]byte, NTLMBUF_LEN) + out_buf.BufferType = SECBUFFER_TOKEN + out_buf.pvBuffer = &outbuf[0] + out_buf.cbBuffer = NTLMBUF_LEN + + var attrs uint32 + var ts TimeStamp + sec_ok, _, _ := syscall.Syscall12(sec_fn.InitializeSecurityContext, + 12, + uintptr(unsafe.Pointer(&auth.cred)), + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))), + ISC_REQ, + 0, + SECURITY_NETWORK_DREP, + uintptr(unsafe.Pointer(&in_desc)), + 0, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&out_desc)), + uintptr(unsafe.Pointer(&attrs)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok == SEC_I_COMPLETE_AND_CONTINUE || + sec_ok == SEC_I_COMPLETE_NEEDED { + syscall.Syscall6(sec_fn.CompleteAuthToken, + 2, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&out_desc)), + 0, 0, 0, 0) + } else if sec_ok != SEC_E_OK && + sec_ok != SEC_I_CONTINUE_NEEDED { + return nil, fmt.Errorf("NextBytes InitializeSecurityContext failed %x", sec_ok) + } + + return outbuf[:out_buf.cbBuffer], nil +} + +func (auth *SSPIAuth) Free() { + syscall.Syscall6(sec_fn.DeleteSecurityContext, + 1, + uintptr(unsafe.Pointer(&auth.ctxt)), + 0, 0, 0, 0, 0) + syscall.Syscall6(sec_fn.FreeCredentialsHandle, + 1, + uintptr(unsafe.Pointer(&auth.cred)), + 0, 0, 0, 0, 0) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go new file mode 100644 index 0000000..a45711d --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go @@ -0,0 +1,1367 @@ +package mssql + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "net/url" + "os" + "sort" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +func parseInstances(msg []byte) map[string]map[string]string { + results := map[string]map[string]string{} + if len(msg) > 3 && msg[0] == 5 { + out_s := string(msg[3:]) + tokens := strings.Split(out_s, ";") + instdict := map[string]string{} + got_name := false + var name string + for _, token := range tokens { + if got_name { + instdict[name] = token + got_name = false + } else { + name = token + if len(name) == 0 { + if len(instdict) == 0 { + break + } + results[strings.ToUpper(instdict["InstanceName"])] = instdict + instdict = map[string]string{} + continue + } + got_name = true + } + } + } + return results +} + +func getInstances(ctx context.Context, address string) (map[string]map[string]string, error) { + maxTime := 5 * time.Second + dialer := &net.Dialer{ + Timeout: maxTime, + } + conn, err := dialer.DialContext(ctx, "udp", address+":1434") + if err != nil { + return nil, err + } + defer conn.Close() + conn.SetDeadline(time.Now().Add(maxTime)) + _, err = conn.Write([]byte{3}) + if err != nil { + return nil, err + } + var resp = make([]byte, 16*1024-1) + read, err := conn.Read(resp) + if err != nil { + return nil, err + } + return parseInstances(resp[:read]), nil +} + +// tds versions +const ( + verTDS70 = 0x70000000 + verTDS71 = 0x71000000 + verTDS71rev1 = 0x71000001 + verTDS72 = 0x72090002 + verTDS73A = 0x730A0003 + verTDS73 = verTDS73A + verTDS73B = 0x730B0003 + verTDS74 = 0x74000004 +) + +// packet types +// https://msdn.microsoft.com/en-us/library/dd304214.aspx +const ( + packSQLBatch packetType = 1 + packRPCRequest = 3 + packReply = 4 + + // 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx + // 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx + packAttention = 6 + + packBulkLoadBCP = 7 + packTransMgrReq = 14 + packNormal = 15 + packLogin7 = 16 + packSSPIMessage = 17 + packPrelogin = 18 +) + +// prelogin fields +// http://msdn.microsoft.com/en-us/library/dd357559.aspx +const ( + preloginVERSION = 0 + preloginENCRYPTION = 1 + preloginINSTOPT = 2 + preloginTHREADID = 3 + preloginMARS = 4 + preloginTRACEID = 5 + preloginTERMINATOR = 0xff +) + +const ( + encryptOff = 0 // Encryption is available but off. + encryptOn = 1 // Encryption is available and on. + encryptNotSup = 2 // Encryption is not available. + encryptReq = 3 // Encryption is required. +) + +type tdsSession struct { + buf *tdsBuffer + loginAck loginAckStruct + database string + partner string + columns []columnStruct + tranid uint64 + logFlags uint64 + log optionalLogger + routedServer string + routedPort uint16 +} + +const ( + logErrors = 1 + logMessages = 2 + logRows = 4 + logSQL = 8 + logParams = 16 + logTransaction = 32 + logDebug = 64 +) + +type columnStruct struct { + UserType uint32 + Flags uint16 + ColName string + ti typeInfo +} + +type keySlice []uint8 + +func (p keySlice) Len() int { return len(p) } +func (p keySlice) Less(i, j int) bool { return p[i] < p[j] } +func (p keySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// http://msdn.microsoft.com/en-us/library/dd357559.aspx +func writePrelogin(w *tdsBuffer, fields map[uint8][]byte) error { + var err error + + w.BeginPacket(packPrelogin, false) + offset := uint16(5*len(fields) + 1) + keys := make(keySlice, 0, len(fields)) + for k, _ := range fields { + keys = append(keys, k) + } + sort.Sort(keys) + // writing header + for _, k := range keys { + err = w.WriteByte(k) + if err != nil { + return err + } + err = binary.Write(w, binary.BigEndian, offset) + if err != nil { + return err + } + v := fields[k] + size := uint16(len(v)) + err = binary.Write(w, binary.BigEndian, size) + if err != nil { + return err + } + offset += size + } + err = w.WriteByte(preloginTERMINATOR) + if err != nil { + return err + } + // writing values + for _, k := range keys { + v := fields[k] + written, err := w.Write(v) + if err != nil { + return err + } + if written != len(v) { + return errors.New("Write method didn't write the whole value") + } + } + return w.FinishPacket() +} + +func readPrelogin(r *tdsBuffer) (map[uint8][]byte, error) { + packet_type, err := r.BeginRead() + if err != nil { + return nil, err + } + struct_buf, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + if packet_type != 4 { + return nil, errors.New("Invalid respones, expected packet type 4, PRELOGIN RESPONSE") + } + offset := 0 + results := map[uint8][]byte{} + for true { + rec_type := struct_buf[offset] + if rec_type == preloginTERMINATOR { + break + } + + rec_offset := binary.BigEndian.Uint16(struct_buf[offset+1:]) + rec_len := binary.BigEndian.Uint16(struct_buf[offset+3:]) + value := struct_buf[rec_offset : rec_offset+rec_len] + results[rec_type] = value + offset += 5 + } + return results, nil +} + +// OptionFlags2 +// http://msdn.microsoft.com/en-us/library/dd304019.aspx +const ( + fLanguageFatal = 1 + fODBC = 2 + fTransBoundary = 4 + fCacheConnect = 8 + fIntSecurity = 0x80 +) + +// TypeFlags +const ( + // 4 bits for fSQLType + // 1 bit for fOLEDB + fReadOnlyIntent = 32 +) + +type login struct { + TDSVersion uint32 + PacketSize uint32 + ClientProgVer uint32 + ClientPID uint32 + ConnectionID uint32 + OptionFlags1 uint8 + OptionFlags2 uint8 + TypeFlags uint8 + OptionFlags3 uint8 + ClientTimeZone int32 + ClientLCID uint32 + HostName string + UserName string + Password string + AppName string + ServerName string + CtlIntName string + Language string + Database string + ClientID [6]byte + SSPI []byte + AtchDBFile string + ChangePassword string +} + +type loginHeader struct { + Length uint32 + TDSVersion uint32 + PacketSize uint32 + ClientProgVer uint32 + ClientPID uint32 + ConnectionID uint32 + OptionFlags1 uint8 + OptionFlags2 uint8 + TypeFlags uint8 + OptionFlags3 uint8 + ClientTimeZone int32 + ClientLCID uint32 + HostNameOffset uint16 + HostNameLength uint16 + UserNameOffset uint16 + UserNameLength uint16 + PasswordOffset uint16 + PasswordLength uint16 + AppNameOffset uint16 + AppNameLength uint16 + ServerNameOffset uint16 + ServerNameLength uint16 + ExtensionOffset uint16 + ExtensionLenght uint16 + CtlIntNameOffset uint16 + CtlIntNameLength uint16 + LanguageOffset uint16 + LanguageLength uint16 + DatabaseOffset uint16 + DatabaseLength uint16 + ClientID [6]byte + SSPIOffset uint16 + SSPILength uint16 + AtchDBFileOffset uint16 + AtchDBFileLength uint16 + ChangePasswordOffset uint16 + ChangePasswordLength uint16 + SSPILongLength uint32 +} + +// convert Go string to UTF-16 encoded []byte (littleEndian) +// done manually rather than using bytes and binary packages +// for performance reasons +func str2ucs2(s string) []byte { + res := utf16.Encode([]rune(s)) + ucs2 := make([]byte, 2*len(res)) + for i := 0; i < len(res); i++ { + ucs2[2*i] = byte(res[i]) + ucs2[2*i+1] = byte(res[i] >> 8) + } + return ucs2 +} + +func ucs22str(s []byte) (string, error) { + if len(s)%2 != 0 { + return "", fmt.Errorf("Illegal UCS2 string length: %d", len(s)) + } + buf := make([]uint16, len(s)/2) + for i := 0; i < len(s); i += 2 { + buf[i/2] = binary.LittleEndian.Uint16(s[i:]) + } + return string(utf16.Decode(buf)), nil +} + +func manglePassword(password string) []byte { + var ucs2password []byte = str2ucs2(password) + for i, ch := range ucs2password { + ucs2password[i] = ((ch<<4)&0xff | (ch >> 4)) ^ 0xA5 + } + return ucs2password +} + +// http://msdn.microsoft.com/en-us/library/dd304019.aspx +func sendLogin(w *tdsBuffer, login login) error { + w.BeginPacket(packLogin7, false) + hostname := str2ucs2(login.HostName) + username := str2ucs2(login.UserName) + password := manglePassword(login.Password) + appname := str2ucs2(login.AppName) + servername := str2ucs2(login.ServerName) + ctlintname := str2ucs2(login.CtlIntName) + language := str2ucs2(login.Language) + database := str2ucs2(login.Database) + atchdbfile := str2ucs2(login.AtchDBFile) + changepassword := str2ucs2(login.ChangePassword) + hdr := loginHeader{ + TDSVersion: login.TDSVersion, + PacketSize: login.PacketSize, + ClientProgVer: login.ClientProgVer, + ClientPID: login.ClientPID, + ConnectionID: login.ConnectionID, + OptionFlags1: login.OptionFlags1, + OptionFlags2: login.OptionFlags2, + TypeFlags: login.TypeFlags, + OptionFlags3: login.OptionFlags3, + ClientTimeZone: login.ClientTimeZone, + ClientLCID: login.ClientLCID, + HostNameLength: uint16(utf8.RuneCountInString(login.HostName)), + UserNameLength: uint16(utf8.RuneCountInString(login.UserName)), + PasswordLength: uint16(utf8.RuneCountInString(login.Password)), + AppNameLength: uint16(utf8.RuneCountInString(login.AppName)), + ServerNameLength: uint16(utf8.RuneCountInString(login.ServerName)), + CtlIntNameLength: uint16(utf8.RuneCountInString(login.CtlIntName)), + LanguageLength: uint16(utf8.RuneCountInString(login.Language)), + DatabaseLength: uint16(utf8.RuneCountInString(login.Database)), + ClientID: login.ClientID, + SSPILength: uint16(len(login.SSPI)), + AtchDBFileLength: uint16(utf8.RuneCountInString(login.AtchDBFile)), + ChangePasswordLength: uint16(utf8.RuneCountInString(login.ChangePassword)), + } + offset := uint16(binary.Size(hdr)) + hdr.HostNameOffset = offset + offset += uint16(len(hostname)) + hdr.UserNameOffset = offset + offset += uint16(len(username)) + hdr.PasswordOffset = offset + offset += uint16(len(password)) + hdr.AppNameOffset = offset + offset += uint16(len(appname)) + hdr.ServerNameOffset = offset + offset += uint16(len(servername)) + hdr.CtlIntNameOffset = offset + offset += uint16(len(ctlintname)) + hdr.LanguageOffset = offset + offset += uint16(len(language)) + hdr.DatabaseOffset = offset + offset += uint16(len(database)) + hdr.SSPIOffset = offset + offset += uint16(len(login.SSPI)) + hdr.AtchDBFileOffset = offset + offset += uint16(len(atchdbfile)) + hdr.ChangePasswordOffset = offset + offset += uint16(len(changepassword)) + hdr.Length = uint32(offset) + var err error + err = binary.Write(w, binary.LittleEndian, &hdr) + if err != nil { + return err + } + _, err = w.Write(hostname) + if err != nil { + return err + } + _, err = w.Write(username) + if err != nil { + return err + } + _, err = w.Write(password) + if err != nil { + return err + } + _, err = w.Write(appname) + if err != nil { + return err + } + _, err = w.Write(servername) + if err != nil { + return err + } + _, err = w.Write(ctlintname) + if err != nil { + return err + } + _, err = w.Write(language) + if err != nil { + return err + } + _, err = w.Write(database) + if err != nil { + return err + } + _, err = w.Write(login.SSPI) + if err != nil { + return err + } + _, err = w.Write(atchdbfile) + if err != nil { + return err + } + _, err = w.Write(changepassword) + if err != nil { + return err + } + return w.FinishPacket() +} + +func readUcs2(r io.Reader, numchars int) (res string, err error) { + buf := make([]byte, numchars*2) + _, err = io.ReadFull(r, buf) + if err != nil { + return "", err + } + return ucs22str(buf) +} + +func readUsVarChar(r io.Reader) (res string, err error) { + var numchars uint16 + err = binary.Read(r, binary.LittleEndian, &numchars) + if err != nil { + return "", err + } + return readUcs2(r, int(numchars)) +} + +func writeUsVarChar(w io.Writer, s string) (err error) { + buf := str2ucs2(s) + var numchars int = len(buf) / 2 + if numchars > 0xffff { + panic("invalid size for US_VARCHAR") + } + err = binary.Write(w, binary.LittleEndian, uint16(numchars)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readBVarChar(r io.Reader) (res string, err error) { + var numchars uint8 + err = binary.Read(r, binary.LittleEndian, &numchars) + if err != nil { + return "", err + } + + // A zero length could be returned, return an empty string + if numchars == 0 { + return "", nil + } + return readUcs2(r, int(numchars)) +} + +func writeBVarChar(w io.Writer, s string) (err error) { + buf := str2ucs2(s) + var numchars int = len(buf) / 2 + if numchars > 0xff { + panic("invalid size for B_VARCHAR") + } + err = binary.Write(w, binary.LittleEndian, uint8(numchars)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readBVarByte(r io.Reader) (res []byte, err error) { + var length uint8 + err = binary.Read(r, binary.LittleEndian, &length) + if err != nil { + return + } + res = make([]byte, length) + _, err = io.ReadFull(r, res) + return +} + +func readUshort(r io.Reader) (res uint16, err error) { + err = binary.Read(r, binary.LittleEndian, &res) + return +} + +func readByte(r io.Reader) (res byte, err error) { + var b [1]byte + _, err = r.Read(b[:]) + res = b[0] + return +} + +// Packet Data Stream Headers +// http://msdn.microsoft.com/en-us/library/dd304953.aspx +type headerStruct struct { + hdrtype uint16 + data []byte +} + +const ( + dataStmHdrQueryNotif = 1 // query notifications + dataStmHdrTransDescr = 2 // MARS transaction descriptor (required) + dataStmHdrTraceActivity = 3 +) + +// Query Notifications Header +// http://msdn.microsoft.com/en-us/library/dd304949.aspx +type queryNotifHdr struct { + notifyId string + ssbDeployment string + notifyTimeout uint32 +} + +func (hdr queryNotifHdr) pack() (res []byte) { + notifyId := str2ucs2(hdr.notifyId) + ssbDeployment := str2ucs2(hdr.ssbDeployment) + + res = make([]byte, 2+len(notifyId)+2+len(ssbDeployment)+4) + b := res + + binary.LittleEndian.PutUint16(b, uint16(len(notifyId))) + b = b[2:] + copy(b, notifyId) + b = b[len(notifyId):] + + binary.LittleEndian.PutUint16(b, uint16(len(ssbDeployment))) + b = b[2:] + copy(b, ssbDeployment) + b = b[len(ssbDeployment):] + + binary.LittleEndian.PutUint32(b, hdr.notifyTimeout) + + return res +} + +// MARS Transaction Descriptor Header +// http://msdn.microsoft.com/en-us/library/dd340515.aspx +type transDescrHdr struct { + transDescr uint64 // transaction descriptor returned from ENVCHANGE + outstandingReqCnt uint32 // outstanding request count +} + +func (hdr transDescrHdr) pack() (res []byte) { + res = make([]byte, 8+4) + binary.LittleEndian.PutUint64(res, hdr.transDescr) + binary.LittleEndian.PutUint32(res[8:], hdr.outstandingReqCnt) + return res +} + +func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { + // Calculating total length. + var totallen uint32 = 4 + for _, hdr := range headers { + totallen += 4 + 2 + uint32(len(hdr.data)) + } + // writing + err = binary.Write(w, binary.LittleEndian, totallen) + if err != nil { + return err + } + for _, hdr := range headers { + var headerlen uint32 = 4 + 2 + uint32(len(hdr.data)) + err = binary.Write(w, binary.LittleEndian, headerlen) + if err != nil { + return err + } + err = binary.Write(w, binary.LittleEndian, hdr.hdrtype) + if err != nil { + return err + } + _, err = w.Write(hdr.data) + if err != nil { + return err + } + } + return nil +} + +func sendSqlBatch72(buf *tdsBuffer, sqltext string, headers []headerStruct, resetSession bool) (err error) { + buf.BeginPacket(packSQLBatch, resetSession) + + if err = writeAllHeaders(buf, headers); err != nil { + return + } + + _, err = buf.Write(str2ucs2(sqltext)) + if err != nil { + return + } + return buf.FinishPacket() +} + +// 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx +// 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx +func sendAttention(buf *tdsBuffer) error { + buf.BeginPacket(packAttention, false) + return buf.FinishPacket() +} + +type connectParams struct { + logFlags uint64 + port uint64 + host string + instance string + database string + user string + password string + dial_timeout time.Duration + conn_timeout time.Duration + keepAlive time.Duration + encrypt bool + disableEncryption bool + trustServerCertificate bool + certificate string + hostInCertificate string + serverSPN string + workstation string + appname string + typeFlags uint8 + failOverPartner string + failOverPort uint64 + packetSize uint16 +} + +func splitConnectionString(dsn string) (res map[string]string) { + res = map[string]string{} + parts := strings.Split(dsn, ";") + for _, part := range parts { + if len(part) == 0 { + continue + } + lst := strings.SplitN(part, "=", 2) + name := strings.TrimSpace(strings.ToLower(lst[0])) + if len(name) == 0 { + continue + } + var value string = "" + if len(lst) > 1 { + value = strings.TrimSpace(lst[1]) + } + res[name] = value + } + return res +} + +// Splits a URL in the ODBC format +func splitConnectionStringOdbc(dsn string) (map[string]string, error) { + res := map[string]string{} + + type parserState int + const ( + // Before the start of a key + parserStateBeforeKey parserState = iota + + // Inside a key + parserStateKey + + // Beginning of a value. May be bare or braced + parserStateBeginValue + + // Inside a bare value + parserStateBareValue + + // Inside a braced value + parserStateBracedValue + + // A closing brace inside a braced value. + // May be the end of the value or an escaped closing brace, depending on the next character + parserStateBracedValueClosingBrace + + // After a value. Next character should be a semicolon or whitespace. + parserStateEndValue + ) + + var state = parserStateBeforeKey + + var key string + var value string + + for i, c := range dsn { + switch state { + case parserStateBeforeKey: + switch { + case c == '=': + return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) + case !unicode.IsSpace(c) && c != ';': + state = parserStateKey + key += string(c) + } + + case parserStateKey: + switch c { + case '=': + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + state = parserStateBeginValue + + case ';': + // Key without value + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + res[key] = value + key = "" + value = "" + state = parserStateBeforeKey + + default: + key += string(c) + } + + case parserStateBeginValue: + switch { + case c == '{': + state = parserStateBracedValue + case c == ';': + // Empty value + res[key] = value + key = "" + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + state = parserStateBareValue + value += string(c) + } + + case parserStateBareValue: + if c == ';' { + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + key = "" + value = "" + state = parserStateBeforeKey + } else { + value += string(c) + } + + case parserStateBracedValue: + if c == '}' { + state = parserStateBracedValueClosingBrace + } else { + value += string(c) + } + + case parserStateBracedValueClosingBrace: + if c == '}' { + // Escaped closing brace + value += string(c) + state = parserStateBracedValue + continue + } + + // End of braced value + res[key] = value + key = "" + value = "" + + // This character is the first character past the end, + // so it needs to be parsed like the parserStateEndValue state. + state = parserStateEndValue + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + + case parserStateEndValue: + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + } + } + + switch state { + case parserStateBeforeKey: // Okay + case parserStateKey: // Unfinished key. Treat as key without value. + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", len(dsn)) + } + res[key] = value + case parserStateBeginValue: // Empty value + res[key] = value + case parserStateBareValue: + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + case parserStateBracedValue: + return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) + case parserStateBracedValueClosingBrace: // End of braced value + res[key] = value + case parserStateEndValue: // Okay + } + + return res, nil +} + +// Normalizes the given string as an ODBC-format key +func normalizeOdbcKey(s string) string { + return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) +} + +// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value +func splitConnectionStringURL(dsn string) (map[string]string, error) { + res := map[string]string{} + + u, err := url.Parse(dsn) + if err != nil { + return res, err + } + + if u.Scheme != "sqlserver" { + return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) + } + + if u.User != nil { + res["user id"] = u.User.Username() + p, exists := u.User.Password() + if exists { + res["password"] = p + } + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + + if len(u.Path) > 0 { + res["server"] = host + "\\" + u.Path[1:] + } else { + res["server"] = host + } + + if len(port) > 0 { + res["port"] = port + } + + query := u.Query() + for k, v := range query { + if len(v) > 1 { + return res, fmt.Errorf("key %s provided more than once", k) + } + res[strings.ToLower(k)] = v[0] + } + + return res, nil +} + +func parseConnectParams(dsn string) (connectParams, error) { + var p connectParams + + var params map[string]string + if strings.HasPrefix(dsn, "odbc:") { + parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) + if err != nil { + return p, err + } + params = parameters + } else if strings.HasPrefix(dsn, "sqlserver://") { + parameters, err := splitConnectionStringURL(dsn) + if err != nil { + return p, err + } + params = parameters + } else { + params = splitConnectionString(dsn) + } + + strlog, ok := params["log"] + if ok { + var err error + p.logFlags, err = strconv.ParseUint(strlog, 10, 64) + if err != nil { + return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) + } + } + server := params["server"] + parts := strings.SplitN(server, `\`, 2) + p.host = parts[0] + if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { + p.host = "localhost" + } + if len(parts) > 1 { + p.instance = parts[1] + } + p.database = params["database"] + p.user = params["user id"] + p.password = params["password"] + + p.port = 1433 + strport, ok := params["port"] + if ok { + var err error + p.port, err = strconv.ParseUint(strport, 10, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, strport, err.Error()) + } + } + + // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option + // Default packet size remains at 4096 bytes + p.packetSize = 4096 + strpsize, ok := params["packet size"] + if ok { + var err error + psize, err := strconv.ParseUint(strpsize, 0, 16) + if err != nil { + f := "Invalid packet size '%v': %v" + return p, fmt.Errorf(f, strpsize, err.Error()) + } + + // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes + // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request + // a higher packet size, the server will respond with an ENVCHANGE request to + // alter the packet size to 16383 bytes. + p.packetSize = uint16(psize) + if p.packetSize < 512 { + p.packetSize = 512 + } else if p.packetSize > 32767 { + p.packetSize = 32767 + } + } + + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + // + // Do not set a connection timeout. Use Context to manage such things. + // Default to zero, but still allow it to be set. + if strconntimeout, ok := params["connection timeout"]; ok { + timeout, err := strconv.ParseUint(strconntimeout, 10, 64) + if err != nil { + f := "Invalid connection timeout '%v': %v" + return p, fmt.Errorf(f, strconntimeout, err.Error()) + } + p.conn_timeout = time.Duration(timeout) * time.Second + } + p.dial_timeout = 15 * time.Second + if strdialtimeout, ok := params["dial timeout"]; ok { + timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) + if err != nil { + f := "Invalid dial timeout '%v': %v" + return p, fmt.Errorf(f, strdialtimeout, err.Error()) + } + p.dial_timeout = time.Duration(timeout) * time.Second + } + + // default keep alive should be 30 seconds according to spec: + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.keepAlive = 30 * time.Second + if keepAlive, ok := params["keepalive"]; ok { + timeout, err := strconv.ParseUint(keepAlive, 10, 64) + if err != nil { + f := "Invalid keepAlive value '%s': %s" + return p, fmt.Errorf(f, keepAlive, err.Error()) + } + p.keepAlive = time.Duration(timeout) * time.Second + } + encrypt, ok := params["encrypt"] + if ok { + if strings.EqualFold(encrypt, "DISABLE") { + p.disableEncryption = true + } else { + var err error + p.encrypt, err = strconv.ParseBool(encrypt) + if err != nil { + f := "Invalid encrypt '%s': %s" + return p, fmt.Errorf(f, encrypt, err.Error()) + } + } + } else { + p.trustServerCertificate = true + } + trust, ok := params["trustservercertificate"] + if ok { + var err error + p.trustServerCertificate, err = strconv.ParseBool(trust) + if err != nil { + f := "Invalid trust server certificate '%s': %s" + return p, fmt.Errorf(f, trust, err.Error()) + } + } + p.certificate = params["certificate"] + p.hostInCertificate, ok = params["hostnameincertificate"] + if !ok { + p.hostInCertificate = p.host + } + + serverSPN, ok := params["serverspn"] + if ok { + p.serverSPN = serverSPN + } else { + p.serverSPN = fmt.Sprintf("MSSQLSvc/%s:%d", p.host, p.port) + } + + workstation, ok := params["workstation id"] + if ok { + p.workstation = workstation + } else { + workstation, err := os.Hostname() + if err == nil { + p.workstation = workstation + } + } + + appname, ok := params["app name"] + if !ok { + appname = "go-mssqldb" + } + p.appname = appname + + appintent, ok := params["applicationintent"] + if ok { + if appintent == "ReadOnly" { + p.typeFlags |= fReadOnlyIntent + } + } + + failOverPartner, ok := params["failoverpartner"] + if ok { + p.failOverPartner = failOverPartner + } + + failOverPort, ok := params["failoverport"] + if ok { + var err error + p.failOverPort, err = strconv.ParseUint(failOverPort, 0, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, failOverPort, err.Error()) + } + } + + return p, nil +} + +type auth interface { + InitialBytes() ([]byte, error) + NextBytes([]byte) ([]byte, error) + Free() +} + +// SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a +// list of IP addresses. So if there is more than one, try them all and +// use the first one that allows a connection. +func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err error) { + var ips []net.IP + ips, err = net.LookupIP(p.host) + if err != nil { + ip := net.ParseIP(p.host) + if ip == nil { + return nil, err + } + ips = []net.IP{ip} + } + if len(ips) == 1 { + d := createDialer(&p) + addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port))) + conn, err = d.Dial(ctx, addr) + + } else { + //Try Dials in parallel to avoid waiting for timeouts. + connChan := make(chan net.Conn, len(ips)) + errChan := make(chan error, len(ips)) + portStr := strconv.Itoa(int(p.port)) + for _, ip := range ips { + go func(ip net.IP) { + d := createDialer(&p) + addr := net.JoinHostPort(ip.String(), portStr) + conn, err := d.Dial(ctx, addr) + if err == nil { + connChan <- conn + } else { + errChan <- err + } + }(ip) + } + // Wait for either the *first* successful connection, or all the errors + wait_loop: + for i, _ := range ips { + select { + case conn = <-connChan: + // Got a connection to use, close any others + go func(n int) { + for i := 0; i < n; i++ { + select { + case conn := <-connChan: + conn.Close() + case <-errChan: + } + } + }(len(ips) - i - 1) + // Remove any earlier errors we may have collected + err = nil + break wait_loop + case err = <-errChan: + } + } + } + // Can't do the usual err != nil check, as it is possible to have gotten an error before a successful connection + if conn == nil { + f := "Unable to open tcp connection with host '%v:%v': %v" + return nil, fmt.Errorf(f, p.host, p.port, err.Error()) + } + return conn, err +} + +func connect(ctx context.Context, log optionalLogger, p connectParams) (res *tdsSession, err error) { + dialCtx := ctx + if p.dial_timeout > 0 { + var cancel func() + dialCtx, cancel = context.WithTimeout(ctx, p.dial_timeout) + defer cancel() + } + // if instance is specified use instance resolution service + if p.instance != "" { + p.instance = strings.ToUpper(p.instance) + instances, err := getInstances(dialCtx, p.host) + if err != nil { + f := "Unable to get instances from Sql Server Browser on host %v: %v" + return nil, fmt.Errorf(f, p.host, err.Error()) + } + strport, ok := instances[p.instance]["tcp"] + if !ok { + f := "No instance matching '%v' returned from host '%v'" + return nil, fmt.Errorf(f, p.instance, p.host) + } + p.port, err = strconv.ParseUint(strport, 0, 16) + if err != nil { + f := "Invalid tcp port returned from Sql Server Browser '%v': %v" + return nil, fmt.Errorf(f, strport, err.Error()) + } + } + +initiate_connection: + conn, err := dialConnection(dialCtx, p) + if err != nil { + return nil, err + } + + toconn := newTimeoutConn(conn, p.conn_timeout) + + outbuf := newTdsBuffer(p.packetSize, toconn) + sess := tdsSession{ + buf: outbuf, + log: log, + logFlags: p.logFlags, + } + + instance_buf := []byte(p.instance) + instance_buf = append(instance_buf, 0) // zero terminate instance name + var encrypt byte + if p.disableEncryption { + encrypt = encryptNotSup + } else if p.encrypt { + encrypt = encryptOn + } else { + encrypt = encryptOff + } + fields := map[uint8][]byte{ + preloginVERSION: {0, 0, 0, 0, 0, 0}, + preloginENCRYPTION: {encrypt}, + preloginINSTOPT: instance_buf, + preloginTHREADID: {0, 0, 0, 0}, + preloginMARS: {0}, // MARS disabled + } + + err = writePrelogin(outbuf, fields) + if err != nil { + return nil, err + } + + fields, err = readPrelogin(outbuf) + if err != nil { + return nil, err + } + + encryptBytes, ok := fields[preloginENCRYPTION] + if !ok { + return nil, fmt.Errorf("Encrypt negotiation failed") + } + encrypt = encryptBytes[0] + if p.encrypt && (encrypt == encryptNotSup || encrypt == encryptOff) { + return nil, fmt.Errorf("Server does not support encryption") + } + + if encrypt != encryptNotSup { + var config tls.Config + if p.certificate != "" { + pem, err := ioutil.ReadFile(p.certificate) + if err != nil { + return nil, fmt.Errorf("Cannot read certificate %q: %v", p.certificate, err) + } + certs := x509.NewCertPool() + certs.AppendCertsFromPEM(pem) + config.RootCAs = certs + } + if p.trustServerCertificate { + config.InsecureSkipVerify = true + } + config.ServerName = p.hostInCertificate + // fix for https://github.com/denisenkom/go-mssqldb/issues/166 + // Go implementation of TLS payload size heuristic algorithm splits single TDS package to multiple TCP segments, + // while SQL Server seems to expect one TCP segment per encrypted TDS package. + // Setting DynamicRecordSizingDisabled to true disables that algorithm and uses 16384 bytes per TLS package + config.DynamicRecordSizingDisabled = true + outbuf.transport = conn + toconn.buf = outbuf + tlsConn := tls.Client(toconn, &config) + err = tlsConn.Handshake() + + toconn.buf = nil + outbuf.transport = tlsConn + if err != nil { + return nil, fmt.Errorf("TLS Handshake failed: %v", err) + } + if encrypt == encryptOff { + outbuf.afterFirst = func() { + outbuf.transport = toconn + } + } + } + + login := login{ + TDSVersion: verTDS74, + PacketSize: uint32(outbuf.PackageSize()), + Database: p.database, + OptionFlags2: fODBC, // to get unlimited TEXTSIZE + HostName: p.workstation, + ServerName: p.host, + AppName: p.appname, + TypeFlags: p.typeFlags, + } + auth, auth_ok := getAuth(p.user, p.password, p.serverSPN, p.workstation) + if auth_ok { + login.SSPI, err = auth.InitialBytes() + if err != nil { + return nil, err + } + login.OptionFlags2 |= fIntSecurity + defer auth.Free() + } else { + login.UserName = p.user + login.Password = p.password + } + err = sendLogin(outbuf, login) + if err != nil { + return nil, err + } + + // processing login response + var sspi_msg []byte +continue_login: + tokchan := make(chan tokenStruct, 5) + go processResponse(context.Background(), &sess, tokchan, nil) + success := false + for tok := range tokchan { + switch token := tok.(type) { + case sspiMsg: + sspi_msg, err = auth.NextBytes(token) + if err != nil { + return nil, err + } + case loginAckStruct: + success = true + sess.loginAck = token + case error: + return nil, fmt.Errorf("Login error: %s", token.Error()) + case doneStruct: + if token.isError() { + return nil, fmt.Errorf("Login error: %s", token.getError()) + } + } + } + if sspi_msg != nil { + outbuf.BeginPacket(packSSPIMessage, false) + _, err = outbuf.Write(sspi_msg) + if err != nil { + return nil, err + } + err = outbuf.FinishPacket() + if err != nil { + return nil, err + } + sspi_msg = nil + goto continue_login + } + if !success { + return nil, fmt.Errorf("Login failed") + } + if sess.routedServer != "" { + toconn.Close() + p.host = sess.routedServer + p.port = uint64(sess.routedPort) + goto initiate_connection + } + return &sess, nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/token.go b/vendor/github.com/denisenkom/go-mssqldb/token.go new file mode 100644 index 0000000..67fdcc2 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token.go @@ -0,0 +1,806 @@ +package mssql + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "strconv" + "strings" +) + +//go:generate stringer -type token + +type token byte + +// token ids +const ( + tokenReturnStatus token = 121 // 0x79 + tokenColMetadata token = 129 // 0x81 + tokenOrder token = 169 // 0xA9 + tokenError token = 170 // 0xAA + tokenInfo token = 171 // 0xAB + tokenReturnValue token = 0xAC + tokenLoginAck token = 173 // 0xad + tokenRow token = 209 // 0xd1 + tokenNbcRow token = 210 // 0xd2 + tokenEnvChange token = 227 // 0xE3 + tokenSSPI token = 237 // 0xED + tokenDone token = 253 // 0xFD + tokenDoneProc token = 254 + tokenDoneInProc token = 255 +) + +// done flags +// https://msdn.microsoft.com/en-us/library/dd340421.aspx +const ( + doneFinal = 0 + doneMore = 1 + doneError = 2 + doneInxact = 4 + doneCount = 0x10 + doneAttn = 0x20 + doneSrvError = 0x100 +) + +// ENVCHANGE types +// http://msdn.microsoft.com/en-us/library/dd303449.aspx +const ( + envTypDatabase = 1 + envTypLanguage = 2 + envTypCharset = 3 + envTypPacketSize = 4 + envSortId = 5 + envSortFlags = 6 + envSqlCollation = 7 + envTypBeginTran = 8 + envTypCommitTran = 9 + envTypRollbackTran = 10 + envEnlistDTC = 11 + envDefectTran = 12 + envDatabaseMirrorPartner = 13 + envPromoteTran = 15 + envTranMgrAddr = 16 + envTranEnded = 17 + envResetConnAck = 18 + envStartedInstanceName = 19 + envRouting = 20 +) + +// COLMETADATA flags +// https://msdn.microsoft.com/en-us/library/dd357363.aspx +const ( + colFlagNullable = 1 + // TODO implement more flags +) + +// interface for all tokens +type tokenStruct interface{} + +type orderStruct struct { + ColIds []uint16 +} + +type doneStruct struct { + Status uint16 + CurCmd uint16 + RowCount uint64 + errors []Error +} + +func (d doneStruct) isError() bool { + return d.Status&doneError != 0 || len(d.errors) > 0 +} + +func (d doneStruct) getError() Error { + if len(d.errors) > 0 { + return d.errors[len(d.errors)-1] + } else { + return Error{Message: "Request failed but didn't provide reason"} + } +} + +type doneInProcStruct doneStruct + +var doneFlags2str = map[uint16]string{ + doneFinal: "final", + doneMore: "more", + doneError: "error", + doneInxact: "inxact", + doneCount: "count", + doneAttn: "attn", + doneSrvError: "srverror", +} + +func doneFlags2Str(flags uint16) string { + strs := make([]string, 0, len(doneFlags2str)) + for flag, tag := range doneFlags2str { + if flags&flag != 0 { + strs = append(strs, tag) + } + } + return strings.Join(strs, "|") +} + +// ENVCHANGE stream +// http://msdn.microsoft.com/en-us/library/dd303449.aspx +func processEnvChg(sess *tdsSession) { + size := sess.buf.uint16() + r := &io.LimitedReader{R: sess.buf, N: int64(size)} + for { + var err error + var envtype uint8 + err = binary.Read(r, binary.LittleEndian, &envtype) + if err == io.EOF { + return + } + if err != nil { + badStreamPanic(err) + } + switch envtype { + case envTypDatabase: + sess.database, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + case envTypLanguage: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypCharset: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypPacketSize: + packetsize, err := readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + packetsizei, err := strconv.Atoi(packetsize) + if err != nil { + badStreamPanicf("Invalid Packet size value returned from server (%s): %s", packetsize, err.Error()) + } + sess.buf.ResizeBuffer(packetsizei) + case envSortId: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envSortFlags: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envSqlCollation: + // currently ignored + var collationSize uint8 + err = binary.Read(r, binary.LittleEndian, &collationSize) + if err != nil { + badStreamPanic(err) + } + + // SQL Collation data should contain 5 bytes in length + if collationSize != 5 { + badStreamPanicf("Invalid SQL Collation size value returned from server: %s", collationSize) + } + + // 4 bytes, contains: LCID ColFlags Version + var info uint32 + err = binary.Read(r, binary.LittleEndian, &info) + if err != nil { + badStreamPanic(err) + } + + // 1 byte, contains: sortID + var sortID uint8 + err = binary.Read(r, binary.LittleEndian, &sortID) + if err != nil { + badStreamPanic(err) + } + + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypBeginTran: + tranid, err := readBVarByte(r) + if len(tranid) != 8 { + badStreamPanicf("invalid size of transaction identifier: %d", len(tranid)) + } + sess.tranid = binary.LittleEndian.Uint64(tranid) + if err != nil { + badStreamPanic(err) + } + if sess.logFlags&logTransaction != 0 { + sess.log.Printf("BEGIN TRANSACTION %x\n", sess.tranid) + } + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + case envTypCommitTran, envTypRollbackTran: + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + if sess.logFlags&logTransaction != 0 { + if envtype == envTypCommitTran { + sess.log.Printf("COMMIT TRANSACTION %x\n", sess.tranid) + } else { + sess.log.Printf("ROLLBACK TRANSACTION %x\n", sess.tranid) + } + } + sess.tranid = 0 + case envEnlistDTC: + // currently ignored + // new value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envDefectTran: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envDatabaseMirrorPartner: + sess.partner, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + case envPromoteTran: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // dtc token + // spec says it should be L_VARBYTE, so this code might be wrong + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTranMgrAddr: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // XACT_MANAGER_ADDRESS = B_VARBYTE + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTranEnded: + // currently ignored + // old value, B_VARBYTE + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envResetConnAck: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envStartedInstanceName: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // instance name + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envRouting: + // RoutingData message is: + // ValueLength USHORT + // Protocol (TCP = 0) BYTE + // ProtocolProperty (new port) USHORT + // AlternateServer US_VARCHAR + _, err := readUshort(r) + if err != nil { + badStreamPanic(err) + } + protocol, err := readByte(r) + if err != nil || protocol != 0 { + badStreamPanic(err) + } + newPort, err := readUshort(r) + if err != nil { + badStreamPanic(err) + } + newServer, err := readUsVarChar(r) + if err != nil { + badStreamPanic(err) + } + // consume the OLDVALUE = %x00 %x00 + _, err = readUshort(r) + if err != nil { + badStreamPanic(err) + } + sess.routedServer = newServer + sess.routedPort = newPort + default: + // ignore rest of records because we don't know how to skip those + sess.log.Printf("WARN: Unknown ENVCHANGE record detected with type id = %d\n", envtype) + break + } + + } +} + +type returnStatus int32 + +// http://msdn.microsoft.com/en-us/library/dd358180.aspx +func parseReturnStatus(r *tdsBuffer) returnStatus { + return returnStatus(r.int32()) +} + +func parseOrder(r *tdsBuffer) (res orderStruct) { + len := int(r.uint16()) + res.ColIds = make([]uint16, len/2) + for i := 0; i < len/2; i++ { + res.ColIds[i] = r.uint16() + } + return res +} + +// https://msdn.microsoft.com/en-us/library/dd340421.aspx +func parseDone(r *tdsBuffer) (res doneStruct) { + res.Status = r.uint16() + res.CurCmd = r.uint16() + res.RowCount = r.uint64() + return res +} + +// https://msdn.microsoft.com/en-us/library/dd340553.aspx +func parseDoneInProc(r *tdsBuffer) (res doneInProcStruct) { + res.Status = r.uint16() + res.CurCmd = r.uint16() + res.RowCount = r.uint64() + return res +} + +type sspiMsg []byte + +func parseSSPIMsg(r *tdsBuffer) sspiMsg { + size := r.uint16() + buf := make([]byte, size) + r.ReadFull(buf) + return sspiMsg(buf) +} + +type loginAckStruct struct { + Interface uint8 + TDSVersion uint32 + ProgName string + ProgVer uint32 +} + +func parseLoginAck(r *tdsBuffer) loginAckStruct { + size := r.uint16() + buf := make([]byte, size) + r.ReadFull(buf) + var res loginAckStruct + res.Interface = buf[0] + res.TDSVersion = binary.BigEndian.Uint32(buf[1:]) + prognamelen := buf[1+4] + var err error + if res.ProgName, err = ucs22str(buf[1+4+1 : 1+4+1+prognamelen*2]); err != nil { + badStreamPanic(err) + } + res.ProgVer = binary.BigEndian.Uint32(buf[size-4:]) + return res +} + +// http://msdn.microsoft.com/en-us/library/dd357363.aspx +func parseColMetadata72(r *tdsBuffer) (columns []columnStruct) { + count := r.uint16() + if count == 0xffff { + // no metadata is sent + return nil + } + columns = make([]columnStruct, count) + for i := range columns { + column := &columns[i] + column.UserType = r.uint32() + column.Flags = r.uint16() + + // parsing TYPE_INFO structure + column.ti = readTypeInfo(r) + column.ColName = r.BVarChar() + } + return columns +} + +// http://msdn.microsoft.com/en-us/library/dd357254.aspx +func parseRow(r *tdsBuffer, columns []columnStruct, row []interface{}) { + for i, column := range columns { + row[i] = column.ti.Reader(&column.ti, r) + } +} + +// http://msdn.microsoft.com/en-us/library/dd304783.aspx +func parseNbcRow(r *tdsBuffer, columns []columnStruct, row []interface{}) { + bitlen := (len(columns) + 7) / 8 + pres := make([]byte, bitlen) + r.ReadFull(pres) + for i, col := range columns { + if pres[i/8]&(1<<(uint(i)%8)) != 0 { + row[i] = nil + continue + } + row[i] = col.ti.Reader(&col.ti, r) + } +} + +// http://msdn.microsoft.com/en-us/library/dd304156.aspx +func parseError72(r *tdsBuffer) (res Error) { + length := r.uint16() + _ = length // ignore length + res.Number = r.int32() + res.State = r.byte() + res.Class = r.byte() + res.Message = r.UsVarChar() + res.ServerName = r.BVarChar() + res.ProcName = r.BVarChar() + res.LineNo = r.int32() + return +} + +// http://msdn.microsoft.com/en-us/library/dd304156.aspx +func parseInfo(r *tdsBuffer) (res Error) { + length := r.uint16() + _ = length // ignore length + res.Number = r.int32() + res.State = r.byte() + res.Class = r.byte() + res.Message = r.UsVarChar() + res.ServerName = r.BVarChar() + res.ProcName = r.BVarChar() + res.LineNo = r.int32() + return +} + +// https://msdn.microsoft.com/en-us/library/dd303881.aspx +func parseReturnValue(r *tdsBuffer) (nv namedValue) { + /* + ParamOrdinal + ParamName + Status + UserType + Flags + TypeInfo + CryptoMetadata + Value + */ + r.uint16() + nv.Name = r.BVarChar() + r.byte() + r.uint32() // UserType (uint16 prior to 7.2) + r.uint16() + ti := readTypeInfo(r) + nv.Value = ti.Reader(&ti, r) + return +} + +func processSingleResponse(sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + defer func() { + if err := recover(); err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: Intercepted panic %v", err) + } + ch <- err + } + close(ch) + }() + + packet_type, err := sess.buf.BeginRead() + if err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: BeginRead failed %v", err) + } + ch <- err + return + } + if packet_type != packReply { + badStreamPanic(fmt.Errorf("unexpected packet type in reply: got %v, expected %v", packet_type, packReply)) + } + var columns []columnStruct + errs := make([]Error, 0, 5) + for { + token := token(sess.buf.byte()) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got token %v", token) + } + switch token { + case tokenSSPI: + ch <- parseSSPIMsg(sess.buf) + return + case tokenReturnStatus: + returnStatus := parseReturnStatus(sess.buf) + ch <- returnStatus + case tokenLoginAck: + loginAck := parseLoginAck(sess.buf) + ch <- loginAck + case tokenOrder: + order := parseOrder(sess.buf) + ch <- order + case tokenDoneInProc: + done := parseDoneInProc(sess.buf) + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } + ch <- done + case tokenDone, tokenDoneProc: + done := parseDone(sess.buf) + done.errors = errs + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got DONE or DONEPROC status=%d", done.Status) + } + if done.Status&doneSrvError != 0 { + ch <- errors.New("SQL Server had internal error") + return + } + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } + ch <- done + if done.Status&doneMore == 0 { + return + } + case tokenColMetadata: + columns = parseColMetadata72(sess.buf) + ch <- columns + case tokenRow: + row := make([]interface{}, len(columns)) + parseRow(sess.buf, columns, row) + ch <- row + case tokenNbcRow: + row := make([]interface{}, len(columns)) + parseNbcRow(sess.buf, columns, row) + ch <- row + case tokenEnvChange: + processEnvChg(sess) + case tokenError: + err := parseError72(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got ERROR %d %s", err.Number, err.Message) + } + errs = append(errs, err) + if sess.logFlags&logErrors != 0 { + sess.log.Println(err.Message) + } + case tokenInfo: + info := parseInfo(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got INFO %d %s", info.Number, info.Message) + } + if sess.logFlags&logMessages != 0 { + sess.log.Println(info.Message) + } + case tokenReturnValue: + nv := parseReturnValue(sess.buf) + if len(nv.Name) > 0 { + name := nv.Name[1:] // Remove the leading "@". + if ov, has := outs[name]; has { + err = scanIntoOut(name, nv.Value, ov) + if err != nil { + fmt.Println("scan error", err) + ch <- err + } + } + } + default: + badStreamPanic(fmt.Errorf("unknown token type returned: %v", token)) + } + } +} + +type parseRespIter byte + +const ( + parseRespIterContinue parseRespIter = iota // Continue parsing current token. + parseRespIterNext // Fetch the next token. + parseRespIterDone // Done with parsing the response. +) + +type parseRespState byte + +const ( + parseRespStateNormal parseRespState = iota // Normal response state. + parseRespStateCancel // Query is canceled, wait for server to confirm. + parseRespStateClosing // Waiting for tokens to come through. +) + +type parseResp struct { + sess *tdsSession + ctxDone <-chan struct{} + state parseRespState + cancelError error +} + +func (ts *parseResp) sendAttention(ch chan tokenStruct) parseRespIter { + if err := sendAttention(ts.sess.buf); err != nil { + ts.dlogf("failed to send attention signal %v", err) + ch <- err + return parseRespIterDone + } + ts.state = parseRespStateCancel + return parseRespIterContinue +} + +func (ts *parseResp) dlog(msg string) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Println(msg) + } +} +func (ts *parseResp) dlogf(f string, v ...interface{}) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Printf(f, v...) + } +} + +func (ts *parseResp) iter(ctx context.Context, ch chan tokenStruct, tokChan chan tokenStruct) parseRespIter { + switch ts.state { + default: + panic("unknown state") + case parseRespStateNormal: + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished") + return parseRespIterDone + } + if err, ok := tok.(net.Error); ok && err.Timeout() { + ts.cancelError = err + ts.dlog("got timeout error, sending attention signal to server") + return ts.sendAttention(ch) + } + // Pass the token along. + ch <- tok + return parseRespIterContinue + + case <-ts.ctxDone: + ts.ctxDone = nil + ts.dlog("got cancel message, sending attention signal to server") + return ts.sendAttention(ch) + } + case parseRespStateCancel: // Read all responses until a DONE or error is received.Auth + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished but waiting for attention ack") + return parseRespIterNext + } + switch tok := tok.(type) { + default: + // Ignore all other tokens while waiting. + // The TDS spec says other tokens may arrive after an attention + // signal is sent. Ignore these tokens and continue looking for + // a DONE with attention confirm mark. + case doneStruct: + if tok.Status&doneAttn != 0 { + ts.dlog("got cancellation confirmation from server") + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } else { + ch <- ctx.Err() + } + return parseRespIterDone + } + + // If an error happens during cancel, pass it along and just stop. + // We are uncertain to receive more tokens. + case error: + ch <- tok + ts.state = parseRespStateClosing + } + return parseRespIterContinue + case <-ts.ctxDone: + ts.ctxDone = nil + ts.state = parseRespStateClosing + return parseRespIterContinue + } + case parseRespStateClosing: // Wait for current token chan to close. + if _, ok := <-tokChan; !ok { + ts.dlog("response finished") + return parseRespIterDone + } + return parseRespIterContinue + } +} + +func processResponse(ctx context.Context, sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + ts := &parseResp{ + sess: sess, + ctxDone: ctx.Done(), + } + defer func() { + // Ensure any remaining error is piped through + // or the query may look like it executed when it actually failed. + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } + close(ch) + }() + + // Loop over multiple responses. + for { + ts.dlog("initiating response reading") + + tokChan := make(chan tokenStruct) + go processSingleResponse(sess, tokChan, outs) + + // Loop over multiple tokens in response. + tokensLoop: + for { + switch ts.iter(ctx, ch, tokChan) { + case parseRespIterContinue: + // Nothing, continue to next token. + case parseRespIterNext: + break tokensLoop + case parseRespIterDone: + return + } + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/token_string.go b/vendor/github.com/denisenkom/go-mssqldb/token_string.go new file mode 100644 index 0000000..c075b23 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token_string.go @@ -0,0 +1,53 @@ +// Code generated by "stringer -type token"; DO NOT EDIT + +package mssql + +import "fmt" + +const ( + _token_name_0 = "tokenReturnStatus" + _token_name_1 = "tokenColMetadata" + _token_name_2 = "tokenOrdertokenErrortokenInfo" + _token_name_3 = "tokenLoginAck" + _token_name_4 = "tokenRowtokenNbcRow" + _token_name_5 = "tokenEnvChange" + _token_name_6 = "tokenSSPI" + _token_name_7 = "tokenDonetokenDoneProctokenDoneInProc" +) + +var ( + _token_index_0 = [...]uint8{0, 17} + _token_index_1 = [...]uint8{0, 16} + _token_index_2 = [...]uint8{0, 10, 20, 29} + _token_index_3 = [...]uint8{0, 13} + _token_index_4 = [...]uint8{0, 8, 19} + _token_index_5 = [...]uint8{0, 14} + _token_index_6 = [...]uint8{0, 9} + _token_index_7 = [...]uint8{0, 9, 22, 37} +) + +func (i token) String() string { + switch { + case i == 121: + return _token_name_0 + case i == 129: + return _token_name_1 + case 169 <= i && i <= 171: + i -= 169 + return _token_name_2[_token_index_2[i]:_token_index_2[i+1]] + case i == 173: + return _token_name_3 + case 209 <= i && i <= 210: + i -= 209 + return _token_name_4[_token_index_4[i]:_token_index_4[i+1]] + case i == 227: + return _token_name_5 + case i == 237: + return _token_name_6 + case 253 <= i && i <= 255: + i -= 253 + return _token_name_7[_token_index_7[i]:_token_index_7[i+1]] + default: + return fmt.Sprintf("token(%d)", i) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tran.go b/vendor/github.com/denisenkom/go-mssqldb/tran.go new file mode 100644 index 0000000..cb64368 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tran.go @@ -0,0 +1,110 @@ +package mssql + +// Transaction Manager requests +// http://msdn.microsoft.com/en-us/library/dd339887.aspx + +import ( + "encoding/binary" +) + +const ( + tmGetDtcAddr = 0 + tmPropagateXact = 1 + tmBeginXact = 5 + tmPromoteXact = 6 + tmCommitXact = 7 + tmRollbackXact = 8 + tmSaveXact = 9 +) + +type isoLevel uint8 + +const ( + isolationUseCurrent isoLevel = 0 + isolationReadUncommited = 1 + isolationReadCommited = 2 + isolationRepeatableRead = 3 + isolationSerializable = 4 + isolationSnapshot = 5 +) + +func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation isoLevel, name string, resetSession bool) (err error) { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmBeginXact + err = binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return + } + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return + } + err = writeBVarChar(buf, name) + if err != nil { + return + } + return buf.FinishPacket() +} + +const ( + fBeginXact = 1 +) + +func sendCommitXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmCommitXact + err := binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return err + } + if flags&fBeginXact != 0 { + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + } + return buf.FinishPacket() +} + +func sendRollbackXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmRollbackXact + err := binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return err + } + if flags&fBeginXact != 0 { + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + } + return buf.FinishPacket() +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/types.go b/vendor/github.com/denisenkom/go-mssqldb/types.go new file mode 100644 index 0000000..4c925db --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -0,0 +1,1450 @@ +package mssql + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "math" + "reflect" + "strconv" + "time" + + "github.com/denisenkom/go-mssqldb/internal/cp" +) + +// fixed-length data types +// http://msdn.microsoft.com/en-us/library/dd341171.aspx +const ( + typeNull = 0x1f + typeInt1 = 0x30 + typeBit = 0x32 + typeInt2 = 0x34 + typeInt4 = 0x38 + typeDateTim4 = 0x3a + typeFlt4 = 0x3b + typeMoney = 0x3c + typeDateTime = 0x3d + typeFlt8 = 0x3e + typeMoney4 = 0x7a + typeInt8 = 0x7f +) + +// variable-length data types +// http://msdn.microsoft.com/en-us/library/dd358341.aspx +const ( + // byte len types + typeGuid = 0x24 + typeIntN = 0x26 + typeDecimal = 0x37 // legacy + typeNumeric = 0x3f // legacy + typeBitN = 0x68 + typeDecimalN = 0x6a + typeNumericN = 0x6c + typeFltN = 0x6d + typeMoneyN = 0x6e + typeDateTimeN = 0x6f + typeDateN = 0x28 + typeTimeN = 0x29 + typeDateTime2N = 0x2a + typeDateTimeOffsetN = 0x2b + typeChar = 0x2f // legacy + typeVarChar = 0x27 // legacy + typeBinary = 0x2d // legacy + typeVarBinary = 0x25 // legacy + + // short length types + typeBigVarBin = 0xa5 + typeBigVarChar = 0xa7 + typeBigBinary = 0xad + typeBigChar = 0xaf + typeNVarChar = 0xe7 + typeNChar = 0xef + typeXml = 0xf1 + typeUdt = 0xf0 + + // long length types + typeText = 0x23 + typeImage = 0x22 + typeNText = 0x63 + typeVariant = 0x62 +) +const _PLP_NULL = 0xFFFFFFFFFFFFFFFF +const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE +const _PLP_TERMINATOR = 0x00000000 + +// TYPE_INFO rule +// http://msdn.microsoft.com/en-us/library/dd358284.aspx +type typeInfo struct { + TypeId uint8 + Size int + Scale uint8 + Prec uint8 + Buffer []byte + Collation cp.Collation + UdtInfo udtInfo + XmlInfo xmlInfo + Reader func(ti *typeInfo, r *tdsBuffer) (res interface{}) + Writer func(w io.Writer, ti typeInfo, buf []byte) (err error) +} + +// Common Language Runtime (CLR) Instances +// http://msdn.microsoft.com/en-us/library/dd357962.aspx +type udtInfo struct { + //MaxByteSize uint32 + DBName string + SchemaName string + TypeName string + AssemblyQualifiedName string +} + +// XML Values +// http://msdn.microsoft.com/en-us/library/dd304764.aspx +type xmlInfo struct { + SchemaPresent uint8 + DBName string + OwningSchema string + XmlSchemaCollection string +} + +func readTypeInfo(r *tdsBuffer) (res typeInfo) { + res.TypeId = r.byte() + switch res.TypeId { + case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, + typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: + // those are fixed length types + switch res.TypeId { + case typeNull: + res.Size = 0 + case typeInt1, typeBit: + res.Size = 1 + case typeInt2: + res.Size = 2 + case typeInt4, typeDateTim4, typeFlt4, typeMoney4: + res.Size = 4 + case typeMoney, typeDateTime, typeFlt8, typeInt8: + res.Size = 8 + } + res.Reader = readFixedType + res.Buffer = make([]byte, res.Size) + default: // all others are VARLENTYPE + readVarLen(&res, r) + } + return +} + +func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { + err = binary.Write(w, binary.LittleEndian, ti.TypeId) + if err != nil { + return + } + switch ti.TypeId { + case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, + typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: + // those are fixed length + ti.Writer = writeFixedType + default: // all others are VARLENTYPE + err = writeVarLen(w, ti) + if err != nil { + return + } + } + return +} + +func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { + _, err = w.Write(buf) + return +} + +func writeVarLen(w io.Writer, ti *typeInfo) (err error) { + switch ti.TypeId { + case typeDateN: + ti.Writer = writeByteLenType + case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: + if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil { + return + } + ti.Writer = writeByteLenType + case typeIntN, typeDecimal, typeNumeric, + typeBitN, typeDecimalN, typeNumericN, typeFltN, + typeMoneyN, typeDateTimeN, typeChar, + typeVarChar, typeBinary, typeVarBinary: + + // byle len types + if ti.Size > 0xff { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + switch ti.TypeId { + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + err = binary.Write(w, binary.LittleEndian, ti.Prec) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, ti.Scale) + if err != nil { + return + } + } + ti.Writer = writeByteLenType + case typeGuid: + if !(ti.Size == 0x10 || ti.Size == 0x00) { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + ti.Writer = writeByteLenType + case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, + typeNVarChar, typeNChar, typeXml, typeUdt: + // short len types + if ti.Size > 8000 || ti.Size == 0 { + if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil { + return + } + ti.Writer = writePLPType + } else { + if err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)); err != nil { + return + } + ti.Writer = writeShortLenType + } + switch ti.TypeId { + case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: + if err = writeCollation(w, ti.Collation); err != nil { + return + } + case typeXml: + if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil { + return + } + } + case typeText, typeImage, typeNText, typeVariant: + // LONGLEN_TYPE + if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil { + return + } + if err = writeCollation(w, ti.Collation); err != nil { + return + } + ti.Writer = writeLongLenType + default: + panic("Invalid type") + } + return +} + +// http://msdn.microsoft.com/en-us/library/ee780895.aspx +func decodeDateTim4(buf []byte) time.Time { + days := binary.LittleEndian.Uint16(buf) + mins := binary.LittleEndian.Uint16(buf[2:]) + return time.Date(1900, 1, 1+int(days), + 0, int(mins), 0, 0, time.UTC) +} + +func decodeDateTime(buf []byte) time.Time { + days := int32(binary.LittleEndian.Uint32(buf)) + tm := binary.LittleEndian.Uint32(buf[4:]) + ns := int(math.Trunc(float64(tm%300)/0.3+0.5)) * 1000000 + secs := int(tm / 300) + return time.Date(1900, 1, 1+int(days), + 0, 0, secs, ns, time.UTC) +} + +func readFixedType(ti *typeInfo, r *tdsBuffer) interface{} { + r.ReadFull(ti.Buffer) + buf := ti.Buffer + switch ti.TypeId { + case typeNull: + return nil + case typeInt1: + return int64(buf[0]) + case typeBit: + return buf[0] != 0 + case typeInt2: + return int64(int16(binary.LittleEndian.Uint16(buf))) + case typeInt4: + return int64(int32(binary.LittleEndian.Uint32(buf))) + case typeDateTim4: + return decodeDateTim4(buf) + case typeFlt4: + return math.Float32frombits(binary.LittleEndian.Uint32(buf)) + case typeMoney4: + return decodeMoney4(buf) + case typeMoney: + return decodeMoney(buf) + case typeDateTime: + return decodeDateTime(buf) + case typeFlt8: + return math.Float64frombits(binary.LittleEndian.Uint64(buf)) + case typeInt8: + return int64(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func readByteLenType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.byte() + if size == 0 { + return nil + } + r.ReadFull(ti.Buffer[:size]) + buf := ti.Buffer[:size] + switch ti.TypeId { + case typeDateN: + if len(buf) != 3 { + badStreamPanicf("Invalid size for DATENTYPE") + } + return decodeDate(buf) + case typeTimeN: + return decodeTime(ti.Scale, buf) + case typeDateTime2N: + return decodeDateTime2(ti.Scale, buf) + case typeDateTimeOffsetN: + return decodeDateTimeOffset(ti.Scale, buf) + case typeGuid: + return decodeGuid(buf) + case typeIntN: + switch len(buf) { + case 1: + return int64(buf[0]) + case 2: + return int64(int16((binary.LittleEndian.Uint16(buf)))) + case 4: + return int64(int32(binary.LittleEndian.Uint32(buf))) + case 8: + return int64(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid size for INTNTYPE") + } + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + return decodeDecimal(ti.Prec, ti.Scale, buf) + case typeBitN: + if len(buf) != 1 { + badStreamPanicf("Invalid size for BITNTYPE") + } + return buf[0] != 0 + case typeFltN: + switch len(buf) { + case 4: + return float64(math.Float32frombits(binary.LittleEndian.Uint32(buf))) + case 8: + return math.Float64frombits(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid size for FLTNTYPE") + } + case typeMoneyN: + switch len(buf) { + case 4: + return decodeMoney4(buf) + case 8: + return decodeMoney(buf) + default: + badStreamPanicf("Invalid size for MONEYNTYPE") + } + case typeDateTim4: + return decodeDateTim4(buf) + case typeDateTime: + return decodeDateTime(buf) + case typeDateTimeN: + switch len(buf) { + case 4: + return decodeDateTim4(buf) + case 8: + return decodeDateTime(buf) + default: + badStreamPanicf("Invalid size for DATETIMENTYPE") + } + case typeChar, typeVarChar: + return decodeChar(ti.Collation, buf) + case typeBinary, typeVarBinary: + // a copy, because the backing array for ti.Buffer is reused + // and can be overwritten by the next row while this row waits + // in a buffered chan + cpy := make([]byte, len(buf)) + copy(cpy, buf) + return cpy + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if ti.Size > 0xff { + panic("Invalid size for BYTELEN_TYPE") + } + err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readShortLenType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.uint16() + if size == 0xffff { + return nil + } + r.ReadFull(ti.Buffer[:size]) + buf := ti.Buffer[:size] + switch ti.TypeId { + case typeBigVarChar, typeBigChar: + return decodeChar(ti.Collation, buf) + case typeBigVarBin, typeBigBinary: + // a copy, because the backing array for ti.Buffer is reused + // and can be overwritten by the next row while this row waits + // in a buffered chan + cpy := make([]byte, len(buf)) + copy(cpy, buf) + return cpy + case typeNVarChar, typeNChar: + return decodeNChar(buf) + case typeUdt: + return decodeUdt(*ti, buf) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if buf == nil { + err = binary.Write(w, binary.LittleEndian, uint16(0xffff)) + return + } + if ti.Size > 0xfffe { + panic("Invalid size for USHORTLEN_TYPE") + } + err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readLongLenType(ti *typeInfo, r *tdsBuffer) interface{} { + // information about this format can be found here: + // http://msdn.microsoft.com/en-us/library/dd304783.aspx + // and here: + // http://msdn.microsoft.com/en-us/library/dd357254.aspx + textptrsize := int(r.byte()) + if textptrsize == 0 { + return nil + } + textptr := make([]byte, textptrsize) + r.ReadFull(textptr) + timestamp := r.uint64() + _ = timestamp // ignore timestamp + size := r.int32() + if size == -1 { + return nil + } + buf := make([]byte, size) + r.ReadFull(buf) + switch ti.TypeId { + case typeText: + return decodeChar(ti.Collation, buf) + case typeImage: + return buf + case typeNText: + return decodeNChar(buf) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} +func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + //textptr + err = binary.Write(w, binary.LittleEndian, byte(0x10)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + //timestamp? + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + + err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readCollation(r *tdsBuffer) (res cp.Collation) { + res.LcidAndFlags = r.uint32() + res.SortId = r.byte() + return +} + +func writeCollation(w io.Writer, col cp.Collation) (err error) { + if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, col.SortId) + return +} + +// reads variant value +// http://msdn.microsoft.com/en-us/library/dd303302.aspx +func readVariantType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.int32() + if size == 0 { + return nil + } + vartype := r.byte() + propbytes := int32(r.byte()) + switch vartype { + case typeGuid: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return buf + case typeBit: + return r.byte() != 0 + case typeInt1: + return int64(r.byte()) + case typeInt2: + return int64(int16(r.uint16())) + case typeInt4: + return int64(r.int32()) + case typeInt8: + return int64(r.uint64()) + case typeDateTime: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTime(buf) + case typeDateTim4: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTim4(buf) + case typeFlt4: + return float64(math.Float32frombits(r.uint32())) + case typeFlt8: + return math.Float64frombits(r.uint64()) + case typeMoney4: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeMoney4(buf) + case typeMoney: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeMoney(buf) + case typeDateN: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDate(buf) + case typeTimeN: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeTime(scale, buf) + case typeDateTime2N: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTime2(scale, buf) + case typeDateTimeOffsetN: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTimeOffset(scale, buf) + case typeBigVarBin, typeBigBinary: + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return buf + case typeDecimalN, typeNumericN: + prec := r.byte() + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDecimal(prec, scale, buf) + case typeBigVarChar, typeBigChar: + col := readCollation(r) + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeChar(col, buf) + case typeNVarChar, typeNChar: + _ = readCollation(r) + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeNChar(buf) + default: + badStreamPanicf("Invalid variant typeid") + } + panic("shoulnd't get here") +} + +// partially length prefixed stream +// http://msdn.microsoft.com/en-us/library/dd340469.aspx +func readPLPType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.uint64() + var buf *bytes.Buffer + switch size { + case _PLP_NULL: + // null + return nil + case _UNKNOWN_PLP_LEN: + // size unknown + buf = bytes.NewBuffer(make([]byte, 0, 1000)) + default: + buf = bytes.NewBuffer(make([]byte, 0, size)) + } + for true { + chunksize := r.uint32() + if chunksize == 0 { + break + } + if _, err := io.CopyN(buf, r, int64(chunksize)); err != nil { + badStreamPanicf("Reading PLP type failed: %s", err.Error()) + } + } + switch ti.TypeId { + case typeXml: + return decodeXml(*ti, buf.Bytes()) + case typeBigVarChar, typeBigChar, typeText: + return decodeChar(ti.Collation, buf.Bytes()) + case typeBigVarBin, typeBigBinary, typeImage: + return buf.Bytes() + case typeNVarChar, typeNChar, typeNText: + return decodeNChar(buf.Bytes()) + case typeUdt: + return decodeUdt(*ti, buf.Bytes()) + } + panic("shoulnd't get here") +} + +func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if err = binary.Write(w, binary.LittleEndian, uint64(_UNKNOWN_PLP_LEN)); err != nil { + return + } + for { + chunksize := uint32(len(buf)) + if chunksize == 0 { + err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR)) + return + } + if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { + return + } + if _, err = w.Write(buf[:chunksize]); err != nil { + return + } + buf = buf[chunksize:] + } +} + +func readVarLen(ti *typeInfo, r *tdsBuffer) { + switch ti.TypeId { + case typeDateN: + ti.Size = 3 + ti.Reader = readByteLenType + ti.Buffer = make([]byte, ti.Size) + case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: + ti.Scale = r.byte() + switch ti.Scale { + case 0, 1, 2: + ti.Size = 3 + case 3, 4: + ti.Size = 4 + case 5, 6, 7: + ti.Size = 5 + default: + badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type") + } + switch ti.TypeId { + case typeDateTime2N: + ti.Size += 3 + case typeDateTimeOffsetN: + ti.Size += 5 + } + ti.Reader = readByteLenType + ti.Buffer = make([]byte, ti.Size) + case typeGuid, typeIntN, typeDecimal, typeNumeric, + typeBitN, typeDecimalN, typeNumericN, typeFltN, + typeMoneyN, typeDateTimeN, typeChar, + typeVarChar, typeBinary, typeVarBinary: + // byle len types + ti.Size = int(r.byte()) + ti.Buffer = make([]byte, ti.Size) + switch ti.TypeId { + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + ti.Prec = r.byte() + ti.Scale = r.byte() + } + ti.Reader = readByteLenType + case typeXml: + ti.XmlInfo.SchemaPresent = r.byte() + if ti.XmlInfo.SchemaPresent != 0 { + // dbname + ti.XmlInfo.DBName = r.BVarChar() + // owning schema + ti.XmlInfo.OwningSchema = r.BVarChar() + // xml schema collection + ti.XmlInfo.XmlSchemaCollection = r.UsVarChar() + } + ti.Reader = readPLPType + case typeUdt: + ti.Size = int(r.uint16()) + ti.UdtInfo.DBName = r.BVarChar() + ti.UdtInfo.SchemaName = r.BVarChar() + ti.UdtInfo.TypeName = r.BVarChar() + ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar() + + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readPLPType + case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, + typeNVarChar, typeNChar: + // short len types + ti.Size = int(r.uint16()) + switch ti.TypeId { + case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: + ti.Collation = readCollation(r) + } + if ti.Size == 0xffff { + ti.Reader = readPLPType + } else { + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readShortLenType + } + case typeText, typeImage, typeNText, typeVariant: + // LONGLEN_TYPE + ti.Size = int(r.int32()) + switch ti.TypeId { + case typeText, typeNText: + ti.Collation = readCollation(r) + // ignore tablenames + numparts := int(r.byte()) + for i := 0; i < numparts; i++ { + r.UsVarChar() + } + ti.Reader = readLongLenType + case typeImage: + // ignore tablenames + numparts := int(r.byte()) + for i := 0; i < numparts; i++ { + r.UsVarChar() + } + ti.Reader = readLongLenType + case typeVariant: + ti.Reader = readVariantType + } + default: + badStreamPanicf("Invalid type %d", ti.TypeId) + } + return +} + +func decodeMoney(buf []byte) []byte { + money := int64(uint64(buf[4]) | + uint64(buf[5])<<8 | + uint64(buf[6])<<16 | + uint64(buf[7])<<24 | + uint64(buf[0])<<32 | + uint64(buf[1])<<40 | + uint64(buf[2])<<48 | + uint64(buf[3])<<56) + return scaleBytes(strconv.FormatInt(money, 10), 4) +} + +func decodeMoney4(buf []byte) []byte { + money := int32(binary.LittleEndian.Uint32(buf[0:4])) + return scaleBytes(strconv.FormatInt(int64(money), 10), 4) +} + +func decodeGuid(buf []byte) []byte { + res := make([]byte, 16) + copy(res, buf) + return res +} + +func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { + var sign uint8 + sign = buf[0] + dec := Decimal{ + positive: sign != 0, + prec: prec, + scale: scale, + } + buf = buf[1:] + l := len(buf) / 4 + for i := 0; i < l; i++ { + dec.integer[i] = binary.LittleEndian.Uint32(buf[0:4]) + buf = buf[4:] + } + return dec.Bytes() +} + +// http://msdn.microsoft.com/en-us/library/ee780895.aspx +func decodeDateInt(buf []byte) (days int) { + days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + return +} + +func decodeDate(buf []byte) time.Time { + return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC) +} + +func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) { + var acc uint64 = 0 + for i := len(buf) - 1; i >= 0; i-- { + acc <<= 8 + acc |= uint64(buf[i]) + } + for i := 0; i < 7-int(scale); i++ { + acc *= 10 + } + nsbig := acc * 100 + sec = int(nsbig / 1000000000) + ns = int(nsbig % 1000000000) + return +} + +func decodeTime(scale uint8, buf []byte) time.Time { + sec, ns := decodeTimeInt(scale, buf) + return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC) +} + +func decodeDateTime2(scale uint8, buf []byte) time.Time { + timesize := len(buf) - 3 + sec, ns := decodeTimeInt(scale, buf[:timesize]) + days := decodeDateInt(buf[timesize:]) + return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC) +} + +func decodeDateTimeOffset(scale uint8, buf []byte) time.Time { + timesize := len(buf) - 3 - 2 + sec, ns := decodeTimeInt(scale, buf[:timesize]) + buf = buf[timesize:] + days := decodeDateInt(buf[:3]) + buf = buf[3:] + offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins + return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns, + time.FixedZone("", offset*60)) +} + +func divFloor(x int64, y int64) int64 { + q := x / y + r := x % y + if r != 0 && ((r < 0) != (y < 0)) { + q-- + } + return q +} + +func dateTime2(t time.Time) (days int32, ns int64) { + // number of days since Jan 1 1970 UTC + days64 := divFloor(t.Unix(), 24*60*60) + // number of days since Jan 1 1 UTC + days = int32(days64) + 1969*365 + 1969/4 - 1969/100 + 1969/400 + // number of seconds within day + secs := t.Unix() - days64*24*60*60 + // number of nanoseconds within day + ns = secs*1e9 + int64(t.Nanosecond()) + return +} + +func decodeChar(col cp.Collation, buf []byte) string { + return cp.CharsetToUTF8(col, buf) +} + +func decodeUcs2(buf []byte) string { + res, err := ucs22str(buf) + if err != nil { + badStreamPanicf("Invalid UCS2 encoding: %s", err.Error()) + } + return res +} + +func decodeNChar(buf []byte) string { + return decodeUcs2(buf) +} + +func decodeXml(ti typeInfo, buf []byte) string { + return decodeUcs2(buf) +} + +func decodeUdt(ti typeInfo, buf []byte) []byte { + return buf +} + +// makes go/sql type instance as described below +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func makeGoLangScanType(ti typeInfo) reflect.Type { + switch ti.TypeId { + case typeInt1: + return reflect.TypeOf(int64(0)) + case typeInt2: + return reflect.TypeOf(int64(0)) + case typeInt4: + return reflect.TypeOf(int64(0)) + case typeInt8: + return reflect.TypeOf(int64(0)) + case typeFlt4: + return reflect.TypeOf(float64(0)) + case typeIntN: + switch ti.Size { + case 1: + return reflect.TypeOf(int64(0)) + case 2: + return reflect.TypeOf(int64(0)) + case 4: + return reflect.TypeOf(int64(0)) + case 8: + return reflect.TypeOf(int64(0)) + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return reflect.TypeOf(float64(0)) + case typeFltN: + switch ti.Size { + case 4: + return reflect.TypeOf(float64(0)) + case 8: + return reflect.TypeOf(float64(0)) + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return reflect.TypeOf([]byte{}) + case typeVarChar: + return reflect.TypeOf("") + case typeNVarChar: + return reflect.TypeOf("") + case typeBit, typeBitN: + return reflect.TypeOf(true) + case typeDecimalN, typeNumericN: + return reflect.TypeOf([]byte{}) + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return reflect.TypeOf([]byte{}) + case 8: + return reflect.TypeOf([]byte{}) + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return reflect.TypeOf(time.Time{}) + case typeDateTime: + return reflect.TypeOf(time.Time{}) + case typeDateTimeN: + switch ti.Size { + case 4: + return reflect.TypeOf(time.Time{}) + case 8: + return reflect.TypeOf(time.Time{}) + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return reflect.TypeOf(time.Time{}) + case typeDateN: + return reflect.TypeOf(time.Time{}) + case typeTimeN: + return reflect.TypeOf(time.Time{}) + case typeDateTimeOffsetN: + return reflect.TypeOf(time.Time{}) + case typeBigVarChar: + return reflect.TypeOf("") + case typeBigChar: + return reflect.TypeOf("") + case typeNChar: + return reflect.TypeOf("") + case typeGuid: + return reflect.TypeOf([]byte{}) + case typeXml: + return reflect.TypeOf("") + case typeText: + return reflect.TypeOf("") + case typeNText: + return reflect.TypeOf("") + case typeImage: + return reflect.TypeOf([]byte{}) + case typeBigBinary: + return reflect.TypeOf([]byte{}) + case typeVariant: + return reflect.TypeOf(nil) + default: + panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId)) + } +} + +func makeDecl(ti typeInfo) string { + switch ti.TypeId { + case typeNull: + // maybe we should use something else here + // this is tested in TestNull + return "nvarchar(1)" + case typeInt1: + return "tinyint" + case typeInt2: + return "smallint" + case typeInt4: + return "int" + case typeInt8: + return "bigint" + case typeFlt4: + return "real" + case typeIntN: + switch ti.Size { + case 1: + return "tinyint" + case 2: + return "smallint" + case 4: + return "int" + case 8: + return "bigint" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "float" + case typeFltN: + switch ti.Size { + case 4: + return "real" + case 8: + return "float" + default: + panic("invalid size of FLNNTYPE") + } + case typeDecimal, typeDecimalN: + return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale) + case typeNumeric, typeNumericN: + return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale) + case typeMoney4: + return "smallmoney" + case typeMoney: + return "money" + case typeMoneyN: + switch ti.Size { + case 4: + return "smallmoney" + case 8: + return "money" + default: + panic("invalid size of MONEYNTYPE") + } + case typeBigVarBin: + if ti.Size > 8000 || ti.Size == 0 { + return "varbinary(max)" + } else { + return fmt.Sprintf("varbinary(%d)", ti.Size) + } + case typeNChar: + return fmt.Sprintf("nchar(%d)", ti.Size/2) + case typeBigChar, typeChar: + return fmt.Sprintf("char(%d)", ti.Size) + case typeBigVarChar, typeVarChar: + if ti.Size > 4000 || ti.Size == 0 { + return fmt.Sprintf("varchar(max)") + } else { + return fmt.Sprintf("varchar(%d)", ti.Size) + } + case typeNVarChar: + if ti.Size > 8000 || ti.Size == 0 { + return "nvarchar(max)" + } else { + return fmt.Sprintf("nvarchar(%d)", ti.Size/2) + } + case typeBit, typeBitN: + return "bit" + case typeDateN: + return "date" + case typeDateTim4: + return "smalldatetime" + case typeDateTime: + return "datetime" + case typeDateTimeN: + switch ti.Size { + case 4: + return "smalldatetime" + case 8: + return "datetime" + default: + panic("invalid size of DATETIMNTYPE") + } + case typeTimeN: + return "time" + case typeDateTime2N: + return fmt.Sprintf("datetime2(%d)", ti.Scale) + case typeDateTimeOffsetN: + return fmt.Sprintf("datetimeoffset(%d)", ti.Scale) + case typeText: + return "text" + case typeNText: + return "ntext" + case typeUdt: + return ti.UdtInfo.TypeName + case typeGuid: + return "uniqueidentifier" + default: + panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId)) + } +} + +// makes go/sql type name as described below +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func makeGoLangTypeName(ti typeInfo) string { + switch ti.TypeId { + case typeInt1: + return "TINYINT" + case typeInt2: + return "SMALLINT" + case typeInt4: + return "INT" + case typeInt8: + return "BIGINT" + case typeFlt4: + return "REAL" + case typeIntN: + switch ti.Size { + case 1: + return "TINYINT" + case 2: + return "SMALLINT" + case 4: + return "INT" + case 8: + return "BIGINT" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "FLOAT" + case typeFltN: + switch ti.Size { + case 4: + return "REAL" + case 8: + return "FLOAT" + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return "VARBINARY" + case typeVarChar: + return "VARCHAR" + case typeNVarChar: + return "NVARCHAR" + case typeBit, typeBitN: + return "BIT" + case typeDecimalN, typeNumericN: + return "DECIMAL" + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return "SMALLMONEY" + case 8: + return "MONEY" + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return "SMALLDATETIME" + case typeDateTime: + return "DATETIME" + case typeDateTimeN: + switch ti.Size { + case 4: + return "SMALLDATETIME" + case 8: + return "DATETIME" + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return "DATETIME2" + case typeDateN: + return "DATE" + case typeTimeN: + return "TIME" + case typeDateTimeOffsetN: + return "DATETIMEOFFSET" + case typeBigVarChar: + return "VARCHAR" + case typeBigChar: + return "CHAR" + case typeNChar: + return "NCHAR" + case typeGuid: + return "UNIQUEIDENTIFIER" + case typeXml: + return "XML" + case typeText: + return "TEXT" + case typeNText: + return "NTEXT" + case typeImage: + return "IMAGE" + case typeVariant: + return "SQL_VARIANT" + case typeBigBinary: + return "BINARY" + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId)) + } +} + +// makes go/sql type length as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypeLength(ti typeInfo) (int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, false + case typeInt2: + return 0, false + case typeInt4: + return 0, false + case typeInt8: + return 0, false + case typeFlt4: + return 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, false + case 2: + return 0, false + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, false + case typeDecimalN, typeNumericN: + return 0, false + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, false + case typeDateN: + return 0, false + case typeTimeN: + return 0, false + case typeDateTimeOffsetN: + return 0, false + case typeBigVarBin: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeVarChar: + return int64(ti.Size), true + case typeBigVarChar: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeBigChar: + return int64(ti.Size), true + case typeNVarChar: + if ti.Size == 0xffff { + return 2147483645 / 2, true + } else { + return int64(ti.Size) / 2, true + } + case typeNChar: + return int64(ti.Size) / 2, true + case typeGuid: + return 0, false + case typeXml: + return 1073741822, true + case typeText: + return 2147483647, true + case typeNText: + return 1073741823, true + case typeImage: + return 2147483647, true + case typeVariant: + return 0, false + case typeBigBinary: + return 0, false + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId)) + } +} + +// makes go/sql type precision and scale as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, 0, false + case typeInt2: + return 0, 0, false + case typeInt4: + return 0, 0, false + case typeInt8: + return 0, 0, false + case typeFlt4: + return 0, 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, 0, false + case 2: + return 0, 0, false + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, 0, false + case typeDecimalN, typeNumericN: + return int64(ti.Prec), int64(ti.Scale), true + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, 0, false + case typeDateN: + return 0, 0, false + case typeTimeN: + return 0, 0, false + case typeDateTimeOffsetN: + return 0, 0, false + case typeBigVarBin: + return 0, 0, false + case typeVarChar: + return 0, 0, false + case typeBigVarChar: + return 0, 0, false + case typeBigChar: + return 0, 0, false + case typeNVarChar: + return 0, 0, false + case typeNChar: + return 0, 0, false + case typeGuid: + return 0, 0, false + case typeXml: + return 0, 0, false + case typeText: + return 0, 0, false + case typeNText: + return 0, 0, false + case typeImage: + return 0, 0, false + case typeVariant: + return 0, 0, false + case typeBigBinary: + return 0, 0, false + default: + panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId)) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go new file mode 100644 index 0000000..c8ef314 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go @@ -0,0 +1,74 @@ +package mssql + +import ( + "database/sql/driver" + "encoding/hex" + "errors" + "fmt" +) + +type UniqueIdentifier [16]byte + +func (u *UniqueIdentifier) Scan(v interface{}) error { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + switch vt := v.(type) { + case []byte: + if len(vt) != 16 { + return errors.New("mssql: invalid UniqueIdentifier length") + } + + var raw UniqueIdentifier + + copy(raw[:], vt) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + *u = raw + + return nil + case string: + if len(vt) != 36 { + return errors.New("mssql: invalid UniqueIdentifier string length") + } + + b := []byte(vt) + for i, c := range b { + switch c { + case '-': + b = append(b[:i], b[i+1:]...) + } + } + + _, err := hex.Decode(u[:], []byte(b)) + return err + default: + return fmt.Errorf("mssql: cannot convert %T to UniqueIdentifier", v) + } +} + +func (u UniqueIdentifier) Value() (driver.Value, error) { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + raw := make([]byte, len(u)) + copy(raw, u[:]) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + + return raw, nil +} + +func (u UniqueIdentifier) String() string { + return fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/vendor/github.com/duosecurity/duo_api_golang/LICENSE b/vendor/github.com/duosecurity/duo_api_golang/LICENSE new file mode 100644 index 0000000..2510e98 --- /dev/null +++ b/vendor/github.com/duosecurity/duo_api_golang/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2015, Duo Security, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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/vendor/github.com/duosecurity/duo_api_golang/README.md b/vendor/github.com/duosecurity/duo_api_golang/README.md new file mode 100644 index 0000000..9216f8c --- /dev/null +++ b/vendor/github.com/duosecurity/duo_api_golang/README.md @@ -0,0 +1,14 @@ +# Overview + +**duo_client** - Demonstration client to call Duo API methods +with Go. + +# Duo Auth API + +The Duo Auth API provides a low-level API for adding strong two-factor +authentication to applications that cannot directly display rich web +content. + +For more information see the Duo Auth API guide: + + diff --git a/vendor/github.com/duosecurity/duo_api_golang/authapi/authapi.go b/vendor/github.com/duosecurity/duo_api_golang/authapi/authapi.go new file mode 100644 index 0000000..27d80a2 --- /dev/null +++ b/vendor/github.com/duosecurity/duo_api_golang/authapi/authapi.go @@ -0,0 +1,382 @@ +package authapi + +import ( + "encoding/json" + "net/url" + "strconv" + + "github.com/duosecurity/duo_api_golang" +) + +type AuthApi struct { + duoapi.DuoApi +} + +// Build a new Duo Auth API object. +// api is a duoapi.DuoApi object used to make the Duo Rest API calls. +// Example: authapi.NewAuthApi(*duoapi.NewDuoApi(ikey,skey,host,userAgent,duoapi.SetTimeout(10*time.Second))) +func NewAuthApi(api duoapi.DuoApi) *AuthApi { + return &AuthApi{api} +} + +// API calls will return a StatResult object. On success, Stat is 'OK'. +// On error, Stat is 'FAIL', and Code, Message, and Message_Detail +// contain error information. +type StatResult struct { + Stat string + Code *int32 + Message *string + Message_Detail *string +} + +// Return object for the 'Ping' API call. +type PingResult struct { + StatResult + Response struct { + Time int64 + } +} + +// Duo's Ping method. https://www.duosecurity.com/docs/authapi#/ping +// This is an unsigned Duo Rest API call which returns the Duo system's time. +// Use this method to determine whether your system time is in sync with Duo's. +func (api *AuthApi) Ping() (*PingResult, error) { + _, body, err := api.Call("GET", "/auth/v2/ping", nil, duoapi.UseTimeout) + if err != nil { + return nil, err + } + ret := &PingResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// Return object for the 'Check' API call. +type CheckResult struct { + StatResult + Response struct { + Time int64 + } +} + +// Call Duo's Check method. https://www.duosecurity.com/docs/authapi#/check +// Check is a signed Duo API call, which returns the Duo system's time. +// Use this method to determine whether your ikey, skey and host are correct, +// and whether your system time is in sync with Duo's. +func (api *AuthApi) Check() (*CheckResult, error) { + _, body, err := api.SignedCall("GET", "/auth/v2/check", nil, duoapi.UseTimeout) + if err != nil { + return nil, err + } + ret := &CheckResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// Return object for the 'Logo' API call. +type LogoResult struct { + StatResult + png *[]byte +} + +// Duo's Logo method. https://www.duosecurity.com/docs/authapi#/logo +// If the API call is successful, the configured logo png is returned. Othwerwise, +// error information is returned in the LogoResult return value. +func (api *AuthApi) Logo() (*LogoResult, error) { + resp, body, err := api.SignedCall("GET", "/auth/v2/logo", nil, duoapi.UseTimeout) + if err != nil { + return nil, err + } + if resp.StatusCode == 200 { + ret := &LogoResult{StatResult: StatResult{Stat: "OK"}, + png: &body} + return ret, nil + } + ret := &LogoResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// Optional parameter for the Enroll method. +func EnrollUsername(username string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("username", username) + } +} + +// Optional parameter for the Enroll method. +func EnrollValidSeconds(secs uint64) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("valid_secs", strconv.FormatUint(secs, 10)) + } +} + +// Enroll return type. +type EnrollResult struct { + StatResult + Response struct { + Activation_Barcode string + Activation_Code string + Expiration int64 + User_Id string + Username string + } +} + +// Duo's Enroll method. https://www.duosecurity.com/docs/authapi#/enroll +// Use EnrollUsername() to include the optional username parameter. +// Use EnrollValidSeconds() to change the default validation time limit that the +// user has to complete enrollment. +func (api *AuthApi) Enroll(options ...func(*url.Values)) (*EnrollResult, error) { + opts := url.Values{} + for _, o := range options { + o(&opts) + } + + _, body, err := api.SignedCall("POST", "/auth/v2/enroll", opts, duoapi.UseTimeout) + if err != nil { + return nil, err + } + ret := &EnrollResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// Response is "success", "invalid" or "waiting". +type EnrollStatusResult struct { + StatResult + Response string +} + +// Duo's EnrollStatus method. https://www.duosecurity.com/docs/authapi#/enroll_status +// Return the status of an outstanding Enrollment. +func (api *AuthApi) EnrollStatus(userid string, + activationCode string) (*EnrollStatusResult, error) { + queryArgs := url.Values{} + queryArgs.Set("user_id", userid) + queryArgs.Set("activation_code", activationCode) + + _, body, err := api.SignedCall("POST", + "/auth/v2/enroll_status", + queryArgs, + duoapi.UseTimeout) + + if err != nil { + return nil, err + } + ret := &EnrollStatusResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// Preauth return type. +type PreauthResult struct { + StatResult + Response struct { + Result string + Status_Msg string + Enroll_Portal_Url string + Devices []struct { + Device string + Type string + Name string + Number string + Capabilities []string + } + } +} + +func PreauthUserId(userid string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("user_id", userid) + } +} + +func PreauthUsername(username string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("username", username) + } +} + +func PreauthIpAddr(ip string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("ipaddr", ip) + } +} + +func PreauthTrustedToken(trustedtoken string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("trusted_device_token", trustedtoken) + } +} + +// Duo's Preauth method. https://www.duosecurity.com/docs/authapi#/preauth +// options Optional values to include in the preauth call. +// Use PreauthUserId to specify the user_id parameter. +// Use PreauthUsername to specify the username parameter. You must +// specify PreauthUserId or PreauthUsername, but not both. +// Use PreauthIpAddr to include the ipaddr parameter, the ip address +// of the client attempting authroization. +// Use PreauthTrustedToken to specify the trusted_device_token parameter. +func (api *AuthApi) Preauth(options ...func(*url.Values)) (*PreauthResult, error) { + opts := url.Values{} + for _, o := range options { + o(&opts) + } + _, body, err := api.SignedCall("POST", "/auth/v2/preauth", opts, duoapi.UseTimeout) + if err != nil { + return nil, err + } + ret := &PreauthResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +func AuthUserId(userid string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("user_id", userid) + } +} + +func AuthUsername(username string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("username", username) + } +} + +func AuthIpAddr(ip string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("ipaddr", ip) + } +} + +func AuthAsync() func(*url.Values) { + return func(opts *url.Values) { + opts.Set("async", "1") + } +} + +func AuthDevice(device string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("device", device) + } +} + +func AuthType(type_ string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("type", type_) + } +} + +func AuthDisplayUsername(username string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("display_username", username) + } +} + +func AuthPushinfo(pushinfo string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("pushinfo", pushinfo) + } +} + +func AuthPasscode(passcode string) func(*url.Values) { + return func(opts *url.Values) { + opts.Set("passcode", passcode) + } +} + +// Auth return type. +type AuthResult struct { + StatResult + Response struct { + // Synchronous + Result string + Status string + Status_Msg string + Trusted_Device_Token string + // Asynchronous + Txid string + } +} + +// Duo's Auth method. https://www.duosecurity.com/docs/authapi#/auth +// Factor must be one of 'auto', 'push', 'passcode', 'sms' or 'phone'. +// Use AuthUserId to specify the user_id. +// Use AuthUsername to speicy the username. You must specify either AuthUserId +// or AuthUsername, but not both. +// Use AuthIpAddr to include the client's IP address. +// Use AuthAsync to toggle whether the call blocks for the user's response or not. +// If used asynchronously, get the auth status with the AuthStatus method. +// When using factor 'push', use AuthDevice to specify the device ID to push to. +// When using factor 'push', use AuthType to display some extra auth text to the user. +// When using factor 'push', use AuthDisplayUsername to display some extra text +// to the user. +// When using factor 'push', use AuthPushInfo to include some URL-encoded key/value +// pairs to display to the user. +// When using factor 'passcode', use AuthPasscode to specify the passcode entered +// by the user. +// When using factor 'sms' or 'phone', use AuthDevice to specify which device +// should receive the SMS or phone call. +func (api *AuthApi) Auth(factor string, options ...func(*url.Values)) (*AuthResult, error) { + params := url.Values{} + for _, o := range options { + o(¶ms) + } + params.Set("factor", factor) + + var apiOps []duoapi.DuoApiOption + if _, ok := params["async"]; ok == true { + apiOps = append(apiOps, duoapi.UseTimeout) + } + + _, body, err := api.SignedCall("POST", "/auth/v2/auth", params, apiOps...) + if err != nil { + return nil, err + } + ret := &AuthResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} + +// AuthStatus return type. +type AuthStatusResult struct { + StatResult + Response struct { + Result string + Status string + Status_Msg string + Trusted_Device_Token string + } +} + +// Duo's auth_status method. https://www.duosecurity.com/docs/authapi#/auth_status +// When using the Auth call in async mode, use this method to retrieve the +// result of the authentication attempt. +// txid is returned by the Auth call. +func (api *AuthApi) AuthStatus(txid string) (*AuthStatusResult, error) { + opts := url.Values{} + opts.Set("txid", txid) + _, body, err := api.SignedCall("GET", "/auth/v2/auth_status", opts) + if err != nil { + return nil, err + } + ret := &AuthStatusResult{} + if err = json.Unmarshal(body, ret); err != nil { + return nil, err + } + return ret, nil +} diff --git a/vendor/github.com/duosecurity/duo_api_golang/duoapi.go b/vendor/github.com/duosecurity/duo_api_golang/duoapi.go new file mode 100644 index 0000000..a00ba8a --- /dev/null +++ b/vendor/github.com/duosecurity/duo_api_golang/duoapi.go @@ -0,0 +1,377 @@ +package duoapi + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +var spaceReplacer *strings.Replacer = strings.NewReplacer("+", "%20") + +func canonParams(params url.Values) string { + // Values must be in sorted order + for key, val := range params { + sort.Strings(val) + params[key] = val + } + // Encode will place Keys in sorted order + ordered_params := params.Encode() + // Encoder turns spaces into +, but we need %XX escaping + return spaceReplacer.Replace(ordered_params) +} + +func canonicalize(method string, + host string, + uri string, + params url.Values, + date string) string { + var canon [5]string + canon[0] = date + canon[1] = strings.ToUpper(method) + canon[2] = strings.ToLower(host) + canon[3] = uri + canon[4] = canonParams(params) + return strings.Join(canon[:], "\n") +} + +func sign(ikey string, + skey string, + method string, + host string, + uri string, + date string, + params url.Values) string { + canon := canonicalize(method, host, uri, params, date) + mac := hmac.New(sha1.New, []byte(skey)) + mac.Write([]byte(canon)) + sig := hex.EncodeToString(mac.Sum(nil)) + auth := ikey + ":" + sig + return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) +} + +type DuoApi struct { + ikey string + skey string + host string + userAgent string + apiClient *http.Client + authClient *http.Client +} + +type apiOptions struct { + timeout time.Duration + insecure bool + proxy func(*http.Request) (*url.URL, error) +} + +// Optional parameter for NewDuoApi, used to configure timeouts on API calls. +func SetTimeout(timeout time.Duration) func(*apiOptions) { + return func(opts *apiOptions) { + opts.timeout = timeout + return + } +} + +// Optional parameter for testing only. Bypasses all TLS certificate validation. +func SetInsecure() func(*apiOptions) { + return func(opts *apiOptions) { + opts.insecure = true + } +} + +// Optional parameter for NewDuoApi, used to configure an HTTP Connect proxy +// server for all outbound communications. +func SetProxy(proxy func(*http.Request) (*url.URL, error)) func(*apiOptions) { + return func(opts *apiOptions) { + opts.proxy = proxy + } +} + +// Build an return a DuoApi struct. +// ikey is your Duo integration key +// skey is your Duo integration secret key +// host is your Duo host +// userAgent allows you to specify the user agent string used when making +// the web request to Duo. +// options are optional parameters. Use SetTimeout() to specify a timeout value +// for Rest API calls. Use SetProxy() to specify proxy settings for Duo API calls. +// +// Example: duoapi.NewDuoApi(ikey,skey,host,userAgent,duoapi.SetTimeout(10*time.Second)) +func NewDuoApi(ikey string, + skey string, + host string, + userAgent string, + options ...func(*apiOptions)) *DuoApi { + opts := apiOptions{proxy: http.ProxyFromEnvironment} + for _, o := range options { + o(&opts) + } + + // Certificate pinning + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM([]byte(duoPinnedCert)) + + tr := &http.Transport{ + Proxy: opts.proxy, + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + InsecureSkipVerify: opts.insecure, + }, + } + return &DuoApi{ + ikey: ikey, + skey: skey, + host: host, + userAgent: userAgent, + apiClient: &http.Client{ + Timeout: opts.timeout, + Transport: tr, + }, + authClient: &http.Client{ + Transport: tr, + }, + } +} + +type requestOptions struct { + timeout bool +} + +type DuoApiOption func(*requestOptions) + +// Pass to Request or SignedRequest to configure a timeout on the request +func UseTimeout(opts *requestOptions) { + opts.timeout = true +} + +func (duoapi *DuoApi) buildOptions(options ...DuoApiOption) *requestOptions { + opts := &requestOptions{} + for _, o := range options { + o(opts) + } + return opts +} + +// Make an unsigned Duo Rest API call. See Duo's online documentation +// for the available REST API's. +// method is POST or GET +// uri is the URI of the Duo Rest call +// params HTTP query parameters to include in the call. +// options Optional parameters. Use UseTimeout to toggle whether the +// Duo Rest API call should timeout or not. +// +// Example: duo.Call("GET", "/auth/v2/ping", nil, duoapi.UseTimeout) +func (duoapi *DuoApi) Call(method string, + uri string, + params url.Values, + options ...DuoApiOption) (*http.Response, []byte, error) { + opts := duoapi.buildOptions(options...) + + client := duoapi.authClient + if opts.timeout { + client = duoapi.apiClient + } + + url := url.URL{ + Scheme: "https", + Host: duoapi.host, + Path: uri, + RawQuery: params.Encode(), + } + request, err := http.NewRequest(method, url.String(), nil) + if err != nil { + return nil, nil, err + } + resp, err := client.Do(request) + var body []byte + if err == nil { + body, err = ioutil.ReadAll(resp.Body) + resp.Body.Close() + } + return resp, body, err +} + +// Make a signed Duo Rest API call. See Duo's online documentation +// for the available REST API's. +// method is POST or GET +// uri is the URI of the Duo Rest call +// params HTTP query parameters to include in the call. +// options Optional parameters. Use UseTimeout to toggle whether the +// Duo Rest API call should timeout or not. +// +// Example: duo.SignedCall("GET", "/auth/v2/check", nil, duoapi.UseTimeout) +func (duoapi *DuoApi) SignedCall(method string, + uri string, + params url.Values, + options ...DuoApiOption) (*http.Response, []byte, error) { + opts := duoapi.buildOptions(options...) + + now := time.Now().UTC().Format(time.RFC1123Z) + auth_sig := sign(duoapi.ikey, duoapi.skey, method, duoapi.host, uri, now, params) + + url := url.URL{ + Scheme: "https", + Host: duoapi.host, + Path: uri, + } + method = strings.ToUpper(method) + + if method == "GET" { + url.RawQuery = params.Encode() + } + + request, err := http.NewRequest(method, url.String(), nil) + if err != nil { + return nil, nil, err + } + request.Header.Set("Authorization", auth_sig) + request.Header.Set("Date", now) + + if method == "POST" || method == "PUT" { + request.Body = ioutil.NopCloser(strings.NewReader(params.Encode())) + request.Header.Set("Content-type", "application/x-www-form-urlencoded") + } + + client := duoapi.authClient + if opts.timeout { + client = duoapi.apiClient + } + resp, err := client.Do(request) + var body []byte + if err == nil { + body, err = ioutil.ReadAll(resp.Body) + resp.Body.Close() + } + return resp, body, err +} + +const duoPinnedCert string = ` +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +subject= /C=US/O=SecureTrust Corporation/CN=SecureTrust CA +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +subject= /C=US/O=SecureTrust Corporation/CN=Secure Global CA +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE-----` diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE b/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE new file mode 100644 index 0000000..5782c72 --- /dev/null +++ b/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014, Elazar Leibovich +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. + +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 HOLDER 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/vendor/github.com/elazarl/go-bindata-assetfs/README.md b/vendor/github.com/elazarl/go-bindata-assetfs/README.md new file mode 100644 index 0000000..27ee48f --- /dev/null +++ b/vendor/github.com/elazarl/go-bindata-assetfs/README.md @@ -0,0 +1,46 @@ +# go-bindata-assetfs + +Serve embedded files from [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) with `net/http`. + +[GoDoc](http://godoc.org/github.com/elazarl/go-bindata-assetfs) + +### Installation + +Install with + + $ go get github.com/jteeuwen/go-bindata/... + $ go get github.com/elazarl/go-bindata-assetfs/... + +### Creating embedded data + +Usage is identical to [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) usage, +instead of running `go-bindata` run `go-bindata-assetfs`. + +The tool will create a `bindata_assetfs.go` file, which contains the embedded data. + +A typical use case is + + $ go-bindata-assetfs data/... + +### Using assetFS in your code + +The generated file provides an `assetFS()` function that returns a `http.Filesystem` +wrapping the embedded files. What you usually want to do is: + + http.Handle("/", http.FileServer(assetFS())) + +This would run an HTTP server serving the embedded files. + +## Without running binary tool + +You can always just run the `go-bindata` tool, and then + +use + + import "github.com/elazarl/go-bindata-assetfs" + ... + http.Handle("/", + http.FileServer( + &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: "data"})) + +to serve files embedded from the `data` directory. diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go new file mode 100644 index 0000000..04f6d7a --- /dev/null +++ b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go @@ -0,0 +1,167 @@ +package assetfs + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + "net/http" + "os" + "path" + "path/filepath" + "strings" + "time" +) + +var ( + defaultFileTimestamp = time.Now() +) + +// FakeFile implements os.FileInfo interface for a given path and size +type FakeFile struct { + // Path is the path of this file + Path string + // Dir marks of the path is a directory + Dir bool + // Len is the length of the fake file, zero if it is a directory + Len int64 + // Timestamp is the ModTime of this file + Timestamp time.Time +} + +func (f *FakeFile) Name() string { + _, name := filepath.Split(f.Path) + return name +} + +func (f *FakeFile) Mode() os.FileMode { + mode := os.FileMode(0644) + if f.Dir { + return mode | os.ModeDir + } + return mode +} + +func (f *FakeFile) ModTime() time.Time { + return f.Timestamp +} + +func (f *FakeFile) Size() int64 { + return f.Len +} + +func (f *FakeFile) IsDir() bool { + return f.Mode().IsDir() +} + +func (f *FakeFile) Sys() interface{} { + return nil +} + +// AssetFile implements http.File interface for a no-directory file with content +type AssetFile struct { + *bytes.Reader + io.Closer + FakeFile +} + +func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile { + if timestamp.IsZero() { + timestamp = defaultFileTimestamp + } + return &AssetFile{ + bytes.NewReader(content), + ioutil.NopCloser(nil), + FakeFile{name, false, int64(len(content)), timestamp}} +} + +func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) { + return nil, errors.New("not a directory") +} + +func (f *AssetFile) Size() int64 { + return f.FakeFile.Size() +} + +func (f *AssetFile) Stat() (os.FileInfo, error) { + return f, nil +} + +// AssetDirectory implements http.File interface for a directory +type AssetDirectory struct { + AssetFile + ChildrenRead int + Children []os.FileInfo +} + +func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory { + fileinfos := make([]os.FileInfo, 0, len(children)) + for _, child := range children { + _, err := fs.AssetDir(filepath.Join(name, child)) + fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}}) + } + return &AssetDirectory{ + AssetFile{ + bytes.NewReader(nil), + ioutil.NopCloser(nil), + FakeFile{name, true, 0, time.Time{}}, + }, + 0, + fileinfos} +} + +func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) { + if count <= 0 { + return f.Children, nil + } + if f.ChildrenRead+count > len(f.Children) { + count = len(f.Children) - f.ChildrenRead + } + rv := f.Children[f.ChildrenRead : f.ChildrenRead+count] + f.ChildrenRead += count + return rv, nil +} + +func (f *AssetDirectory) Stat() (os.FileInfo, error) { + return f, nil +} + +// AssetFS implements http.FileSystem, allowing +// embedded files to be served from net/http package. +type AssetFS struct { + // Asset should return content of file in path if exists + Asset func(path string) ([]byte, error) + // AssetDir should return list of files in the path + AssetDir func(path string) ([]string, error) + // AssetInfo should return the info of file in path if exists + AssetInfo func(path string) (os.FileInfo, error) + // Prefix would be prepended to http requests + Prefix string +} + +func (fs *AssetFS) Open(name string) (http.File, error) { + name = path.Join(fs.Prefix, name) + if len(name) > 0 && name[0] == '/' { + name = name[1:] + } + if b, err := fs.Asset(name); err == nil { + timestamp := defaultFileTimestamp + if fs.AssetInfo != nil { + if info, err := fs.AssetInfo(name); err == nil { + timestamp = info.ModTime() + } + } + return NewAssetFile(name, b, timestamp), nil + } + if children, err := fs.AssetDir(name); err == nil { + return NewAssetDirectory(name, children, fs), nil + } else { + // If the error is not found, return an error that will + // result in a 404 error. Otherwise the server returns + // a 500 error for files not found. + if strings.Contains(err.Error(), "not found") { + return nil, os.ErrNotExist + } + return nil, err + } +} diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/doc.go b/vendor/github.com/elazarl/go-bindata-assetfs/doc.go new file mode 100644 index 0000000..a664249 --- /dev/null +++ b/vendor/github.com/elazarl/go-bindata-assetfs/doc.go @@ -0,0 +1,13 @@ +// assetfs allows packages to serve static content embedded +// with the go-bindata tool with the standard net/http package. +// +// See https://github.com/jteeuwen/go-bindata for more information +// about embedding binary data with go-bindata. +// +// Usage example, after running +// $ go-bindata data/... +// use: +// http.Handle("/", +// http.FileServer( +// &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "data"})) +package assetfs diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml new file mode 100644 index 0000000..95f8a1f --- /dev/null +++ b/vendor/github.com/fatih/color/.travis.yml @@ -0,0 +1,5 @@ +language: go +go: + - 1.8.x + - tip + diff --git a/vendor/github.com/fatih/color/Gopkg.lock b/vendor/github.com/fatih/color/Gopkg.lock new file mode 100644 index 0000000..7d879e9 --- /dev/null +++ b/vendor/github.com/fatih/color/Gopkg.lock @@ -0,0 +1,27 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/fatih/color/Gopkg.toml b/vendor/github.com/fatih/color/Gopkg.toml new file mode 100644 index 0000000..ff1617f --- /dev/null +++ b/vendor/github.com/fatih/color/Gopkg.toml @@ -0,0 +1,30 @@ + +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + name = "github.com/mattn/go-colorable" + version = "0.0.9" + +[[constraint]] + name = "github.com/mattn/go-isatty" + version = "0.0.3" diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md new file mode 100644 index 0000000..25fdaf6 --- /dev/null +++ b/vendor/github.com/fatih/color/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Fatih Arslan + +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/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md new file mode 100644 index 0000000..3fc9544 --- /dev/null +++ b/vendor/github.com/fatih/color/README.md @@ -0,0 +1,179 @@ +# Color [![GoDoc](https://godoc.org/github.com/fatih/color?status.svg)](https://godoc.org/github.com/fatih/color) [![Build Status](https://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color) + + + +Color lets you use colorized outputs in terms of [ANSI Escape +Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It +has support for Windows too! The API can be used in several ways, pick one that +suits you. + + +![Color](https://i.imgur.com/c1JI0lA.png) + + +## Install + +```bash +go get github.com/fatih/color +``` + +Note that the `vendor` folder is here for stability. Remove the folder if you +already have the dependencies in your GOPATH. + +## Examples + +### Standard colors + +```go +// Print with default helper functions +color.Cyan("Prints text in cyan.") + +// A newline will be appended automatically +color.Blue("Prints %s in blue.", "text") + +// These are using the default foreground colors +color.Red("We have red") +color.Magenta("And many others ..") + +``` + +### Mix and reuse colors + +```go +// Create a new color object +c := color.New(color.FgCyan).Add(color.Underline) +c.Println("Prints cyan text with an underline.") + +// Or just add them to New() +d := color.New(color.FgCyan, color.Bold) +d.Printf("This prints bold cyan %s\n", "too!.") + +// Mix up foreground and background colors, create new mixes! +red := color.New(color.FgRed) + +boldRed := red.Add(color.Bold) +boldRed.Println("This will print text in bold red.") + +whiteBackground := red.Add(color.BgWhite) +whiteBackground.Println("Red text with white background.") +``` + +### Use your own output (io.Writer) + +```go +// Use your own io.Writer output +color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + +blue := color.New(color.FgBlue) +blue.Fprint(writer, "This will print text in blue.") +``` + +### Custom print functions (PrintFunc) + +```go +// Create a custom print function for convenience +red := color.New(color.FgRed).PrintfFunc() +red("Warning") +red("Error: %s", err) + +// Mix up multiple attributes +notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() +notice("Don't forget this...") +``` + +### Custom fprint functions (FprintFunc) + +```go +blue := color.New(FgBlue).FprintfFunc() +blue(myWriter, "important notice: %s", stars) + +// Mix up with multiple attributes +success := color.New(color.Bold, color.FgGreen).FprintlnFunc() +success(myWriter, "Don't forget this...") +``` + +### Insert into noncolor strings (SprintFunc) + +```go +// Create SprintXxx functions to mix strings with other non-colorized strings: +yellow := color.New(color.FgYellow).SprintFunc() +red := color.New(color.FgRed).SprintFunc() +fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error")) + +info := color.New(color.FgWhite, color.BgGreen).SprintFunc() +fmt.Printf("This %s rocks!\n", info("package")) + +// Use helper functions +fmt.Println("This", color.RedString("warning"), "should be not neglected.") +fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.") + +// Windows supported too! Just don't forget to change the output to color.Output +fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) +``` + +### Plug into existing code + +```go +// Use handy standard colors +color.Set(color.FgYellow) + +fmt.Println("Existing text will now be in yellow") +fmt.Printf("This one %s\n", "too") + +color.Unset() // Don't forget to unset + +// You can mix up parameters +color.Set(color.FgMagenta, color.Bold) +defer color.Unset() // Use it in your function + +fmt.Println("All text will now be bold magenta.") +``` + +### Disable/Enable color + +There might be a case where you want to explicitly disable/enable color output. the +`go-isatty` package will automatically disable color output for non-tty output streams +(for example if the output were piped directly to `less`) + +`Color` has support to disable/enable colors both globally and for single color +definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You +can easily disable the color output with: + +```go + +var flagNoColor = flag.Bool("no-color", false, "Disable color output") + +if *flagNoColor { + color.NoColor = true // disables colorized output +} +``` + +It also has support for single color definitions (local). You can +disable/enable color output on the fly: + +```go +c := color.New(color.FgCyan) +c.Println("Prints cyan text") + +c.DisableColor() +c.Println("This is printed without any color") + +c.EnableColor() +c.Println("This prints again cyan...") +``` + +## Todo + +* Save/Return previous values +* Evaluate fmt.Formatter interface + + +## Credits + + * [Fatih Arslan](https://github.com/fatih) + * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) + +## License + +The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details + diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go new file mode 100644 index 0000000..91c8e9f --- /dev/null +++ b/vendor/github.com/fatih/color/color.go @@ -0,0 +1,603 @@ +package color + +import ( + "fmt" + "io" + "os" + "strconv" + "strings" + "sync" + + "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" +) + +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = os.Getenv("TERM") == "dumb" || + (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // Error defines a color supporting writer for os.Stderr. + Error = colorable.NewColorableStderr() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) + +// Color defines a custom color object which is defined by SGR parameters. +type Color struct { + params []Attribute + noColor *bool +} + +// Attribute defines a single SGR Code +type Attribute int + +const escape = "\x1b" + +// Base attributes +const ( + Reset Attribute = iota + Bold + Faint + Italic + Underline + BlinkSlow + BlinkRapid + ReverseVideo + Concealed + CrossedOut +) + +// Foreground text colors +const ( + FgBlack Attribute = iota + 30 + FgRed + FgGreen + FgYellow + FgBlue + FgMagenta + FgCyan + FgWhite +) + +// Foreground Hi-Intensity text colors +const ( + FgHiBlack Attribute = iota + 90 + FgHiRed + FgHiGreen + FgHiYellow + FgHiBlue + FgHiMagenta + FgHiCyan + FgHiWhite +) + +// Background text colors +const ( + BgBlack Attribute = iota + 40 + BgRed + BgGreen + BgYellow + BgBlue + BgMagenta + BgCyan + BgWhite +) + +// Background Hi-Intensity text colors +const ( + BgHiBlack Attribute = iota + 100 + BgHiRed + BgHiGreen + BgHiYellow + BgHiBlue + BgHiMagenta + BgHiCyan + BgHiWhite +) + +// New returns a newly created color object. +func New(value ...Attribute) *Color { + c := &Color{params: make([]Attribute, 0)} + c.Add(value...) + return c +} + +// Set sets the given parameters immediately. It will change the color of +// output with the given SGR parameters until color.Unset() is called. +func Set(p ...Attribute) *Color { + c := New(p...) + c.Set() + return c +} + +// Unset resets all escape attributes and clears the output. Usually should +// be called after Set(). +func Unset() { + if NoColor { + return + } + + fmt.Fprintf(Output, "%s[%dm", escape, Reset) +} + +// Set sets the SGR sequence. +func (c *Color) Set() *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(Output, c.format()) + return c +} + +func (c *Color) unset() { + if c.isNoColorSet() { + return + } + + Unset() +} + +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + +// Add is used to chain SGR parameters. Use as many as parameters to combine +// and create custom color objects. Example: Add(color.FgRed, color.Underline). +func (c *Color) Add(value ...Attribute) *Color { + c.params = append(c.params, value...) + return c +} + +func (c *Color) prepend(value Attribute) { + c.params = append(c.params, 0) + copy(c.params[1:], c.params[0:]) + c.params[0] = value +} + +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} + +// Print formats using the default formats for its operands and writes to +// standard output. Spaces are added between operands when neither is a +// string. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Print(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprint(Output, a...) +} + +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + +// Printf formats according to a format specifier and writes to standard output. +// It returns the number of bytes written and any write error encountered. +// This is the standard fmt.Printf() method wrapped with the given color. +func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintf(Output, format, a...) +} + +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + +// Println formats using the default formats for its operands and writes to +// standard output. Spaces are always added between operands and a newline is +// appended. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Println(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintln(Output, a...) +} + +// Sprint is just like Print, but returns a string instead of printing it. +func (c *Color) Sprint(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) +} + +// Sprintln is just like Println, but returns a string instead of printing it. +func (c *Color) Sprintln(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) +} + +// Sprintf is just like Printf, but returns a string instead of printing it. +func (c *Color) Sprintf(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) +} + +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + +// PrintFunc returns a new function that prints the passed arguments as +// colorized with color.Print(). +func (c *Color) PrintFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } +} + +// PrintfFunc returns a new function that prints the passed arguments as +// colorized with color.Printf(). +func (c *Color) PrintfFunc() func(format string, a ...interface{}) { + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } +} + +// PrintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Println(). +func (c *Color) PrintlnFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Println(a...) + } +} + +// SprintFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprint(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output, example: +// +// put := New(FgYellow).SprintFunc() +// fmt.Fprintf(color.Output, "This is a %s", put("warning")) +func (c *Color) SprintFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) + } +} + +// SprintfFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintf(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { + return func(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) + } +} + +// SprintlnFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintln(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintlnFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) + } +} + +// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m" +// an example output might be: "1;36" -> bold cyan +func (c *Color) sequence() string { + format := make([]string, len(c.params)) + for i, v := range c.params { + format[i] = strconv.Itoa(int(v)) + } + + return strings.Join(format, ";") +} + +// wrap wraps the s string with the colors attributes. The string is ready to +// be printed. +func (c *Color) wrap(s string) string { + if c.isNoColorSet() { + return s + } + + return c.format() + s + c.unformat() +} + +func (c *Color) format() string { + return fmt.Sprintf("%s[%sm", escape, c.sequence()) +} + +func (c *Color) unformat() string { + return fmt.Sprintf("%s[%dm", escape, Reset) +} + +// DisableColor disables the color output. Useful to not change any existing +// code and still being able to output. Can be used for flags like +// "--no-color". To enable back use EnableColor() method. +func (c *Color) DisableColor() { + c.noColor = boolPtr(true) +} + +// EnableColor enables the color output. Use it in conjunction with +// DisableColor(). Otherwise this method has no side effects. +func (c *Color) EnableColor() { + c.noColor = boolPtr(false) +} + +func (c *Color) isNoColorSet() bool { + // check first if we have user setted action + if c.noColor != nil { + return *c.noColor + } + + // if not return the global option, which is disabled by default + return NoColor +} + +// Equals returns a boolean value indicating whether two colors are equal. +func (c *Color) Equals(c2 *Color) bool { + if len(c.params) != len(c2.params) { + return false + } + + for _, attr := range c.params { + if !c2.attrExists(attr) { + return false + } + } + + return true +} + +func (c *Color) attrExists(a Attribute) bool { + for _, attr := range c.params { + if attr == a { + return true + } + } + + return false +} + +func boolPtr(v bool) *bool { + return &v +} + +func getCachedColor(p Attribute) *Color { + colorsCacheMu.Lock() + defer colorsCacheMu.Unlock() + + c, ok := colorsCache[p] + if !ok { + c = New(p) + colorsCache[p] = c + } + + return c +} + +func colorPrint(format string, p Attribute, a ...interface{}) { + c := getCachedColor(p) + + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + if len(a) == 0 { + c.Print(format) + } else { + c.Printf(format, a...) + } +} + +func colorString(format string, p Attribute, a ...interface{}) string { + c := getCachedColor(p) + + if len(a) == 0 { + return c.SprintFunc()(format) + } + + return c.SprintfFunc()(format, a...) +} + +// Black is a convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } + +// Red is a convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } + +// Green is a convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } + +// Yellow is a convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } + +// Blue is a convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } + +// Magenta is a convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } + +// Cyan is a convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } + +// White is a convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } + +// BlackString is a convenient helper function to return a string with black +// foreground. +func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } + +// RedString is a convenient helper function to return a string with red +// foreground. +func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } + +// GreenString is a convenient helper function to return a string with green +// foreground. +func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } + +// YellowString is a convenient helper function to return a string with yellow +// foreground. +func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } + +// BlueString is a convenient helper function to return a string with blue +// foreground. +func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } + +// MagentaString is a convenient helper function to return a string with magenta +// foreground. +func MagentaString(format string, a ...interface{}) string { + return colorString(format, FgMagenta, a...) +} + +// CyanString is a convenient helper function to return a string with cyan +// foreground. +func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } + +// WhiteString is a convenient helper function to return a string with white +// foreground. +func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } + +// HiBlack is a convenient helper function to print with hi-intensity black foreground. A +// newline is appended to format by default. +func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) } + +// HiRed is a convenient helper function to print with hi-intensity red foreground. A +// newline is appended to format by default. +func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) } + +// HiGreen is a convenient helper function to print with hi-intensity green foreground. A +// newline is appended to format by default. +func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) } + +// HiYellow is a convenient helper function to print with hi-intensity yellow foreground. +// A newline is appended to format by default. +func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) } + +// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A +// newline is appended to format by default. +func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) } + +// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground. +// A newline is appended to format by default. +func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) } + +// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A +// newline is appended to format by default. +func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) } + +// HiWhite is a convenient helper function to print with hi-intensity white foreground. A +// newline is appended to format by default. +func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) } + +// HiBlackString is a convenient helper function to return a string with hi-intensity black +// foreground. +func HiBlackString(format string, a ...interface{}) string { + return colorString(format, FgHiBlack, a...) +} + +// HiRedString is a convenient helper function to return a string with hi-intensity red +// foreground. +func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) } + +// HiGreenString is a convenient helper function to return a string with hi-intensity green +// foreground. +func HiGreenString(format string, a ...interface{}) string { + return colorString(format, FgHiGreen, a...) +} + +// HiYellowString is a convenient helper function to return a string with hi-intensity yellow +// foreground. +func HiYellowString(format string, a ...interface{}) string { + return colorString(format, FgHiYellow, a...) +} + +// HiBlueString is a convenient helper function to return a string with hi-intensity blue +// foreground. +func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) } + +// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta +// foreground. +func HiMagentaString(format string, a ...interface{}) string { + return colorString(format, FgHiMagenta, a...) +} + +// HiCyanString is a convenient helper function to return a string with hi-intensity cyan +// foreground. +func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) } + +// HiWhiteString is a convenient helper function to return a string with hi-intensity white +// foreground. +func HiWhiteString(format string, a ...interface{}) string { + return colorString(format, FgHiWhite, a...) +} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go new file mode 100644 index 0000000..cf1e965 --- /dev/null +++ b/vendor/github.com/fatih/color/doc.go @@ -0,0 +1,133 @@ +/* +Package color is an ANSI color package to output colorized or SGR defined +output to the standard output. The API can be used in several way, pick one +that suits you. + +Use simple and default helper functions with predefined foreground colors: + + color.Cyan("Prints text in cyan.") + + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") + + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") + + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") + +However there are times where custom color mixes are required. Below are some +examples to create custom color objects and use the print functions of each +separate color object. + + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") + + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") + + + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) + + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") + + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") + + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") + +You can create PrintXxx functions to simplify even more: + + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) + + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") + +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + + +Or create SprintXxx functions to mix strings with other non-colorized strings: + + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() + + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) + +Windows support is enabled by default. All Print functions work as intended. +However only for color.SprintXXX functions, user should use fmt.FprintXXX and +set the output to color.Output: + + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + +Using with existing code is possible. Just use the Set() method to set the +standard output to the given parameters. That way a rewrite of an existing +code is not required. + + // Use handy standard colors. + color.Set(color.FgYellow) + + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") + + color.Unset() // don't forget to unset + + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function + + fmt.Println("All text will be now bold magenta.") + +There might be a case where you want to disable color output (for example to +pipe the standard output of your app to somewhere else). `Color` has support to +disable colors both globally and for single color definition. For example +suppose you have a CLI app and a `--no-color` bool flag. You can easily disable +the color output with: + + var flagNoColor = flag.Bool("no-color", false, "Disable color output") + + if *flagNoColor { + color.NoColor = true // disables colorized output + } + +It also has support for single color definitions (local). You can +disable/enable color output on the fly: + + c := color.New(color.FgCyan) + c.Println("Prints cyan text") + + c.DisableColor() + c.Println("This is printed without any color") + + c.EnableColor() + c.Println("This prints again cyan...") +*/ +package color diff --git a/vendor/github.com/ghodss/yaml/.gitignore b/vendor/github.com/ghodss/yaml/.gitignore new file mode 100644 index 0000000..e256a31 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.gitignore @@ -0,0 +1,20 @@ +# OSX leaves these everywhere on SMB shares +._* + +# Eclipse files +.classpath +.project +.settings/** + +# Emacs save files +*~ + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# Go test binaries +*.test diff --git a/vendor/github.com/ghodss/yaml/.travis.yml b/vendor/github.com/ghodss/yaml/.travis.yml new file mode 100644 index 0000000..0e9d6ed --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: + - 1.3 + - 1.4 +script: + - go test + - go build diff --git a/vendor/github.com/ghodss/yaml/LICENSE b/vendor/github.com/ghodss/yaml/LICENSE new file mode 100644 index 0000000..7805d36 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/LICENSE @@ -0,0 +1,50 @@ +The MIT License (MIT) + +Copyright (c) 2014 Sam Ghods + +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. + + +Copyright (c) 2012 The Go Authors. 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/vendor/github.com/ghodss/yaml/README.md b/vendor/github.com/ghodss/yaml/README.md new file mode 100644 index 0000000..0200f75 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/README.md @@ -0,0 +1,121 @@ +# YAML marshaling and unmarshaling support for Go + +[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"age"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + age: 30 + name: John + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err = yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/vendor/github.com/ghodss/yaml/fields.go b/vendor/github.com/ghodss/yaml/fields.go new file mode 100644 index 0000000..5860074 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/fields.go @@ -0,0 +1,501 @@ +// 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 yaml + +import ( + "bytes" + "encoding" + "encoding/json" + "reflect" + "sort" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// if it encounters an Unmarshaler, indirect stops and returns that. +// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { + break + } + if v.IsNil() { + if v.CanSet() { + v.Set(reflect.New(v.Type().Elem())) + } else { + v = reflect.New(v.Type().Elem()) + } + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(json.Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + v = v.Elem() + } + return nil, nil, v +} + +// A field represents a single field found in a struct. +type field struct { + name string + nameBytes []byte // []byte(name) + equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent + + tag bool + index []int + typ reflect.Type + omitEmpty bool + quoted bool +} + +func fillField(f field) field { + f.nameBytes = []byte(f.name) + f.equalFold = foldFunc(f.nameBytes) + return f +} + +// byName sorts field by name, breaking ties with depth, +// then breaking ties with "name came from json tag", then +// breaking ties with index sequence. +type byName []field + +func (x byName) Len() int { return len(x) } + +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byName) Less(i, j int) bool { + if x[i].name != x[j].name { + return x[i].name < x[j].name + } + if len(x[i].index) != len(x[j].index) { + return len(x[i].index) < len(x[j].index) + } + if x[i].tag != x[j].tag { + return x[i].tag + } + return byIndex(x).Less(i, j) +} + +// byIndex sorts field by index sequence. +type byIndex []field + +func (x byIndex) Len() int { return len(x) } + +func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byIndex) Less(i, j int) bool { + for k, xik := range x[i].index { + if k >= len(x[j].index) { + return false + } + if xik != x[j].index[k] { + return xik < x[j].index[k] + } + } + return len(x[i].index) < len(x[j].index) +} + +// typeFields returns a list of fields that JSON should recognize for the given type. +// The algorithm is breadth-first search over the set of structs to include - the top struct +// and then any reachable anonymous structs. +func typeFields(t reflect.Type) []field { + // Anonymous fields to explore at the current level and the next. + current := []field{} + next := []field{{typ: t}} + + // Count of queued names for current level and the next. + count := map[reflect.Type]int{} + nextCount := map[reflect.Type]int{} + + // Types already visited at an earlier level. + visited := map[reflect.Type]bool{} + + // Fields found. + var fields []field + + for len(next) > 0 { + current, next = next, current[:0] + count, nextCount = nextCount, map[reflect.Type]int{} + + for _, f := range current { + if visited[f.typ] { + continue + } + visited[f.typ] = true + + // Scan f.typ for fields to include. + for i := 0; i < f.typ.NumField(); i++ { + sf := f.typ.Field(i) + if sf.PkgPath != "" { // unexported + continue + } + tag := sf.Tag.Get("json") + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if !isValidTag(name) { + name = "" + } + index := make([]int, len(f.index)+1) + copy(index, f.index) + index[len(f.index)] = i + + ft := sf.Type + if ft.Name() == "" && ft.Kind() == reflect.Ptr { + // Follow pointer. + ft = ft.Elem() + } + + // Record found field and index sequence. + if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { + tagged := name != "" + if name == "" { + name = sf.Name + } + fields = append(fields, fillField(field{ + name: name, + tag: tagged, + index: index, + typ: ft, + omitEmpty: opts.Contains("omitempty"), + quoted: opts.Contains("string"), + })) + if count[f.typ] > 1 { + // If there were multiple instances, add a second, + // so that the annihilation code will see a duplicate. + // It only cares about the distinction between 1 or 2, + // so don't bother generating any more copies. + fields = append(fields, fields[len(fields)-1]) + } + continue + } + + // Record new anonymous struct to explore in next round. + nextCount[ft]++ + if nextCount[ft] == 1 { + next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) + } + } + } + } + + sort.Sort(byName(fields)) + + // Delete all fields that are hidden by the Go rules for embedded fields, + // except that fields with JSON tags are promoted. + + // The fields are sorted in primary order of name, secondary order + // of field index length. Loop over names; for each name, delete + // hidden fields by choosing the one dominant field that survives. + out := fields[:0] + for advance, i := 0, 0; i < len(fields); i += advance { + // One iteration per name. + // Find the sequence of fields with the name of this first field. + fi := fields[i] + name := fi.name + for advance = 1; i+advance < len(fields); advance++ { + fj := fields[i+advance] + if fj.name != name { + break + } + } + if advance == 1 { // Only one field with this name + out = append(out, fi) + continue + } + dominant, ok := dominantField(fields[i : i+advance]) + if ok { + out = append(out, dominant) + } + } + + fields = out + sort.Sort(byIndex(fields)) + + return fields +} + +// dominantField looks through the fields, all of which are known to +// have the same name, to find the single field that dominates the +// others using Go's embedding rules, modified by the presence of +// JSON tags. If there are multiple top-level fields, the boolean +// will be false: This condition is an error in Go and we skip all +// the fields. +func dominantField(fields []field) (field, bool) { + // The fields are sorted in increasing index-length order. The winner + // must therefore be one with the shortest index length. Drop all + // longer entries, which is easy: just truncate the slice. + length := len(fields[0].index) + tagged := -1 // Index of first tagged field. + for i, f := range fields { + if len(f.index) > length { + fields = fields[:i] + break + } + if f.tag { + if tagged >= 0 { + // Multiple tagged fields at the same level: conflict. + // Return no field. + return field{}, false + } + tagged = i + } + } + if tagged >= 0 { + return fields[tagged], true + } + // All remaining fields have the same length. If there's more than one, + // we have a conflict (two fields named "X" at the same level) and we + // return no field. + if len(fields) > 1 { + return field{}, false + } + return fields[0], true +} + +var fieldCache struct { + sync.RWMutex + m map[reflect.Type][]field +} + +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. +func cachedTypeFields(t reflect.Type) []field { + fieldCache.RLock() + f := fieldCache.m[t] + fieldCache.RUnlock() + if f != nil { + return f + } + + // Compute fields without lock. + // Might duplicate effort but won't hold other computations back. + f = typeFields(t) + if f == nil { + f = []field{} + } + + fieldCache.Lock() + if fieldCache.m == nil { + fieldCache.m = map[reflect.Type][]field{} + } + fieldCache.m[t] = f + fieldCache.Unlock() + return f +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + default: + if !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } + } + } + return true +} + +const ( + caseMask = ^byte(0x20) // Mask to ignore case in ASCII. + kelvin = '\u212a' + smallLongEss = '\u017f' +) + +// foldFunc returns one of four different case folding equivalence +// functions, from most general (and slow) to fastest: +// +// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 +// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') +// 3) asciiEqualFold, no special, but includes non-letters (including _) +// 4) simpleLetterEqualFold, no specials, no non-letters. +// +// The letters S and K are special because they map to 3 runes, not just 2: +// * S maps to s and to U+017F 'ſ' Latin small letter long s +// * k maps to K and to U+212A 'K' Kelvin sign +// See http://play.golang.org/p/tTxjOc0OGo +// +// The returned function is specialized for matching against s and +// should only be given s. It's not curried for performance reasons. +func foldFunc(s []byte) func(s, t []byte) bool { + nonLetter := false + special := false // special letter + for _, b := range s { + if b >= utf8.RuneSelf { + return bytes.EqualFold + } + upper := b & caseMask + if upper < 'A' || upper > 'Z' { + nonLetter = true + } else if upper == 'K' || upper == 'S' { + // See above for why these letters are special. + special = true + } + } + if special { + return equalFoldRight + } + if nonLetter { + return asciiEqualFold + } + return simpleLetterEqualFold +} + +// equalFoldRight is a specialization of bytes.EqualFold when s is +// known to be all ASCII (including punctuation), but contains an 's', +// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. +// See comments on foldFunc. +func equalFoldRight(s, t []byte) bool { + for _, sb := range s { + if len(t) == 0 { + return false + } + tb := t[0] + if tb < utf8.RuneSelf { + if sb != tb { + sbUpper := sb & caseMask + if 'A' <= sbUpper && sbUpper <= 'Z' { + if sbUpper != tb&caseMask { + return false + } + } else { + return false + } + } + t = t[1:] + continue + } + // sb is ASCII and t is not. t must be either kelvin + // sign or long s; sb must be s, S, k, or K. + tr, size := utf8.DecodeRune(t) + switch sb { + case 's', 'S': + if tr != smallLongEss { + return false + } + case 'k', 'K': + if tr != kelvin { + return false + } + default: + return false + } + t = t[size:] + + } + if len(t) > 0 { + return false + } + return true +} + +// asciiEqualFold is a specialization of bytes.EqualFold for use when +// s is all ASCII (but may contain non-letters) and contains no +// special-folding letters. +// See comments on foldFunc. +func asciiEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, sb := range s { + tb := t[i] + if sb == tb { + continue + } + if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { + if sb&caseMask != tb&caseMask { + return false + } + } else { + return false + } + } + return true +} + +// simpleLetterEqualFold is a specialization of bytes.EqualFold for +// use when s is all ASCII letters (no underscores, etc) and also +// doesn't contain 'k', 'K', 's', or 'S'. +// See comments on foldFunc. +func simpleLetterEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, b := range s { + if b&caseMask != t[i]&caseMask { + return false + } + } + return true +} + +// tagOptions is the string following a comma in a struct field's "json" +// tag, or the empty string. It does not include the leading comma. +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx], tagOptions(tag[idx+1:]) + } + return tag, tagOptions("") +} + +// Contains reports whether a comma-separated list of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var next string + i := strings.Index(s, ",") + if i >= 0 { + s, next = s[:i], s[i+1:] + } + if s == optionName { + return true + } + s = next + } + return false +} diff --git a/vendor/github.com/ghodss/yaml/yaml.go b/vendor/github.com/ghodss/yaml/yaml.go new file mode 100644 index 0000000..4fb4054 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml.go @@ -0,0 +1,277 @@ +package yaml + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strconv" + + "gopkg.in/yaml.v2" +) + +// Marshals the object into JSON then converts JSON to YAML and returns the +// YAML. +func Marshal(o interface{}) ([]byte, error) { + j, err := json.Marshal(o) + if err != nil { + return nil, fmt.Errorf("error marshaling into JSON: %v", err) + } + + y, err := JSONToYAML(j) + if err != nil { + return nil, fmt.Errorf("error converting JSON to YAML: %v", err) + } + + return y, nil +} + +// Converts YAML to JSON then uses JSON to unmarshal into an object. +func Unmarshal(y []byte, o interface{}) error { + vo := reflect.ValueOf(o) + j, err := yamlToJSON(y, &vo) + if err != nil { + return fmt.Errorf("error converting YAML to JSON: %v", err) + } + + err = json.Unmarshal(j, o) + if err != nil { + return fmt.Errorf("error unmarshaling JSON: %v", err) + } + + return nil +} + +// Convert JSON to YAML. +func JSONToYAML(j []byte) ([]byte, error) { + // Convert the JSON to an object. + var jsonObj interface{} + // We are using yaml.Unmarshal here (instead of json.Unmarshal) because the + // Go JSON library doesn't try to pick the right number type (int, float, + // etc.) when unmarshalling to interface{}, it just picks float64 + // universally. go-yaml does go through the effort of picking the right + // number type, so we can preserve number type throughout this process. + err := yaml.Unmarshal(j, &jsonObj) + if err != nil { + return nil, err + } + + // Marshal this object into YAML. + return yaml.Marshal(jsonObj) +} + +// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through +// this method should be a no-op. +// +// Things YAML can do that are not supported by JSON: +// * In YAML you can have binary and null keys in your maps. These are invalid +// in JSON. (int and float keys are converted to strings.) +// * Binary data in YAML with the !!binary tag is not supported. If you want to +// use binary data with this library, encode the data as base64 as usual but do +// not use the !!binary tag in your YAML. This will ensure the original base64 +// encoded data makes it all the way through to the JSON. +func YAMLToJSON(y []byte) ([]byte, error) { + return yamlToJSON(y, nil) +} + +func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { + // Convert the YAML to an object. + var yamlObj interface{} + err := yaml.Unmarshal(y, &yamlObj) + if err != nil { + return nil, err + } + + // YAML objects are not completely compatible with JSON objects (e.g. you + // can have non-string keys in YAML). So, convert the YAML-compatible object + // to a JSON-compatible object, failing with an error if irrecoverable + // incompatibilties happen along the way. + jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget) + if err != nil { + return nil, err + } + + // Convert this object to JSON and return the data. + return json.Marshal(jsonObj) +} + +func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) { + var err error + + // Resolve jsonTarget to a concrete value (i.e. not a pointer or an + // interface). We pass decodingNull as false because we're not actually + // decoding into the value, we're just checking if the ultimate target is a + // string. + if jsonTarget != nil { + ju, tu, pv := indirect(*jsonTarget, false) + // We have a JSON or Text Umarshaler at this level, so we can't be trying + // to decode into a string. + if ju != nil || tu != nil { + jsonTarget = nil + } else { + jsonTarget = &pv + } + } + + // If yamlObj is a number or a boolean, check if jsonTarget is a string - + // if so, coerce. Else return normal. + // If yamlObj is a map or array, find the field that each key is + // unmarshaling to, and when you recurse pass the reflect.Value for that + // field back into this function. + switch typedYAMLObj := yamlObj.(type) { + case map[interface{}]interface{}: + // JSON does not support arbitrary keys in a map, so we must convert + // these keys to strings. + // + // From my reading of go-yaml v2 (specifically the resolve function), + // keys can only have the types string, int, int64, float64, binary + // (unsupported), or null (unsupported). + strMap := make(map[string]interface{}) + for k, v := range typedYAMLObj { + // Resolve the key to a string first. + var keyString string + switch typedKey := k.(type) { + case string: + keyString = typedKey + case int: + keyString = strconv.Itoa(typedKey) + case int64: + // go-yaml will only return an int64 as a key if the system + // architecture is 32-bit and the key's value is between 32-bit + // and 64-bit. Otherwise the key type will simply be int. + keyString = strconv.FormatInt(typedKey, 10) + case float64: + // Stolen from go-yaml to use the same conversion to string as + // the go-yaml library uses to convert float to string when + // Marshaling. + s := strconv.FormatFloat(typedKey, 'g', -1, 32) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + keyString = s + case bool: + if typedKey { + keyString = "true" + } else { + keyString = "false" + } + default: + return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", + reflect.TypeOf(k), k, v) + } + + // jsonTarget should be a struct or a map. If it's a struct, find + // the field it's going to map to and pass its reflect.Value. If + // it's a map, find the element type of the map and pass the + // reflect.Value created from that type. If it's neither, just pass + // nil - JSON conversion will error for us if it's a real issue. + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Struct { + keyBytes := []byte(keyString) + // Find the field that the JSON library would use. + var f *field + fields := cachedTypeFields(t.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, keyBytes) { + f = ff + break + } + // Do case-insensitive comparison. + if f == nil && ff.equalFold(ff.nameBytes, keyBytes) { + f = ff + } + } + if f != nil { + // Find the reflect.Value of the most preferential + // struct field. + jtf := t.Field(f.index[0]) + strMap[keyString], err = convertToJSONableObject(v, &jtf) + if err != nil { + return nil, err + } + continue + } + } else if t.Kind() == reflect.Map { + // Create a zero value of the map's element type to use as + // the JSON target. + jtv := reflect.Zero(t.Type().Elem()) + strMap[keyString], err = convertToJSONableObject(v, &jtv) + if err != nil { + return nil, err + } + continue + } + } + strMap[keyString], err = convertToJSONableObject(v, nil) + if err != nil { + return nil, err + } + } + return strMap, nil + case []interface{}: + // We need to recurse into arrays in case there are any + // map[interface{}]interface{}'s inside and to convert any + // numbers to strings. + + // If jsonTarget is a slice (which it really should be), find the + // thing it's going to map to. If it's not a slice, just pass nil + // - JSON conversion will error for us if it's a real issue. + var jsonSliceElemValue *reflect.Value + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Slice { + // By default slices point to nil, but we need a reflect.Value + // pointing to a value of the slice type, so we create one here. + ev := reflect.Indirect(reflect.New(t.Type().Elem())) + jsonSliceElemValue = &ev + } + } + + // Make and use a new array. + arr := make([]interface{}, len(typedYAMLObj)) + for i, v := range typedYAMLObj { + arr[i], err = convertToJSONableObject(v, jsonSliceElemValue) + if err != nil { + return nil, err + } + } + return arr, nil + default: + // If the target type is a string and the YAML type is a number, + // convert the YAML type to a string. + if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String { + // Based on my reading of go-yaml, it may return int, int64, + // float64, or uint64. + var s string + switch typedVal := typedYAMLObj.(type) { + case int: + s = strconv.FormatInt(int64(typedVal), 10) + case int64: + s = strconv.FormatInt(typedVal, 10) + case float64: + s = strconv.FormatFloat(typedVal, 'g', -1, 32) + case uint64: + s = strconv.FormatUint(typedVal, 10) + case bool: + if typedVal { + s = "true" + } else { + s = "false" + } + } + if len(s) > 0 { + yamlObj = interface{}(s) + } + } + return yamlObj, nil + } + + return nil, nil +} diff --git a/vendor/github.com/go-errors/errors/.travis.yml b/vendor/github.com/go-errors/errors/.travis.yml new file mode 100644 index 0000000..9d00fdd --- /dev/null +++ b/vendor/github.com/go-errors/errors/.travis.yml @@ -0,0 +1,5 @@ +language: go + +go: + - "1.8.x" + - "1.10.x" diff --git a/vendor/github.com/go-errors/errors/LICENSE.MIT b/vendor/github.com/go-errors/errors/LICENSE.MIT new file mode 100644 index 0000000..c9a5b2e --- /dev/null +++ b/vendor/github.com/go-errors/errors/LICENSE.MIT @@ -0,0 +1,7 @@ +Copyright (c) 2015 Conrad Irwin + +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/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md new file mode 100644 index 0000000..5d4f187 --- /dev/null +++ b/vendor/github.com/go-errors/errors/README.md @@ -0,0 +1,66 @@ +go-errors/errors +================ + +[![Build Status](https://travis-ci.org/go-errors/errors.svg?branch=master)](https://travis-ci.org/go-errors/errors) + +Package errors adds stacktrace support to errors in go. + +This is particularly useful when you want to understand the state of execution +when an error was returned unexpectedly. + +It provides the type \*Error which implements the standard golang error +interface, so you can use this library interchangably with code that is +expecting a normal error return. + +Usage +----- + +Full documentation is available on +[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple +example: + +```go +package crashy + +import "github.com/go-errors/errors" + +var Crashed = errors.Errorf("oh dear") + +func Crash() error { + return errors.New(Crashed) +} +``` + +This can be called as follows: + +```go +package main + +import ( + "crashy" + "fmt" + "github.com/go-errors/errors" +) + +func main() { + err := crashy.Crash() + if err != nil { + if errors.Is(err, crashy.Crashed) { + fmt.Println(err.(*errors.Error).ErrorStack()) + } else { + panic(err) + } + } +} +``` + +Meta-fu +------- + +This package was original written to allow reporting to +[Bugsnag](https://bugsnag.com/) from +[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar +packages by Facebook and Dropbox, it was moved to one canonical location so +everyone can benefit. + +This package is licensed under the MIT license, see LICENSE.MIT for details. diff --git a/vendor/github.com/go-errors/errors/cover.out b/vendor/github.com/go-errors/errors/cover.out new file mode 100644 index 0000000..ab18b05 --- /dev/null +++ b/vendor/github.com/go-errors/errors/cover.out @@ -0,0 +1,89 @@ +mode: set +github.com/go-errors/errors/stackframe.go:27.51,30.25 2 1 +github.com/go-errors/errors/stackframe.go:33.2,38.8 3 1 +github.com/go-errors/errors/stackframe.go:30.25,32.3 1 0 +github.com/go-errors/errors/stackframe.go:43.47,44.31 1 1 +github.com/go-errors/errors/stackframe.go:47.2,47.48 1 1 +github.com/go-errors/errors/stackframe.go:44.31,46.3 1 1 +github.com/go-errors/errors/stackframe.go:52.42,56.16 3 1 +github.com/go-errors/errors/stackframe.go:60.2,60.60 1 1 +github.com/go-errors/errors/stackframe.go:56.16,58.3 1 0 +github.com/go-errors/errors/stackframe.go:64.55,67.16 2 1 +github.com/go-errors/errors/stackframe.go:71.2,72.61 2 1 +github.com/go-errors/errors/stackframe.go:76.2,76.66 1 1 +github.com/go-errors/errors/stackframe.go:67.16,69.3 1 0 +github.com/go-errors/errors/stackframe.go:72.61,74.3 1 0 +github.com/go-errors/errors/stackframe.go:79.56,91.63 3 1 +github.com/go-errors/errors/stackframe.go:95.2,95.53 1 1 +github.com/go-errors/errors/stackframe.go:100.2,101.18 2 1 +github.com/go-errors/errors/stackframe.go:91.63,94.3 2 1 +github.com/go-errors/errors/stackframe.go:95.53,98.3 2 1 +github.com/go-errors/errors/error.go:70.32,73.23 2 1 +github.com/go-errors/errors/error.go:80.2,85.3 3 1 +github.com/go-errors/errors/error.go:74.2,75.10 1 1 +github.com/go-errors/errors/error.go:76.2,77.28 1 1 +github.com/go-errors/errors/error.go:92.43,95.23 2 1 +github.com/go-errors/errors/error.go:104.2,109.3 3 1 +github.com/go-errors/errors/error.go:96.2,97.11 1 1 +github.com/go-errors/errors/error.go:98.2,99.10 1 1 +github.com/go-errors/errors/error.go:100.2,101.28 1 1 +github.com/go-errors/errors/error.go:115.39,117.19 1 1 +github.com/go-errors/errors/error.go:121.2,121.29 1 1 +github.com/go-errors/errors/error.go:125.2,125.43 1 1 +github.com/go-errors/errors/error.go:129.2,129.14 1 1 +github.com/go-errors/errors/error.go:117.19,119.3 1 1 +github.com/go-errors/errors/error.go:121.29,123.3 1 1 +github.com/go-errors/errors/error.go:125.43,127.3 1 1 +github.com/go-errors/errors/error.go:135.53,137.2 1 1 +github.com/go-errors/errors/error.go:140.34,142.2 1 1 +github.com/go-errors/errors/error.go:146.34,149.42 2 1 +github.com/go-errors/errors/error.go:153.2,153.20 1 1 +github.com/go-errors/errors/error.go:149.42,151.3 1 1 +github.com/go-errors/errors/error.go:158.39,160.2 1 1 +github.com/go-errors/errors/error.go:164.46,165.23 1 1 +github.com/go-errors/errors/error.go:173.2,173.19 1 1 +github.com/go-errors/errors/error.go:165.23,168.32 2 1 +github.com/go-errors/errors/error.go:168.32,170.4 1 1 +github.com/go-errors/errors/error.go:177.37,178.42 1 1 +github.com/go-errors/errors/error.go:181.2,181.41 1 1 +github.com/go-errors/errors/error.go:178.42,180.3 1 1 +github.com/go-errors/errors/parse_panic.go:10.39,12.2 1 1 +github.com/go-errors/errors/parse_panic.go:16.46,24.34 5 1 +github.com/go-errors/errors/parse_panic.go:70.2,70.43 1 1 +github.com/go-errors/errors/parse_panic.go:73.2,73.55 1 0 +github.com/go-errors/errors/parse_panic.go:24.34,27.23 2 1 +github.com/go-errors/errors/parse_panic.go:27.23,28.42 1 1 +github.com/go-errors/errors/parse_panic.go:28.42,31.5 2 1 +github.com/go-errors/errors/parse_panic.go:31.6,33.5 1 0 +github.com/go-errors/errors/parse_panic.go:35.5,35.29 1 1 +github.com/go-errors/errors/parse_panic.go:35.29,36.86 1 1 +github.com/go-errors/errors/parse_panic.go:36.86,38.5 1 1 +github.com/go-errors/errors/parse_panic.go:40.5,40.32 1 1 +github.com/go-errors/errors/parse_panic.go:40.32,41.18 1 1 +github.com/go-errors/errors/parse_panic.go:45.4,46.46 2 1 +github.com/go-errors/errors/parse_panic.go:51.4,53.23 2 1 +github.com/go-errors/errors/parse_panic.go:57.4,58.18 2 1 +github.com/go-errors/errors/parse_panic.go:62.4,63.17 2 1 +github.com/go-errors/errors/parse_panic.go:41.18,43.10 2 1 +github.com/go-errors/errors/parse_panic.go:46.46,49.5 2 1 +github.com/go-errors/errors/parse_panic.go:53.23,55.5 1 0 +github.com/go-errors/errors/parse_panic.go:58.18,60.5 1 0 +github.com/go-errors/errors/parse_panic.go:63.17,65.10 2 1 +github.com/go-errors/errors/parse_panic.go:70.43,72.3 1 1 +github.com/go-errors/errors/parse_panic.go:80.85,82.29 2 1 +github.com/go-errors/errors/parse_panic.go:85.2,85.15 1 1 +github.com/go-errors/errors/parse_panic.go:88.2,90.63 2 1 +github.com/go-errors/errors/parse_panic.go:94.2,94.53 1 1 +github.com/go-errors/errors/parse_panic.go:99.2,101.36 2 1 +github.com/go-errors/errors/parse_panic.go:105.2,106.15 2 1 +github.com/go-errors/errors/parse_panic.go:109.2,112.49 3 1 +github.com/go-errors/errors/parse_panic.go:116.2,117.16 2 1 +github.com/go-errors/errors/parse_panic.go:121.2,126.8 1 1 +github.com/go-errors/errors/parse_panic.go:82.29,84.3 1 0 +github.com/go-errors/errors/parse_panic.go:85.15,87.3 1 1 +github.com/go-errors/errors/parse_panic.go:90.63,93.3 2 1 +github.com/go-errors/errors/parse_panic.go:94.53,97.3 2 1 +github.com/go-errors/errors/parse_panic.go:101.36,103.3 1 0 +github.com/go-errors/errors/parse_panic.go:106.15,108.3 1 0 +github.com/go-errors/errors/parse_panic.go:112.49,114.3 1 1 +github.com/go-errors/errors/parse_panic.go:117.16,119.3 1 0 diff --git a/vendor/github.com/go-errors/errors/error.go b/vendor/github.com/go-errors/errors/error.go new file mode 100644 index 0000000..60062a4 --- /dev/null +++ b/vendor/github.com/go-errors/errors/error.go @@ -0,0 +1,217 @@ +// Package errors provides errors that have stack-traces. +// +// This is particularly useful when you want to understand the +// state of execution when an error was returned unexpectedly. +// +// It provides the type *Error which implements the standard +// golang error interface, so you can use this library interchangably +// with code that is expecting a normal error return. +// +// For example: +// +// package crashy +// +// import "github.com/go-errors/errors" +// +// var Crashed = errors.Errorf("oh dear") +// +// func Crash() error { +// return errors.New(Crashed) +// } +// +// This can be called as follows: +// +// package main +// +// import ( +// "crashy" +// "fmt" +// "github.com/go-errors/errors" +// ) +// +// func main() { +// err := crashy.Crash() +// if err != nil { +// if errors.Is(err, crashy.Crashed) { +// fmt.Println(err.(*errors.Error).ErrorStack()) +// } else { +// panic(err) +// } +// } +// } +// +// This package was original written to allow reporting to Bugsnag, +// but after I found similar packages by Facebook and Dropbox, it +// was moved to one canonical location so everyone can benefit. +package errors + +import ( + "bytes" + "fmt" + "reflect" + "runtime" +) + +// The maximum number of stackframes on any error. +var MaxStackDepth = 50 + +// Error is an error with an attached stacktrace. It can be used +// wherever the builtin error interface is expected. +type Error struct { + Err error + stack []uintptr + frames []StackFrame + prefix string +} + +// New makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The stacktrace will point to the line of code that +// called New. +func New(e interface{}) *Error { + var err error + + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// Wrap makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The skip parameter indicates how far up the stack +// to start the stacktrace. 0 is from the current call, 1 from its caller, etc. +func Wrap(e interface{}, skip int) *Error { + var err error + + switch e := e.(type) { + case *Error: + return e + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2+skip, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// WrapPrefix makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the +// error message when calling Error(). The skip parameter indicates how far +// up the stack to start the stacktrace. 0 is from the current call, +// 1 from its caller, etc. +func WrapPrefix(e interface{}, prefix string, skip int) *Error { + + err := Wrap(e, 1+skip) + + if err.prefix != "" { + prefix = fmt.Sprintf("%s: %s", prefix, err.prefix) + } + + return &Error{ + Err: err.Err, + stack: err.stack, + prefix: prefix, + } + +} + +// Is detects whether the error is equal to a given error. Errors +// are considered equal by this function if they are the same object, +// or if they both contain the same error inside an errors.Error. +func Is(e error, original error) bool { + + if e == original { + return true + } + + if e, ok := e.(*Error); ok { + return Is(e.Err, original) + } + + if original, ok := original.(*Error); ok { + return Is(e, original.Err) + } + + return false +} + +// Errorf creates a new error with the given message. You can use it +// as a drop-in replacement for fmt.Errorf() to provide descriptive +// errors in return values. +func Errorf(format string, a ...interface{}) *Error { + return Wrap(fmt.Errorf(format, a...), 1) +} + +// Error returns the underlying error's message. +func (err *Error) Error() string { + + msg := err.Err.Error() + if err.prefix != "" { + msg = fmt.Sprintf("%s: %s", err.prefix, msg) + } + + return msg +} + +// Stack returns the callstack formatted the same way that go does +// in runtime/debug.Stack() +func (err *Error) Stack() []byte { + buf := bytes.Buffer{} + + for _, frame := range err.StackFrames() { + buf.WriteString(frame.String()) + } + + return buf.Bytes() +} + +// Callers satisfies the bugsnag ErrorWithCallerS() interface +// so that the stack can be read out. +func (err *Error) Callers() []uintptr { + return err.stack +} + +// ErrorStack returns a string that contains both the +// error message and the callstack. +func (err *Error) ErrorStack() string { + return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack()) +} + +// StackFrames returns an array of frames containing information about the +// stack. +func (err *Error) StackFrames() []StackFrame { + if err.frames == nil { + err.frames = make([]StackFrame, len(err.stack)) + + for i, pc := range err.stack { + err.frames[i] = NewStackFrame(pc) + } + } + + return err.frames +} + +// TypeName returns the type this error. e.g. *errors.stringError. +func (err *Error) TypeName() string { + if _, ok := err.Err.(uncaughtPanic); ok { + return "panic" + } + return reflect.TypeOf(err.Err).String() +} diff --git a/vendor/github.com/go-errors/errors/parse_panic.go b/vendor/github.com/go-errors/errors/parse_panic.go new file mode 100644 index 0000000..cc37052 --- /dev/null +++ b/vendor/github.com/go-errors/errors/parse_panic.go @@ -0,0 +1,127 @@ +package errors + +import ( + "strconv" + "strings" +) + +type uncaughtPanic struct{ message string } + +func (p uncaughtPanic) Error() string { + return p.message +} + +// ParsePanic allows you to get an error object from the output of a go program +// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap. +func ParsePanic(text string) (*Error, error) { + lines := strings.Split(text, "\n") + + state := "start" + + var message string + var stack []StackFrame + + for i := 0; i < len(lines); i++ { + line := lines[i] + + if state == "start" { + if strings.HasPrefix(line, "panic: ") { + message = strings.TrimPrefix(line, "panic: ") + state = "seek" + } else { + return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line) + } + + } else if state == "seek" { + if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") { + state = "parsing" + } + + } else if state == "parsing" { + if line == "" { + state = "done" + break + } + createdBy := false + if strings.HasPrefix(line, "created by ") { + line = strings.TrimPrefix(line, "created by ") + createdBy = true + } + + i++ + + if i >= len(lines) { + return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line) + } + + frame, err := parsePanicFrame(line, lines[i], createdBy) + if err != nil { + return nil, err + } + + stack = append(stack, *frame) + if createdBy { + state = "done" + break + } + } + } + + if state == "done" || state == "parsing" { + return &Error{Err: uncaughtPanic{message}, frames: stack}, nil + } + return nil, Errorf("could not parse panic: %v", text) +} + +// The lines we're passing look like this: +// +// main.(*foo).destruct(0xc208067e98) +// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151 +func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) { + idx := strings.LastIndex(name, "(") + if idx == -1 && !createdBy { + return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name) + } + if idx != -1 { + name = name[:idx] + } + pkg := "" + + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + + if !strings.HasPrefix(line, "\t") { + return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line) + } + + idx = strings.LastIndex(line, ":") + if idx == -1 { + return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line) + } + file := line[1:idx] + + number := line[idx+1:] + if idx = strings.Index(number, " +"); idx > -1 { + number = number[:idx] + } + + lno, err := strconv.ParseInt(number, 10, 32) + if err != nil { + return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line) + } + + return &StackFrame{ + File: file, + LineNumber: int(lno), + Package: pkg, + Name: name, + }, nil +} diff --git a/vendor/github.com/go-errors/errors/stackframe.go b/vendor/github.com/go-errors/errors/stackframe.go new file mode 100644 index 0000000..750ab9a --- /dev/null +++ b/vendor/github.com/go-errors/errors/stackframe.go @@ -0,0 +1,102 @@ +package errors + +import ( + "bytes" + "fmt" + "io/ioutil" + "runtime" + "strings" +) + +// A StackFrame contains all necessary information about to generate a line +// in a callstack. +type StackFrame struct { + // The path to the file containing this ProgramCounter + File string + // The LineNumber in that file + LineNumber int + // The Name of the function that contains this ProgramCounter + Name string + // The Package that contains this function + Package string + // The underlying ProgramCounter + ProgramCounter uintptr +} + +// NewStackFrame popoulates a stack frame object from the program counter. +func NewStackFrame(pc uintptr) (frame StackFrame) { + + frame = StackFrame{ProgramCounter: pc} + if frame.Func() == nil { + return + } + frame.Package, frame.Name = packageAndName(frame.Func()) + + // pc -1 because the program counters we use are usually return addresses, + // and we want to show the line that corresponds to the function call + frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1) + return + +} + +// Func returns the function that contained this frame. +func (frame *StackFrame) Func() *runtime.Func { + if frame.ProgramCounter == 0 { + return nil + } + return runtime.FuncForPC(frame.ProgramCounter) +} + +// String returns the stackframe formatted in the same way as go does +// in runtime/debug.Stack() +func (frame *StackFrame) String() string { + str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter) + + source, err := frame.SourceLine() + if err != nil { + return str + } + + return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source) +} + +// SourceLine gets the line of code (from File and Line) of the original source if possible. +func (frame *StackFrame) SourceLine() (string, error) { + data, err := ioutil.ReadFile(frame.File) + + if err != nil { + return "", New(err) + } + + lines := bytes.Split(data, []byte{'\n'}) + if frame.LineNumber <= 0 || frame.LineNumber >= len(lines) { + return "???", nil + } + // -1 because line-numbers are 1 based, but our array is 0 based + return string(bytes.Trim(lines[frame.LineNumber-1], " \t")), nil +} + +func packageAndName(fn *runtime.Func) (string, string) { + name := fn.Name() + pkg := "" + + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Since the package path might contains dots (e.g. code.google.com/...), + // we first remove the path prefix if there is one. + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + return pkg, name +} diff --git a/vendor/github.com/go-sql-driver/mysql/.gitignore b/vendor/github.com/go-sql-driver/mysql/.gitignore new file mode 100644 index 0000000..2de28da --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +.idea diff --git a/vendor/github.com/go-sql-driver/mysql/.travis.yml b/vendor/github.com/go-sql-driver/mysql/.travis.yml new file mode 100644 index 0000000..cc1268c --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/.travis.yml @@ -0,0 +1,107 @@ +sudo: false +language: go +go: + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - master + +before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + +before_script: + - echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf + - sudo service mysql restart + - .travis/wait_mysql.sh + - mysql -e 'create database gotest;' + +matrix: + include: + - env: DB=MYSQL8 + sudo: required + dist: trusty + go: 1.10.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mysql:8.0 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mysql:8.0 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 + - cp .travis/docker.cnf ~/.my.cnf + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + + - env: DB=MYSQL57 + sudo: required + dist: trusty + go: 1.10.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mysql:5.7 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 + - cp .travis/docker.cnf ~/.my.cnf + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + + - env: DB=MARIA55 + sudo: required + dist: trusty + go: 1.10.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mariadb:5.5 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 + - cp .travis/docker.cnf ~/.my.cnf + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + + - env: DB=MARIA10_1 + sudo: required + dist: trusty + go: 1.10.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mariadb:10.1 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 + - cp .travis/docker.cnf ~/.my.cnf + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + +script: + - go test -v -covermode=count -coverprofile=coverage.out + - go vet ./... + - .travis/gofmt.sh +after_script: + - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS new file mode 100644 index 0000000..73ff68f --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/AUTHORS @@ -0,0 +1,89 @@ +# This is the official list of Go-MySQL-Driver authors for copyright purposes. + +# If you are submitting a patch, please add your name or the name of the +# organization which holds the copyright to this list in alphabetical order. + +# Names should be added to this file as +# Name +# The email address is not required for organizations. +# Please keep the list sorted. + + +# Individual Persons + +Aaron Hopkins +Achille Roussel +Alexey Palazhchenko +Andrew Reid +Arne Hormann +Asta Xie +Bulat Gaifullin +Carlos Nieto +Chris Moos +Craig Wilson +Daniel Montoya +Daniel Nichter +Daniël van Eeden +Dave Protasowski +DisposaBoy +Egor Smolyakov +Evan Shaw +Frederick Mayle +Gustavo Kristic +Hajime Nakagami +Hanno Braun +Henri Yandell +Hirotaka Yamamoto +ICHINOSE Shogo +INADA Naoki +Jacek Szwec +James Harr +Jeff Hodges +Jeffrey Charles +Jian Zhen +Joshua Prunier +Julien Lefevre +Julien Schmidt +Justin Li +Justin Nuß +Kamil Dziedzic +Kevin Malachowski +Kieron Woodhouse +Lennart Rudolph +Leonardo YongUk Kim +Linh Tran Tuan +Lion Yang +Luca Looz +Lucas Liu +Luke Scott +Maciej Zimnoch +Michael Woolnough +Nicola Peduzzi +Olivier Mengué +oscarzhao +Paul Bonser +Peter Schultz +Rebecca Chin +Reed Allman +Richard Wilkes +Robert Russell +Runrioter Wung +Shuode Li +Soroush Pour +Stan Putrya +Stanley Gunawan +Xiangyu Hu +Xiaobing Jiang +Xiuming Chen +Zhenye Xie + +# Organizations + +Barracuda Networks, Inc. +Counting Ltd. +Google Inc. +InfoSum Ltd. +Keybase Inc. +Percona LLC +Pivotal Inc. +Stripe Inc. diff --git a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md new file mode 100644 index 0000000..2d87d74 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md @@ -0,0 +1,167 @@ +## Version 1.4 (2018-06-03) + +Changes: + + - Documentation fixes (#530, #535, #567) + - Refactoring (#575, #579, #580, #581, #603, #615, #704) + - Cache column names (#444) + - Sort the DSN parameters in DSNs generated from a config (#637) + - Allow native password authentication by default (#644) + - Use the default port if it is missing in the DSN (#668) + - Removed the `strict` mode (#676) + - Do not query `max_allowed_packet` by default (#680) + - Dropped support Go 1.6 and lower (#696) + - Updated `ConvertValue()` to match the database/sql/driver implementation (#760) + - Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783) + - Improved the compatibility of the authentication system (#807) + +New Features: + + - Multi-Results support (#537) + - `rejectReadOnly` DSN option (#604) + - `context.Context` support (#608, #612, #627, #761) + - Transaction isolation level support (#619, #744) + - Read-Only transactions support (#618, #634) + - `NewConfig` function which initializes a config with default values (#679) + - Implemented the `ColumnType` interfaces (#667, #724) + - Support for custom string types in `ConvertValue` (#623) + - Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710) + - `caching_sha2_password` authentication plugin support (#794, #800, #801, #802) + - Implemented `driver.SessionResetter` (#779) + - `sha256_password` authentication plugin support (#808) + +Bugfixes: + + - Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718) + - Fixed LOAD LOCAL DATA INFILE for empty files (#590) + - Removed columns definition cache since it sometimes cached invalid data (#592) + - Don't mutate registered TLS configs (#600) + - Make RegisterTLSConfig concurrency-safe (#613) + - Handle missing auth data in the handshake packet correctly (#646) + - Do not retry queries when data was written to avoid data corruption (#302, #736) + - Cache the connection pointer for error handling before invalidating it (#678) + - Fixed imports for appengine/cloudsql (#700) + - Fix sending STMT_LONG_DATA for 0 byte data (#734) + - Set correct capacity for []bytes read from length-encoded strings (#766) + - Make RegisterDial concurrency-safe (#773) + + +## Version 1.3 (2016-12-01) + +Changes: + + - Go 1.1 is no longer supported + - Use decimals fields in MySQL to format time types (#249) + - Buffer optimizations (#269) + - TLS ServerName defaults to the host (#283) + - Refactoring (#400, #410, #437) + - Adjusted documentation for second generation CloudSQL (#485) + - Documented DSN system var quoting rules (#502) + - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512) + +New Features: + + - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) + - Support for returning table alias on Columns() (#289, #359, #382) + - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490) + - Support for uint64 parameters with high bit set (#332, #345) + - Cleartext authentication plugin support (#327) + - Exported ParseDSN function and the Config struct (#403, #419, #429) + - Read / Write timeouts (#401) + - Support for JSON field type (#414) + - Support for multi-statements and multi-results (#411, #431) + - DSN parameter to set the driver-side max_allowed_packet value manually (#489) + - Native password authentication plugin support (#494, #524) + +Bugfixes: + + - Fixed handling of queries without columns and rows (#255) + - Fixed a panic when SetKeepAlive() failed (#298) + - Handle ERR packets while reading rows (#321) + - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349) + - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356) + - Actually zero out bytes in handshake response (#378) + - Fixed race condition in registering LOAD DATA INFILE handler (#383) + - Fixed tests with MySQL 5.7.9+ (#380) + - QueryUnescape TLS config names (#397) + - Fixed "broken pipe" error by writing to closed socket (#390) + - Fixed LOAD LOCAL DATA INFILE buffering (#424) + - Fixed parsing of floats into float64 when placeholders are used (#434) + - Fixed DSN tests with Go 1.7+ (#459) + - Handle ERR packets while waiting for EOF (#473) + - Invalidate connection on error while discarding additional results (#513) + - Allow terminating packets of length 0 (#516) + + +## Version 1.2 (2014-06-03) + +Changes: + + - We switched back to a "rolling release". `go get` installs the current master branch again + - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver + - Exported errors to allow easy checking from application code + - Enabled TCP Keepalives on TCP connections + - Optimized INFILE handling (better buffer size calculation, lazy init, ...) + - The DSN parser also checks for a missing separating slash + - Faster binary date / datetime to string formatting + - Also exported the MySQLWarning type + - mysqlConn.Close returns the first error encountered instead of ignoring all errors + - writePacket() automatically writes the packet size to the header + - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets + +New Features: + + - `RegisterDial` allows the usage of a custom dial function to establish the network connection + - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter + - Logging of critical errors is configurable with `SetLogger` + - Google CloudSQL support + +Bugfixes: + + - Allow more than 32 parameters in prepared statements + - Various old_password fixes + - Fixed TestConcurrent test to pass Go's race detection + - Fixed appendLengthEncodedInteger for large numbers + - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo) + + +## Version 1.1 (2013-11-02) + +Changes: + + - Go-MySQL-Driver now requires Go 1.1 + - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore + - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors + - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")` + - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'. + - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries + - Optimized the buffer for reading + - stmt.Query now caches column metadata + - New Logo + - Changed the copyright header to include all contributors + - Improved the LOAD INFILE documentation + - The driver struct is now exported to make the driver directly accessible + - Refactored the driver tests + - Added more benchmarks and moved all to a separate file + - Other small refactoring + +New Features: + + - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure + - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs + - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used + +Bugfixes: + + - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification + - Convert to DB timezone when inserting `time.Time` + - Splitted packets (more than 16MB) are now merged correctly + - Fixed false positive `io.EOF` errors when the data was fully read + - Avoid panics on reuse of closed connections + - Fixed empty string producing false nil values + - Fixed sign byte for positive TIME fields + + +## Version 1.0 (2013-05-14) + +Initial Release diff --git a/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md b/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md new file mode 100644 index 0000000..8fe16bc --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# Contributing Guidelines + +## Reporting Issues + +Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). + +## Contributing Code + +By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. +Don't forget to add yourself to the AUTHORS file. + +### Code Review + +Everyone is invited to review and comment on pull requests. +If it looks fine to you, comment with "LGTM" (Looks good to me). + +If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. + +Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". + +## Development Ideas + +If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. diff --git a/vendor/github.com/go-sql-driver/mysql/LICENSE b/vendor/github.com/go-sql-driver/mysql/LICENSE new file mode 100644 index 0000000..14e2f77 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md new file mode 100644 index 0000000..2e9b07e --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/README.md @@ -0,0 +1,490 @@ +# Go-MySQL-Driver + +A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package + +![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") + +--------------------------------------- + * [Features](#features) + * [Requirements](#requirements) + * [Installation](#installation) + * [Usage](#usage) + * [DSN (Data Source Name)](#dsn-data-source-name) + * [Password](#password) + * [Protocol](#protocol) + * [Address](#address) + * [Parameters](#parameters) + * [Examples](#examples) + * [Connection pool and timeouts](#connection-pool-and-timeouts) + * [context.Context Support](#contextcontext-support) + * [ColumnType Support](#columntype-support) + * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) + * [time.Time support](#timetime-support) + * [Unicode support](#unicode-support) + * [Testing / Development](#testing--development) + * [License](#license) + +--------------------------------------- + +## Features + * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") + * Native Go implementation. No C-bindings, just pure Go + * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) + * Automatic handling of broken connections + * Automatic Connection Pooling *(by database/sql package)* + * Supports queries larger than 16MB + * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. + * Intelligent `LONG DATA` handling in prepared statements + * Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support + * Optional `time.Time` parsing + * Optional placeholder interpolation + +## Requirements + * Go 1.7 or higher. We aim to support the 3 latest versions of Go. + * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) + +--------------------------------------- + +## Installation +Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: +```bash +$ go get -u github.com/go-sql-driver/mysql +``` +Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. + +## Usage +_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. + +Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: +```go +import "database/sql" +import _ "github.com/go-sql-driver/mysql" + +db, err := sql.Open("mysql", "user:password@/dbname") +``` + +[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples"). + + +### DSN (Data Source Name) + +The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets): +``` +[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] +``` + +A DSN in its fullest form: +``` +username:password@protocol(address)/dbname?param=value +``` + +Except for the databasename, all values are optional. So the minimal DSN is: +``` +/dbname +``` + +If you do not want to preselect a database, leave `dbname` empty: +``` +/ +``` +This has the same effect as an empty DSN string: +``` + +``` + +Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. + +#### Password +Passwords can consist of any character. Escaping is **not** necessary. + +#### Protocol +See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. +In general you should use an Unix domain socket if available and TCP otherwise for best performance. + +#### Address +For TCP and UDP networks, addresses have the form `host[:port]`. +If `port` is omitted, the default port will be used. +If `host` is a literal IPv6 address, it must be enclosed in square brackets. +The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. + +For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. + +#### Parameters +*Parameters are case-sensitive!* + +Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`. + +##### `allowAllFiles` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files. +[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html) + +##### `allowCleartextPasswords` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network. + +##### `allowNativePasswords` + +``` +Type: bool +Valid Values: true, false +Default: true +``` +`allowNativePasswords=false` disallows the usage of MySQL native password method. + +##### `allowOldPasswords` + +``` +Type: bool +Valid Values: true, false +Default: false +``` +`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords). + +##### `charset` + +``` +Type: string +Valid Values: +Default: none +``` + +Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). + +Usage of the `charset` parameter is discouraged because it issues additional queries to the server. +Unless you need the fallback behavior, please use `collation` instead. + +##### `collation` + +``` +Type: string +Valid Values: +Default: utf8_general_ci +``` + +Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail. + +A list of valid charsets for a server is retrievable with `SHOW COLLATION`. + +##### `clientFoundRows` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed. + +##### `columnsWithAlias` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example: + +``` +SELECT u.id FROM users as u +``` + +will return `u.id` instead of just `id` if `columnsWithAlias=true`. + +##### `interpolateParams` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`. + +*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are blacklisted as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!* + +##### `loc` + +``` +Type: string +Valid Values: +Default: UTC +``` + +Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. + +Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. + +Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. + +##### `maxAllowedPacket` +``` +Type: decimal number +Default: 4194304 +``` + +Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. + +##### `multiStatements` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded. + +When `multiStatements` is used, `?` parameters must only be used in the first statement. + +##### `parseTime` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string` +The date or datetime like `0000-00-00 00:00:00` is converted into zero value of `time.Time`. + + +##### `readTimeout` + +``` +Type: duration +Default: 0 +``` + +I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. + +##### `rejectReadOnly` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + + +`rejectReadOnly=true` causes the driver to reject read-only connections. This +is for a possible race condition during an automatic failover, where the mysql +client gets connected to a read-only replica after the failover. + +Note that this should be a fairly rare case, as an automatic failover normally +happens when the primary is down, and the race condition shouldn't happen +unless it comes back up online as soon as the failover is kicked off. On the +other hand, when this happens, a MySQL application can get stuck on a +read-only connection until restarted. It is however fairly easy to reproduce, +for example, using a manual failover on AWS Aurora's MySQL-compatible cluster. + +If you are not relying on read-only transactions to reject writes that aren't +supposed to happen, setting this on some MySQL providers (such as AWS Aurora) +is safer for failovers. + +Note that ERROR 1290 can be returned for a `read-only` server and this option will +cause a retry for that error. However the same error number is used for some +other cases. You should ensure your application will never cause an ERROR 1290 +except for `read-only` mode when enabling this option. + + +##### `serverPubKey` + +``` +Type: string +Valid Values: +Default: none +``` + +Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN. +Public keys are used to transmit encrypted data, e.g. for authentication. +If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required. + + +##### `timeout` + +``` +Type: duration +Default: OS default +``` + +Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. + + +##### `tls` + +``` +Type: bool / string +Valid Values: true, false, skip-verify, +Default: false +``` + +`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). + + +##### `writeTimeout` + +``` +Type: duration +Default: 0 +``` + +I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. + + +##### System Variables + +Any other parameters are interpreted as system variables: + * `=`: `SET =` + * `=`: `SET =` + * `=%27%27`: `SET =''` + +Rules: +* The values for string variables must be quoted with `'`. +* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! + (which implies values of string variables must be wrapped with `%27`). + +Examples: + * `autocommit=1`: `SET autocommit=1` + * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` + * [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'` + + +#### Examples +``` +user@unix(/path/to/socket)/dbname +``` + +``` +root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local +``` + +``` +user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true +``` + +Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html): +``` +user:password@/dbname?sql_mode=TRADITIONAL +``` + +TCP via IPv6: +``` +user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci +``` + +TCP on a remote host, e.g. Amazon RDS: +``` +id:password@tcp(your-amazonaws-uri.com:3306)/dbname +``` + +Google Cloud SQL on App Engine (First Generation MySQL Server): +``` +user@cloudsql(project-id:instance-name)/dbname +``` + +Google Cloud SQL on App Engine (Second Generation MySQL Server): +``` +user@cloudsql(project-id:regionname:instance-name)/dbname +``` + +TCP using default port (3306) on localhost: +``` +user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped +``` + +Use the default protocol (tcp) and host (localhost:3306): +``` +user:password@/dbname +``` + +No Database preselected: +``` +user:password@/ +``` + + +### Connection pool and timeouts +The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. + +## `ColumnType` Support +This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. + +## `context.Context` Support +Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. +See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. + + +### `LOAD DATA LOCAL INFILE` support +For this feature you need direct access to the package. Therefore you must change the import path (no `_`): +```go +import "github.com/go-sql-driver/mysql" +``` + +Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)). + +To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. + +See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. + + +### `time.Time` support +The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program. + +However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. + +**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). + +Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`. + + +### Unicode support +Since version 1.1 Go-MySQL-Driver automatically uses the collation `utf8_general_ci` by default. + +Other collations / charsets can be set using the [`collation`](#collation) DSN parameter. + +Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default. + +See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support. + +## Testing / Development +To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. + +Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. +If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls). + +See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details. + +--------------------------------------- + +## License +Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) + +Mozilla summarizes the license scope as follows: +> MPL: The copyleft applies to any files containing MPLed code. + + +That means: + * You can **use** the **unchanged** source code both in private and commercially. + * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0). + * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**. + +Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. + +You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE). + +![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") + diff --git a/vendor/github.com/go-sql-driver/mysql/appengine.go b/vendor/github.com/go-sql-driver/mysql/appengine.go new file mode 100644 index 0000000..be41f2e --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/appengine.go @@ -0,0 +1,19 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build appengine + +package mysql + +import ( + "google.golang.org/appengine/cloudsql" +) + +func init() { + RegisterDial("cloudsql", cloudsql.Dial) +} diff --git a/vendor/github.com/go-sql-driver/mysql/auth.go b/vendor/github.com/go-sql-driver/mysql/auth.go new file mode 100644 index 0000000..0b59f52 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/auth.go @@ -0,0 +1,420 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/x509" + "encoding/pem" + "sync" +) + +// server pub keys registry +var ( + serverPubKeyLock sync.RWMutex + serverPubKeyRegistry map[string]*rsa.PublicKey +) + +// RegisterServerPubKey registers a server RSA public key which can be used to +// send data in a secure manner to the server without receiving the public key +// in a potentially insecure way from the server first. +// Registered keys can afterwards be used adding serverPubKey= to the DSN. +// +// Note: The provided rsa.PublicKey instance is exclusively owned by the driver +// after registering it and may not be modified. +// +// data, err := ioutil.ReadFile("mykey.pem") +// if err != nil { +// log.Fatal(err) +// } +// +// block, _ := pem.Decode(data) +// if block == nil || block.Type != "PUBLIC KEY" { +// log.Fatal("failed to decode PEM block containing public key") +// } +// +// pub, err := x509.ParsePKIXPublicKey(block.Bytes) +// if err != nil { +// log.Fatal(err) +// } +// +// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok { +// mysql.RegisterServerPubKey("mykey", rsaPubKey) +// } else { +// log.Fatal("not a RSA public key") +// } +// +func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) { + serverPubKeyLock.Lock() + if serverPubKeyRegistry == nil { + serverPubKeyRegistry = make(map[string]*rsa.PublicKey) + } + + serverPubKeyRegistry[name] = pubKey + serverPubKeyLock.Unlock() +} + +// DeregisterServerPubKey removes the public key registered with the given name. +func DeregisterServerPubKey(name string) { + serverPubKeyLock.Lock() + if serverPubKeyRegistry != nil { + delete(serverPubKeyRegistry, name) + } + serverPubKeyLock.Unlock() +} + +func getServerPubKey(name string) (pubKey *rsa.PublicKey) { + serverPubKeyLock.RLock() + if v, ok := serverPubKeyRegistry[name]; ok { + pubKey = v + } + serverPubKeyLock.RUnlock() + return +} + +// Hash password using pre 4.1 (old password) method +// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c +type myRnd struct { + seed1, seed2 uint32 +} + +const myRndMaxVal = 0x3FFFFFFF + +// Pseudo random number generator +func newMyRnd(seed1, seed2 uint32) *myRnd { + return &myRnd{ + seed1: seed1 % myRndMaxVal, + seed2: seed2 % myRndMaxVal, + } +} + +// Tested to be equivalent to MariaDB's floating point variant +// http://play.golang.org/p/QHvhd4qved +// http://play.golang.org/p/RG0q4ElWDx +func (r *myRnd) NextByte() byte { + r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal + r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal + + return byte(uint64(r.seed1) * 31 / myRndMaxVal) +} + +// Generate binary hash from byte string using insecure pre 4.1 method +func pwHash(password []byte) (result [2]uint32) { + var add uint32 = 7 + var tmp uint32 + + result[0] = 1345345333 + result[1] = 0x12345671 + + for _, c := range password { + // skip spaces and tabs in password + if c == ' ' || c == '\t' { + continue + } + + tmp = uint32(c) + result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8) + result[1] += (result[1] << 8) ^ result[0] + add += tmp + } + + // Remove sign bit (1<<31)-1) + result[0] &= 0x7FFFFFFF + result[1] &= 0x7FFFFFFF + + return +} + +// Hash password using insecure pre 4.1 method +func scrambleOldPassword(scramble []byte, password string) []byte { + if len(password) == 0 { + return nil + } + + scramble = scramble[:8] + + hashPw := pwHash([]byte(password)) + hashSc := pwHash(scramble) + + r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) + + var out [8]byte + for i := range out { + out[i] = r.NextByte() + 64 + } + + mask := r.NextByte() + for i := range out { + out[i] ^= mask + } + + return out[:] +} + +// Hash password using 4.1+ method (SHA1) +func scramblePassword(scramble []byte, password string) []byte { + if len(password) == 0 { + return nil + } + + // stage1Hash = SHA1(password) + crypt := sha1.New() + crypt.Write([]byte(password)) + stage1 := crypt.Sum(nil) + + // scrambleHash = SHA1(scramble + SHA1(stage1Hash)) + // inner Hash + crypt.Reset() + crypt.Write(stage1) + hash := crypt.Sum(nil) + + // outer Hash + crypt.Reset() + crypt.Write(scramble) + crypt.Write(hash) + scramble = crypt.Sum(nil) + + // token = scrambleHash XOR stage1Hash + for i := range scramble { + scramble[i] ^= stage1[i] + } + return scramble +} + +// Hash password using MySQL 8+ method (SHA256) +func scrambleSHA256Password(scramble []byte, password string) []byte { + if len(password) == 0 { + return nil + } + + // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble)) + + crypt := sha256.New() + crypt.Write([]byte(password)) + message1 := crypt.Sum(nil) + + crypt.Reset() + crypt.Write(message1) + message1Hash := crypt.Sum(nil) + + crypt.Reset() + crypt.Write(message1Hash) + crypt.Write(scramble) + message2 := crypt.Sum(nil) + + for i := range message1 { + message1[i] ^= message2[i] + } + + return message1 +} + +func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) { + plain := make([]byte, len(password)+1) + copy(plain, password) + for i := range plain { + j := i % len(seed) + plain[i] ^= seed[j] + } + sha1 := sha1.New() + return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) +} + +func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error { + enc, err := encryptPassword(mc.cfg.Passwd, seed, pub) + if err != nil { + return err + } + return mc.writeAuthSwitchPacket(enc, false) +} + +func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, bool, error) { + switch plugin { + case "caching_sha2_password": + authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) + return authResp, (authResp == nil), nil + + case "mysql_old_password": + if !mc.cfg.AllowOldPasswords { + return nil, false, ErrOldPassword + } + // Note: there are edge cases where this should work but doesn't; + // this is currently "wontfix": + // https://github.com/go-sql-driver/mysql/issues/184 + authResp := scrambleOldPassword(authData[:8], mc.cfg.Passwd) + return authResp, true, nil + + case "mysql_clear_password": + if !mc.cfg.AllowCleartextPasswords { + return nil, false, ErrCleartextPassword + } + // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html + // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html + return []byte(mc.cfg.Passwd), true, nil + + case "mysql_native_password": + if !mc.cfg.AllowNativePasswords { + return nil, false, ErrNativePassword + } + // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html + // Native password authentication only need and will need 20-byte challenge. + authResp := scramblePassword(authData[:20], mc.cfg.Passwd) + return authResp, false, nil + + case "sha256_password": + if len(mc.cfg.Passwd) == 0 { + return nil, true, nil + } + if mc.cfg.tls != nil || mc.cfg.Net == "unix" { + // write cleartext auth packet + return []byte(mc.cfg.Passwd), true, nil + } + + pubKey := mc.cfg.pubKey + if pubKey == nil { + // request public key from server + return []byte{1}, false, nil + } + + // encrypted password + enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) + return enc, false, err + + default: + errLog.Print("unknown auth plugin:", plugin) + return nil, false, ErrUnknownPlugin + } +} + +func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error { + // Read Result Packet + authData, newPlugin, err := mc.readAuthResult() + if err != nil { + return err + } + + // handle auth plugin switch, if requested + if newPlugin != "" { + // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is + // sent and we have to keep using the cipher sent in the init packet. + if authData == nil { + authData = oldAuthData + } else { + // copy data from read buffer to owned slice + copy(oldAuthData, authData) + } + + plugin = newPlugin + + authResp, addNUL, err := mc.auth(authData, plugin) + if err != nil { + return err + } + if err = mc.writeAuthSwitchPacket(authResp, addNUL); err != nil { + return err + } + + // Read Result Packet + authData, newPlugin, err = mc.readAuthResult() + if err != nil { + return err + } + + // Do not allow to change the auth plugin more than once + if newPlugin != "" { + return ErrMalformPkt + } + } + + switch plugin { + + // https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/ + case "caching_sha2_password": + switch len(authData) { + case 0: + return nil // auth successful + case 1: + switch authData[0] { + case cachingSha2PasswordFastAuthSuccess: + if err = mc.readResultOK(); err == nil { + return nil // auth successful + } + + case cachingSha2PasswordPerformFullAuthentication: + if mc.cfg.tls != nil || mc.cfg.Net == "unix" { + // write cleartext auth packet + err = mc.writeAuthSwitchPacket([]byte(mc.cfg.Passwd), true) + if err != nil { + return err + } + } else { + pubKey := mc.cfg.pubKey + if pubKey == nil { + // request public key from server + data := mc.buf.takeSmallBuffer(4 + 1) + data[4] = cachingSha2PasswordRequestPublicKey + mc.writePacket(data) + + // parse public key + data, err := mc.readPacket() + if err != nil { + return err + } + + block, _ := pem.Decode(data[1:]) + pkix, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + pubKey = pkix.(*rsa.PublicKey) + } + + // send encrypted password + err = mc.sendEncryptedPassword(oldAuthData, pubKey) + if err != nil { + return err + } + } + return mc.readResultOK() + + default: + return ErrMalformPkt + } + default: + return ErrMalformPkt + } + + case "sha256_password": + switch len(authData) { + case 0: + return nil // auth successful + default: + block, _ := pem.Decode(authData) + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + + // send encrypted password + err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey)) + if err != nil { + return err + } + return mc.readResultOK() + } + + default: + return nil // auth successful + } + + return err +} diff --git a/vendor/github.com/go-sql-driver/mysql/buffer.go b/vendor/github.com/go-sql-driver/mysql/buffer.go new file mode 100644 index 0000000..eb4748b --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/buffer.go @@ -0,0 +1,147 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "io" + "net" + "time" +) + +const defaultBufSize = 4096 + +// A buffer which is used for both reading and writing. +// This is possible since communication on each connection is synchronous. +// In other words, we can't write and read simultaneously on the same connection. +// The buffer is similar to bufio.Reader / Writer but zero-copy-ish +// Also highly optimized for this particular use case. +type buffer struct { + buf []byte + nc net.Conn + idx int + length int + timeout time.Duration +} + +func newBuffer(nc net.Conn) buffer { + var b [defaultBufSize]byte + return buffer{ + buf: b[:], + nc: nc, + } +} + +// fill reads into the buffer until at least _need_ bytes are in it +func (b *buffer) fill(need int) error { + n := b.length + + // move existing data to the beginning + if n > 0 && b.idx > 0 { + copy(b.buf[0:n], b.buf[b.idx:]) + } + + // grow buffer if necessary + // TODO: let the buffer shrink again at some point + // Maybe keep the org buf slice and swap back? + if need > len(b.buf) { + // Round up to the next multiple of the default size + newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) + copy(newBuf, b.buf) + b.buf = newBuf + } + + b.idx = 0 + + for { + if b.timeout > 0 { + if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { + return err + } + } + + nn, err := b.nc.Read(b.buf[n:]) + n += nn + + switch err { + case nil: + if n < need { + continue + } + b.length = n + return nil + + case io.EOF: + if n >= need { + b.length = n + return nil + } + return io.ErrUnexpectedEOF + + default: + return err + } + } +} + +// returns next N bytes from buffer. +// The returned slice is only guaranteed to be valid until the next read +func (b *buffer) readNext(need int) ([]byte, error) { + if b.length < need { + // refill + if err := b.fill(need); err != nil { + return nil, err + } + } + + offset := b.idx + b.idx += need + b.length -= need + return b.buf[offset:b.idx], nil +} + +// returns a buffer with the requested size. +// If possible, a slice from the existing buffer is returned. +// Otherwise a bigger buffer is made. +// Only one buffer (total) can be used at a time. +func (b *buffer) takeBuffer(length int) []byte { + if b.length > 0 { + return nil + } + + // test (cheap) general case first + if length <= defaultBufSize || length <= cap(b.buf) { + return b.buf[:length] + } + + if length < maxPacketSize { + b.buf = make([]byte, length) + return b.buf + } + return make([]byte, length) +} + +// shortcut which can be used if the requested buffer is guaranteed to be +// smaller than defaultBufSize +// Only one buffer (total) can be used at a time. +func (b *buffer) takeSmallBuffer(length int) []byte { + if b.length > 0 { + return nil + } + return b.buf[:length] +} + +// takeCompleteBuffer returns the complete existing buffer. +// This can be used if the necessary buffer size is unknown. +// Only one buffer (total) can be used at a time. +func (b *buffer) takeCompleteBuffer() []byte { + if b.length > 0 { + return nil + } + return b.buf +} diff --git a/vendor/github.com/go-sql-driver/mysql/collations.go b/vendor/github.com/go-sql-driver/mysql/collations.go new file mode 100644 index 0000000..136c9e4 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/collations.go @@ -0,0 +1,251 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +const defaultCollation = "utf8_general_ci" +const binaryCollation = "binary" + +// A list of available collations mapped to the internal ID. +// To update this map use the following MySQL query: +// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS +var collations = map[string]byte{ + "big5_chinese_ci": 1, + "latin2_czech_cs": 2, + "dec8_swedish_ci": 3, + "cp850_general_ci": 4, + "latin1_german1_ci": 5, + "hp8_english_ci": 6, + "koi8r_general_ci": 7, + "latin1_swedish_ci": 8, + "latin2_general_ci": 9, + "swe7_swedish_ci": 10, + "ascii_general_ci": 11, + "ujis_japanese_ci": 12, + "sjis_japanese_ci": 13, + "cp1251_bulgarian_ci": 14, + "latin1_danish_ci": 15, + "hebrew_general_ci": 16, + "tis620_thai_ci": 18, + "euckr_korean_ci": 19, + "latin7_estonian_cs": 20, + "latin2_hungarian_ci": 21, + "koi8u_general_ci": 22, + "cp1251_ukrainian_ci": 23, + "gb2312_chinese_ci": 24, + "greek_general_ci": 25, + "cp1250_general_ci": 26, + "latin2_croatian_ci": 27, + "gbk_chinese_ci": 28, + "cp1257_lithuanian_ci": 29, + "latin5_turkish_ci": 30, + "latin1_german2_ci": 31, + "armscii8_general_ci": 32, + "utf8_general_ci": 33, + "cp1250_czech_cs": 34, + "ucs2_general_ci": 35, + "cp866_general_ci": 36, + "keybcs2_general_ci": 37, + "macce_general_ci": 38, + "macroman_general_ci": 39, + "cp852_general_ci": 40, + "latin7_general_ci": 41, + "latin7_general_cs": 42, + "macce_bin": 43, + "cp1250_croatian_ci": 44, + "utf8mb4_general_ci": 45, + "utf8mb4_bin": 46, + "latin1_bin": 47, + "latin1_general_ci": 48, + "latin1_general_cs": 49, + "cp1251_bin": 50, + "cp1251_general_ci": 51, + "cp1251_general_cs": 52, + "macroman_bin": 53, + "utf16_general_ci": 54, + "utf16_bin": 55, + "utf16le_general_ci": 56, + "cp1256_general_ci": 57, + "cp1257_bin": 58, + "cp1257_general_ci": 59, + "utf32_general_ci": 60, + "utf32_bin": 61, + "utf16le_bin": 62, + "binary": 63, + "armscii8_bin": 64, + "ascii_bin": 65, + "cp1250_bin": 66, + "cp1256_bin": 67, + "cp866_bin": 68, + "dec8_bin": 69, + "greek_bin": 70, + "hebrew_bin": 71, + "hp8_bin": 72, + "keybcs2_bin": 73, + "koi8r_bin": 74, + "koi8u_bin": 75, + "latin2_bin": 77, + "latin5_bin": 78, + "latin7_bin": 79, + "cp850_bin": 80, + "cp852_bin": 81, + "swe7_bin": 82, + "utf8_bin": 83, + "big5_bin": 84, + "euckr_bin": 85, + "gb2312_bin": 86, + "gbk_bin": 87, + "sjis_bin": 88, + "tis620_bin": 89, + "ucs2_bin": 90, + "ujis_bin": 91, + "geostd8_general_ci": 92, + "geostd8_bin": 93, + "latin1_spanish_ci": 94, + "cp932_japanese_ci": 95, + "cp932_bin": 96, + "eucjpms_japanese_ci": 97, + "eucjpms_bin": 98, + "cp1250_polish_ci": 99, + "utf16_unicode_ci": 101, + "utf16_icelandic_ci": 102, + "utf16_latvian_ci": 103, + "utf16_romanian_ci": 104, + "utf16_slovenian_ci": 105, + "utf16_polish_ci": 106, + "utf16_estonian_ci": 107, + "utf16_spanish_ci": 108, + "utf16_swedish_ci": 109, + "utf16_turkish_ci": 110, + "utf16_czech_ci": 111, + "utf16_danish_ci": 112, + "utf16_lithuanian_ci": 113, + "utf16_slovak_ci": 114, + "utf16_spanish2_ci": 115, + "utf16_roman_ci": 116, + "utf16_persian_ci": 117, + "utf16_esperanto_ci": 118, + "utf16_hungarian_ci": 119, + "utf16_sinhala_ci": 120, + "utf16_german2_ci": 121, + "utf16_croatian_ci": 122, + "utf16_unicode_520_ci": 123, + "utf16_vietnamese_ci": 124, + "ucs2_unicode_ci": 128, + "ucs2_icelandic_ci": 129, + "ucs2_latvian_ci": 130, + "ucs2_romanian_ci": 131, + "ucs2_slovenian_ci": 132, + "ucs2_polish_ci": 133, + "ucs2_estonian_ci": 134, + "ucs2_spanish_ci": 135, + "ucs2_swedish_ci": 136, + "ucs2_turkish_ci": 137, + "ucs2_czech_ci": 138, + "ucs2_danish_ci": 139, + "ucs2_lithuanian_ci": 140, + "ucs2_slovak_ci": 141, + "ucs2_spanish2_ci": 142, + "ucs2_roman_ci": 143, + "ucs2_persian_ci": 144, + "ucs2_esperanto_ci": 145, + "ucs2_hungarian_ci": 146, + "ucs2_sinhala_ci": 147, + "ucs2_german2_ci": 148, + "ucs2_croatian_ci": 149, + "ucs2_unicode_520_ci": 150, + "ucs2_vietnamese_ci": 151, + "ucs2_general_mysql500_ci": 159, + "utf32_unicode_ci": 160, + "utf32_icelandic_ci": 161, + "utf32_latvian_ci": 162, + "utf32_romanian_ci": 163, + "utf32_slovenian_ci": 164, + "utf32_polish_ci": 165, + "utf32_estonian_ci": 166, + "utf32_spanish_ci": 167, + "utf32_swedish_ci": 168, + "utf32_turkish_ci": 169, + "utf32_czech_ci": 170, + "utf32_danish_ci": 171, + "utf32_lithuanian_ci": 172, + "utf32_slovak_ci": 173, + "utf32_spanish2_ci": 174, + "utf32_roman_ci": 175, + "utf32_persian_ci": 176, + "utf32_esperanto_ci": 177, + "utf32_hungarian_ci": 178, + "utf32_sinhala_ci": 179, + "utf32_german2_ci": 180, + "utf32_croatian_ci": 181, + "utf32_unicode_520_ci": 182, + "utf32_vietnamese_ci": 183, + "utf8_unicode_ci": 192, + "utf8_icelandic_ci": 193, + "utf8_latvian_ci": 194, + "utf8_romanian_ci": 195, + "utf8_slovenian_ci": 196, + "utf8_polish_ci": 197, + "utf8_estonian_ci": 198, + "utf8_spanish_ci": 199, + "utf8_swedish_ci": 200, + "utf8_turkish_ci": 201, + "utf8_czech_ci": 202, + "utf8_danish_ci": 203, + "utf8_lithuanian_ci": 204, + "utf8_slovak_ci": 205, + "utf8_spanish2_ci": 206, + "utf8_roman_ci": 207, + "utf8_persian_ci": 208, + "utf8_esperanto_ci": 209, + "utf8_hungarian_ci": 210, + "utf8_sinhala_ci": 211, + "utf8_german2_ci": 212, + "utf8_croatian_ci": 213, + "utf8_unicode_520_ci": 214, + "utf8_vietnamese_ci": 215, + "utf8_general_mysql500_ci": 223, + "utf8mb4_unicode_ci": 224, + "utf8mb4_icelandic_ci": 225, + "utf8mb4_latvian_ci": 226, + "utf8mb4_romanian_ci": 227, + "utf8mb4_slovenian_ci": 228, + "utf8mb4_polish_ci": 229, + "utf8mb4_estonian_ci": 230, + "utf8mb4_spanish_ci": 231, + "utf8mb4_swedish_ci": 232, + "utf8mb4_turkish_ci": 233, + "utf8mb4_czech_ci": 234, + "utf8mb4_danish_ci": 235, + "utf8mb4_lithuanian_ci": 236, + "utf8mb4_slovak_ci": 237, + "utf8mb4_spanish2_ci": 238, + "utf8mb4_roman_ci": 239, + "utf8mb4_persian_ci": 240, + "utf8mb4_esperanto_ci": 241, + "utf8mb4_hungarian_ci": 242, + "utf8mb4_sinhala_ci": 243, + "utf8mb4_german2_ci": 244, + "utf8mb4_croatian_ci": 245, + "utf8mb4_unicode_520_ci": 246, + "utf8mb4_vietnamese_ci": 247, +} + +// A blacklist of collations which is unsafe to interpolate parameters. +// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes. +var unsafeCollations = map[string]bool{ + "big5_chinese_ci": true, + "sjis_japanese_ci": true, + "gbk_chinese_ci": true, + "big5_bin": true, + "gb2312_bin": true, + "gbk_bin": true, + "sjis_bin": true, + "cp932_japanese_ci": true, + "cp932_bin": true, +} diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go new file mode 100644 index 0000000..e570614 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -0,0 +1,461 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql/driver" + "io" + "net" + "strconv" + "strings" + "time" +) + +// a copy of context.Context for Go 1.7 and earlier +type mysqlContext interface { + Done() <-chan struct{} + Err() error + + // defined in context.Context, but not used in this driver: + // Deadline() (deadline time.Time, ok bool) + // Value(key interface{}) interface{} +} + +type mysqlConn struct { + buf buffer + netConn net.Conn + affectedRows uint64 + insertId uint64 + cfg *Config + maxAllowedPacket int + maxWriteSize int + writeTimeout time.Duration + flags clientFlag + status statusFlag + sequence uint8 + parseTime bool + + // for context support (Go 1.8+) + watching bool + watcher chan<- mysqlContext + closech chan struct{} + finished chan<- struct{} + canceled atomicError // set non-nil if conn is canceled + closed atomicBool // set when conn is closed, before closech is closed +} + +// Handles parameters set in DSN after the connection is established +func (mc *mysqlConn) handleParams() (err error) { + for param, val := range mc.cfg.Params { + switch param { + // Charset + case "charset": + charsets := strings.Split(val, ",") + for i := range charsets { + // ignore errors here - a charset may not exist + err = mc.exec("SET NAMES " + charsets[i]) + if err == nil { + break + } + } + if err != nil { + return + } + + // System Vars + default: + err = mc.exec("SET " + param + "=" + val + "") + if err != nil { + return + } + } + } + + return +} + +func (mc *mysqlConn) markBadConn(err error) error { + if mc == nil { + return err + } + if err != errBadConnNoWrite { + return err + } + return driver.ErrBadConn +} + +func (mc *mysqlConn) Begin() (driver.Tx, error) { + return mc.begin(false) +} + +func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + var q string + if readOnly { + q = "START TRANSACTION READ ONLY" + } else { + q = "START TRANSACTION" + } + err := mc.exec(q) + if err == nil { + return &mysqlTx{mc}, err + } + return nil, mc.markBadConn(err) +} + +func (mc *mysqlConn) Close() (err error) { + // Makes Close idempotent + if !mc.closed.IsSet() { + err = mc.writeCommandPacket(comQuit) + } + + mc.cleanup() + + return +} + +// Closes the network connection and unsets internal variables. Do not call this +// function after successfully authentication, call Close instead. This function +// is called before auth or on auth failure because MySQL will have already +// closed the network connection. +func (mc *mysqlConn) cleanup() { + if !mc.closed.TrySet(true) { + return + } + + // Makes cleanup idempotent + close(mc.closech) + if mc.netConn == nil { + return + } + if err := mc.netConn.Close(); err != nil { + errLog.Print(err) + } +} + +func (mc *mysqlConn) error() error { + if mc.closed.IsSet() { + if err := mc.canceled.Value(); err != nil { + return err + } + return ErrInvalidConn + } + return nil +} + +func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + // Send command + err := mc.writeCommandPacketStr(comStmtPrepare, query) + if err != nil { + return nil, mc.markBadConn(err) + } + + stmt := &mysqlStmt{ + mc: mc, + } + + // Read Result + columnCount, err := stmt.readPrepareResultPacket() + if err == nil { + if stmt.paramCount > 0 { + if err = mc.readUntilEOF(); err != nil { + return nil, err + } + } + + if columnCount > 0 { + err = mc.readUntilEOF() + } + } + + return stmt, err +} + +func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { + // Number of ? should be same to len(args) + if strings.Count(query, "?") != len(args) { + return "", driver.ErrSkip + } + + buf := mc.buf.takeCompleteBuffer() + if buf == nil { + // can not take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return "", ErrInvalidConn + } + buf = buf[:0] + argPos := 0 + + for i := 0; i < len(query); i++ { + q := strings.IndexByte(query[i:], '?') + if q == -1 { + buf = append(buf, query[i:]...) + break + } + buf = append(buf, query[i:i+q]...) + i += q + + arg := args[argPos] + argPos++ + + if arg == nil { + buf = append(buf, "NULL"...) + continue + } + + switch v := arg.(type) { + case int64: + buf = strconv.AppendInt(buf, v, 10) + case float64: + buf = strconv.AppendFloat(buf, v, 'g', -1, 64) + case bool: + if v { + buf = append(buf, '1') + } else { + buf = append(buf, '0') + } + case time.Time: + if v.IsZero() { + buf = append(buf, "'0000-00-00'"...) + } else { + v := v.In(mc.cfg.Loc) + v = v.Add(time.Nanosecond * 500) // To round under microsecond + year := v.Year() + year100 := year / 100 + year1 := year % 100 + month := v.Month() + day := v.Day() + hour := v.Hour() + minute := v.Minute() + second := v.Second() + micro := v.Nanosecond() / 1000 + + buf = append(buf, []byte{ + '\'', + digits10[year100], digits01[year100], + digits10[year1], digits01[year1], + '-', + digits10[month], digits01[month], + '-', + digits10[day], digits01[day], + ' ', + digits10[hour], digits01[hour], + ':', + digits10[minute], digits01[minute], + ':', + digits10[second], digits01[second], + }...) + + if micro != 0 { + micro10000 := micro / 10000 + micro100 := micro / 100 % 100 + micro1 := micro % 100 + buf = append(buf, []byte{ + '.', + digits10[micro10000], digits01[micro10000], + digits10[micro100], digits01[micro100], + digits10[micro1], digits01[micro1], + }...) + } + buf = append(buf, '\'') + } + case []byte: + if v == nil { + buf = append(buf, "NULL"...) + } else { + buf = append(buf, "_binary'"...) + if mc.status&statusNoBackslashEscapes == 0 { + buf = escapeBytesBackslash(buf, v) + } else { + buf = escapeBytesQuotes(buf, v) + } + buf = append(buf, '\'') + } + case string: + buf = append(buf, '\'') + if mc.status&statusNoBackslashEscapes == 0 { + buf = escapeStringBackslash(buf, v) + } else { + buf = escapeStringQuotes(buf, v) + } + buf = append(buf, '\'') + default: + return "", driver.ErrSkip + } + + if len(buf)+4 > mc.maxAllowedPacket { + return "", driver.ErrSkip + } + } + if argPos != len(args) { + return "", driver.ErrSkip + } + return string(buf), nil +} + +func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + if len(args) != 0 { + if !mc.cfg.InterpolateParams { + return nil, driver.ErrSkip + } + // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement + prepared, err := mc.interpolateParams(query, args) + if err != nil { + return nil, err + } + query = prepared + } + mc.affectedRows = 0 + mc.insertId = 0 + + err := mc.exec(query) + if err == nil { + return &mysqlResult{ + affectedRows: int64(mc.affectedRows), + insertId: int64(mc.insertId), + }, err + } + return nil, mc.markBadConn(err) +} + +// Internal function to execute commands +func (mc *mysqlConn) exec(query string) error { + // Send command + if err := mc.writeCommandPacketStr(comQuery, query); err != nil { + return mc.markBadConn(err) + } + + // Read Result + resLen, err := mc.readResultSetHeaderPacket() + if err != nil { + return err + } + + if resLen > 0 { + // columns + if err := mc.readUntilEOF(); err != nil { + return err + } + + // rows + if err := mc.readUntilEOF(); err != nil { + return err + } + } + + return mc.discardResults() +} + +func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { + return mc.query(query, args) +} + +func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + if len(args) != 0 { + if !mc.cfg.InterpolateParams { + return nil, driver.ErrSkip + } + // try client-side prepare to reduce roundtrip + prepared, err := mc.interpolateParams(query, args) + if err != nil { + return nil, err + } + query = prepared + } + // Send command + err := mc.writeCommandPacketStr(comQuery, query) + if err == nil { + // Read Result + var resLen int + resLen, err = mc.readResultSetHeaderPacket() + if err == nil { + rows := new(textRows) + rows.mc = mc + + if resLen == 0 { + rows.rs.done = true + + switch err := rows.NextResultSet(); err { + case nil, io.EOF: + return rows, nil + default: + return nil, err + } + } + + // Columns + rows.rs.columns, err = mc.readColumns(resLen) + return rows, err + } + } + return nil, mc.markBadConn(err) +} + +// Gets the value of the given MySQL System Variable +// The returned byte slice is only valid until the next read +func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { + // Send command + if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { + return nil, err + } + + // Read Result + resLen, err := mc.readResultSetHeaderPacket() + if err == nil { + rows := new(textRows) + rows.mc = mc + rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}} + + if resLen > 0 { + // Columns + if err := mc.readUntilEOF(); err != nil { + return nil, err + } + } + + dest := make([]driver.Value, resLen) + if err = rows.readRow(dest); err == nil { + return dest[0].([]byte), mc.readUntilEOF() + } + } + return nil, err +} + +// finish is called when the query has canceled. +func (mc *mysqlConn) cancel(err error) { + mc.canceled.Set(err) + mc.cleanup() +} + +// finish is called when the query has succeeded. +func (mc *mysqlConn) finish() { + if !mc.watching || mc.finished == nil { + return + } + select { + case mc.finished <- struct{}{}: + mc.watching = false + case <-mc.closech: + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/connection_go18.go b/vendor/github.com/go-sql-driver/mysql/connection_go18.go new file mode 100644 index 0000000..62796bf --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection_go18.go @@ -0,0 +1,208 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "database/sql/driver" +) + +// Ping implements driver.Pinger interface +func (mc *mysqlConn) Ping(ctx context.Context) (err error) { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return driver.ErrBadConn + } + + if err = mc.watchCancel(ctx); err != nil { + return + } + defer mc.finish() + + if err = mc.writeCommandPacket(comPing); err != nil { + return + } + + return mc.readResultOK() +} + +// BeginTx implements driver.ConnBeginTx interface +func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { + level, err := mapIsolationLevel(opts.Isolation) + if err != nil { + return nil, err + } + err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) + if err != nil { + return nil, err + } + } + + return mc.begin(opts.ReadOnly) +} + +func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := mc.query(query, dargs) + if err != nil { + mc.finish() + return nil, err + } + rows.finish = mc.finish + return rows, err +} + +func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + return mc.Exec(query, dargs) +} + +func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + stmt, err := mc.Prepare(query) + mc.finish() + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + stmt.Close() + return nil, ctx.Err() + } + return stmt, nil +} + +func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := stmt.query(dargs) + if err != nil { + stmt.mc.finish() + return nil, err + } + rows.finish = stmt.mc.finish + return rows, err +} + +func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.mc.finish() + + return stmt.Exec(dargs) +} + +func (mc *mysqlConn) watchCancel(ctx context.Context) error { + if mc.watching { + // Reach here if canceled, + // so the connection is already invalid + mc.cleanup() + return nil + } + if ctx.Done() == nil { + return nil + } + + mc.watching = true + select { + default: + case <-ctx.Done(): + return ctx.Err() + } + if mc.watcher == nil { + return nil + } + + mc.watcher <- ctx + + return nil +} + +func (mc *mysqlConn) startWatcher() { + watcher := make(chan mysqlContext, 1) + mc.watcher = watcher + finished := make(chan struct{}) + mc.finished = finished + go func() { + for { + var ctx mysqlContext + select { + case ctx = <-watcher: + case <-mc.closech: + return + } + + select { + case <-ctx.Done(): + mc.cancel(ctx.Err()) + case <-finished: + case <-mc.closech: + return + } + } + }() +} + +func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { + nv.Value, err = converter{}.ConvertValue(nv.Value) + return +} + +// ResetSession implements driver.SessionResetter. +// (From Go 1.10) +func (mc *mysqlConn) ResetSession(ctx context.Context) error { + if mc.closed.IsSet() { + return driver.ErrBadConn + } + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/const.go b/vendor/github.com/go-sql-driver/mysql/const.go new file mode 100644 index 0000000..b1e6b85 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/const.go @@ -0,0 +1,174 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +const ( + defaultAuthPlugin = "mysql_native_password" + defaultMaxAllowedPacket = 4 << 20 // 4 MiB + minProtocolVersion = 10 + maxPacketSize = 1<<24 - 1 + timeFormat = "2006-01-02 15:04:05.999999" +) + +// MySQL constants documentation: +// http://dev.mysql.com/doc/internals/en/client-server-protocol.html + +const ( + iOK byte = 0x00 + iAuthMoreData byte = 0x01 + iLocalInFile byte = 0xfb + iEOF byte = 0xfe + iERR byte = 0xff +) + +// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags +type clientFlag uint32 + +const ( + clientLongPassword clientFlag = 1 << iota + clientFoundRows + clientLongFlag + clientConnectWithDB + clientNoSchema + clientCompress + clientODBC + clientLocalFiles + clientIgnoreSpace + clientProtocol41 + clientInteractive + clientSSL + clientIgnoreSIGPIPE + clientTransactions + clientReserved + clientSecureConn + clientMultiStatements + clientMultiResults + clientPSMultiResults + clientPluginAuth + clientConnectAttrs + clientPluginAuthLenEncClientData + clientCanHandleExpiredPasswords + clientSessionTrack + clientDeprecateEOF +) + +const ( + comQuit byte = iota + 1 + comInitDB + comQuery + comFieldList + comCreateDB + comDropDB + comRefresh + comShutdown + comStatistics + comProcessInfo + comConnect + comProcessKill + comDebug + comPing + comTime + comDelayedInsert + comChangeUser + comBinlogDump + comTableDump + comConnectOut + comRegisterSlave + comStmtPrepare + comStmtExecute + comStmtSendLongData + comStmtClose + comStmtReset + comSetOption + comStmtFetch +) + +// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType +type fieldType byte + +const ( + fieldTypeDecimal fieldType = iota + fieldTypeTiny + fieldTypeShort + fieldTypeLong + fieldTypeFloat + fieldTypeDouble + fieldTypeNULL + fieldTypeTimestamp + fieldTypeLongLong + fieldTypeInt24 + fieldTypeDate + fieldTypeTime + fieldTypeDateTime + fieldTypeYear + fieldTypeNewDate + fieldTypeVarChar + fieldTypeBit +) +const ( + fieldTypeJSON fieldType = iota + 0xf5 + fieldTypeNewDecimal + fieldTypeEnum + fieldTypeSet + fieldTypeTinyBLOB + fieldTypeMediumBLOB + fieldTypeLongBLOB + fieldTypeBLOB + fieldTypeVarString + fieldTypeString + fieldTypeGeometry +) + +type fieldFlag uint16 + +const ( + flagNotNULL fieldFlag = 1 << iota + flagPriKey + flagUniqueKey + flagMultipleKey + flagBLOB + flagUnsigned + flagZeroFill + flagBinary + flagEnum + flagAutoIncrement + flagTimestamp + flagSet + flagUnknown1 + flagUnknown2 + flagUnknown3 + flagUnknown4 +) + +// http://dev.mysql.com/doc/internals/en/status-flags.html +type statusFlag uint16 + +const ( + statusInTrans statusFlag = 1 << iota + statusInAutocommit + statusReserved // Not in documentation + statusMoreResultsExists + statusNoGoodIndexUsed + statusNoIndexUsed + statusCursorExists + statusLastRowSent + statusDbDropped + statusNoBackslashEscapes + statusMetadataChanged + statusQueryWasSlow + statusPsOutParams + statusInTransReadonly + statusSessionStateChanged +) + +const ( + cachingSha2PasswordRequestPublicKey = 2 + cachingSha2PasswordFastAuthSuccess = 3 + cachingSha2PasswordPerformFullAuthentication = 4 +) diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go new file mode 100644 index 0000000..1a75a16 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/driver.go @@ -0,0 +1,169 @@ +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package mysql provides a MySQL driver for Go's database/sql package. +// +// The driver should be used via the database/sql package: +// +// import "database/sql" +// import _ "github.com/go-sql-driver/mysql" +// +// db, err := sql.Open("mysql", "user:password@/dbname") +// +// See https://github.com/go-sql-driver/mysql#usage for details +package mysql + +import ( + "database/sql" + "database/sql/driver" + "net" + "sync" +) + +// watcher interface is used for context support (From Go 1.8) +type watcher interface { + startWatcher() +} + +// MySQLDriver is exported to make the driver directly accessible. +// In general the driver is used via the database/sql package. +type MySQLDriver struct{} + +// DialFunc is a function which can be used to establish the network connection. +// Custom dial functions must be registered with RegisterDial +type DialFunc func(addr string) (net.Conn, error) + +var ( + dialsLock sync.RWMutex + dials map[string]DialFunc +) + +// RegisterDial registers a custom dial function. It can then be used by the +// network address mynet(addr), where mynet is the registered new network. +// addr is passed as a parameter to the dial function. +func RegisterDial(net string, dial DialFunc) { + dialsLock.Lock() + defer dialsLock.Unlock() + if dials == nil { + dials = make(map[string]DialFunc) + } + dials[net] = dial +} + +// Open new Connection. +// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how +// the DSN string is formated +func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { + var err error + + // New mysqlConn + mc := &mysqlConn{ + maxAllowedPacket: maxPacketSize, + maxWriteSize: maxPacketSize - 1, + closech: make(chan struct{}), + } + mc.cfg, err = ParseDSN(dsn) + if err != nil { + return nil, err + } + mc.parseTime = mc.cfg.ParseTime + + // Connect to Server + dialsLock.RLock() + dial, ok := dials[mc.cfg.Net] + dialsLock.RUnlock() + if ok { + mc.netConn, err = dial(mc.cfg.Addr) + } else { + nd := net.Dialer{Timeout: mc.cfg.Timeout} + mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr) + } + if err != nil { + return nil, err + } + + // Enable TCP Keepalives on TCP connections + if tc, ok := mc.netConn.(*net.TCPConn); ok { + if err := tc.SetKeepAlive(true); err != nil { + // Don't send COM_QUIT before handshake. + mc.netConn.Close() + mc.netConn = nil + return nil, err + } + } + + // Call startWatcher for context support (From Go 1.8) + if s, ok := interface{}(mc).(watcher); ok { + s.startWatcher() + } + + mc.buf = newBuffer(mc.netConn) + + // Set I/O timeouts + mc.buf.timeout = mc.cfg.ReadTimeout + mc.writeTimeout = mc.cfg.WriteTimeout + + // Reading Handshake Initialization Packet + authData, plugin, err := mc.readHandshakePacket() + if err != nil { + mc.cleanup() + return nil, err + } + + // Send Client Authentication Packet + authResp, addNUL, err := mc.auth(authData, plugin) + if err != nil { + // try the default auth plugin, if using the requested plugin failed + errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) + plugin = defaultAuthPlugin + authResp, addNUL, err = mc.auth(authData, plugin) + if err != nil { + mc.cleanup() + return nil, err + } + } + if err = mc.writeHandshakeResponsePacket(authResp, addNUL, plugin); err != nil { + mc.cleanup() + return nil, err + } + + // Handle response to auth packet, switch methods if possible + if err = mc.handleAuthResult(authData, plugin); err != nil { + // Authentication failed and MySQL has already closed the connection + // (https://dev.mysql.com/doc/internals/en/authentication-fails.html). + // Do not send COM_QUIT, just cleanup and return the error. + mc.cleanup() + return nil, err + } + + if mc.cfg.MaxAllowedPacket > 0 { + mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket + } else { + // Get max allowed packet size + maxap, err := mc.getSystemVar("max_allowed_packet") + if err != nil { + mc.Close() + return nil, err + } + mc.maxAllowedPacket = stringToInt(maxap) - 1 + } + if mc.maxAllowedPacket < maxPacketSize { + mc.maxWriteSize = mc.maxAllowedPacket + } + + // Handle DSN Params + err = mc.handleParams() + if err != nil { + mc.Close() + return nil, err + } + + return mc, nil +} + +func init() { + sql.Register("mysql", &MySQLDriver{}) +} diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go new file mode 100644 index 0000000..be014ba --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/dsn.go @@ -0,0 +1,611 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "bytes" + "crypto/rsa" + "crypto/tls" + "errors" + "fmt" + "net" + "net/url" + "sort" + "strconv" + "strings" + "time" +) + +var ( + errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?") + errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)") + errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name") + errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") +) + +// Config is a configuration parsed from a DSN string. +// If a new Config is created instead of being parsed from a DSN string, +// the NewConfig function should be used, which sets default values. +type Config struct { + User string // Username + Passwd string // Password (requires User) + Net string // Network type + Addr string // Network address (requires Net) + DBName string // Database name + Params map[string]string // Connection parameters + Collation string // Connection collation + Loc *time.Location // Location for time.Time values + MaxAllowedPacket int // Max packet size allowed + ServerPubKey string // Server public key name + pubKey *rsa.PublicKey // Server public key + TLSConfig string // TLS configuration name + tls *tls.Config // TLS configuration + Timeout time.Duration // Dial timeout + ReadTimeout time.Duration // I/O read timeout + WriteTimeout time.Duration // I/O write timeout + + AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE + AllowCleartextPasswords bool // Allows the cleartext client side plugin + AllowNativePasswords bool // Allows the native password authentication method + AllowOldPasswords bool // Allows the old insecure password method + ClientFoundRows bool // Return number of matching rows instead of rows changed + ColumnsWithAlias bool // Prepend table alias to column names + InterpolateParams bool // Interpolate placeholders into query string + MultiStatements bool // Allow multiple statements in one query + ParseTime bool // Parse time values to time.Time + RejectReadOnly bool // Reject read-only connections +} + +// NewConfig creates a new Config and sets default values. +func NewConfig() *Config { + return &Config{ + Collation: defaultCollation, + Loc: time.UTC, + MaxAllowedPacket: defaultMaxAllowedPacket, + AllowNativePasswords: true, + } +} + +func (cfg *Config) normalize() error { + if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { + return errInvalidDSNUnsafeCollation + } + + // Set default network if empty + if cfg.Net == "" { + cfg.Net = "tcp" + } + + // Set default address if empty + if cfg.Addr == "" { + switch cfg.Net { + case "tcp": + cfg.Addr = "127.0.0.1:3306" + case "unix": + cfg.Addr = "/tmp/mysql.sock" + default: + return errors.New("default addr for network '" + cfg.Net + "' unknown") + } + + } else if cfg.Net == "tcp" { + cfg.Addr = ensureHavePort(cfg.Addr) + } + + if cfg.tls != nil { + if cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify { + host, _, err := net.SplitHostPort(cfg.Addr) + if err == nil { + cfg.tls.ServerName = host + } + } + } + + return nil +} + +// FormatDSN formats the given Config into a DSN string which can be passed to +// the driver. +func (cfg *Config) FormatDSN() string { + var buf bytes.Buffer + + // [username[:password]@] + if len(cfg.User) > 0 { + buf.WriteString(cfg.User) + if len(cfg.Passwd) > 0 { + buf.WriteByte(':') + buf.WriteString(cfg.Passwd) + } + buf.WriteByte('@') + } + + // [protocol[(address)]] + if len(cfg.Net) > 0 { + buf.WriteString(cfg.Net) + if len(cfg.Addr) > 0 { + buf.WriteByte('(') + buf.WriteString(cfg.Addr) + buf.WriteByte(')') + } + } + + // /dbname + buf.WriteByte('/') + buf.WriteString(cfg.DBName) + + // [?param1=value1&...¶mN=valueN] + hasParam := false + + if cfg.AllowAllFiles { + hasParam = true + buf.WriteString("?allowAllFiles=true") + } + + if cfg.AllowCleartextPasswords { + if hasParam { + buf.WriteString("&allowCleartextPasswords=true") + } else { + hasParam = true + buf.WriteString("?allowCleartextPasswords=true") + } + } + + if !cfg.AllowNativePasswords { + if hasParam { + buf.WriteString("&allowNativePasswords=false") + } else { + hasParam = true + buf.WriteString("?allowNativePasswords=false") + } + } + + if cfg.AllowOldPasswords { + if hasParam { + buf.WriteString("&allowOldPasswords=true") + } else { + hasParam = true + buf.WriteString("?allowOldPasswords=true") + } + } + + if cfg.ClientFoundRows { + if hasParam { + buf.WriteString("&clientFoundRows=true") + } else { + hasParam = true + buf.WriteString("?clientFoundRows=true") + } + } + + if col := cfg.Collation; col != defaultCollation && len(col) > 0 { + if hasParam { + buf.WriteString("&collation=") + } else { + hasParam = true + buf.WriteString("?collation=") + } + buf.WriteString(col) + } + + if cfg.ColumnsWithAlias { + if hasParam { + buf.WriteString("&columnsWithAlias=true") + } else { + hasParam = true + buf.WriteString("?columnsWithAlias=true") + } + } + + if cfg.InterpolateParams { + if hasParam { + buf.WriteString("&interpolateParams=true") + } else { + hasParam = true + buf.WriteString("?interpolateParams=true") + } + } + + if cfg.Loc != time.UTC && cfg.Loc != nil { + if hasParam { + buf.WriteString("&loc=") + } else { + hasParam = true + buf.WriteString("?loc=") + } + buf.WriteString(url.QueryEscape(cfg.Loc.String())) + } + + if cfg.MultiStatements { + if hasParam { + buf.WriteString("&multiStatements=true") + } else { + hasParam = true + buf.WriteString("?multiStatements=true") + } + } + + if cfg.ParseTime { + if hasParam { + buf.WriteString("&parseTime=true") + } else { + hasParam = true + buf.WriteString("?parseTime=true") + } + } + + if cfg.ReadTimeout > 0 { + if hasParam { + buf.WriteString("&readTimeout=") + } else { + hasParam = true + buf.WriteString("?readTimeout=") + } + buf.WriteString(cfg.ReadTimeout.String()) + } + + if cfg.RejectReadOnly { + if hasParam { + buf.WriteString("&rejectReadOnly=true") + } else { + hasParam = true + buf.WriteString("?rejectReadOnly=true") + } + } + + if len(cfg.ServerPubKey) > 0 { + if hasParam { + buf.WriteString("&serverPubKey=") + } else { + hasParam = true + buf.WriteString("?serverPubKey=") + } + buf.WriteString(url.QueryEscape(cfg.ServerPubKey)) + } + + if cfg.Timeout > 0 { + if hasParam { + buf.WriteString("&timeout=") + } else { + hasParam = true + buf.WriteString("?timeout=") + } + buf.WriteString(cfg.Timeout.String()) + } + + if len(cfg.TLSConfig) > 0 { + if hasParam { + buf.WriteString("&tls=") + } else { + hasParam = true + buf.WriteString("?tls=") + } + buf.WriteString(url.QueryEscape(cfg.TLSConfig)) + } + + if cfg.WriteTimeout > 0 { + if hasParam { + buf.WriteString("&writeTimeout=") + } else { + hasParam = true + buf.WriteString("?writeTimeout=") + } + buf.WriteString(cfg.WriteTimeout.String()) + } + + if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { + if hasParam { + buf.WriteString("&maxAllowedPacket=") + } else { + hasParam = true + buf.WriteString("?maxAllowedPacket=") + } + buf.WriteString(strconv.Itoa(cfg.MaxAllowedPacket)) + + } + + // other params + if cfg.Params != nil { + var params []string + for param := range cfg.Params { + params = append(params, param) + } + sort.Strings(params) + for _, param := range params { + if hasParam { + buf.WriteByte('&') + } else { + hasParam = true + buf.WriteByte('?') + } + + buf.WriteString(param) + buf.WriteByte('=') + buf.WriteString(url.QueryEscape(cfg.Params[param])) + } + } + + return buf.String() +} + +// ParseDSN parses the DSN string to a Config +func ParseDSN(dsn string) (cfg *Config, err error) { + // New config with some default values + cfg = NewConfig() + + // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] + // Find the last '/' (since the password or the net addr might contain a '/') + foundSlash := false + for i := len(dsn) - 1; i >= 0; i-- { + if dsn[i] == '/' { + foundSlash = true + var j, k int + + // left part is empty if i <= 0 + if i > 0 { + // [username[:password]@][protocol[(address)]] + // Find the last '@' in dsn[:i] + for j = i; j >= 0; j-- { + if dsn[j] == '@' { + // username[:password] + // Find the first ':' in dsn[:j] + for k = 0; k < j; k++ { + if dsn[k] == ':' { + cfg.Passwd = dsn[k+1 : j] + break + } + } + cfg.User = dsn[:k] + + break + } + } + + // [protocol[(address)]] + // Find the first '(' in dsn[j+1:i] + for k = j + 1; k < i; k++ { + if dsn[k] == '(' { + // dsn[i-1] must be == ')' if an address is specified + if dsn[i-1] != ')' { + if strings.ContainsRune(dsn[k+1:i], ')') { + return nil, errInvalidDSNUnescaped + } + return nil, errInvalidDSNAddr + } + cfg.Addr = dsn[k+1 : i-1] + break + } + } + cfg.Net = dsn[j+1 : k] + } + + // dbname[?param1=value1&...¶mN=valueN] + // Find the first '?' in dsn[i+1:] + for j = i + 1; j < len(dsn); j++ { + if dsn[j] == '?' { + if err = parseDSNParams(cfg, dsn[j+1:]); err != nil { + return + } + break + } + } + cfg.DBName = dsn[i+1 : j] + + break + } + } + + if !foundSlash && len(dsn) > 0 { + return nil, errInvalidDSNNoSlash + } + + if err = cfg.normalize(); err != nil { + return nil, err + } + return +} + +// parseDSNParams parses the DSN "query string" +// Values must be url.QueryEscape'ed +func parseDSNParams(cfg *Config, params string) (err error) { + for _, v := range strings.Split(params, "&") { + param := strings.SplitN(v, "=", 2) + if len(param) != 2 { + continue + } + + // cfg params + switch value := param[1]; param[0] { + // Disable INFILE whitelist / enable all files + case "allowAllFiles": + var isBool bool + cfg.AllowAllFiles, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Use cleartext authentication mode (MySQL 5.5.10+) + case "allowCleartextPasswords": + var isBool bool + cfg.AllowCleartextPasswords, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Use native password authentication + case "allowNativePasswords": + var isBool bool + cfg.AllowNativePasswords, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Use old authentication mode (pre MySQL 4.1) + case "allowOldPasswords": + var isBool bool + cfg.AllowOldPasswords, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Switch "rowsAffected" mode + case "clientFoundRows": + var isBool bool + cfg.ClientFoundRows, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Collation + case "collation": + cfg.Collation = value + break + + case "columnsWithAlias": + var isBool bool + cfg.ColumnsWithAlias, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Compression + case "compress": + return errors.New("compression not implemented yet") + + // Enable client side placeholder substitution + case "interpolateParams": + var isBool bool + cfg.InterpolateParams, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Time Location + case "loc": + if value, err = url.QueryUnescape(value); err != nil { + return + } + cfg.Loc, err = time.LoadLocation(value) + if err != nil { + return + } + + // multiple statements in one query + case "multiStatements": + var isBool bool + cfg.MultiStatements, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // time.Time parsing + case "parseTime": + var isBool bool + cfg.ParseTime, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // I/O read Timeout + case "readTimeout": + cfg.ReadTimeout, err = time.ParseDuration(value) + if err != nil { + return + } + + // Reject read-only connections + case "rejectReadOnly": + var isBool bool + cfg.RejectReadOnly, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } + + // Server public key + case "serverPubKey": + name, err := url.QueryUnescape(value) + if err != nil { + return fmt.Errorf("invalid value for server pub key name: %v", err) + } + + if pubKey := getServerPubKey(name); pubKey != nil { + cfg.ServerPubKey = name + cfg.pubKey = pubKey + } else { + return errors.New("invalid value / unknown server pub key name: " + name) + } + + // Strict mode + case "strict": + panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") + + // Dial Timeout + case "timeout": + cfg.Timeout, err = time.ParseDuration(value) + if err != nil { + return + } + + // TLS-Encryption + case "tls": + boolValue, isBool := readBool(value) + if isBool { + if boolValue { + cfg.TLSConfig = "true" + cfg.tls = &tls.Config{} + } else { + cfg.TLSConfig = "false" + } + } else if vl := strings.ToLower(value); vl == "skip-verify" { + cfg.TLSConfig = vl + cfg.tls = &tls.Config{InsecureSkipVerify: true} + } else { + name, err := url.QueryUnescape(value) + if err != nil { + return fmt.Errorf("invalid value for TLS config name: %v", err) + } + + if tlsConfig := getTLSConfigClone(name); tlsConfig != nil { + cfg.TLSConfig = name + cfg.tls = tlsConfig + } else { + return errors.New("invalid value / unknown config name: " + name) + } + } + + // I/O write Timeout + case "writeTimeout": + cfg.WriteTimeout, err = time.ParseDuration(value) + if err != nil { + return + } + case "maxAllowedPacket": + cfg.MaxAllowedPacket, err = strconv.Atoi(value) + if err != nil { + return + } + default: + // lazy init + if cfg.Params == nil { + cfg.Params = make(map[string]string) + } + + if cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil { + return + } + } + } + + return +} + +func ensureHavePort(addr string) string { + if _, _, err := net.SplitHostPort(addr); err != nil { + return net.JoinHostPort(addr, "3306") + } + return addr +} diff --git a/vendor/github.com/go-sql-driver/mysql/errors.go b/vendor/github.com/go-sql-driver/mysql/errors.go new file mode 100644 index 0000000..760782f --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/errors.go @@ -0,0 +1,65 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "errors" + "fmt" + "log" + "os" +) + +// Various errors the driver might return. Can change between driver versions. +var ( + ErrInvalidConn = errors.New("invalid connection") + ErrMalformPkt = errors.New("malformed packet") + ErrNoTLS = errors.New("TLS requested but server does not support TLS") + ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN") + ErrNativePassword = errors.New("this user requires mysql native password authentication.") + ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") + ErrUnknownPlugin = errors.New("this authentication plugin is not supported") + ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+") + ErrPktSync = errors.New("commands out of sync. You can't run this command now") + ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") + ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") + ErrBusyBuffer = errors.New("busy buffer") + + // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. + // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn + // to trigger a resend. + // See https://github.com/go-sql-driver/mysql/pull/302 + errBadConnNoWrite = errors.New("bad connection") +) + +var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) + +// Logger is used to log critical error messages. +type Logger interface { + Print(v ...interface{}) +} + +// SetLogger is used to set the logger for critical errors. +// The initial logger is os.Stderr. +func SetLogger(logger Logger) error { + if logger == nil { + return errors.New("logger is nil") + } + errLog = logger + return nil +} + +// MySQLError is an error type which represents a single MySQL error +type MySQLError struct { + Number uint16 + Message string +} + +func (me *MySQLError) Error() string { + return fmt.Sprintf("Error %d: %s", me.Number, me.Message) +} diff --git a/vendor/github.com/go-sql-driver/mysql/fields.go b/vendor/github.com/go-sql-driver/mysql/fields.go new file mode 100644 index 0000000..e1e2ece --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/fields.go @@ -0,0 +1,194 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql" + "reflect" +) + +func (mf *mysqlField) typeDatabaseName() string { + switch mf.fieldType { + case fieldTypeBit: + return "BIT" + case fieldTypeBLOB: + if mf.charSet != collations[binaryCollation] { + return "TEXT" + } + return "BLOB" + case fieldTypeDate: + return "DATE" + case fieldTypeDateTime: + return "DATETIME" + case fieldTypeDecimal: + return "DECIMAL" + case fieldTypeDouble: + return "DOUBLE" + case fieldTypeEnum: + return "ENUM" + case fieldTypeFloat: + return "FLOAT" + case fieldTypeGeometry: + return "GEOMETRY" + case fieldTypeInt24: + return "MEDIUMINT" + case fieldTypeJSON: + return "JSON" + case fieldTypeLong: + return "INT" + case fieldTypeLongBLOB: + if mf.charSet != collations[binaryCollation] { + return "LONGTEXT" + } + return "LONGBLOB" + case fieldTypeLongLong: + return "BIGINT" + case fieldTypeMediumBLOB: + if mf.charSet != collations[binaryCollation] { + return "MEDIUMTEXT" + } + return "MEDIUMBLOB" + case fieldTypeNewDate: + return "DATE" + case fieldTypeNewDecimal: + return "DECIMAL" + case fieldTypeNULL: + return "NULL" + case fieldTypeSet: + return "SET" + case fieldTypeShort: + return "SMALLINT" + case fieldTypeString: + if mf.charSet == collations[binaryCollation] { + return "BINARY" + } + return "CHAR" + case fieldTypeTime: + return "TIME" + case fieldTypeTimestamp: + return "TIMESTAMP" + case fieldTypeTiny: + return "TINYINT" + case fieldTypeTinyBLOB: + if mf.charSet != collations[binaryCollation] { + return "TINYTEXT" + } + return "TINYBLOB" + case fieldTypeVarChar: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeVarString: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeYear: + return "YEAR" + default: + return "" + } +} + +var ( + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullTime = reflect.TypeOf(NullTime{}) + scanTypeUint8 = reflect.TypeOf(uint8(0)) + scanTypeUint16 = reflect.TypeOf(uint16(0)) + scanTypeUint32 = reflect.TypeOf(uint32(0)) + scanTypeUint64 = reflect.TypeOf(uint64(0)) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeUnknown = reflect.TypeOf(new(interface{})) +) + +type mysqlField struct { + tableName string + name string + length uint32 + flags fieldFlag + fieldType fieldType + decimals byte + charSet uint8 +} + +func (mf *mysqlField) scanType() reflect.Type { + switch mf.fieldType { + case fieldTypeTiny: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint8 + } + return scanTypeInt8 + } + return scanTypeNullInt + + case fieldTypeShort, fieldTypeYear: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint16 + } + return scanTypeInt16 + } + return scanTypeNullInt + + case fieldTypeInt24, fieldTypeLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint32 + } + return scanTypeInt32 + } + return scanTypeNullInt + + case fieldTypeLongLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint64 + } + return scanTypeInt64 + } + return scanTypeNullInt + + case fieldTypeFloat: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat32 + } + return scanTypeNullFloat + + case fieldTypeDouble: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat64 + } + return scanTypeNullFloat + + case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, + fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, + fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, + fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, + fieldTypeTime: + return scanTypeRawBytes + + case fieldTypeDate, fieldTypeNewDate, + fieldTypeTimestamp, fieldTypeDateTime: + // NullTime is always returned for more consistent behavior as it can + // handle both cases of parseTime regardless if the field is nullable. + return scanTypeNullTime + + default: + return scanTypeUnknown + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/infile.go b/vendor/github.com/go-sql-driver/mysql/infile.go new file mode 100644 index 0000000..273cb0b --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/infile.go @@ -0,0 +1,182 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "fmt" + "io" + "os" + "strings" + "sync" +) + +var ( + fileRegister map[string]bool + fileRegisterLock sync.RWMutex + readerRegister map[string]func() io.Reader + readerRegisterLock sync.RWMutex +) + +// RegisterLocalFile adds the given file to the file whitelist, +// so that it can be used by "LOAD DATA LOCAL INFILE ". +// Alternatively you can allow the use of all local files with +// the DSN parameter 'allowAllFiles=true' +// +// filePath := "/home/gopher/data.csv" +// mysql.RegisterLocalFile(filePath) +// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo") +// if err != nil { +// ... +// +func RegisterLocalFile(filePath string) { + fileRegisterLock.Lock() + // lazy map init + if fileRegister == nil { + fileRegister = make(map[string]bool) + } + + fileRegister[strings.Trim(filePath, `"`)] = true + fileRegisterLock.Unlock() +} + +// DeregisterLocalFile removes the given filepath from the whitelist. +func DeregisterLocalFile(filePath string) { + fileRegisterLock.Lock() + delete(fileRegister, strings.Trim(filePath, `"`)) + fileRegisterLock.Unlock() +} + +// RegisterReaderHandler registers a handler function which is used +// to receive a io.Reader. +// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::". +// If the handler returns a io.ReadCloser Close() is called when the +// request is finished. +// +// mysql.RegisterReaderHandler("data", func() io.Reader { +// var csvReader io.Reader // Some Reader that returns CSV data +// ... // Open Reader here +// return csvReader +// }) +// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo") +// if err != nil { +// ... +// +func RegisterReaderHandler(name string, handler func() io.Reader) { + readerRegisterLock.Lock() + // lazy map init + if readerRegister == nil { + readerRegister = make(map[string]func() io.Reader) + } + + readerRegister[name] = handler + readerRegisterLock.Unlock() +} + +// DeregisterReaderHandler removes the ReaderHandler function with +// the given name from the registry. +func DeregisterReaderHandler(name string) { + readerRegisterLock.Lock() + delete(readerRegister, name) + readerRegisterLock.Unlock() +} + +func deferredClose(err *error, closer io.Closer) { + closeErr := closer.Close() + if *err == nil { + *err = closeErr + } +} + +func (mc *mysqlConn) handleInFileRequest(name string) (err error) { + var rdr io.Reader + var data []byte + packetSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP + if mc.maxWriteSize < packetSize { + packetSize = mc.maxWriteSize + } + + if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader + // The server might return an an absolute path. See issue #355. + name = name[idx+8:] + + readerRegisterLock.RLock() + handler, inMap := readerRegister[name] + readerRegisterLock.RUnlock() + + if inMap { + rdr = handler() + if rdr != nil { + if cl, ok := rdr.(io.Closer); ok { + defer deferredClose(&err, cl) + } + } else { + err = fmt.Errorf("Reader '%s' is ", name) + } + } else { + err = fmt.Errorf("Reader '%s' is not registered", name) + } + } else { // File + name = strings.Trim(name, `"`) + fileRegisterLock.RLock() + fr := fileRegister[name] + fileRegisterLock.RUnlock() + if mc.cfg.AllowAllFiles || fr { + var file *os.File + var fi os.FileInfo + + if file, err = os.Open(name); err == nil { + defer deferredClose(&err, file) + + // get file size + if fi, err = file.Stat(); err == nil { + rdr = file + if fileSize := int(fi.Size()); fileSize < packetSize { + packetSize = fileSize + } + } + } + } else { + err = fmt.Errorf("local file '%s' is not registered", name) + } + } + + // send content packets + // if packetSize == 0, the Reader contains no data + if err == nil && packetSize > 0 { + data := make([]byte, 4+packetSize) + var n int + for err == nil { + n, err = rdr.Read(data[4:]) + if n > 0 { + if ioErr := mc.writePacket(data[:4+n]); ioErr != nil { + return ioErr + } + } + } + if err == io.EOF { + err = nil + } + } + + // send empty packet (termination) + if data == nil { + data = make([]byte, 4) + } + if ioErr := mc.writePacket(data[:4]); ioErr != nil { + return ioErr + } + + // read OK packet + if err == nil { + return mc.readResultOK() + } + + mc.readPacket() + return err +} diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go new file mode 100644 index 0000000..d873a97 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/packets.go @@ -0,0 +1,1301 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "bytes" + "crypto/tls" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "time" +) + +// Packets documentation: +// http://dev.mysql.com/doc/internals/en/client-server-protocol.html + +// Read packet to buffer 'data' +func (mc *mysqlConn) readPacket() ([]byte, error) { + var prevData []byte + for { + // read packet header + data, err := mc.buf.readNext(4) + if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } + errLog.Print(err) + mc.Close() + return nil, ErrInvalidConn + } + + // packet length [24 bit] + pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) + + // check packet sync [8 bit] + if data[3] != mc.sequence { + if data[3] > mc.sequence { + return nil, ErrPktSyncMul + } + return nil, ErrPktSync + } + mc.sequence++ + + // packets with length 0 terminate a previous packet which is a + // multiple of (2^24)−1 bytes long + if pktLen == 0 { + // there was no previous packet + if prevData == nil { + errLog.Print(ErrMalformPkt) + mc.Close() + return nil, ErrInvalidConn + } + + return prevData, nil + } + + // read packet body [pktLen bytes] + data, err = mc.buf.readNext(pktLen) + if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } + errLog.Print(err) + mc.Close() + return nil, ErrInvalidConn + } + + // return data if this was the last packet + if pktLen < maxPacketSize { + // zero allocations for non-split packets + if prevData == nil { + return data, nil + } + + return append(prevData, data...), nil + } + + prevData = append(prevData, data...) + } +} + +// Write packet buffer 'data' +func (mc *mysqlConn) writePacket(data []byte) error { + pktLen := len(data) - 4 + + if pktLen > mc.maxAllowedPacket { + return ErrPktTooLarge + } + + for { + var size int + if pktLen >= maxPacketSize { + data[0] = 0xff + data[1] = 0xff + data[2] = 0xff + size = maxPacketSize + } else { + data[0] = byte(pktLen) + data[1] = byte(pktLen >> 8) + data[2] = byte(pktLen >> 16) + size = pktLen + } + data[3] = mc.sequence + + // Write packet + if mc.writeTimeout > 0 { + if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { + return err + } + } + + n, err := mc.netConn.Write(data[:4+size]) + if err == nil && n == 4+size { + mc.sequence++ + if size != maxPacketSize { + return nil + } + pktLen -= size + data = data[size:] + continue + } + + // Handle error + if err == nil { // n != len(data) + mc.cleanup() + errLog.Print(ErrMalformPkt) + } else { + if cerr := mc.canceled.Value(); cerr != nil { + return cerr + } + if n == 0 && pktLen == len(data)-4 { + // only for the first loop iteration when nothing was written yet + return errBadConnNoWrite + } + mc.cleanup() + errLog.Print(err) + } + return ErrInvalidConn + } +} + +/****************************************************************************** +* Initialization Process * +******************************************************************************/ + +// Handshake Initialization Packet +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake +func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) { + data, err := mc.readPacket() + if err != nil { + // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since + // in connection initialization we don't risk retrying non-idempotent actions. + if err == ErrInvalidConn { + return nil, "", driver.ErrBadConn + } + return nil, "", err + } + + if data[0] == iERR { + return nil, "", mc.handleErrorPacket(data) + } + + // protocol version [1 byte] + if data[0] < minProtocolVersion { + return nil, "", fmt.Errorf( + "unsupported protocol version %d. Version %d or higher is required", + data[0], + minProtocolVersion, + ) + } + + // server version [null terminated string] + // connection id [4 bytes] + pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4 + + // first part of the password cipher [8 bytes] + authData := data[pos : pos+8] + + // (filler) always 0x00 [1 byte] + pos += 8 + 1 + + // capability flags (lower 2 bytes) [2 bytes] + mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) + if mc.flags&clientProtocol41 == 0 { + return nil, "", ErrOldProtocol + } + if mc.flags&clientSSL == 0 && mc.cfg.tls != nil { + return nil, "", ErrNoTLS + } + pos += 2 + + plugin := "" + if len(data) > pos { + // character set [1 byte] + // status flags [2 bytes] + // capability flags (upper 2 bytes) [2 bytes] + // length of auth-plugin-data [1 byte] + // reserved (all [00]) [10 bytes] + pos += 1 + 2 + 2 + 1 + 10 + + // second part of the password cipher [mininum 13 bytes], + // where len=MAX(13, length of auth-plugin-data - 8) + // + // The web documentation is ambiguous about the length. However, + // according to mysql-5.7/sql/auth/sql_authentication.cc line 538, + // the 13th byte is "\0 byte, terminating the second part of + // a scramble". So the second part of the password cipher is + // a NULL terminated string that's at least 13 bytes with the + // last byte being NULL. + // + // The official Python library uses the fixed length 12 + // which seems to work but technically could have a hidden bug. + authData = append(authData, data[pos:pos+12]...) + pos += 13 + + // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2) + // \NUL otherwise + if end := bytes.IndexByte(data[pos:], 0x00); end != -1 { + plugin = string(data[pos : pos+end]) + } else { + plugin = string(data[pos:]) + } + + // make a memory safe copy of the cipher slice + var b [20]byte + copy(b[:], authData) + return b[:], plugin, nil + } + + plugin = defaultAuthPlugin + + // make a memory safe copy of the cipher slice + var b [8]byte + copy(b[:], authData) + return b[:], plugin, nil +} + +// Client Authentication Packet +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse +func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error { + // Adjust client flags based on server support + clientFlags := clientProtocol41 | + clientSecureConn | + clientLongPassword | + clientTransactions | + clientLocalFiles | + clientPluginAuth | + clientMultiResults | + mc.flags&clientLongFlag + + if mc.cfg.ClientFoundRows { + clientFlags |= clientFoundRows + } + + // To enable TLS / SSL + if mc.cfg.tls != nil { + clientFlags |= clientSSL + } + + if mc.cfg.MultiStatements { + clientFlags |= clientMultiStatements + } + + // encode length of the auth plugin data + var authRespLEIBuf [9]byte + authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp))) + if len(authRespLEI) > 1 { + // if the length can not be written in 1 byte, it must be written as a + // length encoded integer + clientFlags |= clientPluginAuthLenEncClientData + } + + pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 + if addNUL { + pktLen++ + } + + // To specify a db name + if n := len(mc.cfg.DBName); n > 0 { + clientFlags |= clientConnectWithDB + pktLen += n + 1 + } + + // Calculate packet length and get buffer with that size + data := mc.buf.takeSmallBuffer(pktLen + 4) + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // ClientFlags [32 bit] + data[4] = byte(clientFlags) + data[5] = byte(clientFlags >> 8) + data[6] = byte(clientFlags >> 16) + data[7] = byte(clientFlags >> 24) + + // MaxPacketSize [32 bit] (none) + data[8] = 0x00 + data[9] = 0x00 + data[10] = 0x00 + data[11] = 0x00 + + // Charset [1 byte] + var found bool + data[12], found = collations[mc.cfg.Collation] + if !found { + // Note possibility for false negatives: + // could be triggered although the collation is valid if the + // collations map does not contain entries the server supports. + return errors.New("unknown collation") + } + + // SSL Connection Request Packet + // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest + if mc.cfg.tls != nil { + // Send TLS / SSL request packet + if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil { + return err + } + + // Switch to TLS + tlsConn := tls.Client(mc.netConn, mc.cfg.tls) + if err := tlsConn.Handshake(); err != nil { + return err + } + mc.netConn = tlsConn + mc.buf.nc = tlsConn + } + + // Filler [23 bytes] (all 0x00) + pos := 13 + for ; pos < 13+23; pos++ { + data[pos] = 0 + } + + // User [null terminated string] + if len(mc.cfg.User) > 0 { + pos += copy(data[pos:], mc.cfg.User) + } + data[pos] = 0x00 + pos++ + + // Auth Data [length encoded integer] + pos += copy(data[pos:], authRespLEI) + pos += copy(data[pos:], authResp) + if addNUL { + data[pos] = 0x00 + pos++ + } + + // Databasename [null terminated string] + if len(mc.cfg.DBName) > 0 { + pos += copy(data[pos:], mc.cfg.DBName) + data[pos] = 0x00 + pos++ + } + + pos += copy(data[pos:], plugin) + data[pos] = 0x00 + + // Send Auth packet + return mc.writePacket(data) +} + +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse +func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error { + pktLen := 4 + len(authData) + if addNUL { + pktLen++ + } + data := mc.buf.takeSmallBuffer(pktLen) + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // Add the auth data [EOF] + copy(data[4:], authData) + if addNUL { + data[pktLen-1] = 0x00 + } + + return mc.writePacket(data) +} + +/****************************************************************************** +* Command Packets * +******************************************************************************/ + +func (mc *mysqlConn) writeCommandPacket(command byte) error { + // Reset Packet Sequence + mc.sequence = 0 + + data := mc.buf.takeSmallBuffer(4 + 1) + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // Add command byte + data[4] = command + + // Send CMD packet + return mc.writePacket(data) +} + +func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { + // Reset Packet Sequence + mc.sequence = 0 + + pktLen := 1 + len(arg) + data := mc.buf.takeBuffer(pktLen + 4) + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // Add command byte + data[4] = command + + // Add arg + copy(data[5:], arg) + + // Send CMD packet + return mc.writePacket(data) +} + +func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { + // Reset Packet Sequence + mc.sequence = 0 + + data := mc.buf.takeSmallBuffer(4 + 1 + 4) + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // Add command byte + data[4] = command + + // Add arg [32 bit] + data[5] = byte(arg) + data[6] = byte(arg >> 8) + data[7] = byte(arg >> 16) + data[8] = byte(arg >> 24) + + // Send CMD packet + return mc.writePacket(data) +} + +/****************************************************************************** +* Result Packets * +******************************************************************************/ + +func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { + data, err := mc.readPacket() + if err != nil { + return nil, "", err + } + + // packet indicator + switch data[0] { + + case iOK: + return nil, "", mc.handleOkPacket(data) + + case iAuthMoreData: + return data[1:], "", err + + case iEOF: + if len(data) < 1 { + // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest + return nil, "mysql_old_password", nil + } + pluginEndIndex := bytes.IndexByte(data, 0x00) + if pluginEndIndex < 0 { + return nil, "", ErrMalformPkt + } + plugin := string(data[1:pluginEndIndex]) + authData := data[pluginEndIndex+1:] + return authData, plugin, nil + + default: // Error otherwise + return nil, "", mc.handleErrorPacket(data) + } +} + +// Returns error if Packet is not an 'Result OK'-Packet +func (mc *mysqlConn) readResultOK() error { + data, err := mc.readPacket() + if err != nil { + return err + } + + if data[0] == iOK { + return mc.handleOkPacket(data) + } + return mc.handleErrorPacket(data) +} + +// Result Set Header Packet +// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset +func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) { + data, err := mc.readPacket() + if err == nil { + switch data[0] { + + case iOK: + return 0, mc.handleOkPacket(data) + + case iERR: + return 0, mc.handleErrorPacket(data) + + case iLocalInFile: + return 0, mc.handleInFileRequest(string(data[1:])) + } + + // column count + num, _, n := readLengthEncodedInteger(data) + if n-len(data) == 0 { + return int(num), nil + } + + return 0, ErrMalformPkt + } + return 0, err +} + +// Error Packet +// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet +func (mc *mysqlConn) handleErrorPacket(data []byte) error { + if data[0] != iERR { + return ErrMalformPkt + } + + // 0xff [1 byte] + + // Error Number [16 bit uint] + errno := binary.LittleEndian.Uint16(data[1:3]) + + // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION + // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) + if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { + // Oops; we are connected to a read-only connection, and won't be able + // to issue any write statements. Since RejectReadOnly is configured, + // we throw away this connection hoping this one would have write + // permission. This is specifically for a possible race condition + // during failover (e.g. on AWS Aurora). See README.md for more. + // + // We explicitly close the connection before returning + // driver.ErrBadConn to ensure that `database/sql` purges this + // connection and initiates a new one for next statement next time. + mc.Close() + return driver.ErrBadConn + } + + pos := 3 + + // SQL State [optional: # + 5bytes string] + if data[3] == 0x23 { + //sqlstate := string(data[4 : 4+5]) + pos = 9 + } + + // Error Message [string] + return &MySQLError{ + Number: errno, + Message: string(data[pos:]), + } +} + +func readStatus(b []byte) statusFlag { + return statusFlag(b[0]) | statusFlag(b[1])<<8 +} + +// Ok Packet +// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet +func (mc *mysqlConn) handleOkPacket(data []byte) error { + var n, m int + + // 0x00 [1 byte] + + // Affected rows [Length Coded Binary] + mc.affectedRows, _, n = readLengthEncodedInteger(data[1:]) + + // Insert id [Length Coded Binary] + mc.insertId, _, m = readLengthEncodedInteger(data[1+n:]) + + // server_status [2 bytes] + mc.status = readStatus(data[1+n+m : 1+n+m+2]) + if mc.status&statusMoreResultsExists != 0 { + return nil + } + + // warning count [2 bytes] + + return nil +} + +// Read Packets as Field Packets until EOF-Packet or an Error appears +// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 +func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { + columns := make([]mysqlField, count) + + for i := 0; ; i++ { + data, err := mc.readPacket() + if err != nil { + return nil, err + } + + // EOF Packet + if data[0] == iEOF && (len(data) == 5 || len(data) == 1) { + if i == count { + return columns, nil + } + return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns)) + } + + // Catalog + pos, err := skipLengthEncodedString(data) + if err != nil { + return nil, err + } + + // Database [len coded string] + n, err := skipLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + pos += n + + // Table [len coded string] + if mc.cfg.ColumnsWithAlias { + tableName, _, n, err := readLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + pos += n + columns[i].tableName = string(tableName) + } else { + n, err = skipLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + pos += n + } + + // Original table [len coded string] + n, err = skipLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + pos += n + + // Name [len coded string] + name, _, n, err := readLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + columns[i].name = string(name) + pos += n + + // Original name [len coded string] + n, err = skipLengthEncodedString(data[pos:]) + if err != nil { + return nil, err + } + pos += n + + // Filler [uint8] + pos++ + + // Charset [charset, collation uint8] + columns[i].charSet = data[pos] + pos += 2 + + // Length [uint32] + columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) + pos += 4 + + // Field type [uint8] + columns[i].fieldType = fieldType(data[pos]) + pos++ + + // Flags [uint16] + columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) + pos += 2 + + // Decimals [uint8] + columns[i].decimals = data[pos] + //pos++ + + // Default value [len coded binary] + //if pos < len(data) { + // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:]) + //} + } +} + +// Read Packets as Field Packets until EOF-Packet or an Error appears +// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow +func (rows *textRows) readRow(dest []driver.Value) error { + mc := rows.mc + + if rows.rs.done { + return io.EOF + } + + data, err := mc.readPacket() + if err != nil { + return err + } + + // EOF Packet + if data[0] == iEOF && len(data) == 5 { + // server_status [2 bytes] + rows.mc.status = readStatus(data[3:]) + rows.rs.done = true + if !rows.HasNextResultSet() { + rows.mc = nil + } + return io.EOF + } + if data[0] == iERR { + rows.mc = nil + return mc.handleErrorPacket(data) + } + + // RowSet Packet + var n int + var isNull bool + pos := 0 + + for i := range dest { + // Read bytes and convert to string + dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) + pos += n + if err == nil { + if !isNull { + if !mc.parseTime { + continue + } else { + switch rows.rs.columns[i].fieldType { + case fieldTypeTimestamp, fieldTypeDateTime, + fieldTypeDate, fieldTypeNewDate: + dest[i], err = parseDateTime( + string(dest[i].([]byte)), + mc.cfg.Loc, + ) + if err == nil { + continue + } + default: + continue + } + } + + } else { + dest[i] = nil + continue + } + } + return err // err != nil + } + + return nil +} + +// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read +func (mc *mysqlConn) readUntilEOF() error { + for { + data, err := mc.readPacket() + if err != nil { + return err + } + + switch data[0] { + case iERR: + return mc.handleErrorPacket(data) + case iEOF: + if len(data) == 5 { + mc.status = readStatus(data[3:]) + } + return nil + } + } +} + +/****************************************************************************** +* Prepared Statements * +******************************************************************************/ + +// Prepare Result Packets +// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html +func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { + data, err := stmt.mc.readPacket() + if err == nil { + // packet indicator [1 byte] + if data[0] != iOK { + return 0, stmt.mc.handleErrorPacket(data) + } + + // statement id [4 bytes] + stmt.id = binary.LittleEndian.Uint32(data[1:5]) + + // Column count [16 bit uint] + columnCount := binary.LittleEndian.Uint16(data[5:7]) + + // Param count [16 bit uint] + stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9])) + + // Reserved [8 bit] + + // Warning count [16 bit uint] + + return columnCount, nil + } + return 0, err +} + +// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html +func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { + maxLen := stmt.mc.maxAllowedPacket - 1 + pktLen := maxLen + + // After the header (bytes 0-3) follows before the data: + // 1 byte command + // 4 bytes stmtID + // 2 bytes paramID + const dataOffset = 1 + 4 + 2 + + // Cannot use the write buffer since + // a) the buffer is too small + // b) it is in use + data := make([]byte, 4+1+4+2+len(arg)) + + copy(data[4+dataOffset:], arg) + + for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset { + if dataOffset+argLen < maxLen { + pktLen = dataOffset + argLen + } + + stmt.mc.sequence = 0 + // Add command byte [1 byte] + data[4] = comStmtSendLongData + + // Add stmtID [32 bit] + data[5] = byte(stmt.id) + data[6] = byte(stmt.id >> 8) + data[7] = byte(stmt.id >> 16) + data[8] = byte(stmt.id >> 24) + + // Add paramID [16 bit] + data[9] = byte(paramID) + data[10] = byte(paramID >> 8) + + // Send CMD packet + err := stmt.mc.writePacket(data[:4+pktLen]) + if err == nil { + data = data[pktLen-dataOffset:] + continue + } + return err + + } + + // Reset Packet Sequence + stmt.mc.sequence = 0 + return nil +} + +// Execute Prepared Statement +// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html +func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { + if len(args) != stmt.paramCount { + return fmt.Errorf( + "argument count mismatch (got: %d; has: %d)", + len(args), + stmt.paramCount, + ) + } + + const minPktLen = 4 + 1 + 4 + 1 + 4 + mc := stmt.mc + + // Determine threshould dynamically to avoid packet size shortage. + longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) + if longDataSize < 64 { + longDataSize = 64 + } + + // Reset packet-sequence + mc.sequence = 0 + + var data []byte + + if len(args) == 0 { + data = mc.buf.takeBuffer(minPktLen) + } else { + data = mc.buf.takeCompleteBuffer() + } + if data == nil { + // cannot take the buffer. Something must be wrong with the connection + errLog.Print(ErrBusyBuffer) + return errBadConnNoWrite + } + + // command [1 byte] + data[4] = comStmtExecute + + // statement_id [4 bytes] + data[5] = byte(stmt.id) + data[6] = byte(stmt.id >> 8) + data[7] = byte(stmt.id >> 16) + data[8] = byte(stmt.id >> 24) + + // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] + data[9] = 0x00 + + // iteration_count (uint32(1)) [4 bytes] + data[10] = 0x01 + data[11] = 0x00 + data[12] = 0x00 + data[13] = 0x00 + + if len(args) > 0 { + pos := minPktLen + + var nullMask []byte + if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) { + // buffer has to be extended but we don't know by how much so + // we depend on append after all data with known sizes fit. + // We stop at that because we deal with a lot of columns here + // which makes the required allocation size hard to guess. + tmp := make([]byte, pos+maskLen+typesLen) + copy(tmp[:pos], data[:pos]) + data = tmp + nullMask = data[pos : pos+maskLen] + pos += maskLen + } else { + nullMask = data[pos : pos+maskLen] + for i := 0; i < maskLen; i++ { + nullMask[i] = 0 + } + pos += maskLen + } + + // newParameterBoundFlag 1 [1 byte] + data[pos] = 0x01 + pos++ + + // type of each parameter [len(args)*2 bytes] + paramTypes := data[pos:] + pos += len(args) * 2 + + // value of each parameter [n bytes] + paramValues := data[pos:pos] + valuesCap := cap(paramValues) + + for i, arg := range args { + // build NULL-bitmap + if arg == nil { + nullMask[i/8] |= 1 << (uint(i) & 7) + paramTypes[i+i] = byte(fieldTypeNULL) + paramTypes[i+i+1] = 0x00 + continue + } + + // cache types and values + switch v := arg.(type) { + case int64: + paramTypes[i+i] = byte(fieldTypeLongLong) + paramTypes[i+i+1] = 0x00 + + if cap(paramValues)-len(paramValues)-8 >= 0 { + paramValues = paramValues[:len(paramValues)+8] + binary.LittleEndian.PutUint64( + paramValues[len(paramValues)-8:], + uint64(v), + ) + } else { + paramValues = append(paramValues, + uint64ToBytes(uint64(v))..., + ) + } + + case float64: + paramTypes[i+i] = byte(fieldTypeDouble) + paramTypes[i+i+1] = 0x00 + + if cap(paramValues)-len(paramValues)-8 >= 0 { + paramValues = paramValues[:len(paramValues)+8] + binary.LittleEndian.PutUint64( + paramValues[len(paramValues)-8:], + math.Float64bits(v), + ) + } else { + paramValues = append(paramValues, + uint64ToBytes(math.Float64bits(v))..., + ) + } + + case bool: + paramTypes[i+i] = byte(fieldTypeTiny) + paramTypes[i+i+1] = 0x00 + + if v { + paramValues = append(paramValues, 0x01) + } else { + paramValues = append(paramValues, 0x00) + } + + case []byte: + // Common case (non-nil value) first + if v != nil { + paramTypes[i+i] = byte(fieldTypeString) + paramTypes[i+i+1] = 0x00 + + if len(v) < longDataSize { + paramValues = appendLengthEncodedInteger(paramValues, + uint64(len(v)), + ) + paramValues = append(paramValues, v...) + } else { + if err := stmt.writeCommandLongData(i, v); err != nil { + return err + } + } + continue + } + + // Handle []byte(nil) as a NULL value + nullMask[i/8] |= 1 << (uint(i) & 7) + paramTypes[i+i] = byte(fieldTypeNULL) + paramTypes[i+i+1] = 0x00 + + case string: + paramTypes[i+i] = byte(fieldTypeString) + paramTypes[i+i+1] = 0x00 + + if len(v) < longDataSize { + paramValues = appendLengthEncodedInteger(paramValues, + uint64(len(v)), + ) + paramValues = append(paramValues, v...) + } else { + if err := stmt.writeCommandLongData(i, []byte(v)); err != nil { + return err + } + } + + case time.Time: + paramTypes[i+i] = byte(fieldTypeString) + paramTypes[i+i+1] = 0x00 + + var a [64]byte + var b = a[:0] + + if v.IsZero() { + b = append(b, "0000-00-00"...) + } else { + b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat) + } + + paramValues = appendLengthEncodedInteger(paramValues, + uint64(len(b)), + ) + paramValues = append(paramValues, b...) + + default: + return fmt.Errorf("cannot convert type: %T", arg) + } + } + + // Check if param values exceeded the available buffer + // In that case we must build the data packet with the new values buffer + if valuesCap != cap(paramValues) { + data = append(data[:pos], paramValues...) + mc.buf.buf = data + } + + pos += len(paramValues) + data = data[:pos] + } + + return mc.writePacket(data) +} + +func (mc *mysqlConn) discardResults() error { + for mc.status&statusMoreResultsExists != 0 { + resLen, err := mc.readResultSetHeaderPacket() + if err != nil { + return err + } + if resLen > 0 { + // columns + if err := mc.readUntilEOF(); err != nil { + return err + } + // rows + if err := mc.readUntilEOF(); err != nil { + return err + } + } + } + return nil +} + +// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html +func (rows *binaryRows) readRow(dest []driver.Value) error { + data, err := rows.mc.readPacket() + if err != nil { + return err + } + + // packet indicator [1 byte] + if data[0] != iOK { + // EOF Packet + if data[0] == iEOF && len(data) == 5 { + rows.mc.status = readStatus(data[3:]) + rows.rs.done = true + if !rows.HasNextResultSet() { + rows.mc = nil + } + return io.EOF + } + mc := rows.mc + rows.mc = nil + + // Error otherwise + return mc.handleErrorPacket(data) + } + + // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] + pos := 1 + (len(dest)+7+2)>>3 + nullMask := data[1:pos] + + for i := range dest { + // Field is NULL + // (byte >> bit-pos) % 2 == 1 + if ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 { + dest[i] = nil + continue + } + + // Convert to byte-coded string + switch rows.rs.columns[i].fieldType { + case fieldTypeNULL: + dest[i] = nil + continue + + // Numeric Types + case fieldTypeTiny: + if rows.rs.columns[i].flags&flagUnsigned != 0 { + dest[i] = int64(data[pos]) + } else { + dest[i] = int64(int8(data[pos])) + } + pos++ + continue + + case fieldTypeShort, fieldTypeYear: + if rows.rs.columns[i].flags&flagUnsigned != 0 { + dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) + } else { + dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) + } + pos += 2 + continue + + case fieldTypeInt24, fieldTypeLong: + if rows.rs.columns[i].flags&flagUnsigned != 0 { + dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) + } else { + dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) + } + pos += 4 + continue + + case fieldTypeLongLong: + if rows.rs.columns[i].flags&flagUnsigned != 0 { + val := binary.LittleEndian.Uint64(data[pos : pos+8]) + if val > math.MaxInt64 { + dest[i] = uint64ToString(val) + } else { + dest[i] = int64(val) + } + } else { + dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8])) + } + pos += 8 + continue + + case fieldTypeFloat: + dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) + pos += 4 + continue + + case fieldTypeDouble: + dest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8])) + pos += 8 + continue + + // Length coded Binary Strings + case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, + fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, + fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, + fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: + var isNull bool + var n int + dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) + pos += n + if err == nil { + if !isNull { + continue + } else { + dest[i] = nil + continue + } + } + return err + + case + fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD + fieldTypeTime, // Time [-][H]HH:MM:SS[.fractal] + fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal] + + num, isNull, n := readLengthEncodedInteger(data[pos:]) + pos += n + + switch { + case isNull: + dest[i] = nil + continue + case rows.rs.columns[i].fieldType == fieldTypeTime: + // database/sql does not support an equivalent to TIME, return a string + var dstlen uint8 + switch decimals := rows.rs.columns[i].decimals; decimals { + case 0x00, 0x1f: + dstlen = 8 + case 1, 2, 3, 4, 5, 6: + dstlen = 8 + 1 + decimals + default: + return fmt.Errorf( + "protocol error, illegal decimals value %d", + rows.rs.columns[i].decimals, + ) + } + dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true) + case rows.mc.parseTime: + dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) + default: + var dstlen uint8 + if rows.rs.columns[i].fieldType == fieldTypeDate { + dstlen = 10 + } else { + switch decimals := rows.rs.columns[i].decimals; decimals { + case 0x00, 0x1f: + dstlen = 19 + case 1, 2, 3, 4, 5, 6: + dstlen = 19 + 1 + decimals + default: + return fmt.Errorf( + "protocol error, illegal decimals value %d", + rows.rs.columns[i].decimals, + ) + } + } + dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, false) + } + + if err == nil { + pos += int(num) + continue + } else { + return err + } + + // Please report if this happens! + default: + return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType) + } + } + + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/result.go b/vendor/github.com/go-sql-driver/mysql/result.go new file mode 100644 index 0000000..c6438d0 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/result.go @@ -0,0 +1,22 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +type mysqlResult struct { + affectedRows int64 + insertId int64 +} + +func (res *mysqlResult) LastInsertId() (int64, error) { + return res.insertId, nil +} + +func (res *mysqlResult) RowsAffected() (int64, error) { + return res.affectedRows, nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/rows.go b/vendor/github.com/go-sql-driver/mysql/rows.go new file mode 100644 index 0000000..d3b1e28 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/rows.go @@ -0,0 +1,216 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql/driver" + "io" + "math" + "reflect" +) + +type resultSet struct { + columns []mysqlField + columnNames []string + done bool +} + +type mysqlRows struct { + mc *mysqlConn + rs resultSet + finish func() +} + +type binaryRows struct { + mysqlRows +} + +type textRows struct { + mysqlRows +} + +func (rows *mysqlRows) Columns() []string { + if rows.rs.columnNames != nil { + return rows.rs.columnNames + } + + columns := make([]string, len(rows.rs.columns)) + if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { + for i := range columns { + if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { + columns[i] = tableName + "." + rows.rs.columns[i].name + } else { + columns[i] = rows.rs.columns[i].name + } + } + } else { + for i := range columns { + columns[i] = rows.rs.columns[i].name + } + } + + rows.rs.columnNames = columns + return columns +} + +func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { + return rows.rs.columns[i].typeDatabaseName() +} + +// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { +// return int64(rows.rs.columns[i].length), true +// } + +func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { + return rows.rs.columns[i].flags&flagNotNULL == 0, true +} + +func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { + column := rows.rs.columns[i] + decimals := int64(column.decimals) + + switch column.fieldType { + case fieldTypeDecimal, fieldTypeNewDecimal: + if decimals > 0 { + return int64(column.length) - 2, decimals, true + } + return int64(column.length) - 1, decimals, true + case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: + return decimals, decimals, true + case fieldTypeFloat, fieldTypeDouble: + if decimals == 0x1f { + return math.MaxInt64, math.MaxInt64, true + } + return math.MaxInt64, decimals, true + } + + return 0, 0, false +} + +func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { + return rows.rs.columns[i].scanType() +} + +func (rows *mysqlRows) Close() (err error) { + if f := rows.finish; f != nil { + f() + rows.finish = nil + } + + mc := rows.mc + if mc == nil { + return nil + } + if err := mc.error(); err != nil { + return err + } + + // Remove unread packets from stream + if !rows.rs.done { + err = mc.readUntilEOF() + } + if err == nil { + if err = mc.discardResults(); err != nil { + return err + } + } + + rows.mc = nil + return err +} + +func (rows *mysqlRows) HasNextResultSet() (b bool) { + if rows.mc == nil { + return false + } + return rows.mc.status&statusMoreResultsExists != 0 +} + +func (rows *mysqlRows) nextResultSet() (int, error) { + if rows.mc == nil { + return 0, io.EOF + } + if err := rows.mc.error(); err != nil { + return 0, err + } + + // Remove unread packets from stream + if !rows.rs.done { + if err := rows.mc.readUntilEOF(); err != nil { + return 0, err + } + rows.rs.done = true + } + + if !rows.HasNextResultSet() { + rows.mc = nil + return 0, io.EOF + } + rows.rs = resultSet{} + return rows.mc.readResultSetHeaderPacket() +} + +func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { + for { + resLen, err := rows.nextResultSet() + if err != nil { + return 0, err + } + + if resLen > 0 { + return resLen, nil + } + + rows.rs.done = true + } +} + +func (rows *binaryRows) NextResultSet() error { + resLen, err := rows.nextNotEmptyResultSet() + if err != nil { + return err + } + + rows.rs.columns, err = rows.mc.readColumns(resLen) + return err +} + +func (rows *binaryRows) Next(dest []driver.Value) error { + if mc := rows.mc; mc != nil { + if err := mc.error(); err != nil { + return err + } + + // Fetch next row from stream + return rows.readRow(dest) + } + return io.EOF +} + +func (rows *textRows) NextResultSet() (err error) { + resLen, err := rows.nextNotEmptyResultSet() + if err != nil { + return err + } + + rows.rs.columns, err = rows.mc.readColumns(resLen) + return err +} + +func (rows *textRows) Next(dest []driver.Value) error { + if mc := rows.mc; mc != nil { + if err := mc.error(); err != nil { + return err + } + + // Fetch next row from stream + return rows.readRow(dest) + } + return io.EOF +} diff --git a/vendor/github.com/go-sql-driver/mysql/statement.go b/vendor/github.com/go-sql-driver/mysql/statement.go new file mode 100644 index 0000000..ce7fe4c --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/statement.go @@ -0,0 +1,211 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql/driver" + "fmt" + "io" + "reflect" + "strconv" +) + +type mysqlStmt struct { + mc *mysqlConn + id uint32 + paramCount int +} + +func (stmt *mysqlStmt) Close() error { + if stmt.mc == nil || stmt.mc.closed.IsSet() { + // driver.Stmt.Close can be called more than once, thus this function + // has to be idempotent. + // See also Issue #450 and golang/go#16019. + //errLog.Print(ErrInvalidConn) + return driver.ErrBadConn + } + + err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) + stmt.mc = nil + return err +} + +func (stmt *mysqlStmt) NumInput() int { + return stmt.paramCount +} + +func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { + return converter{} +} + +func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { + if stmt.mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + // Send command + err := stmt.writeExecutePacket(args) + if err != nil { + return nil, stmt.mc.markBadConn(err) + } + + mc := stmt.mc + + mc.affectedRows = 0 + mc.insertId = 0 + + // Read Result + resLen, err := mc.readResultSetHeaderPacket() + if err != nil { + return nil, err + } + + if resLen > 0 { + // Columns + if err = mc.readUntilEOF(); err != nil { + return nil, err + } + + // Rows + if err := mc.readUntilEOF(); err != nil { + return nil, err + } + } + + if err := mc.discardResults(); err != nil { + return nil, err + } + + return &mysqlResult{ + affectedRows: int64(mc.affectedRows), + insertId: int64(mc.insertId), + }, nil +} + +func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { + return stmt.query(args) +} + +func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { + if stmt.mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return nil, driver.ErrBadConn + } + // Send command + err := stmt.writeExecutePacket(args) + if err != nil { + return nil, stmt.mc.markBadConn(err) + } + + mc := stmt.mc + + // Read Result + resLen, err := mc.readResultSetHeaderPacket() + if err != nil { + return nil, err + } + + rows := new(binaryRows) + + if resLen > 0 { + rows.mc = mc + rows.rs.columns, err = mc.readColumns(resLen) + } else { + rows.rs.done = true + + switch err := rows.NextResultSet(); err { + case nil, io.EOF: + return rows, nil + default: + return nil, err + } + } + + return rows, err +} + +type converter struct{} + +// ConvertValue mirrors the reference/default converter in database/sql/driver +// with _one_ exception. We support uint64 with their high bit and the default +// implementation does not. This function should be kept in sync with +// database/sql/driver defaultConverter.ConvertValue() except for that +// deliberate difference. +func (c converter) ConvertValue(v interface{}) (driver.Value, error) { + if driver.IsValue(v) { + return v, nil + } + + if vr, ok := v.(driver.Valuer); ok { + sv, err := callValuerValue(vr) + if err != nil { + return nil, err + } + if !driver.IsValue(sv) { + return nil, fmt.Errorf("non-Value type %T returned from Value", sv) + } + return sv, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Ptr: + // indirect pointers + if rv.IsNil() { + return nil, nil + } else { + return c.ConvertValue(rv.Elem().Interface()) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64(rv.Uint()), nil + case reflect.Uint64: + u64 := rv.Uint() + if u64 >= 1<<63 { + return strconv.FormatUint(u64, 10), nil + } + return int64(u64), nil + case reflect.Float32, reflect.Float64: + return rv.Float(), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil + } + return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) +} + +var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() + +// callValuerValue returns vr.Value(), with one exception: +// If vr.Value is an auto-generated method on a pointer type and the +// pointer is nil, it would panic at runtime in the panicwrap +// method. Treat it like nil instead. +// +// This is so people can implement driver.Value on value types and +// still use nil pointers to those types to mean nil/NULL, just like +// string/*string. +// +// This is an exact copy of the same-named unexported function from the +// database/sql package. +func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && + rv.IsNil() && + rv.Type().Elem().Implements(valuerReflectType) { + return nil, nil + } + return vr.Value() +} diff --git a/vendor/github.com/go-sql-driver/mysql/transaction.go b/vendor/github.com/go-sql-driver/mysql/transaction.go new file mode 100644 index 0000000..417d727 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/transaction.go @@ -0,0 +1,31 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +type mysqlTx struct { + mc *mysqlConn +} + +func (tx *mysqlTx) Commit() (err error) { + if tx.mc == nil || tx.mc.closed.IsSet() { + return ErrInvalidConn + } + err = tx.mc.exec("COMMIT") + tx.mc = nil + return +} + +func (tx *mysqlTx) Rollback() (err error) { + if tx.mc == nil || tx.mc.closed.IsSet() { + return ErrInvalidConn + } + err = tx.mc.exec("ROLLBACK") + tx.mc = nil + return +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go new file mode 100644 index 0000000..84d595b --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -0,0 +1,710 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "crypto/tls" + "database/sql/driver" + "encoding/binary" + "fmt" + "io" + "strings" + "sync" + "sync/atomic" + "time" +) + +// Registry for custom tls.Configs +var ( + tlsConfigLock sync.RWMutex + tlsConfigRegistry map[string]*tls.Config +) + +// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. +// Use the key as a value in the DSN where tls=value. +// +// Note: The provided tls.Config is exclusively owned by the driver after +// registering it. +// +// rootCertPool := x509.NewCertPool() +// pem, err := ioutil.ReadFile("/path/ca-cert.pem") +// if err != nil { +// log.Fatal(err) +// } +// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { +// log.Fatal("Failed to append PEM.") +// } +// clientCert := make([]tls.Certificate, 0, 1) +// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem") +// if err != nil { +// log.Fatal(err) +// } +// clientCert = append(clientCert, certs) +// mysql.RegisterTLSConfig("custom", &tls.Config{ +// RootCAs: rootCertPool, +// Certificates: clientCert, +// }) +// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") +// +func RegisterTLSConfig(key string, config *tls.Config) error { + if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" { + return fmt.Errorf("key '%s' is reserved", key) + } + + tlsConfigLock.Lock() + if tlsConfigRegistry == nil { + tlsConfigRegistry = make(map[string]*tls.Config) + } + + tlsConfigRegistry[key] = config + tlsConfigLock.Unlock() + return nil +} + +// DeregisterTLSConfig removes the tls.Config associated with key. +func DeregisterTLSConfig(key string) { + tlsConfigLock.Lock() + if tlsConfigRegistry != nil { + delete(tlsConfigRegistry, key) + } + tlsConfigLock.Unlock() +} + +func getTLSConfigClone(key string) (config *tls.Config) { + tlsConfigLock.RLock() + if v, ok := tlsConfigRegistry[key]; ok { + config = cloneTLSConfig(v) + } + tlsConfigLock.RUnlock() + return +} + +// Returns the bool value of the input. +// The 2nd return value indicates if the input was a valid bool value +func readBool(input string) (value bool, valid bool) { + switch input { + case "1", "true", "TRUE", "True": + return true, true + case "0", "false", "FALSE", "False": + return false, true + } + + // Not a valid bool value + return +} + +/****************************************************************************** +* Time related utils * +******************************************************************************/ + +// NullTime represents a time.Time that may be NULL. +// NullTime implements the Scanner interface so +// it can be used as a scan destination: +// +// var nt NullTime +// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) +// ... +// if nt.Valid { +// // use nt.Time +// } else { +// // NULL value +// } +// +// This NullTime implementation is not driver-specific +type NullTime struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL +} + +// Scan implements the Scanner interface. +// The value type must be time.Time or string / []byte (formatted time-string), +// otherwise Scan fails. +func (nt *NullTime) Scan(value interface{}) (err error) { + if value == nil { + nt.Time, nt.Valid = time.Time{}, false + return + } + + switch v := value.(type) { + case time.Time: + nt.Time, nt.Valid = v, true + return + case []byte: + nt.Time, err = parseDateTime(string(v), time.UTC) + nt.Valid = (err == nil) + return + case string: + nt.Time, err = parseDateTime(v, time.UTC) + nt.Valid = (err == nil) + return + } + + nt.Valid = false + return fmt.Errorf("Can't convert %T to time.Time", value) +} + +// Value implements the driver Valuer interface. +func (nt NullTime) Value() (driver.Value, error) { + if !nt.Valid { + return nil, nil + } + return nt.Time, nil +} + +func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { + base := "0000-00-00 00:00:00.0000000" + switch len(str) { + case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" + if str == base[:len(str)] { + return + } + t, err = time.Parse(timeFormat[:len(str)], str) + default: + err = fmt.Errorf("invalid time string: %s", str) + return + } + + // Adjust location + if err == nil && loc != time.UTC { + y, mo, d := t.Date() + h, mi, s := t.Clock() + t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil + } + + return +} + +func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) { + switch num { + case 0: + return time.Time{}, nil + case 4: + return time.Date( + int(binary.LittleEndian.Uint16(data[:2])), // year + time.Month(data[2]), // month + int(data[3]), // day + 0, 0, 0, 0, + loc, + ), nil + case 7: + return time.Date( + int(binary.LittleEndian.Uint16(data[:2])), // year + time.Month(data[2]), // month + int(data[3]), // day + int(data[4]), // hour + int(data[5]), // minutes + int(data[6]), // seconds + 0, + loc, + ), nil + case 11: + return time.Date( + int(binary.LittleEndian.Uint16(data[:2])), // year + time.Month(data[2]), // month + int(data[3]), // day + int(data[4]), // hour + int(data[5]), // minutes + int(data[6]), // seconds + int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds + loc, + ), nil + } + return nil, fmt.Errorf("invalid DATETIME packet length %d", num) +} + +// zeroDateTime is used in formatBinaryDateTime to avoid an allocation +// if the DATE or DATETIME has the zero value. +// It must never be changed. +// The current behavior depends on database/sql copying the result. +var zeroDateTime = []byte("0000-00-00 00:00:00.000000") + +const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" + +func formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value, error) { + // length expects the deterministic length of the zero value, + // negative time and 100+ hours are automatically added if needed + if len(src) == 0 { + if justTime { + return zeroDateTime[11 : 11+length], nil + } + return zeroDateTime[:length], nil + } + var dst []byte // return value + var pt, p1, p2, p3 byte // current digit pair + var zOffs byte // offset of value in zeroDateTime + if justTime { + switch length { + case + 8, // time (can be up to 10 when negative and 100+ hours) + 10, 11, 12, 13, 14, 15: // time with fractional seconds + default: + return nil, fmt.Errorf("illegal TIME length %d", length) + } + switch len(src) { + case 8, 12: + default: + return nil, fmt.Errorf("invalid TIME packet length %d", len(src)) + } + // +2 to enable negative time and 100+ hours + dst = make([]byte, 0, length+2) + if src[0] == 1 { + dst = append(dst, '-') + } + if src[1] != 0 { + hour := uint16(src[1])*24 + uint16(src[5]) + pt = byte(hour / 100) + p1 = byte(hour - 100*uint16(pt)) + dst = append(dst, digits01[pt]) + } else { + p1 = src[5] + } + zOffs = 11 + src = src[6:] + } else { + switch length { + case 10, 19, 21, 22, 23, 24, 25, 26: + default: + t := "DATE" + if length > 10 { + t += "TIME" + } + return nil, fmt.Errorf("illegal %s length %d", t, length) + } + switch len(src) { + case 4, 7, 11: + default: + t := "DATE" + if length > 10 { + t += "TIME" + } + return nil, fmt.Errorf("illegal %s packet length %d", t, len(src)) + } + dst = make([]byte, 0, length) + // start with the date + year := binary.LittleEndian.Uint16(src[:2]) + pt = byte(year / 100) + p1 = byte(year - 100*uint16(pt)) + p2, p3 = src[2], src[3] + dst = append(dst, + digits10[pt], digits01[pt], + digits10[p1], digits01[p1], '-', + digits10[p2], digits01[p2], '-', + digits10[p3], digits01[p3], + ) + if length == 10 { + return dst, nil + } + if len(src) == 4 { + return append(dst, zeroDateTime[10:length]...), nil + } + dst = append(dst, ' ') + p1 = src[4] // hour + src = src[5:] + } + // p1 is 2-digit hour, src is after hour + p2, p3 = src[0], src[1] + dst = append(dst, + digits10[p1], digits01[p1], ':', + digits10[p2], digits01[p2], ':', + digits10[p3], digits01[p3], + ) + if length <= byte(len(dst)) { + return dst, nil + } + src = src[2:] + if len(src) == 0 { + return append(dst, zeroDateTime[19:zOffs+length]...), nil + } + microsecs := binary.LittleEndian.Uint32(src[:4]) + p1 = byte(microsecs / 10000) + microsecs -= 10000 * uint32(p1) + p2 = byte(microsecs / 100) + microsecs -= 100 * uint32(p2) + p3 = byte(microsecs) + switch decimals := zOffs + length - 20; decimals { + default: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + digits10[p3], digits01[p3], + ), nil + case 1: + return append(dst, '.', + digits10[p1], + ), nil + case 2: + return append(dst, '.', + digits10[p1], digits01[p1], + ), nil + case 3: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], + ), nil + case 4: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + ), nil + case 5: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + digits10[p3], + ), nil + } +} + +/****************************************************************************** +* Convert from and to bytes * +******************************************************************************/ + +func uint64ToBytes(n uint64) []byte { + return []byte{ + byte(n), + byte(n >> 8), + byte(n >> 16), + byte(n >> 24), + byte(n >> 32), + byte(n >> 40), + byte(n >> 48), + byte(n >> 56), + } +} + +func uint64ToString(n uint64) []byte { + var a [20]byte + i := 20 + + // U+0030 = 0 + // ... + // U+0039 = 9 + + var q uint64 + for n >= 10 { + i-- + q = n / 10 + a[i] = uint8(n-q*10) + 0x30 + n = q + } + + i-- + a[i] = uint8(n) + 0x30 + + return a[i:] +} + +// treats string value as unsigned integer representation +func stringToInt(b []byte) int { + val := 0 + for i := range b { + val *= 10 + val += int(b[i] - 0x30) + } + return val +} + +// returns the string read as a bytes slice, wheter the value is NULL, +// the number of bytes read and an error, in case the string is longer than +// the input slice +func readLengthEncodedString(b []byte) ([]byte, bool, int, error) { + // Get length + num, isNull, n := readLengthEncodedInteger(b) + if num < 1 { + return b[n:n], isNull, n, nil + } + + n += int(num) + + // Check data length + if len(b) >= n { + return b[n-int(num) : n : n], false, n, nil + } + return nil, false, n, io.EOF +} + +// returns the number of bytes skipped and an error, in case the string is +// longer than the input slice +func skipLengthEncodedString(b []byte) (int, error) { + // Get length + num, _, n := readLengthEncodedInteger(b) + if num < 1 { + return n, nil + } + + n += int(num) + + // Check data length + if len(b) >= n { + return n, nil + } + return n, io.EOF +} + +// returns the number read, whether the value is NULL and the number of bytes read +func readLengthEncodedInteger(b []byte) (uint64, bool, int) { + // See issue #349 + if len(b) == 0 { + return 0, true, 1 + } + + switch b[0] { + // 251: NULL + case 0xfb: + return 0, true, 1 + + // 252: value of following 2 + case 0xfc: + return uint64(b[1]) | uint64(b[2])<<8, false, 3 + + // 253: value of following 3 + case 0xfd: + return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 + + // 254: value of following 8 + case 0xfe: + return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | + uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 | + uint64(b[7])<<48 | uint64(b[8])<<56, + false, 9 + } + + // 0-250: value of first byte + return uint64(b[0]), false, 1 +} + +// encodes a uint64 value and appends it to the given bytes slice +func appendLengthEncodedInteger(b []byte, n uint64) []byte { + switch { + case n <= 250: + return append(b, byte(n)) + + case n <= 0xffff: + return append(b, 0xfc, byte(n), byte(n>>8)) + + case n <= 0xffffff: + return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) + } + return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), + byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) +} + +// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. +// If cap(buf) is not enough, reallocate new buffer. +func reserveBuffer(buf []byte, appendSize int) []byte { + newSize := len(buf) + appendSize + if cap(buf) < newSize { + // Grow buffer exponentially + newBuf := make([]byte, len(buf)*2+appendSize) + copy(newBuf, buf) + buf = newBuf + } + return buf[:newSize] +} + +// escapeBytesBackslash escapes []byte with backslashes (\) +// This escapes the contents of a string (provided as []byte) by adding backslashes before special +// characters, and turning others into specific escape sequences, such as +// turning newlines into \n and null bytes into \0. +// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932 +func escapeBytesBackslash(buf, v []byte) []byte { + pos := len(buf) + buf = reserveBuffer(buf, len(v)*2) + + for _, c := range v { + switch c { + case '\x00': + buf[pos] = '\\' + buf[pos+1] = '0' + pos += 2 + case '\n': + buf[pos] = '\\' + buf[pos+1] = 'n' + pos += 2 + case '\r': + buf[pos] = '\\' + buf[pos+1] = 'r' + pos += 2 + case '\x1a': + buf[pos] = '\\' + buf[pos+1] = 'Z' + pos += 2 + case '\'': + buf[pos] = '\\' + buf[pos+1] = '\'' + pos += 2 + case '"': + buf[pos] = '\\' + buf[pos+1] = '"' + pos += 2 + case '\\': + buf[pos] = '\\' + buf[pos+1] = '\\' + pos += 2 + default: + buf[pos] = c + pos++ + } + } + + return buf[:pos] +} + +// escapeStringBackslash is similar to escapeBytesBackslash but for string. +func escapeStringBackslash(buf []byte, v string) []byte { + pos := len(buf) + buf = reserveBuffer(buf, len(v)*2) + + for i := 0; i < len(v); i++ { + c := v[i] + switch c { + case '\x00': + buf[pos] = '\\' + buf[pos+1] = '0' + pos += 2 + case '\n': + buf[pos] = '\\' + buf[pos+1] = 'n' + pos += 2 + case '\r': + buf[pos] = '\\' + buf[pos+1] = 'r' + pos += 2 + case '\x1a': + buf[pos] = '\\' + buf[pos+1] = 'Z' + pos += 2 + case '\'': + buf[pos] = '\\' + buf[pos+1] = '\'' + pos += 2 + case '"': + buf[pos] = '\\' + buf[pos+1] = '"' + pos += 2 + case '\\': + buf[pos] = '\\' + buf[pos+1] = '\\' + pos += 2 + default: + buf[pos] = c + pos++ + } + } + + return buf[:pos] +} + +// escapeBytesQuotes escapes apostrophes in []byte by doubling them up. +// This escapes the contents of a string by doubling up any apostrophes that +// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in +// effect on the server. +// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038 +func escapeBytesQuotes(buf, v []byte) []byte { + pos := len(buf) + buf = reserveBuffer(buf, len(v)*2) + + for _, c := range v { + if c == '\'' { + buf[pos] = '\'' + buf[pos+1] = '\'' + pos += 2 + } else { + buf[pos] = c + pos++ + } + } + + return buf[:pos] +} + +// escapeStringQuotes is similar to escapeBytesQuotes but for string. +func escapeStringQuotes(buf []byte, v string) []byte { + pos := len(buf) + buf = reserveBuffer(buf, len(v)*2) + + for i := 0; i < len(v); i++ { + c := v[i] + if c == '\'' { + buf[pos] = '\'' + buf[pos+1] = '\'' + pos += 2 + } else { + buf[pos] = c + pos++ + } + } + + return buf[:pos] +} + +/****************************************************************************** +* Sync utils * +******************************************************************************/ + +// noCopy may be embedded into structs which must not be copied +// after the first use. +// +// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// for details. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} + +// atomicBool is a wrapper around uint32 for usage as a boolean value with +// atomic access. +type atomicBool struct { + _noCopy noCopy + value uint32 +} + +// IsSet returns wether the current boolean value is true +func (ab *atomicBool) IsSet() bool { + return atomic.LoadUint32(&ab.value) > 0 +} + +// Set sets the value of the bool regardless of the previous value +func (ab *atomicBool) Set(value bool) { + if value { + atomic.StoreUint32(&ab.value, 1) + } else { + atomic.StoreUint32(&ab.value, 0) + } +} + +// TrySet sets the value of the bool and returns wether the value changed +func (ab *atomicBool) TrySet(value bool) bool { + if value { + return atomic.SwapUint32(&ab.value, 1) == 0 + } + return atomic.SwapUint32(&ab.value, 0) > 0 +} + +// atomicError is a wrapper for atomically accessed error values +type atomicError struct { + _noCopy noCopy + value atomic.Value +} + +// Set sets the error value regardless of the previous value. +// The value must not be nil +func (ae *atomicError) Set(value error) { + ae.value.Store(value) +} + +// Value returns the current error value +func (ae *atomicError) Value() error { + if v := ae.value.Load(); v != nil { + // this will panic if the value doesn't implement the error interface + return v.(error) + } + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go17.go b/vendor/github.com/go-sql-driver/mysql/utils_go17.go new file mode 100644 index 0000000..f595634 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go17.go @@ -0,0 +1,40 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.7 +// +build !go1.8 + +package mysql + +import "crypto/tls" + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return &tls.Config{ + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go18.go b/vendor/github.com/go-sql-driver/mysql/utils_go18.go new file mode 100644 index 0000000..c35c2a6 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go18.go @@ -0,0 +1,50 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "crypto/tls" + "database/sql" + "database/sql/driver" + "errors" + "fmt" +) + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return c.Clone() +} + +func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { + dargs := make([]driver.Value, len(named)) + for n, param := range named { + if len(param.Name) > 0 { + // TODO: support the use of Named Parameters #561 + return nil, errors.New("mysql: driver does not support the use of Named Parameters") + } + dargs[n] = param.Value + } + return dargs, nil +} + +func mapIsolationLevel(level driver.IsolationLevel) (string, error) { + switch sql.IsolationLevel(level) { + case sql.LevelRepeatableRead: + return "REPEATABLE READ", nil + case sql.LevelReadCommitted: + return "READ COMMITTED", nil + case sql.LevelReadUncommitted: + return "READ UNCOMMITTED", nil + case sql.LevelSerializable: + return "SERIALIZABLE", nil + default: + return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) + } +} diff --git a/vendor/github.com/gocql/gocql/.gitignore b/vendor/github.com/gocql/gocql/.gitignore new file mode 100644 index 0000000..bce6cf5 --- /dev/null +++ b/vendor/github.com/gocql/gocql/.gitignore @@ -0,0 +1,5 @@ +gocql-fuzz +fuzz-corpus +fuzz-work +gocql.test +.idea diff --git a/vendor/github.com/gocql/gocql/.travis.yml b/vendor/github.com/gocql/gocql/.travis.yml new file mode 100644 index 0000000..636e711 --- /dev/null +++ b/vendor/github.com/gocql/gocql/.travis.yml @@ -0,0 +1,47 @@ +language: go + +sudo: required +dist: trusty + +cache: + directories: + - $HOME/.ccm/repository + - $HOME/.local/lib/python2.7 + +matrix: + fast_finish: true + +branches: + only: + - master + +env: + global: + - GOMAXPROCS=2 + matrix: + - CASS=2.1.12 + AUTH=false + - CASS=2.2.5 + AUTH=true + - CASS=2.2.5 + AUTH=false + - CASS=3.0.8 + AUTH=false + +go: + - "1.9" + - "1.10" + +install: + - ./install_test_deps.sh $TRAVIS_REPO_SLUG + - cd ../.. + - cd gocql/gocql + - go get . + +script: + - set -e + - PATH=$PATH:$HOME/.local/bin bash integration.sh $CASS $AUTH + - go vet . + +notifications: + - email: false diff --git a/vendor/github.com/gocql/gocql/AUTHORS b/vendor/github.com/gocql/gocql/AUTHORS new file mode 100644 index 0000000..14cae30 --- /dev/null +++ b/vendor/github.com/gocql/gocql/AUTHORS @@ -0,0 +1,108 @@ +# This source file refers to The gocql Authors for copyright purposes. + +Christoph Hack +Jonathan Rudenberg +Thorsten von Eicken +Matt Robenolt +Phillip Couto +Niklas Korz +Nimi Wariboko Jr +Ghais Issa +Sasha Klizhentas +Konstantin Cherkasov +Ben Hood <0x6e6562@gmail.com> +Pete Hopkins +Chris Bannister +Maxim Bublis +Alex Zorin +Kasper Middelboe Petersen +Harpreet Sawhney +Charlie Andrews +Stanislavs Koikovs +Dan Forest +Miguel Serrano +Stefan Radomski +Josh Wright +Jacob Rhoden +Ben Frye +Fred McCann +Dan Simmons +Muir Manders +Sankar P +Julien Da Silva +Dan Kennedy +Nick Dhupia +Yasuharu Goto +Jeremy Schlatter +Matthias Kadenbach +Dean Elbaz +Mike Berman +Dmitriy Fedorenko +Zach Marcantel +James Maloney +Ashwin Purohit +Dan Kinder +Oliver Beattie +Justin Corpron +Miles Delahunty +Zach Badgett +Maciek Sakrejda +Jeff Mitchell +Baptiste Fontaine +Matt Heath +Jamie Cuthill +Adrian Casajus +John Weldon +Adrien Bustany +Andrey Smirnov +Adam Weiner +Daniel Cannon +Johnny Bergström +Adriano Orioli +Claudiu Raveica +Artem Chernyshev +Ference Fu +LOVOO +nikandfor +Anthony Woods +Alexander Inozemtsev +Rob McColl ; +Viktor Tönköl +Ian Lozinski +Michael Highstead +Sarah Brown +Caleb Doxsey +Frederic Hemery +Pekka Enberg +Mark M +Bartosz Burclaf +Marcus King +Andrew de Andrade +Robert Nix +Nathan Youngman +Charles Law ; +Nathan Davies +Bo Blanton +Vincent Rischmann +Jesse Claven +Derrick Wippler +Leigh McCulloch +Ron Kuris +Raphael Gavache +Yasser Abdolmaleki +Krishnanand Thommandra +Blake Atkinson +Dharmendra Parsaila +Nayef Ghattas +Michał Matczuk +Ben Krebsbach +Vivian Mathews +Sascha Steinbiss +Seth Rosenblum +Javier Zunzunegui +Luke Hines +Zhixin Wen +Chang Liu +Ingo Oeser +Luke Hines +Jacob Greenleaf diff --git a/vendor/github.com/gocql/gocql/CONTRIBUTING.md b/vendor/github.com/gocql/gocql/CONTRIBUTING.md new file mode 100644 index 0000000..093045a --- /dev/null +++ b/vendor/github.com/gocql/gocql/CONTRIBUTING.md @@ -0,0 +1,78 @@ +# Contributing to gocql + +**TL;DR** - this manifesto sets out the bare minimum requirements for submitting a patch to gocql. + +This guide outlines the process of landing patches in gocql and the general approach to maintaining the code base. + +## Background + +The goal of the gocql project is to provide a stable and robust CQL driver for Go. gocql is a community driven project that is coordinated by a small team of core developers. + +## Minimum Requirement Checklist + +The following is a check list of requirements that need to be satisfied in order for us to merge your patch: + +* You should raise a pull request to gocql/gocql on Github +* The pull request has a title that clearly summarizes the purpose of the patch +* The motivation behind the patch is clearly defined in the pull request summary +* Your name and email have been added to the `AUTHORS` file (for copyright purposes) +* The patch will merge cleanly +* The test coverage does not fall below the critical threshold (currently 64%) +* The merge commit passes the regression test suite on Travis +* `go fmt` has been applied to the submitted code +* Functional changes (i.e. new features or changed behavior) are appropriately documented, either as a godoc or in the README (non-functional changes such as bug fixes may not require documentation) + +If there are any requirements that can't be reasonably satisfied, please state this either on the pull request or as part of discussion on the mailing list. Where appropriate, the core team may apply discretion and make an exception to these requirements. + +## Beyond The Checklist + +In addition to stating the hard requirements, there are a bunch of things that we consider when assessing changes to the library. These soft requirements are helpful pointers of how to get a patch landed quicker and with less fuss. + +### General QA Approach + +The gocql team needs to consider the ongoing maintainability of the library at all times. Patches that look like they will introduce maintenance issues for the team will not be accepted. + +Your patch will get merged quicker if you have decent test cases that provide test coverage for the new behavior you wish to introduce. + +Unit tests are good, integration tests are even better. An example of a unit test is `marshal_test.go` - this tests the serialization code in isolation. `cassandra_test.go` is an integration test suite that is executed against every version of Cassandra that gocql supports as part of the CI process on Travis. + +That said, the point of writing tests is to provide a safety net to catch regressions, so there is no need to go overboard with tests. Remember that the more tests you write, the more code we will have to maintain. So there's a balance to strike there. + +### When It's Too Difficult To Automate Testing + +There are legitimate examples of where it is infeasible to write a regression test for a change. Never fear, we will still consider the patch and quite possibly accept the change without a test. The gocql team takes a pragmatic approach to testing. At the end of the day, you could be addressing an issue that is too difficult to reproduce in a test suite, but still occurs in a real production app. In this case, your production app is the test case, and we will have to trust that your change is good. + +Examples of pull requests that have been accepted without tests include: + +* https://github.com/gocql/gocql/pull/181 - this patch would otherwise require a multi-node cluster to be booted as part of the CI build +* https://github.com/gocql/gocql/pull/179 - this bug can only be reproduced under heavy load in certain circumstances + +### Sign Off Procedure + +Generally speaking, a pull request can get merged by any one of the core gocql team. If your change is minor, chances are that one team member will just go ahead and merge it there and then. As stated earlier, suitable test coverage will increase the likelihood that a single reviewer will assess and merge your change. If your change has no test coverage, or looks like it may have wider implications for the health and stability of the library, the reviewer may elect to refer the change to another team member to achieve consensus before proceeding. Therefore, the tighter and cleaner your patch is, the quicker it will go through the review process. + +### Supported Features + +gocql is a low level wire driver for Cassandra CQL. By and large, we would like to keep the functional scope of the library as narrow as possible. We think that gocql should be tight and focused, and we will be naturally skeptical of things that could just as easily be implemented in a higher layer. Inevitably you will come across something that could be implemented in a higher layer, save for a minor change to the core API. In this instance, please strike up a conversation with the gocql team. Chances are we will understand what you are trying to achieve and will try to accommodate this in a maintainable way. + +### Longer Term Evolution + +There are some long term plans for gocql that have to be taken into account when assessing changes. That said, gocql is ultimately a community driven project and we don't have a massive development budget, so sometimes the long term view might need to be de-prioritized ahead of short term changes. + +## Officially Supported Server Versions + +Currently, the officially supported versions of the Cassandra server include: + +* 1.2.18 +* 2.0.9 + +Chances are that gocql will work with many other versions. If you would like us to support a particular version of Cassandra, please start a conversation about what version you'd like us to consider. We are more likely to accept a new version if you help out by extending the regression suite to cover the new version to be supported. + +## The Core Dev Team + +The core development team includes: + +* tux21b +* phillipCouto +* Zariel +* 0x6e6562 diff --git a/vendor/github.com/gocql/gocql/LICENSE b/vendor/github.com/gocql/gocql/LICENSE new file mode 100644 index 0000000..3836494 --- /dev/null +++ b/vendor/github.com/gocql/gocql/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016, The Gocql authors +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 the copyright holder 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 HOLDER 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/vendor/github.com/gocql/gocql/README.md b/vendor/github.com/gocql/gocql/README.md new file mode 100644 index 0000000..6b75cc4 --- /dev/null +++ b/vendor/github.com/gocql/gocql/README.md @@ -0,0 +1,215 @@ +gocql +===== + +[![Join the chat at https://gitter.im/gocql/gocql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gocql/gocql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Build Status](https://travis-ci.org/gocql/gocql.svg?branch=master)](https://travis-ci.org/gocql/gocql) +[![GoDoc](https://godoc.org/github.com/gocql/gocql?status.svg)](https://godoc.org/github.com/gocql/gocql) + +Package gocql implements a fast and robust Cassandra client for the +Go programming language. + +Project Website: https://gocql.github.io/
+API documentation: https://godoc.org/github.com/gocql/gocql
+Discussions: https://groups.google.com/forum/#!forum/gocql + +Supported Versions +------------------ + +The following matrix shows the versions of Go and Cassandra that are tested with the integration test suite as part of the CI build: + +Go/Cassandra | 2.1.x | 2.2.x | 3.0.x +-------------| -------| ------| --------- +1.8 | yes | yes | yes +1.9 | yes | yes | yes + +Gocql has been tested in production against many different versions of Cassandra. Due to limits in our CI setup we only test against the latest 3 major releases, which coincide with the official support from the Apache project. + +Sunsetting Model +---------------- + +In general, the gocql team will focus on supporting the current and previous versions of Go. gocql may still work with older versions of Go, but official support for these versions will have been sunset. + +Installation +------------ + + go get github.com/gocql/gocql + + +Features +-------- + +* Modern Cassandra client using the native transport +* Automatic type conversions between Cassandra and Go + * Support for all common types including sets, lists and maps + * Custom types can implement a `Marshaler` and `Unmarshaler` interface + * Strict type conversions without any loss of precision + * Built-In support for UUIDs (version 1 and 4) +* Support for logged, unlogged and counter batches +* Cluster management + * Automatic reconnect on connection failures with exponential falloff + * Round robin distribution of queries to different hosts + * Round robin distribution of queries to different connections on a host + * Each connection can execute up to n concurrent queries (whereby n is the limit set by the protocol version the client chooses to use) + * Optional automatic discovery of nodes + * Policy based connection pool with token aware and round-robin policy implementations +* Support for password authentication +* Iteration over paged results with configurable page size +* Support for TLS/SSL +* Optional frame compression (using snappy) +* Automatic query preparation +* Support for query tracing +* Support for Cassandra 2.1+ [binary protocol version 3](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v3.spec) + * Support for up to 32768 streams + * Support for tuple types + * Support for client side timestamps by default + * Support for UDTs via a custom marshaller or struct tags +* Support for Cassandra 3.0+ [binary protocol version 4](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec) +* An API to access the schema metadata of a given keyspace + +Performance +----------- +While the driver strives to be highly performant, there are cases where it is difficult to test and verify. The driver is built +with maintainability and code readability in mind first and then performance and features, as such every now and then performance +may degrade, if this occurs please report and issue and it will be looked at and remedied. The only time the driver copies data from +its read buffer is when it Unmarshal's data into supplied types. + +Some tips for getting more performance from the driver: +* Use the TokenAware policy +* Use many goroutines when doing inserts, the driver is asynchronous but provides a synchronous API, it can execute many queries concurrently +* Tune query page size +* Reading data from the network to unmarshal will incur a large amount of allocations, this can adversely affect the garbage collector, tune `GOGC` +* Close iterators after use to recycle byte buffers + +Important Default Keyspace Changes +---------------------------------- +gocql no longer supports executing "use " statements to simplify the library. The user still has the +ability to define the default keyspace for connections but now the keyspace can only be defined before a +session is created. Queries can still access keyspaces by indicating the keyspace in the query: +```sql +SELECT * FROM example2.table; +``` + +Example of correct usage: +```go + cluster := gocql.NewCluster("192.168.1.1", "192.168.1.2", "192.168.1.3") + cluster.Keyspace = "example" + ... + session, err := cluster.CreateSession() + +``` +Example of incorrect usage: +```go + cluster := gocql.NewCluster("192.168.1.1", "192.168.1.2", "192.168.1.3") + cluster.Keyspace = "example" + ... + session, err := cluster.CreateSession() + + if err = session.Query("use example2").Exec(); err != nil { + log.Fatal(err) + } +``` +This will result in an err being returned from the session.Query line as the user is trying to execute a "use" +statement. + +Example +------- + +```go +/* Before you execute the program, Launch `cqlsh` and execute: +create keyspace example with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }; +create table example.tweet(timeline text, id UUID, text text, PRIMARY KEY(id)); +create index on example.tweet(timeline); +*/ +package main + +import ( + "fmt" + "log" + + "github.com/gocql/gocql" +) + +func main() { + // connect to the cluster + cluster := gocql.NewCluster("192.168.1.1", "192.168.1.2", "192.168.1.3") + cluster.Keyspace = "example" + cluster.Consistency = gocql.Quorum + session, _ := cluster.CreateSession() + defer session.Close() + + // insert a tweet + if err := session.Query(`INSERT INTO tweet (timeline, id, text) VALUES (?, ?, ?)`, + "me", gocql.TimeUUID(), "hello world").Exec(); err != nil { + log.Fatal(err) + } + + var id gocql.UUID + var text string + + /* Search for a specific set of records whose 'timeline' column matches + * the value 'me'. The secondary index that we created earlier will be + * used for optimizing the search */ + if err := session.Query(`SELECT id, text FROM tweet WHERE timeline = ? LIMIT 1`, + "me").Consistency(gocql.One).Scan(&id, &text); err != nil { + log.Fatal(err) + } + fmt.Println("Tweet:", id, text) + + // list all tweets + iter := session.Query(`SELECT id, text FROM tweet WHERE timeline = ?`, "me").Iter() + for iter.Scan(&id, &text) { + fmt.Println("Tweet:", id, text) + } + if err := iter.Close(); err != nil { + log.Fatal(err) + } +} +``` + +Data Binding +------------ + +There are various ways to bind application level data structures to CQL statements: + +* You can write the data binding by hand, as outlined in the Tweet example. This provides you with the greatest flexibility, but it does mean that you need to keep your application code in sync with your Cassandra schema. +* You can dynamically marshal an entire query result into an `[]map[string]interface{}` using the `SliceMap()` API. This returns a slice of row maps keyed by CQL column names. This method requires no special interaction with the gocql API, but it does require your application to be able to deal with a key value view of your data. +* As a refinement on the `SliceMap()` API you can also call `MapScan()` which returns `map[string]interface{}` instances in a row by row fashion. +* The `Bind()` API provides a client app with a low level mechanism to introspect query meta data and extract appropriate field values from application level data structures. +* The [gocqlx](https://github.com/scylladb/gocqlx) package is an idiomatic extension to gocql that provides usability features. With gocqlx you can bind the query parameters from maps and structs, use named query parameters (:identifier) and scan the query results into structs and slices. It comes with a fluent and flexible CQL query builder that supports full CQL spec, including BATCH statements and custom functions. +* Building on top of the gocql driver, [cqlr](https://github.com/relops/cqlr) adds the ability to auto-bind a CQL iterator to a struct or to bind a struct to an INSERT statement. +* Another external project that layers on top of gocql is [cqlc](http://relops.com/cqlc) which generates gocql compliant code from your Cassandra schema so that you can write type safe CQL statements in Go with a natural query syntax. +* [gocassa](https://github.com/hailocab/gocassa) is an external project that layers on top of gocql to provide convenient query building and data binding. +* [gocqltable](https://github.com/kristoiv/gocqltable) provides an ORM-style convenience layer to make CRUD operations with gocql easier. + +Ecosystem +--------- + +The following community maintained tools are known to integrate with gocql: + +* [gocqlx](https://github.com/scylladb/gocqlx) is a gocql extension that automates data binding, adds named queries support, provides flexible query builders and plays well with gocql. +* [journey](https://github.com/db-journey/journey) is a migration tool with Cassandra support. +* [negronicql](https://github.com/mikebthun/negronicql) is gocql middleware for Negroni. +* [cqlr](https://github.com/relops/cqlr) adds the ability to auto-bind a CQL iterator to a struct or to bind a struct to an INSERT statement. +* [cqlc](http://relops.com/cqlc) generates gocql compliant code from your Cassandra schema so that you can write type safe CQL statements in Go with a natural query syntax. +* [gocassa](https://github.com/hailocab/gocassa) provides query building, adds data binding, and provides easy-to-use "recipe" tables for common query use-cases. +* [gocqltable](https://github.com/kristoiv/gocqltable) is a wrapper around gocql that aims to simplify common operations. +* [gockle](https://github.com/willfaught/gockle) provides simple, mockable interfaces that wrap gocql types +* [scylladb](https://github.com/scylladb/scylla) is a fast Apache Cassandra-compatible NoSQL database +* [go-cql-driver](https://github.com/MichaelS11/go-cql-driver) is an CQL driver conforming to the built-in database/sql interface. It is good for simple use cases where the database/sql interface is wanted. The CQL driver is a wrapper around this project. + +Other Projects +-------------- + +* [gocqldriver](https://github.com/tux21b/gocqldriver) is the predecessor of gocql based on Go's `database/sql` package. This project isn't maintained anymore, because Cassandra wasn't a good fit for the traditional `database/sql` API. Use this package instead. + +SEO +--- + +For some reason, when you Google `golang cassandra`, this project doesn't feature very highly in the result list. But if you Google `go cassandra`, then we're a bit higher up the list. So this is note to try to convince Google that golang is an alias for Go. + +License +------- + +> Copyright (c) 2012-2016 The gocql Authors. All rights reserved. +> Use of this source code is governed by a BSD-style +> license that can be found in the LICENSE file. diff --git a/vendor/github.com/gocql/gocql/address_translators.go b/vendor/github.com/gocql/gocql/address_translators.go new file mode 100644 index 0000000..6638bca --- /dev/null +++ b/vendor/github.com/gocql/gocql/address_translators.go @@ -0,0 +1,26 @@ +package gocql + +import "net" + +// AddressTranslator provides a way to translate node addresses (and ports) that are +// discovered or received as a node event. This can be useful in an ec2 environment, +// for instance, to translate public IPs to private IPs. +type AddressTranslator interface { + // Translate will translate the provided address and/or port to another + // address and/or port. If no translation is possible, Translate will return the + // address and port provided to it. + Translate(addr net.IP, port int) (net.IP, int) +} + +type AddressTranslatorFunc func(addr net.IP, port int) (net.IP, int) + +func (fn AddressTranslatorFunc) Translate(addr net.IP, port int) (net.IP, int) { + return fn(addr, port) +} + +// IdentityTranslator will do nothing but return what it was provided. It is essentially a no-op. +func IdentityTranslator() AddressTranslator { + return AddressTranslatorFunc(func(addr net.IP, port int) (net.IP, int) { + return addr, port + }) +} diff --git a/vendor/github.com/gocql/gocql/cluster.go b/vendor/github.com/gocql/gocql/cluster.go new file mode 100644 index 0000000..4214236 --- /dev/null +++ b/vendor/github.com/gocql/gocql/cluster.go @@ -0,0 +1,202 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "errors" + "net" + "time" +) + +// PoolConfig configures the connection pool used by the driver, it defaults to +// using a round-robin host selection policy and a round-robin connection selection +// policy for each host. +type PoolConfig struct { + // HostSelectionPolicy sets the policy for selecting which host to use for a + // given query (default: RoundRobinHostPolicy()) + HostSelectionPolicy HostSelectionPolicy +} + +func (p PoolConfig) buildPool(session *Session) *policyConnPool { + return newPolicyConnPool(session) +} + +// ClusterConfig is a struct to configure the default cluster implementation +// of gocql. It has a variety of attributes that can be used to modify the +// behavior to fit the most common use cases. Applications that require a +// different setup must implement their own cluster. +type ClusterConfig struct { + // addresses for the initial connections. It is recommended to use the value set in + // the Cassandra config for broadcast_address or listen_address, an IP address not + // a domain name. This is because events from Cassandra will use the configured IP + // address, which is used to index connected hosts. If the domain name specified + // resolves to more than 1 IP address then the driver may connect multiple times to + // the same host, and will not mark the node being down or up from events. + Hosts []string + CQLVersion string // CQL version (default: 3.0.0) + + // ProtoVersion sets the version of the native protocol to use, this will + // enable features in the driver for specific protocol versions, generally this + // should be set to a known version (2,3,4) for the cluster being connected to. + // + // If it is 0 or unset (the default) then the driver will attempt to discover the + // highest supported protocol for the cluster. In clusters with nodes of different + // versions the protocol selected is not defined (ie, it can be any of the supported in the cluster) + ProtoVersion int + Timeout time.Duration // connection timeout (default: 600ms) + ConnectTimeout time.Duration // initial connection timeout, used during initial dial to server (default: 600ms) + Port int // port (default: 9042) + Keyspace string // initial keyspace (optional) + NumConns int // number of connections per host (default: 2) + Consistency Consistency // default consistency level (default: Quorum) + Compressor Compressor // compression algorithm (default: nil) + Authenticator Authenticator // authenticator (default: nil) + RetryPolicy RetryPolicy // Default retry policy to use for queries (default: 0) + ConvictionPolicy ConvictionPolicy // Decide whether to mark host as down based on the error and host info (default: SimpleConvictionPolicy) + ReconnectionPolicy ReconnectionPolicy // Default reconnection policy to use for reconnecting before trying to mark host as down (default: see below) + SocketKeepalive time.Duration // The keepalive period to use, enabled if > 0 (default: 0) + MaxPreparedStmts int // Sets the maximum cache size for prepared statements globally for gocql (default: 1000) + MaxRoutingKeyInfo int // Sets the maximum cache size for query info about statements for each session (default: 1000) + PageSize int // Default page size to use for created sessions (default: 5000) + SerialConsistency SerialConsistency // Sets the consistency for the serial part of queries, values can be either SERIAL or LOCAL_SERIAL (default: unset) + SslOpts *SslOptions + DefaultTimestamp bool // Sends a client side timestamp for all requests which overrides the timestamp at which it arrives at the server. (default: true, only enabled for protocol 3 and above) + // PoolConfig configures the underlying connection pool, allowing the + // configuration of host selection and connection selection policies. + PoolConfig PoolConfig + + // If not zero, gocql attempt to reconnect known DOWN nodes in every ReconnectInterval. + ReconnectInterval time.Duration + + // The maximum amount of time to wait for schema agreement in a cluster after + // receiving a schema change frame. (deault: 60s) + MaxWaitSchemaAgreement time.Duration + + // HostFilter will filter all incoming events for host, any which don't pass + // the filter will be ignored. If set will take precedence over any options set + // via Discovery + HostFilter HostFilter + + // AddressTranslator will translate addresses found on peer discovery and/or + // node change events. + AddressTranslator AddressTranslator + + // If IgnorePeerAddr is true and the address in system.peers does not match + // the supplied host by either initial hosts or discovered via events then the + // host will be replaced with the supplied address. + // + // For example if an event comes in with host=10.0.0.1 but when looking up that + // address in system.local or system.peers returns 127.0.0.1, the peer will be + // set to 10.0.0.1 which is what will be used to connect to. + IgnorePeerAddr bool + + // If DisableInitialHostLookup then the driver will not attempt to get host info + // from the system.peers table, this will mean that the driver will connect to + // hosts supplied and will not attempt to lookup the hosts information, this will + // mean that data_centre, rack and token information will not be available and as + // such host filtering and token aware query routing will not be available. + DisableInitialHostLookup bool + + // Configure events the driver will register for + Events struct { + // disable registering for status events (node up/down) + DisableNodeStatusEvents bool + // disable registering for topology events (node added/removed/moved) + DisableTopologyEvents bool + // disable registering for schema events (keyspace/table/function removed/created/updated) + DisableSchemaEvents bool + } + + // DisableSkipMetadata will override the internal result metadata cache so that the driver does not + // send skip_metadata for queries, this means that the result will always contain + // the metadata to parse the rows and will not reuse the metadata from the prepared + // statement. + // + // See https://issues.apache.org/jira/browse/CASSANDRA-10786 + DisableSkipMetadata bool + + // QueryObserver will set the provided query observer on all queries created from this session. + // Use it to collect metrics / stats from queries by providing an implementation of QueryObserver. + QueryObserver QueryObserver + + // BatchObserver will set the provided batch observer on all queries created from this session. + // Use it to collect metrics / stats from batch queries by providing an implementation of BatchObserver. + BatchObserver BatchObserver + + // ConnectObserver will set the provided connect observer on all queries + // created from this session. + ConnectObserver ConnectObserver + + // FrameHeaderObserver will set the provided frame header observer on all frames' headers created from this session. + // Use it to collect metrics / stats from frames by providing an implementation of FrameHeaderObserver. + FrameHeaderObserver FrameHeaderObserver + + // Default idempotence for queries + DefaultIdempotence bool + + // internal config for testing + disableControlConn bool +} + +// NewCluster generates a new config for the default cluster implementation. +// +// The supplied hosts are used to initially connect to the cluster then the rest of +// the ring will be automatically discovered. It is recommended to use the value set in +// the Cassandra config for broadcast_address or listen_address, an IP address not +// a domain name. This is because events from Cassandra will use the configured IP +// address, which is used to index connected hosts. If the domain name specified +// resolves to more than 1 IP address then the driver may connect multiple times to +// the same host, and will not mark the node being down or up from events. +func NewCluster(hosts ...string) *ClusterConfig { + cfg := &ClusterConfig{ + Hosts: hosts, + CQLVersion: "3.0.0", + Timeout: 600 * time.Millisecond, + ConnectTimeout: 600 * time.Millisecond, + Port: 9042, + NumConns: 2, + Consistency: Quorum, + MaxPreparedStmts: defaultMaxPreparedStmts, + MaxRoutingKeyInfo: 1000, + PageSize: 5000, + DefaultTimestamp: true, + MaxWaitSchemaAgreement: 60 * time.Second, + ReconnectInterval: 60 * time.Second, + ConvictionPolicy: &SimpleConvictionPolicy{}, + ReconnectionPolicy: &ConstantReconnectionPolicy{MaxRetries: 3, Interval: 1 * time.Second}, + } + return cfg +} + +// CreateSession initializes the cluster based on this config and returns a +// session object that can be used to interact with the database. +func (cfg *ClusterConfig) CreateSession() (*Session, error) { + return NewSession(*cfg) +} + +// translateAddressPort is a helper method that will use the given AddressTranslator +// if defined, to translate the given address and port into a possibly new address +// and port, If no AddressTranslator or if an error occurs, the given address and +// port will be returned. +func (cfg *ClusterConfig) translateAddressPort(addr net.IP, port int) (net.IP, int) { + if cfg.AddressTranslator == nil || len(addr) == 0 { + return addr, port + } + newAddr, newPort := cfg.AddressTranslator.Translate(addr, port) + if gocqlDebug { + Logger.Printf("gocql: translating address '%v:%d' to '%v:%d'", addr, port, newAddr, newPort) + } + return newAddr, newPort +} + +func (cfg *ClusterConfig) filterHost(host *HostInfo) bool { + return !(cfg.HostFilter == nil || cfg.HostFilter.Accept(host)) +} + +var ( + ErrNoHosts = errors.New("no hosts provided") + ErrNoConnectionsStarted = errors.New("no connections were made when creating the session") + ErrHostQueryFailed = errors.New("unable to populate Hosts") +) diff --git a/vendor/github.com/gocql/gocql/compressor.go b/vendor/github.com/gocql/gocql/compressor.go new file mode 100644 index 0000000..26853ae --- /dev/null +++ b/vendor/github.com/gocql/gocql/compressor.go @@ -0,0 +1,28 @@ +package gocql + +import ( + "github.com/golang/snappy" +) + +type Compressor interface { + Name() string + Encode(data []byte) ([]byte, error) + Decode(data []byte) ([]byte, error) +} + +// SnappyCompressor implements the Compressor interface and can be used to +// compress incoming and outgoing frames. The snappy compression algorithm +// aims for very high speeds and reasonable compression. +type SnappyCompressor struct{} + +func (s SnappyCompressor) Name() string { + return "snappy" +} + +func (s SnappyCompressor) Encode(data []byte) ([]byte, error) { + return snappy.Encode(nil, data), nil +} + +func (s SnappyCompressor) Decode(data []byte) ([]byte, error) { + return snappy.Decode(nil, data) +} diff --git a/vendor/github.com/gocql/gocql/conn.go b/vendor/github.com/gocql/gocql/conn.go new file mode 100644 index 0000000..a8e3de1 --- /dev/null +++ b/vendor/github.com/gocql/gocql/conn.go @@ -0,0 +1,1199 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "bufio" + "context" + "crypto/tls" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/gocql/gocql/internal/lru" + + "github.com/gocql/gocql/internal/streams" +) + +var ( + approvedAuthenticators = [...]string{ + "org.apache.cassandra.auth.PasswordAuthenticator", + "com.instaclustr.cassandra.auth.SharedSecretAuthenticator", + "com.datastax.bdp.cassandra.auth.DseAuthenticator", + } +) + +func approve(authenticator string) bool { + for _, s := range approvedAuthenticators { + if authenticator == s { + return true + } + } + return false +} + +//JoinHostPort is a utility to return a address string that can be used +//gocql.Conn to form a connection with a host. +func JoinHostPort(addr string, port int) string { + addr = strings.TrimSpace(addr) + if _, _, err := net.SplitHostPort(addr); err != nil { + addr = net.JoinHostPort(addr, strconv.Itoa(port)) + } + return addr +} + +type Authenticator interface { + Challenge(req []byte) (resp []byte, auth Authenticator, err error) + Success(data []byte) error +} + +type PasswordAuthenticator struct { + Username string + Password string +} + +func (p PasswordAuthenticator) Challenge(req []byte) ([]byte, Authenticator, error) { + if !approve(string(req)) { + return nil, nil, fmt.Errorf("unexpected authenticator %q", req) + } + resp := make([]byte, 2+len(p.Username)+len(p.Password)) + resp[0] = 0 + copy(resp[1:], p.Username) + resp[len(p.Username)+1] = 0 + copy(resp[2+len(p.Username):], p.Password) + return resp, nil, nil +} + +func (p PasswordAuthenticator) Success(data []byte) error { + return nil +} + +type SslOptions struct { + *tls.Config + + // CertPath and KeyPath are optional depending on server + // config, but both fields must be omitted to avoid using a + // client certificate + CertPath string + KeyPath string + CaPath string //optional depending on server config + // If you want to verify the hostname and server cert (like a wildcard for cass cluster) then you should turn this on + // This option is basically the inverse of InSecureSkipVerify + // See InSecureSkipVerify in http://golang.org/pkg/crypto/tls/ for more info + EnableHostVerification bool +} + +type ConnConfig struct { + ProtoVersion int + CQLVersion string + Timeout time.Duration + ConnectTimeout time.Duration + Compressor Compressor + Authenticator Authenticator + Keepalive time.Duration + tlsConfig *tls.Config +} + +type ConnErrorHandler interface { + HandleError(conn *Conn, err error, closed bool) +} + +type connErrorHandlerFn func(conn *Conn, err error, closed bool) + +func (fn connErrorHandlerFn) HandleError(conn *Conn, err error, closed bool) { + fn(conn, err, closed) +} + +// If not zero, how many timeouts we will allow to occur before the connection is closed +// and restarted. This is to prevent a single query timeout from killing a connection +// which may be serving more queries just fine. +// Default is 10, should not be changed concurrently with queries. +var TimeoutLimit int64 = 10 + +// Conn is a single connection to a Cassandra node. It can be used to execute +// queries, but users are usually advised to use a more reliable, higher +// level API. +type Conn struct { + conn net.Conn + r *bufio.Reader + timeout time.Duration + cfg *ConnConfig + frameObserver FrameHeaderObserver + + headerBuf [maxFrameHeaderSize]byte + + streams *streams.IDGenerator + mu sync.RWMutex + calls map[int]*callReq + + errorHandler ConnErrorHandler + compressor Compressor + auth Authenticator + addr string + + version uint8 + currentKeyspace string + host *HostInfo + + session *Session + + closed int32 + quit chan struct{} + + timeouts int64 +} + +// Connect establishes a connection to a Cassandra node. +func (s *Session) dial(host *HostInfo, cfg *ConnConfig, errorHandler ConnErrorHandler) (*Conn, error) { + ip := host.ConnectAddress() + port := host.port + + // TODO(zariel): remove these + if len(ip) == 0 || ip.IsUnspecified() { + panic(fmt.Sprintf("host missing connect ip address: %v", ip)) + } else if port == 0 { + panic(fmt.Sprintf("host missing port: %v", port)) + } + + var ( + err error + conn net.Conn + ) + + dialer := &net.Dialer{ + Timeout: cfg.ConnectTimeout, + } + + // TODO(zariel): handle ipv6 zone + addr := (&net.TCPAddr{IP: ip, Port: port}).String() + + if cfg.tlsConfig != nil { + // the TLS config is safe to be reused by connections but it must not + // be modified after being used. + conn, err = tls.DialWithDialer(dialer, "tcp", addr, cfg.tlsConfig) + } else { + conn, err = dialer.Dial("tcp", addr) + } + + if err != nil { + return nil, err + } + + c := &Conn{ + conn: conn, + r: bufio.NewReader(conn), + cfg: cfg, + calls: make(map[int]*callReq), + timeout: cfg.Timeout, + version: uint8(cfg.ProtoVersion), + addr: conn.RemoteAddr().String(), + errorHandler: errorHandler, + compressor: cfg.Compressor, + auth: cfg.Authenticator, + quit: make(chan struct{}), + session: s, + streams: streams.New(cfg.ProtoVersion), + host: host, + frameObserver: s.frameObserver, + } + + if cfg.Keepalive > 0 { + c.setKeepalive(cfg.Keepalive) + } + + var ( + ctx context.Context + cancel func() + ) + if cfg.ConnectTimeout > 0 { + ctx, cancel = context.WithTimeout(context.Background(), cfg.ConnectTimeout) + } else { + ctx, cancel = context.WithCancel(context.Background()) + } + defer cancel() + + frameTicker := make(chan struct{}, 1) + startupErr := make(chan error) + go func() { + for range frameTicker { + err := c.recv() + if err != nil { + select { + case startupErr <- err: + case <-ctx.Done(): + } + + return + } + } + }() + + go func() { + defer close(frameTicker) + err := c.startup(ctx, frameTicker) + select { + case startupErr <- err: + case <-ctx.Done(): + } + }() + + select { + case err := <-startupErr: + if err != nil { + c.Close() + return nil, err + } + case <-ctx.Done(): + c.Close() + return nil, errors.New("gocql: no response to connection startup within timeout") + } + + go c.serve() + + return c, nil +} + +func (c *Conn) Write(p []byte) (int, error) { + if c.timeout > 0 { + c.conn.SetWriteDeadline(time.Now().Add(c.timeout)) + } + + return c.conn.Write(p) +} + +func (c *Conn) Read(p []byte) (n int, err error) { + const maxAttempts = 5 + + for i := 0; i < maxAttempts; i++ { + var nn int + if c.timeout > 0 { + c.conn.SetReadDeadline(time.Now().Add(c.timeout)) + } + + nn, err = io.ReadFull(c.r, p[n:]) + n += nn + if err == nil { + break + } + + if verr, ok := err.(net.Error); !ok || !verr.Temporary() { + break + } + } + + return +} + +func (c *Conn) startup(ctx context.Context, frameTicker chan struct{}) error { + m := map[string]string{ + "CQL_VERSION": c.cfg.CQLVersion, + } + + if c.compressor != nil { + m["COMPRESSION"] = c.compressor.Name() + } + + select { + case frameTicker <- struct{}{}: + case <-ctx.Done(): + return ctx.Err() + } + + framer, err := c.exec(ctx, &writeStartupFrame{opts: m}, nil) + if err != nil { + return err + } + + frame, err := framer.parseFrame() + if err != nil { + return err + } + + switch v := frame.(type) { + case error: + return v + case *readyFrame: + return nil + case *authenticateFrame: + return c.authenticateHandshake(ctx, v, frameTicker) + default: + return NewErrProtocol("Unknown type of response to startup frame: %s", v) + } +} + +func (c *Conn) authenticateHandshake(ctx context.Context, authFrame *authenticateFrame, frameTicker chan struct{}) error { + if c.auth == nil { + return fmt.Errorf("authentication required (using %q)", authFrame.class) + } + + resp, challenger, err := c.auth.Challenge([]byte(authFrame.class)) + if err != nil { + return err + } + + req := &writeAuthResponseFrame{data: resp} + + for { + select { + case frameTicker <- struct{}{}: + case <-ctx.Done(): + return ctx.Err() + } + + framer, err := c.exec(ctx, req, nil) + if err != nil { + return err + } + + frame, err := framer.parseFrame() + if err != nil { + return err + } + + switch v := frame.(type) { + case error: + return v + case *authSuccessFrame: + if challenger != nil { + return challenger.Success(v.data) + } + return nil + case *authChallengeFrame: + resp, challenger, err = challenger.Challenge(v.data) + if err != nil { + return err + } + + req = &writeAuthResponseFrame{ + data: resp, + } + default: + return fmt.Errorf("unknown frame response during authentication: %v", v) + } + } +} + +func (c *Conn) closeWithError(err error) { + if !atomic.CompareAndSwapInt32(&c.closed, 0, 1) { + return + } + + // we should attempt to deliver the error back to the caller if it + // exists + if err != nil { + c.mu.RLock() + for _, req := range c.calls { + // we need to send the error to all waiting queries, put the state + // of this conn into not active so that it can not execute any queries. + select { + case req.resp <- err: + case <-req.timeout: + } + } + c.mu.RUnlock() + } + + // if error was nil then unblock the quit channel + close(c.quit) + cerr := c.close() + + if err != nil { + c.errorHandler.HandleError(c, err, true) + } else if cerr != nil { + // TODO(zariel): is it a good idea to do this? + c.errorHandler.HandleError(c, cerr, true) + } +} + +func (c *Conn) close() error { + return c.conn.Close() +} + +func (c *Conn) Close() { + c.closeWithError(nil) +} + +// Serve starts the stream multiplexer for this connection, which is required +// to execute any queries. This method runs as long as the connection is +// open and is therefore usually called in a separate goroutine. +func (c *Conn) serve() { + var err error + for err == nil { + err = c.recv() + } + + c.closeWithError(err) +} + +func (c *Conn) discardFrame(head frameHeader) error { + _, err := io.CopyN(ioutil.Discard, c, int64(head.length)) + if err != nil { + return err + } + return nil +} + +type protocolError struct { + frame frame +} + +func (p *protocolError) Error() string { + if err, ok := p.frame.(error); ok { + return err.Error() + } + return fmt.Sprintf("gocql: received unexpected frame on stream %d: %v", p.frame.Header().stream, p.frame) +} + +func (c *Conn) recv() error { + // not safe for concurrent reads + + // read a full header, ignore timeouts, as this is being ran in a loop + // TODO: TCP level deadlines? or just query level deadlines? + if c.timeout > 0 { + c.conn.SetReadDeadline(time.Time{}) + } + + headStartTime := time.Now() + // were just reading headers over and over and copy bodies + head, err := readHeader(c.r, c.headerBuf[:]) + headEndTime := time.Now() + if err != nil { + return err + } + + if c.frameObserver != nil { + c.frameObserver.ObserveFrameHeader(context.Background(), ObservedFrameHeader{ + Version: byte(head.version), + Flags: head.flags, + Stream: int16(head.stream), + Opcode: byte(head.op), + Length: int32(head.length), + Start: headStartTime, + End: headEndTime, + }) + } + + if head.stream > c.streams.NumStreams { + return fmt.Errorf("gocql: frame header stream is beyond call expected bounds: %d", head.stream) + } else if head.stream == -1 { + // TODO: handle cassandra event frames, we shouldnt get any currently + framer := newFramer(c, c, c.compressor, c.version) + if err := framer.readFrame(&head); err != nil { + return err + } + go c.session.handleEvent(framer) + return nil + } else if head.stream <= 0 { + // reserved stream that we dont use, probably due to a protocol error + // or a bug in Cassandra, this should be an error, parse it and return. + framer := newFramer(c, c, c.compressor, c.version) + if err := framer.readFrame(&head); err != nil { + return err + } + + frame, err := framer.parseFrame() + if err != nil { + return err + } + + return &protocolError{ + frame: frame, + } + } + + c.mu.RLock() + call, ok := c.calls[head.stream] + c.mu.RUnlock() + if call == nil || call.framer == nil || !ok { + Logger.Printf("gocql: received response for stream which has no handler: header=%v\n", head) + return c.discardFrame(head) + } + + err = call.framer.readFrame(&head) + if err != nil { + // only net errors should cause the connection to be closed. Though + // cassandra returning corrupt frames will be returned here as well. + if _, ok := err.(net.Error); ok { + return err + } + } + + // we either, return a response to the caller, the caller timedout, or the + // connection has closed. Either way we should never block indefinatly here + select { + case call.resp <- err: + case <-call.timeout: + c.releaseStream(head.stream) + case <-c.quit: + } + + return nil +} + +func (c *Conn) releaseStream(stream int) { + c.mu.Lock() + call := c.calls[stream] + if call != nil && stream != call.streamID { + panic(fmt.Sprintf("attempt to release streamID with invalid stream: %d -> %+v\n", stream, call)) + } else if call == nil { + panic(fmt.Sprintf("releasing a stream not in use: %d", stream)) + } + delete(c.calls, stream) + c.mu.Unlock() + + if call.timer != nil { + call.timer.Stop() + } + + streamPool.Put(call) + c.streams.Clear(stream) +} + +func (c *Conn) handleTimeout() { + if TimeoutLimit > 0 && atomic.AddInt64(&c.timeouts, 1) > TimeoutLimit { + c.closeWithError(ErrTooManyTimeouts) + } +} + +var ( + streamPool = sync.Pool{ + New: func() interface{} { + return &callReq{ + resp: make(chan error), + } + }, + } +) + +type callReq struct { + // could use a waitgroup but this allows us to do timeouts on the read/send + resp chan error + framer *framer + timeout chan struct{} // indicates to recv() that a call has timedout + streamID int // current stream in use + + timer *time.Timer +} + +func (c *Conn) exec(ctx context.Context, req frameWriter, tracer Tracer) (*framer, error) { + // TODO: move tracer onto conn + stream, ok := c.streams.GetStream() + if !ok { + return nil, ErrNoStreams + } + + // resp is basically a waiting semaphore protecting the framer + framer := newFramer(c, c, c.compressor, c.version) + + call := streamPool.Get().(*callReq) + call.framer = framer + call.timeout = make(chan struct{}) + call.streamID = stream + + c.mu.Lock() + existingCall := c.calls[stream] + if existingCall == nil { + c.calls[stream] = call + } + c.mu.Unlock() + + if existingCall != nil { + return nil, fmt.Errorf("attempting to use stream already in use: %d -> %d", stream, existingCall.streamID) + } + + if tracer != nil { + framer.trace() + } + + err := req.writeFrame(framer, stream) + if err != nil { + // closeWithError will block waiting for this stream to either receive a response + // or for us to timeout, close the timeout chan here. Im not entirely sure + // but we should not get a response after an error on the write side. + close(call.timeout) + // I think this is the correct thing to do, im not entirely sure. It is not + // ideal as readers might still get some data, but they probably wont. + // Here we need to be careful as the stream is not available and if all + // writes just timeout or fail then the pool might use this connection to + // send a frame on, with all the streams used up and not returned. + c.closeWithError(err) + return nil, err + } + + var timeoutCh <-chan time.Time + if c.timeout > 0 { + if call.timer == nil { + call.timer = time.NewTimer(0) + <-call.timer.C + } else { + if !call.timer.Stop() { + select { + case <-call.timer.C: + default: + } + } + } + + call.timer.Reset(c.timeout) + timeoutCh = call.timer.C + } + + var ctxDone <-chan struct{} + if ctx != nil { + ctxDone = ctx.Done() + } + + select { + case err := <-call.resp: + close(call.timeout) + if err != nil { + if !c.Closed() { + // if the connection is closed then we cant release the stream, + // this is because the request is still outstanding and we have + // been handed another error from another stream which caused the + // connection to close. + c.releaseStream(stream) + } + return nil, err + } + case <-timeoutCh: + close(call.timeout) + c.handleTimeout() + return nil, ErrTimeoutNoResponse + case <-ctxDone: + close(call.timeout) + return nil, ctx.Err() + case <-c.quit: + return nil, ErrConnectionClosed + } + + // dont release the stream if detect a timeout as another request can reuse + // that stream and get a response for the old request, which we have no + // easy way of detecting. + // + // Ensure that the stream is not released if there are potentially outstanding + // requests on the stream to prevent nil pointer dereferences in recv(). + defer c.releaseStream(stream) + + if v := framer.header.version.version(); v != c.version { + return nil, NewErrProtocol("unexpected protocol version in response: got %d expected %d", v, c.version) + } + + return framer, nil +} + +type preparedStatment struct { + id []byte + request preparedMetadata + response resultMetadata +} + +type inflightPrepare struct { + wg sync.WaitGroup + err error + + preparedStatment *preparedStatment +} + +func (c *Conn) prepareStatement(ctx context.Context, stmt string, tracer Tracer) (*preparedStatment, error) { + stmtCacheKey := c.session.stmtsLRU.keyFor(c.addr, c.currentKeyspace, stmt) + flight, ok := c.session.stmtsLRU.execIfMissing(stmtCacheKey, func(lru *lru.Cache) *inflightPrepare { + flight := new(inflightPrepare) + flight.wg.Add(1) + lru.Add(stmtCacheKey, flight) + return flight + }) + + if ok { + flight.wg.Wait() + return flight.preparedStatment, flight.err + } + + prep := &writePrepareFrame{ + statement: stmt, + } + + framer, err := c.exec(ctx, prep, tracer) + if err != nil { + flight.err = err + flight.wg.Done() + c.session.stmtsLRU.remove(stmtCacheKey) + return nil, err + } + + frame, err := framer.parseFrame() + if err != nil { + flight.err = err + flight.wg.Done() + c.session.stmtsLRU.remove(stmtCacheKey) + return nil, err + } + + // TODO(zariel): tidy this up, simplify handling of frame parsing so its not duplicated + // everytime we need to parse a frame. + if len(framer.traceID) > 0 && tracer != nil { + tracer.Trace(framer.traceID) + } + + switch x := frame.(type) { + case *resultPreparedFrame: + flight.preparedStatment = &preparedStatment{ + // defensively copy as we will recycle the underlying buffer after we + // return. + id: copyBytes(x.preparedID), + // the type info's should _not_ have a reference to the framers read buffer, + // therefore we can just copy them directly. + request: x.reqMeta, + response: x.respMeta, + } + case error: + flight.err = x + default: + flight.err = NewErrProtocol("Unknown type in response to prepare frame: %s", x) + } + flight.wg.Done() + + if flight.err != nil { + c.session.stmtsLRU.remove(stmtCacheKey) + } + + return flight.preparedStatment, flight.err +} + +func marshalQueryValue(typ TypeInfo, value interface{}, dst *queryValues) error { + if named, ok := value.(*namedValue); ok { + dst.name = named.name + value = named.value + } + + if _, ok := value.(unsetColumn); !ok { + val, err := Marshal(typ, value) + if err != nil { + return err + } + + dst.value = val + } else { + dst.isUnset = true + } + + return nil +} + +func (c *Conn) executeQuery(qry *Query) *Iter { + params := queryParams{ + consistency: qry.cons, + } + + // frame checks that it is not 0 + params.serialConsistency = qry.serialCons + params.defaultTimestamp = qry.defaultTimestamp + params.defaultTimestampValue = qry.defaultTimestampValue + + if len(qry.pageState) > 0 { + params.pagingState = qry.pageState + } + if qry.pageSize > 0 { + params.pageSize = qry.pageSize + } + + var ( + frame frameWriter + info *preparedStatment + ) + + if qry.shouldPrepare() { + // Prepare all DML queries. Other queries can not be prepared. + var err error + info, err = c.prepareStatement(qry.context, qry.stmt, qry.trace) + if err != nil { + return &Iter{err: err} + } + + var values []interface{} + + if qry.binding == nil { + values = qry.values + } else { + values, err = qry.binding(&QueryInfo{ + Id: info.id, + Args: info.request.columns, + Rval: info.response.columns, + PKeyColumns: info.request.pkeyColumns, + }) + + if err != nil { + return &Iter{err: err} + } + } + + if len(values) != info.request.actualColCount { + return &Iter{err: fmt.Errorf("gocql: expected %d values send got %d", info.request.actualColCount, len(values))} + } + + params.values = make([]queryValues, len(values)) + for i := 0; i < len(values); i++ { + v := ¶ms.values[i] + value := values[i] + typ := info.request.columns[i].TypeInfo + if err := marshalQueryValue(typ, value, v); err != nil { + return &Iter{err: err} + } + } + + params.skipMeta = !(c.session.cfg.DisableSkipMetadata || qry.disableSkipMetadata) + + frame = &writeExecuteFrame{ + preparedID: info.id, + params: params, + } + } else { + frame = &writeQueryFrame{ + statement: qry.stmt, + params: params, + } + } + + framer, err := c.exec(qry.context, frame, qry.trace) + if err != nil { + return &Iter{err: err} + } + + resp, err := framer.parseFrame() + if err != nil { + return &Iter{err: err} + } + + if len(framer.traceID) > 0 && qry.trace != nil { + qry.trace.Trace(framer.traceID) + } + + switch x := resp.(type) { + case *resultVoidFrame: + return &Iter{framer: framer} + case *resultRowsFrame: + iter := &Iter{ + meta: x.meta, + framer: framer, + numRows: x.numRows, + } + + if params.skipMeta { + if info != nil { + iter.meta = info.response + iter.meta.pagingState = x.meta.pagingState + } else { + return &Iter{framer: framer, err: errors.New("gocql: did not receive metadata but prepared info is nil")} + } + } else { + iter.meta = x.meta + } + + if len(x.meta.pagingState) > 0 && !qry.disableAutoPage { + iter.next = &nextIter{ + qry: *qry, + pos: int((1 - qry.prefetch) * float64(x.numRows)), + conn: c, + } + + iter.next.qry.pageState = copyBytes(x.meta.pagingState) + if iter.next.pos < 1 { + iter.next.pos = 1 + } + } + + return iter + case *resultKeyspaceFrame: + return &Iter{framer: framer} + case *schemaChangeKeyspace, *schemaChangeTable, *schemaChangeFunction, *schemaChangeAggregate, *schemaChangeType: + iter := &Iter{framer: framer} + if err := c.awaitSchemaAgreement(); err != nil { + // TODO: should have this behind a flag + Logger.Println(err) + } + // dont return an error from this, might be a good idea to give a warning + // though. The impact of this returning an error would be that the cluster + // is not consistent with regards to its schema. + return iter + case *RequestErrUnprepared: + stmtCacheKey := c.session.stmtsLRU.keyFor(c.addr, c.currentKeyspace, qry.stmt) + if c.session.stmtsLRU.remove(stmtCacheKey) { + return c.executeQuery(qry) + } + + return &Iter{err: x, framer: framer} + case error: + return &Iter{err: x, framer: framer} + default: + return &Iter{ + err: NewErrProtocol("Unknown type in response to execute query (%T): %s", x, x), + framer: framer, + } + } +} + +func (c *Conn) Pick(qry *Query) *Conn { + if c.Closed() { + return nil + } + return c +} + +func (c *Conn) Closed() bool { + return atomic.LoadInt32(&c.closed) == 1 +} + +func (c *Conn) Address() string { + return c.addr +} + +func (c *Conn) AvailableStreams() int { + return c.streams.Available() +} + +func (c *Conn) UseKeyspace(keyspace string) error { + q := &writeQueryFrame{statement: `USE "` + keyspace + `"`} + q.params.consistency = Any + + framer, err := c.exec(context.Background(), q, nil) + if err != nil { + return err + } + + resp, err := framer.parseFrame() + if err != nil { + return err + } + + switch x := resp.(type) { + case *resultKeyspaceFrame: + case error: + return x + default: + return NewErrProtocol("unknown frame in response to USE: %v", x) + } + + c.currentKeyspace = keyspace + + return nil +} + +func (c *Conn) executeBatch(batch *Batch) *Iter { + if c.version == protoVersion1 { + return &Iter{err: ErrUnsupported} + } + + n := len(batch.Entries) + req := &writeBatchFrame{ + typ: batch.Type, + statements: make([]batchStatment, n), + consistency: batch.Cons, + serialConsistency: batch.serialCons, + defaultTimestamp: batch.defaultTimestamp, + defaultTimestampValue: batch.defaultTimestampValue, + } + + stmts := make(map[string]string, len(batch.Entries)) + + for i := 0; i < n; i++ { + entry := &batch.Entries[i] + b := &req.statements[i] + + if len(entry.Args) > 0 || entry.binding != nil { + info, err := c.prepareStatement(batch.context, entry.Stmt, nil) + if err != nil { + return &Iter{err: err} + } + + var values []interface{} + if entry.binding == nil { + values = entry.Args + } else { + values, err = entry.binding(&QueryInfo{ + Id: info.id, + Args: info.request.columns, + Rval: info.response.columns, + PKeyColumns: info.request.pkeyColumns, + }) + if err != nil { + return &Iter{err: err} + } + } + + if len(values) != info.request.actualColCount { + return &Iter{err: fmt.Errorf("gocql: batch statement %d expected %d values send got %d", i, info.request.actualColCount, len(values))} + } + + b.preparedID = info.id + stmts[string(info.id)] = entry.Stmt + + b.values = make([]queryValues, info.request.actualColCount) + + for j := 0; j < info.request.actualColCount; j++ { + v := &b.values[j] + value := values[j] + typ := info.request.columns[j].TypeInfo + if err := marshalQueryValue(typ, value, v); err != nil { + return &Iter{err: err} + } + } + } else { + b.statement = entry.Stmt + } + } + + // TODO: should batch support tracing? + framer, err := c.exec(batch.context, req, nil) + if err != nil { + return &Iter{err: err} + } + + resp, err := framer.parseFrame() + if err != nil { + return &Iter{err: err, framer: framer} + } + + switch x := resp.(type) { + case *resultVoidFrame: + return &Iter{} + case *RequestErrUnprepared: + stmt, found := stmts[string(x.StatementId)] + if found { + key := c.session.stmtsLRU.keyFor(c.addr, c.currentKeyspace, stmt) + c.session.stmtsLRU.remove(key) + } + + if found { + return c.executeBatch(batch) + } else { + return &Iter{err: x, framer: framer} + } + case *resultRowsFrame: + iter := &Iter{ + meta: x.meta, + framer: framer, + numRows: x.numRows, + } + + return iter + case error: + return &Iter{err: x, framer: framer} + default: + return &Iter{err: NewErrProtocol("Unknown type in response to batch statement: %s", x), framer: framer} + } +} + +func (c *Conn) setKeepalive(d time.Duration) error { + if tc, ok := c.conn.(*net.TCPConn); ok { + err := tc.SetKeepAlivePeriod(d) + if err != nil { + return err + } + + return tc.SetKeepAlive(true) + } + + return nil +} + +func (c *Conn) query(statement string, values ...interface{}) (iter *Iter) { + q := c.session.Query(statement, values...).Consistency(One) + return c.executeQuery(q) +} + +func (c *Conn) awaitSchemaAgreement() (err error) { + const ( + peerSchemas = "SELECT schema_version, peer FROM system.peers" + localSchemas = "SELECT schema_version FROM system.local WHERE key='local'" + ) + + var versions map[string]struct{} + + endDeadline := time.Now().Add(c.session.cfg.MaxWaitSchemaAgreement) + for time.Now().Before(endDeadline) { + iter := c.query(peerSchemas) + + versions = make(map[string]struct{}) + + var schemaVersion string + var peer string + for iter.Scan(&schemaVersion, &peer) { + if schemaVersion == "" { + Logger.Printf("skipping peer entry with empty schema_version: peer=%q", peer) + continue + } + + versions[schemaVersion] = struct{}{} + schemaVersion = "" + } + + if err = iter.Close(); err != nil { + goto cont + } + + iter = c.query(localSchemas) + for iter.Scan(&schemaVersion) { + versions[schemaVersion] = struct{}{} + schemaVersion = "" + } + + if err = iter.Close(); err != nil { + goto cont + } + + if len(versions) <= 1 { + return nil + } + + cont: + time.Sleep(200 * time.Millisecond) + } + + if err != nil { + return + } + + schemas := make([]string, 0, len(versions)) + for schema := range versions { + schemas = append(schemas, schema) + } + + // not exported + return fmt.Errorf("gocql: cluster schema versions not consistent: %+v", schemas) +} + +const localHostInfo = "SELECT * FROM system.local WHERE key='local'" + +func (c *Conn) localHostInfo() (*HostInfo, error) { + row, err := c.query(localHostInfo).rowMap() + if err != nil { + return nil, err + } + + port := c.conn.RemoteAddr().(*net.TCPAddr).Port + + // TODO(zariel): avoid doing this here + host, err := c.session.hostInfoFromMap(row, port) + if err != nil { + return nil, err + } + + return c.session.ring.addOrUpdate(host), nil +} + +var ( + ErrQueryArgLength = errors.New("gocql: query argument length mismatch") + ErrTimeoutNoResponse = errors.New("gocql: no response received from cassandra within timeout period") + ErrTooManyTimeouts = errors.New("gocql: too many query timeouts on the connection") + ErrConnectionClosed = errors.New("gocql: connection closed waiting for response") + ErrNoStreams = errors.New("gocql: no streams available on connection") +) diff --git a/vendor/github.com/gocql/gocql/connectionpool.go b/vendor/github.com/gocql/gocql/connectionpool.go new file mode 100644 index 0000000..433a788 --- /dev/null +++ b/vendor/github.com/gocql/gocql/connectionpool.go @@ -0,0 +1,578 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io/ioutil" + "math/rand" + "net" + "sync" + "sync/atomic" + "time" +) + +// interface to implement to receive the host information +type SetHosts interface { + SetHosts(hosts []*HostInfo) +} + +// interface to implement to receive the partitioner value +type SetPartitioner interface { + SetPartitioner(partitioner string) +} + +func setupTLSConfig(sslOpts *SslOptions) (*tls.Config, error) { + if sslOpts.Config == nil { + sslOpts.Config = &tls.Config{} + } + + // ca cert is optional + if sslOpts.CaPath != "" { + if sslOpts.RootCAs == nil { + sslOpts.RootCAs = x509.NewCertPool() + } + + pem, err := ioutil.ReadFile(sslOpts.CaPath) + if err != nil { + return nil, fmt.Errorf("connectionpool: unable to open CA certs: %v", err) + } + + if !sslOpts.RootCAs.AppendCertsFromPEM(pem) { + return nil, errors.New("connectionpool: failed parsing or CA certs") + } + } + + if sslOpts.CertPath != "" || sslOpts.KeyPath != "" { + mycert, err := tls.LoadX509KeyPair(sslOpts.CertPath, sslOpts.KeyPath) + if err != nil { + return nil, fmt.Errorf("connectionpool: unable to load X509 key pair: %v", err) + } + sslOpts.Certificates = append(sslOpts.Certificates, mycert) + } + + sslOpts.InsecureSkipVerify = !sslOpts.EnableHostVerification + + return sslOpts.Config, nil +} + +type policyConnPool struct { + session *Session + + port int + numConns int + keyspace string + + mu sync.RWMutex + hostConnPools map[string]*hostConnPool + + endpoints []string +} + +func connConfig(cfg *ClusterConfig) (*ConnConfig, error) { + var ( + err error + tlsConfig *tls.Config + ) + + // TODO(zariel): move tls config setup into session init. + if cfg.SslOpts != nil { + tlsConfig, err = setupTLSConfig(cfg.SslOpts) + if err != nil { + return nil, err + } + } + + return &ConnConfig{ + ProtoVersion: cfg.ProtoVersion, + CQLVersion: cfg.CQLVersion, + Timeout: cfg.Timeout, + ConnectTimeout: cfg.ConnectTimeout, + Compressor: cfg.Compressor, + Authenticator: cfg.Authenticator, + Keepalive: cfg.SocketKeepalive, + tlsConfig: tlsConfig, + }, nil +} + +func newPolicyConnPool(session *Session) *policyConnPool { + // create the pool + pool := &policyConnPool{ + session: session, + port: session.cfg.Port, + numConns: session.cfg.NumConns, + keyspace: session.cfg.Keyspace, + hostConnPools: map[string]*hostConnPool{}, + } + + pool.endpoints = make([]string, len(session.cfg.Hosts)) + copy(pool.endpoints, session.cfg.Hosts) + + return pool +} + +func (p *policyConnPool) SetHosts(hosts []*HostInfo) { + p.mu.Lock() + defer p.mu.Unlock() + + toRemove := make(map[string]struct{}) + for addr := range p.hostConnPools { + toRemove[addr] = struct{}{} + } + + pools := make(chan *hostConnPool) + createCount := 0 + for _, host := range hosts { + if !host.IsUp() { + // don't create a connection pool for a down host + continue + } + ip := host.ConnectAddress().String() + if _, exists := p.hostConnPools[ip]; exists { + // still have this host, so don't remove it + delete(toRemove, ip) + continue + } + + createCount++ + go func(host *HostInfo) { + // create a connection pool for the host + pools <- newHostConnPool( + p.session, + host, + p.port, + p.numConns, + p.keyspace, + ) + }(host) + } + + // add created pools + for createCount > 0 { + pool := <-pools + createCount-- + if pool.Size() > 0 { + // add pool only if there a connections available + p.hostConnPools[string(pool.host.ConnectAddress())] = pool + } + } + + for addr := range toRemove { + pool := p.hostConnPools[addr] + delete(p.hostConnPools, addr) + go pool.Close() + } +} + +func (p *policyConnPool) Size() int { + p.mu.RLock() + count := 0 + for _, pool := range p.hostConnPools { + count += pool.Size() + } + p.mu.RUnlock() + + return count +} + +func (p *policyConnPool) getPool(host *HostInfo) (pool *hostConnPool, ok bool) { + ip := host.ConnectAddress().String() + p.mu.RLock() + pool, ok = p.hostConnPools[ip] + p.mu.RUnlock() + return +} + +func (p *policyConnPool) Close() { + p.mu.Lock() + defer p.mu.Unlock() + + // close the pools + for addr, pool := range p.hostConnPools { + delete(p.hostConnPools, addr) + pool.Close() + } +} + +func (p *policyConnPool) addHost(host *HostInfo) { + ip := host.ConnectAddress().String() + p.mu.Lock() + pool, ok := p.hostConnPools[ip] + if !ok { + pool = newHostConnPool( + p.session, + host, + host.Port(), // TODO: if port == 0 use pool.port? + p.numConns, + p.keyspace, + ) + + p.hostConnPools[ip] = pool + } + p.mu.Unlock() + + pool.fill() +} + +func (p *policyConnPool) removeHost(ip net.IP) { + k := ip.String() + p.mu.Lock() + pool, ok := p.hostConnPools[k] + if !ok { + p.mu.Unlock() + return + } + + delete(p.hostConnPools, k) + p.mu.Unlock() + + go pool.Close() +} + +func (p *policyConnPool) hostUp(host *HostInfo) { + // TODO(zariel): have a set of up hosts and down hosts, we can internally + // detect down hosts, then try to reconnect to them. + p.addHost(host) +} + +func (p *policyConnPool) hostDown(ip net.IP) { + // TODO(zariel): mark host as down so we can try to connect to it later, for + // now just treat it has removed. + p.removeHost(ip) +} + +// hostConnPool is a connection pool for a single host. +// Connection selection is based on a provided ConnSelectionPolicy +type hostConnPool struct { + session *Session + host *HostInfo + port int + addr string + size int + keyspace string + // protection for conns, closed, filling + mu sync.RWMutex + conns []*Conn + closed bool + filling bool + + pos uint32 +} + +func (h *hostConnPool) String() string { + h.mu.RLock() + defer h.mu.RUnlock() + return fmt.Sprintf("[filling=%v closed=%v conns=%v size=%v host=%v]", + h.filling, h.closed, len(h.conns), h.size, h.host) +} + +func newHostConnPool(session *Session, host *HostInfo, port, size int, + keyspace string) *hostConnPool { + + pool := &hostConnPool{ + session: session, + host: host, + port: port, + addr: (&net.TCPAddr{IP: host.ConnectAddress(), Port: host.Port()}).String(), + size: size, + keyspace: keyspace, + conns: make([]*Conn, 0, size), + filling: false, + closed: false, + } + + // the pool is not filled or connected + return pool +} + +// Pick a connection from this connection pool for the given query. +func (pool *hostConnPool) Pick() *Conn { + pool.mu.RLock() + defer pool.mu.RUnlock() + + if pool.closed { + return nil + } + + size := len(pool.conns) + if size < pool.size { + // try to fill the pool + go pool.fill() + + if size == 0 { + return nil + } + } + + pos := int(atomic.AddUint32(&pool.pos, 1) - 1) + + var ( + leastBusyConn *Conn + streamsAvailable int + ) + + // find the conn which has the most available streams, this is racy + for i := 0; i < size; i++ { + conn := pool.conns[(pos+i)%size] + if streams := conn.AvailableStreams(); streams > streamsAvailable { + leastBusyConn = conn + streamsAvailable = streams + } + } + + return leastBusyConn +} + +//Size returns the number of connections currently active in the pool +func (pool *hostConnPool) Size() int { + pool.mu.RLock() + defer pool.mu.RUnlock() + + return len(pool.conns) +} + +//Close the connection pool +func (pool *hostConnPool) Close() { + pool.mu.Lock() + + if pool.closed { + pool.mu.Unlock() + return + } + pool.closed = true + + // ensure we dont try to reacquire the lock in handleError + // TODO: improve this as the following can happen + // 1) we have locked pool.mu write lock + // 2) conn.Close calls conn.closeWithError(nil) + // 3) conn.closeWithError calls conn.Close() which returns an error + // 4) conn.closeWithError calls pool.HandleError with the error from conn.Close + // 5) pool.HandleError tries to lock pool.mu + // deadlock + + // empty the pool + conns := pool.conns + pool.conns = nil + + pool.mu.Unlock() + + // close the connections + for _, conn := range conns { + conn.Close() + } +} + +// Fill the connection pool +func (pool *hostConnPool) fill() { + pool.mu.RLock() + // avoid filling a closed pool, or concurrent filling + if pool.closed || pool.filling { + pool.mu.RUnlock() + return + } + + // determine the filling work to be done + startCount := len(pool.conns) + fillCount := pool.size - startCount + + // avoid filling a full (or overfull) pool + if fillCount <= 0 { + pool.mu.RUnlock() + return + } + + // switch from read to write lock + pool.mu.RUnlock() + pool.mu.Lock() + + // double check everything since the lock was released + startCount = len(pool.conns) + fillCount = pool.size - startCount + if pool.closed || pool.filling || fillCount <= 0 { + // looks like another goroutine already beat this + // goroutine to the filling + pool.mu.Unlock() + return + } + + // ok fill the pool + pool.filling = true + + // allow others to access the pool while filling + pool.mu.Unlock() + // only this goroutine should make calls to fill/empty the pool at this + // point until after this routine or its subordinates calls + // fillingStopped + + // fill only the first connection synchronously + if startCount == 0 { + err := pool.connect() + pool.logConnectErr(err) + + if err != nil { + // probably unreachable host + pool.fillingStopped(true) + + // this is call with the connection pool mutex held, this call will + // then recursively try to lock it again. FIXME + if pool.session.cfg.ConvictionPolicy.AddFailure(err, pool.host) { + go pool.session.handleNodeDown(pool.host.ConnectAddress(), pool.port) + } + return + } + + // filled one + fillCount-- + } + + // fill the rest of the pool asynchronously + go func() { + err := pool.connectMany(fillCount) + + // mark the end of filling + pool.fillingStopped(err != nil) + }() +} + +func (pool *hostConnPool) logConnectErr(err error) { + if opErr, ok := err.(*net.OpError); ok && (opErr.Op == "dial" || opErr.Op == "read") { + // connection refused + // these are typical during a node outage so avoid log spam. + if gocqlDebug { + Logger.Printf("unable to dial %q: %v\n", pool.host.ConnectAddress(), err) + } + } else if err != nil { + // unexpected error + Logger.Printf("error: failed to connect to %s due to error: %v", pool.addr, err) + } +} + +// transition back to a not-filling state. +func (pool *hostConnPool) fillingStopped(hadError bool) { + if hadError { + // wait for some time to avoid back-to-back filling + // this provides some time between failed attempts + // to fill the pool for the host to recover + time.Sleep(time.Duration(rand.Int31n(100)+31) * time.Millisecond) + } + + pool.mu.Lock() + pool.filling = false + pool.mu.Unlock() +} + +// connectMany creates new connections concurrent. +func (pool *hostConnPool) connectMany(count int) error { + if count == 0 { + return nil + } + var ( + wg sync.WaitGroup + mu sync.Mutex + connectErr error + ) + wg.Add(count) + for i := 0; i < count; i++ { + go func() { + defer wg.Done() + err := pool.connect() + pool.logConnectErr(err) + if err != nil { + mu.Lock() + connectErr = err + mu.Unlock() + } + }() + } + // wait for all connections are done + wg.Wait() + + return connectErr +} + +// create a new connection to the host and add it to the pool +func (pool *hostConnPool) connect() (err error) { + // TODO: provide a more robust connection retry mechanism, we should also + // be able to detect hosts that come up by trying to connect to downed ones. + // try to connect + var conn *Conn + reconnectionPolicy := pool.session.cfg.ReconnectionPolicy + for i := 0; i < reconnectionPolicy.GetMaxRetries(); i++ { + conn, err = pool.session.connect(pool.host, pool) + if err == nil { + break + } + if opErr, isOpErr := err.(*net.OpError); isOpErr { + // if the error is not a temporary error (ex: network unreachable) don't + // retry + if !opErr.Temporary() { + break + } + } + if gocqlDebug { + Logger.Printf("connection failed %q: %v, reconnecting with %T\n", + pool.host.ConnectAddress(), err, reconnectionPolicy) + } + time.Sleep(reconnectionPolicy.GetInterval(i)) + } + + if err != nil { + return err + } + + if pool.keyspace != "" { + // set the keyspace + if err = conn.UseKeyspace(pool.keyspace); err != nil { + conn.Close() + return err + } + } + + // add the Conn to the pool + pool.mu.Lock() + defer pool.mu.Unlock() + + if pool.closed { + conn.Close() + return nil + } + + pool.conns = append(pool.conns, conn) + + return nil +} + +// handle any error from a Conn +func (pool *hostConnPool) HandleError(conn *Conn, err error, closed bool) { + if !closed { + // still an open connection, so continue using it + return + } + + // TODO: track the number of errors per host and detect when a host is dead, + // then also have something which can detect when a host comes back. + pool.mu.Lock() + defer pool.mu.Unlock() + + if pool.closed { + // pool closed + return + } + + // find the connection index + for i, candidate := range pool.conns { + if candidate == conn { + // remove the connection, not preserving order + pool.conns[i], pool.conns = pool.conns[len(pool.conns)-1], pool.conns[:len(pool.conns)-1] + + // lost a connection, so fill the pool + go pool.fill() + break + } + } +} diff --git a/vendor/github.com/gocql/gocql/control.go b/vendor/github.com/gocql/gocql/control.go new file mode 100644 index 0000000..01bd5da --- /dev/null +++ b/vendor/github.com/gocql/gocql/control.go @@ -0,0 +1,482 @@ +package gocql + +import ( + "context" + crand "crypto/rand" + "errors" + "fmt" + "math/rand" + "net" + "os" + "regexp" + "strconv" + "sync" + "sync/atomic" + "time" +) + +var ( + randr *rand.Rand + mutRandr sync.Mutex +) + +func init() { + b := make([]byte, 4) + if _, err := crand.Read(b); err != nil { + panic(fmt.Sprintf("unable to seed random number generator: %v", err)) + } + + randr = rand.New(rand.NewSource(int64(readInt(b)))) +} + +// Ensure that the atomic variable is aligned to a 64bit boundary +// so that atomic operations can be applied on 32bit architectures. +type controlConn struct { + started int32 + reconnecting int32 + + session *Session + conn atomic.Value + + retry RetryPolicy + + quit chan struct{} +} + +func createControlConn(session *Session) *controlConn { + control := &controlConn{ + session: session, + quit: make(chan struct{}), + retry: &SimpleRetryPolicy{NumRetries: 3}, + } + + control.conn.Store((*connHost)(nil)) + + return control +} + +func (c *controlConn) heartBeat() { + if !atomic.CompareAndSwapInt32(&c.started, 0, 1) { + return + } + + sleepTime := 1 * time.Second + timer := time.NewTimer(sleepTime) + defer timer.Stop() + + for { + timer.Reset(sleepTime) + + select { + case <-c.quit: + return + case <-timer.C: + } + + resp, err := c.writeFrame(&writeOptionsFrame{}) + if err != nil { + goto reconn + } + + switch resp.(type) { + case *supportedFrame: + // Everything ok + sleepTime = 5 * time.Second + continue + case error: + goto reconn + default: + panic(fmt.Sprintf("gocql: unknown frame in response to options: %T", resp)) + } + + reconn: + // try to connect a bit faster + sleepTime = 1 * time.Second + c.reconnect(true) + continue + } +} + +var hostLookupPreferV4 = os.Getenv("GOCQL_HOST_LOOKUP_PREFER_V4") == "true" + +func hostInfo(addr string, defaultPort int) ([]*HostInfo, error) { + var port int + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + host = addr + port = defaultPort + } else { + port, err = strconv.Atoi(portStr) + if err != nil { + return nil, err + } + } + + var hosts []*HostInfo + + // Check if host is a literal IP address + if ip := net.ParseIP(host); ip != nil { + hosts = append(hosts, &HostInfo{connectAddress: ip, port: port}) + return hosts, nil + } + + // Look up host in DNS + ips, err := net.LookupIP(host) + if err != nil { + return nil, err + } else if len(ips) == 0 { + return nil, fmt.Errorf("No IP's returned from DNS lookup for %q", addr) + } + + // Filter to v4 addresses if any present + if hostLookupPreferV4 { + var preferredIPs []net.IP + for _, v := range ips { + if v4 := v.To4(); v4 != nil { + preferredIPs = append(preferredIPs, v4) + } + } + if len(preferredIPs) != 0 { + ips = preferredIPs + } + } + + for _, ip := range ips { + hosts = append(hosts, &HostInfo{connectAddress: ip, port: port}) + } + + return hosts, nil +} + +func shuffleHosts(hosts []*HostInfo) []*HostInfo { + mutRandr.Lock() + perm := randr.Perm(len(hosts)) + mutRandr.Unlock() + shuffled := make([]*HostInfo, len(hosts)) + + for i, host := range hosts { + shuffled[perm[i]] = host + } + + return shuffled +} + +func (c *controlConn) shuffleDial(endpoints []*HostInfo) (*Conn, error) { + // shuffle endpoints so not all drivers will connect to the same initial + // node. + shuffled := shuffleHosts(endpoints) + + var err error + for _, host := range shuffled { + var conn *Conn + conn, err = c.session.connect(host, c) + if err == nil { + return conn, nil + } + + Logger.Printf("gocql: unable to dial control conn %v: %v\n", host.ConnectAddress(), err) + } + + return nil, err +} + +// this is going to be version dependant and a nightmare to maintain :( +var protocolSupportRe = regexp.MustCompile(`the lowest supported version is \d+ and the greatest is (\d+)$`) + +func parseProtocolFromError(err error) int { + // I really wish this had the actual info in the error frame... + matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1) + if len(matches) != 1 || len(matches[0]) != 2 { + if verr, ok := err.(*protocolError); ok { + return int(verr.frame.Header().version.version()) + } + return 0 + } + + max, err := strconv.Atoi(matches[0][1]) + if err != nil { + return 0 + } + + return max +} + +func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) { + hosts = shuffleHosts(hosts) + + connCfg := *c.session.connCfg + connCfg.ProtoVersion = 4 // TODO: define maxProtocol + + handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) { + // we should never get here, but if we do it means we connected to a + // host successfully which means our attempted protocol version worked + if !closed { + c.Close() + } + }) + + var err error + for _, host := range hosts { + var conn *Conn + conn, err = c.session.dial(host, &connCfg, handler) + if conn != nil { + conn.Close() + } + + if err == nil { + return connCfg.ProtoVersion, nil + } + + if proto := parseProtocolFromError(err); proto > 0 { + return proto, nil + } + } + + return 0, err +} + +func (c *controlConn) connect(hosts []*HostInfo) error { + if len(hosts) == 0 { + return errors.New("control: no endpoints specified") + } + + conn, err := c.shuffleDial(hosts) + if err != nil { + return fmt.Errorf("control: unable to connect to initial hosts: %v", err) + } + + if err := c.setupConn(conn); err != nil { + conn.Close() + return fmt.Errorf("control: unable to setup connection: %v", err) + } + + // we could fetch the initial ring here and update initial host data. So that + // when we return from here we have a ring topology ready to go. + + go c.heartBeat() + + return nil +} + +type connHost struct { + conn *Conn + host *HostInfo +} + +func (c *controlConn) setupConn(conn *Conn) error { + if err := c.registerEvents(conn); err != nil { + conn.Close() + return err + } + + // TODO(zariel): do we need to fetch host info everytime + // the control conn connects? Surely we have it cached? + host, err := conn.localHostInfo() + if err != nil { + return err + } + + ch := &connHost{ + conn: conn, + host: host, + } + + c.conn.Store(ch) + c.session.handleNodeUp(host.ConnectAddress(), host.Port(), false) + + return nil +} + +func (c *controlConn) registerEvents(conn *Conn) error { + var events []string + + if !c.session.cfg.Events.DisableTopologyEvents { + events = append(events, "TOPOLOGY_CHANGE") + } + if !c.session.cfg.Events.DisableNodeStatusEvents { + events = append(events, "STATUS_CHANGE") + } + if !c.session.cfg.Events.DisableSchemaEvents { + events = append(events, "SCHEMA_CHANGE") + } + + if len(events) == 0 { + return nil + } + + framer, err := conn.exec(context.Background(), + &writeRegisterFrame{ + events: events, + }, nil) + if err != nil { + return err + } + + frame, err := framer.parseFrame() + if err != nil { + return err + } else if _, ok := frame.(*readyFrame); !ok { + return fmt.Errorf("unexpected frame in response to register: got %T: %v\n", frame, frame) + } + + return nil +} + +func (c *controlConn) reconnect(refreshring bool) { + if !atomic.CompareAndSwapInt32(&c.reconnecting, 0, 1) { + return + } + defer atomic.StoreInt32(&c.reconnecting, 0) + // TODO: simplify this function, use session.ring to get hosts instead of the + // connection pool + + var host *HostInfo + ch := c.getConn() + if ch != nil { + host = ch.host + ch.conn.Close() + } + + var newConn *Conn + if host != nil { + // try to connect to the old host + conn, err := c.session.connect(host, c) + if err != nil { + // host is dead + // TODO: this is replicated in a few places + if c.session.cfg.ConvictionPolicy.AddFailure(err, host) { + c.session.handleNodeDown(host.ConnectAddress(), host.Port()) + } + } else { + newConn = conn + } + } + + // TODO: should have our own round-robin for hosts so that we can try each + // in succession and guarantee that we get a different host each time. + if newConn == nil { + host := c.session.ring.rrHost() + if host == nil { + c.connect(c.session.ring.endpoints) + return + } + + var err error + newConn, err = c.session.connect(host, c) + if err != nil { + // TODO: add log handler for things like this + return + } + } + + if err := c.setupConn(newConn); err != nil { + newConn.Close() + Logger.Printf("gocql: control unable to register events: %v\n", err) + return + } + + if refreshring { + c.session.hostSource.refreshRing() + } +} + +func (c *controlConn) HandleError(conn *Conn, err error, closed bool) { + if !closed { + return + } + + oldConn := c.getConn() + if oldConn.conn != conn { + return + } + + c.reconnect(false) +} + +func (c *controlConn) getConn() *connHost { + return c.conn.Load().(*connHost) +} + +func (c *controlConn) writeFrame(w frameWriter) (frame, error) { + ch := c.getConn() + if ch == nil { + return nil, errNoControl + } + + framer, err := ch.conn.exec(context.Background(), w, nil) + if err != nil { + return nil, err + } + + return framer.parseFrame() +} + +func (c *controlConn) withConnHost(fn func(*connHost) *Iter) *Iter { + const maxConnectAttempts = 5 + connectAttempts := 0 + + for i := 0; i < maxConnectAttempts; i++ { + ch := c.getConn() + if ch == nil { + if connectAttempts > maxConnectAttempts { + break + } + + connectAttempts++ + + c.reconnect(false) + continue + } + + return fn(ch) + } + + return &Iter{err: errNoControl} +} + +func (c *controlConn) withConn(fn func(*Conn) *Iter) *Iter { + return c.withConnHost(func(ch *connHost) *Iter { + return fn(ch.conn) + }) +} + +// query will return nil if the connection is closed or nil +func (c *controlConn) query(statement string, values ...interface{}) (iter *Iter) { + q := c.session.Query(statement, values...).Consistency(One).RoutingKey([]byte{}).Trace(nil) + + for { + iter = c.withConn(func(conn *Conn) *Iter { + return conn.executeQuery(q) + }) + + if gocqlDebug && iter.err != nil { + Logger.Printf("control: error executing %q: %v\n", statement, iter.err) + } + + q.attempts++ + if iter.err == nil || !c.retry.Attempt(q) { + break + } + } + + return +} + +func (c *controlConn) awaitSchemaAgreement() error { + return c.withConn(func(conn *Conn) *Iter { + return &Iter{err: conn.awaitSchemaAgreement()} + }).err +} + +func (c *controlConn) close() { + if atomic.CompareAndSwapInt32(&c.started, 1, -1) { + c.quit <- struct{}{} + } + + ch := c.getConn() + if ch != nil { + ch.conn.Close() + } +} + +var errNoControl = errors.New("gocql: no control connection available") diff --git a/vendor/github.com/gocql/gocql/debug_off.go b/vendor/github.com/gocql/gocql/debug_off.go new file mode 100644 index 0000000..3af3ae0 --- /dev/null +++ b/vendor/github.com/gocql/gocql/debug_off.go @@ -0,0 +1,5 @@ +// +build !gocql_debug + +package gocql + +const gocqlDebug = false diff --git a/vendor/github.com/gocql/gocql/debug_on.go b/vendor/github.com/gocql/gocql/debug_on.go new file mode 100644 index 0000000..e94a00c --- /dev/null +++ b/vendor/github.com/gocql/gocql/debug_on.go @@ -0,0 +1,5 @@ +// +build gocql_debug + +package gocql + +const gocqlDebug = true diff --git a/vendor/github.com/gocql/gocql/doc.go b/vendor/github.com/gocql/gocql/doc.go new file mode 100644 index 0000000..5c4b041 --- /dev/null +++ b/vendor/github.com/gocql/gocql/doc.go @@ -0,0 +1,9 @@ +// Copyright (c) 2012-2015 The gocql 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 gocql implements a fast and robust Cassandra driver for the +// Go programming language. +package gocql // import "github.com/gocql/gocql" + +// TODO(tux21b): write more docs. diff --git a/vendor/github.com/gocql/gocql/errors.go b/vendor/github.com/gocql/gocql/errors.go new file mode 100644 index 0000000..b87c6fa --- /dev/null +++ b/vendor/github.com/gocql/gocql/errors.go @@ -0,0 +1,116 @@ +package gocql + +import "fmt" + +const ( + errServer = 0x0000 + errProtocol = 0x000A + errCredentials = 0x0100 + errUnavailable = 0x1000 + errOverloaded = 0x1001 + errBootstrapping = 0x1002 + errTruncate = 0x1003 + errWriteTimeout = 0x1100 + errReadTimeout = 0x1200 + errReadFailure = 0x1300 + errFunctionFailure = 0x1400 + errWriteFailure = 0x1500 + errSyntax = 0x2000 + errUnauthorized = 0x2100 + errInvalid = 0x2200 + errConfig = 0x2300 + errAlreadyExists = 0x2400 + errUnprepared = 0x2500 +) + +type RequestError interface { + Code() int + Message() string + Error() string +} + +type errorFrame struct { + frameHeader + + code int + message string +} + +func (e errorFrame) Code() int { + return e.code +} + +func (e errorFrame) Message() string { + return e.message +} + +func (e errorFrame) Error() string { + return e.Message() +} + +func (e errorFrame) String() string { + return fmt.Sprintf("[error code=%x message=%q]", e.code, e.message) +} + +type RequestErrUnavailable struct { + errorFrame + Consistency Consistency + Required int + Alive int +} + +func (e *RequestErrUnavailable) String() string { + return fmt.Sprintf("[request_error_unavailable consistency=%s required=%d alive=%d]", e.Consistency, e.Required, e.Alive) +} + +type RequestErrWriteTimeout struct { + errorFrame + Consistency Consistency + Received int + BlockFor int + WriteType string +} + +type RequestErrWriteFailure struct { + errorFrame + Consistency Consistency + Received int + BlockFor int + NumFailures int + WriteType string +} + +type RequestErrReadTimeout struct { + errorFrame + Consistency Consistency + Received int + BlockFor int + DataPresent byte +} + +type RequestErrAlreadyExists struct { + errorFrame + Keyspace string + Table string +} + +type RequestErrUnprepared struct { + errorFrame + StatementId []byte +} + +type RequestErrReadFailure struct { + errorFrame + Consistency Consistency + Received int + BlockFor int + NumFailures int + DataPresent bool +} + +type RequestErrFunctionFailure struct { + errorFrame + Keyspace string + Function string + ArgTypes []string +} diff --git a/vendor/github.com/gocql/gocql/events.go b/vendor/github.com/gocql/gocql/events.go new file mode 100644 index 0000000..f7f727b --- /dev/null +++ b/vendor/github.com/gocql/gocql/events.go @@ -0,0 +1,293 @@ +package gocql + +import ( + "net" + "sync" + "time" +) + +type eventDebouncer struct { + name string + timer *time.Timer + mu sync.Mutex + events []frame + + callback func([]frame) + quit chan struct{} +} + +func newEventDebouncer(name string, eventHandler func([]frame)) *eventDebouncer { + e := &eventDebouncer{ + name: name, + quit: make(chan struct{}), + timer: time.NewTimer(eventDebounceTime), + callback: eventHandler, + } + e.timer.Stop() + go e.flusher() + + return e +} + +func (e *eventDebouncer) stop() { + e.quit <- struct{}{} // sync with flusher + close(e.quit) +} + +func (e *eventDebouncer) flusher() { + for { + select { + case <-e.timer.C: + e.mu.Lock() + e.flush() + e.mu.Unlock() + case <-e.quit: + return + } + } +} + +const ( + eventBufferSize = 1000 + eventDebounceTime = 1 * time.Second +) + +// flush must be called with mu locked +func (e *eventDebouncer) flush() { + if len(e.events) == 0 { + return + } + + // if the flush interval is faster than the callback then we will end up calling + // the callback multiple times, probably a bad idea. In this case we could drop + // frames? + go e.callback(e.events) + e.events = make([]frame, 0, eventBufferSize) +} + +func (e *eventDebouncer) debounce(frame frame) { + e.mu.Lock() + e.timer.Reset(eventDebounceTime) + + // TODO: probably need a warning to track if this threshold is too low + if len(e.events) < eventBufferSize { + e.events = append(e.events, frame) + } else { + Logger.Printf("%s: buffer full, dropping event frame: %s", e.name, frame) + } + + e.mu.Unlock() +} + +func (s *Session) handleEvent(framer *framer) { + frame, err := framer.parseFrame() + if err != nil { + // TODO: logger + Logger.Printf("gocql: unable to parse event frame: %v\n", err) + return + } + + if gocqlDebug { + Logger.Printf("gocql: handling frame: %v\n", frame) + } + + switch f := frame.(type) { + case *schemaChangeKeyspace, *schemaChangeFunction, + *schemaChangeTable, *schemaChangeAggregate, *schemaChangeType: + + s.schemaEvents.debounce(frame) + case *topologyChangeEventFrame, *statusChangeEventFrame: + s.nodeEvents.debounce(frame) + default: + Logger.Printf("gocql: invalid event frame (%T): %v\n", f, f) + } +} + +func (s *Session) handleSchemaEvent(frames []frame) { + // TODO: debounce events + for _, frame := range frames { + switch f := frame.(type) { + case *schemaChangeKeyspace: + s.schemaDescriber.clearSchema(f.keyspace) + s.handleKeyspaceChange(f.keyspace, f.change) + case *schemaChangeTable: + s.schemaDescriber.clearSchema(f.keyspace) + case *schemaChangeAggregate: + s.schemaDescriber.clearSchema(f.keyspace) + case *schemaChangeFunction: + s.schemaDescriber.clearSchema(f.keyspace) + case *schemaChangeType: + s.schemaDescriber.clearSchema(f.keyspace) + } + } +} + +func (s *Session) handleKeyspaceChange(keyspace, change string) { + s.control.awaitSchemaAgreement() + s.policy.KeyspaceChanged(KeyspaceUpdateEvent{Keyspace: keyspace, Change: change}) +} + +func (s *Session) handleNodeEvent(frames []frame) { + type nodeEvent struct { + change string + host net.IP + port int + } + + events := make(map[string]*nodeEvent) + + for _, frame := range frames { + // TODO: can we be sure the order of events in the buffer is correct? + switch f := frame.(type) { + case *topologyChangeEventFrame: + event, ok := events[f.host.String()] + if !ok { + event = &nodeEvent{change: f.change, host: f.host, port: f.port} + events[f.host.String()] = event + } + event.change = f.change + + case *statusChangeEventFrame: + event, ok := events[f.host.String()] + if !ok { + event = &nodeEvent{change: f.change, host: f.host, port: f.port} + events[f.host.String()] = event + } + event.change = f.change + } + } + + for _, f := range events { + if gocqlDebug { + Logger.Printf("gocql: dispatching event: %+v\n", f) + } + + switch f.change { + case "NEW_NODE": + s.handleNewNode(f.host, f.port, true) + case "REMOVED_NODE": + s.handleRemovedNode(f.host, f.port) + case "MOVED_NODE": + // java-driver handles this, not mentioned in the spec + // TODO(zariel): refresh token map + case "UP": + s.handleNodeUp(f.host, f.port, true) + case "DOWN": + s.handleNodeDown(f.host, f.port) + } + } +} + +func (s *Session) addNewNode(host *HostInfo) { + if s.cfg.filterHost(host) { + return + } + + host.setState(NodeUp) + s.pool.addHost(host) + s.policy.AddHost(host) +} + +func (s *Session) handleNewNode(ip net.IP, port int, waitForBinary bool) { + if gocqlDebug { + Logger.Printf("gocql: Session.handleNewNode: %s:%d\n", ip.String(), port) + } + + ip, port = s.cfg.translateAddressPort(ip, port) + + // Get host info and apply any filters to the host + hostInfo, err := s.hostSource.getHostInfo(ip, port) + if err != nil { + Logger.Printf("gocql: events: unable to fetch host info for (%s:%d): %v\n", ip, port, err) + return + } else if hostInfo == nil { + // If hostInfo is nil, this host was filtered out by cfg.HostFilter + return + } + + if t := hostInfo.Version().nodeUpDelay(); t > 0 && waitForBinary { + time.Sleep(t) + } + + // should this handle token moving? + hostInfo = s.ring.addOrUpdate(hostInfo) + + s.addNewNode(hostInfo) + + if s.control != nil && !s.cfg.IgnorePeerAddr { + // TODO(zariel): debounce ring refresh + s.hostSource.refreshRing() + } +} + +func (s *Session) handleRemovedNode(ip net.IP, port int) { + if gocqlDebug { + Logger.Printf("gocql: Session.handleRemovedNode: %s:%d\n", ip.String(), port) + } + + ip, port = s.cfg.translateAddressPort(ip, port) + + // we remove all nodes but only add ones which pass the filter + host := s.ring.getHost(ip) + if host == nil { + host = &HostInfo{connectAddress: ip, port: port} + } + + if s.cfg.HostFilter != nil && !s.cfg.HostFilter.Accept(host) { + return + } + + host.setState(NodeDown) + s.policy.RemoveHost(host) + s.pool.removeHost(ip) + s.ring.removeHost(ip) + + if !s.cfg.IgnorePeerAddr { + s.hostSource.refreshRing() + } +} + +func (s *Session) handleNodeUp(eventIp net.IP, eventPort int, waitForBinary bool) { + if gocqlDebug { + Logger.Printf("gocql: Session.handleNodeUp: %s:%d\n", eventIp.String(), eventPort) + } + + ip, _ := s.cfg.translateAddressPort(eventIp, eventPort) + + host := s.ring.getHost(ip) + if host == nil { + // TODO(zariel): avoid the need to translate twice in this + // case + s.handleNewNode(eventIp, eventPort, waitForBinary) + return + } + + if s.cfg.HostFilter != nil && !s.cfg.HostFilter.Accept(host) { + return + } + + if t := host.Version().nodeUpDelay(); t > 0 && waitForBinary { + time.Sleep(t) + } + + s.addNewNode(host) +} + +func (s *Session) handleNodeDown(ip net.IP, port int) { + if gocqlDebug { + Logger.Printf("gocql: Session.handleNodeDown: %s:%d\n", ip.String(), port) + } + + host := s.ring.getHost(ip) + if host == nil { + host = &HostInfo{connectAddress: ip, port: port} + } + + if s.cfg.HostFilter != nil && !s.cfg.HostFilter.Accept(host) { + return + } + + host.setState(NodeDown) + s.policy.HostDown(host) + s.pool.hostDown(ip) +} diff --git a/vendor/github.com/gocql/gocql/filters.go b/vendor/github.com/gocql/gocql/filters.go new file mode 100644 index 0000000..32e6ce6 --- /dev/null +++ b/vendor/github.com/gocql/gocql/filters.go @@ -0,0 +1,57 @@ +package gocql + +import "fmt" + +// HostFilter interface is used when a host is discovered via server sent events. +type HostFilter interface { + // Called when a new host is discovered, returning true will cause the host + // to be added to the pools. + Accept(host *HostInfo) bool +} + +// HostFilterFunc converts a func(host HostInfo) bool into a HostFilter +type HostFilterFunc func(host *HostInfo) bool + +func (fn HostFilterFunc) Accept(host *HostInfo) bool { + return fn(host) +} + +// AcceptAllFilter will accept all hosts +func AcceptAllFilter() HostFilter { + return HostFilterFunc(func(host *HostInfo) bool { + return true + }) +} + +func DenyAllFilter() HostFilter { + return HostFilterFunc(func(host *HostInfo) bool { + return false + }) +} + +// DataCentreHostFilter filters all hosts such that they are in the same data centre +// as the supplied data centre. +func DataCentreHostFilter(dataCentre string) HostFilter { + return HostFilterFunc(func(host *HostInfo) bool { + return host.DataCenter() == dataCentre + }) +} + +// WhiteListHostFilter filters incoming hosts by checking that their address is +// in the initial hosts whitelist. +func WhiteListHostFilter(hosts ...string) HostFilter { + hostInfos, err := addrsToHosts(hosts, 9042) + if err != nil { + // dont want to panic here, but rather not break the API + panic(fmt.Errorf("unable to lookup host info from address: %v", err)) + } + + m := make(map[string]bool, len(hostInfos)) + for _, host := range hostInfos { + m[host.ConnectAddress().String()] = true + } + + return HostFilterFunc(func(host *HostInfo) bool { + return m[host.ConnectAddress().String()] + }) +} diff --git a/vendor/github.com/gocql/gocql/frame.go b/vendor/github.com/gocql/gocql/frame.go new file mode 100644 index 0000000..b09ba8d --- /dev/null +++ b/vendor/github.com/gocql/gocql/frame.go @@ -0,0 +1,1957 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "context" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "runtime" + "strings" + "time" +) + +type unsetColumn struct{} + +// UnsetValue represents a value used in a query binding that will be ignored by Cassandra. +// +// By setting a field to the unset value Cassandra will ignore the write completely. +// The main advantage is the ability to keep the same prepared statement even when you don't +// want to update some fields, where before you needed to make another prepared statement. +// +// UnsetValue is only available when using the version 4 of the protocol. +var UnsetValue = unsetColumn{} + +type namedValue struct { + name string + value interface{} +} + +// NamedValue produce a value which will bind to the named parameter in a query +func NamedValue(name string, value interface{}) interface{} { + return &namedValue{ + name: name, + value: value, + } +} + +const ( + protoDirectionMask = 0x80 + protoVersionMask = 0x7F + protoVersion1 = 0x01 + protoVersion2 = 0x02 + protoVersion3 = 0x03 + protoVersion4 = 0x04 + protoVersion5 = 0x05 + + maxFrameSize = 256 * 1024 * 1024 +) + +type protoVersion byte + +func (p protoVersion) request() bool { + return p&protoDirectionMask == 0x00 +} + +func (p protoVersion) response() bool { + return p&protoDirectionMask == 0x80 +} + +func (p protoVersion) version() byte { + return byte(p) & protoVersionMask +} + +func (p protoVersion) String() string { + dir := "REQ" + if p.response() { + dir = "RESP" + } + + return fmt.Sprintf("[version=%d direction=%s]", p.version(), dir) +} + +type frameOp byte + +const ( + // header ops + opError frameOp = 0x00 + opStartup frameOp = 0x01 + opReady frameOp = 0x02 + opAuthenticate frameOp = 0x03 + opOptions frameOp = 0x05 + opSupported frameOp = 0x06 + opQuery frameOp = 0x07 + opResult frameOp = 0x08 + opPrepare frameOp = 0x09 + opExecute frameOp = 0x0A + opRegister frameOp = 0x0B + opEvent frameOp = 0x0C + opBatch frameOp = 0x0D + opAuthChallenge frameOp = 0x0E + opAuthResponse frameOp = 0x0F + opAuthSuccess frameOp = 0x10 +) + +func (f frameOp) String() string { + switch f { + case opError: + return "ERROR" + case opStartup: + return "STARTUP" + case opReady: + return "READY" + case opAuthenticate: + return "AUTHENTICATE" + case opOptions: + return "OPTIONS" + case opSupported: + return "SUPPORTED" + case opQuery: + return "QUERY" + case opResult: + return "RESULT" + case opPrepare: + return "PREPARE" + case opExecute: + return "EXECUTE" + case opRegister: + return "REGISTER" + case opEvent: + return "EVENT" + case opBatch: + return "BATCH" + case opAuthChallenge: + return "AUTH_CHALLENGE" + case opAuthResponse: + return "AUTH_RESPONSE" + case opAuthSuccess: + return "AUTH_SUCCESS" + default: + return fmt.Sprintf("UNKNOWN_OP_%d", f) + } +} + +const ( + // result kind + resultKindVoid = 1 + resultKindRows = 2 + resultKindKeyspace = 3 + resultKindPrepared = 4 + resultKindSchemaChanged = 5 + + // rows flags + flagGlobalTableSpec int = 0x01 + flagHasMorePages int = 0x02 + flagNoMetaData int = 0x04 + + // query flags + flagValues byte = 0x01 + flagSkipMetaData byte = 0x02 + flagPageSize byte = 0x04 + flagWithPagingState byte = 0x08 + flagWithSerialConsistency byte = 0x10 + flagDefaultTimestamp byte = 0x20 + flagWithNameValues byte = 0x40 + + // header flags + flagCompress byte = 0x01 + flagTracing byte = 0x02 + flagCustomPayload byte = 0x04 + flagWarning byte = 0x08 +) + +type Consistency uint16 + +const ( + Any Consistency = 0x00 + One Consistency = 0x01 + Two Consistency = 0x02 + Three Consistency = 0x03 + Quorum Consistency = 0x04 + All Consistency = 0x05 + LocalQuorum Consistency = 0x06 + EachQuorum Consistency = 0x07 + LocalOne Consistency = 0x0A +) + +func (c Consistency) String() string { + switch c { + case Any: + return "ANY" + case One: + return "ONE" + case Two: + return "TWO" + case Three: + return "THREE" + case Quorum: + return "QUORUM" + case All: + return "ALL" + case LocalQuorum: + return "LOCAL_QUORUM" + case EachQuorum: + return "EACH_QUORUM" + case LocalOne: + return "LOCAL_ONE" + default: + return fmt.Sprintf("UNKNOWN_CONS_0x%x", uint16(c)) + } +} + +func (c Consistency) MarshalText() (text []byte, err error) { + return []byte(c.String()), nil +} + +func (c *Consistency) UnmarshalText(text []byte) error { + switch string(text) { + case "ANY": + *c = Any + case "ONE": + *c = One + case "TWO": + *c = Two + case "THREE": + *c = Three + case "QUORUM": + *c = Quorum + case "ALL": + *c = All + case "LOCAL_QUORUM": + *c = LocalQuorum + case "EACH_QUORUM": + *c = EachQuorum + case "LOCAL_ONE": + *c = LocalOne + default: + return fmt.Errorf("invalid consistency %q", string(text)) + } + + return nil +} + +func ParseConsistency(s string) Consistency { + var c Consistency + if err := c.UnmarshalText([]byte(strings.ToUpper(s))); err != nil { + panic(err) + } + return c +} + +// ParseConsistencyWrapper wraps gocql.ParseConsistency to provide an err +// return instead of a panic +func ParseConsistencyWrapper(s string) (consistency Consistency, err error) { + err = consistency.UnmarshalText([]byte(strings.ToUpper(s))) + return +} + +// MustParseConsistency is the same as ParseConsistency except it returns +// an error (never). It is kept here since breaking changes are not good. +// DEPRECATED: use ParseConsistency if you want a panic on parse error. +func MustParseConsistency(s string) (Consistency, error) { + c, err := ParseConsistencyWrapper(s) + if err != nil { + panic(err) + } + return c, nil +} + +type SerialConsistency uint16 + +const ( + Serial SerialConsistency = 0x08 + LocalSerial SerialConsistency = 0x09 +) + +func (s SerialConsistency) String() string { + switch s { + case Serial: + return "SERIAL" + case LocalSerial: + return "LOCAL_SERIAL" + default: + return fmt.Sprintf("UNKNOWN_SERIAL_CONS_0x%x", uint16(s)) + } +} + +func (s SerialConsistency) MarshalText() (text []byte, err error) { + return []byte(s.String()), nil +} + +func (s *SerialConsistency) UnmarshalText(text []byte) error { + switch string(text) { + case "SERIAL": + *s = Serial + case "LOCAL_SERIAL": + *s = LocalSerial + default: + return fmt.Errorf("invalid consistency %q", string(text)) + } + + return nil +} + +const ( + apacheCassandraTypePrefix = "org.apache.cassandra.db.marshal." +) + +var ( + ErrFrameTooBig = errors.New("frame length is bigger than the maximum allowed") +) + +const maxFrameHeaderSize = 9 + +func writeInt(p []byte, n int32) { + p[0] = byte(n >> 24) + p[1] = byte(n >> 16) + p[2] = byte(n >> 8) + p[3] = byte(n) +} + +func readInt(p []byte) int32 { + return int32(p[0])<<24 | int32(p[1])<<16 | int32(p[2])<<8 | int32(p[3]) +} + +func writeShort(p []byte, n uint16) { + p[0] = byte(n >> 8) + p[1] = byte(n) +} + +func readShort(p []byte) uint16 { + return uint16(p[0])<<8 | uint16(p[1]) +} + +type frameHeader struct { + version protoVersion + flags byte + stream int + op frameOp + length int + customPayload map[string][]byte + warnings []string +} + +func (f frameHeader) String() string { + return fmt.Sprintf("[header version=%s flags=0x%x stream=%d op=%s length=%d]", f.version, f.flags, f.stream, f.op, f.length) +} + +func (f frameHeader) Header() frameHeader { + return f +} + +const defaultBufSize = 128 + +type ObservedFrameHeader struct { + Version byte + Flags byte + Stream int16 + Opcode byte + Length int32 + + // StartHeader is the time we started reading the frame header off the network connection. + Start time.Time + // EndHeader is the time we finished reading the frame header off the network connection. + End time.Time +} + +// FrameHeaderObserver is the interface implemented by frame observers / stat collectors. +// +// Experimental, this interface and use may change +type FrameHeaderObserver interface { + // ObserveFrameHeader gets called on every received frame header. + ObserveFrameHeader(context.Context, ObservedFrameHeader) +} + +// a framer is responsible for reading, writing and parsing frames on a single stream +type framer struct { + r io.Reader + w io.Writer + + proto byte + // flags are for outgoing flags, enabling compression and tracing etc + flags byte + compres Compressor + headSize int + // if this frame was read then the header will be here + header *frameHeader + + // if tracing flag is set this is not nil + traceID []byte + + // holds a ref to the whole byte slice for rbuf so that it can be reset to + // 0 after a read. + readBuffer []byte + + rbuf []byte + wbuf []byte +} + +func newFramer(r io.Reader, w io.Writer, compressor Compressor, version byte) *framer { + f := &framer{ + wbuf: make([]byte, defaultBufSize), + readBuffer: make([]byte, defaultBufSize), + } + var flags byte + if compressor != nil { + flags |= flagCompress + } + + version &= protoVersionMask + + headSize := 8 + if version > protoVersion2 { + headSize = 9 + } + + f.compres = compressor + f.proto = version + f.flags = flags + f.headSize = headSize + + f.r = r + f.rbuf = f.readBuffer[:0] + + f.w = w + f.wbuf = f.wbuf[:0] + + f.header = nil + f.traceID = nil + + return f +} + +type frame interface { + Header() frameHeader +} + +func readHeader(r io.Reader, p []byte) (head frameHeader, err error) { + _, err = io.ReadFull(r, p[:1]) + if err != nil { + return frameHeader{}, err + } + + version := p[0] & protoVersionMask + + if version < protoVersion1 || version > protoVersion4 { + return frameHeader{}, fmt.Errorf("gocql: unsupported protocol response version: %d", version) + } + + headSize := 9 + if version < protoVersion3 { + headSize = 8 + } + + _, err = io.ReadFull(r, p[1:headSize]) + if err != nil { + return frameHeader{}, err + } + + p = p[:headSize] + + head.version = protoVersion(p[0]) + head.flags = p[1] + + if version > protoVersion2 { + if len(p) != 9 { + return frameHeader{}, fmt.Errorf("not enough bytes to read header require 9 got: %d", len(p)) + } + + head.stream = int(int16(p[2])<<8 | int16(p[3])) + head.op = frameOp(p[4]) + head.length = int(readInt(p[5:])) + } else { + if len(p) != 8 { + return frameHeader{}, fmt.Errorf("not enough bytes to read header require 8 got: %d", len(p)) + } + + head.stream = int(int8(p[2])) + head.op = frameOp(p[3]) + head.length = int(readInt(p[4:])) + } + + return head, nil +} + +// explicitly enables tracing for the framers outgoing requests +func (f *framer) trace() { + f.flags |= flagTracing +} + +// reads a frame form the wire into the framers buffer +func (f *framer) readFrame(head *frameHeader) error { + if head.length < 0 { + return fmt.Errorf("frame body length can not be less than 0: %d", head.length) + } else if head.length > maxFrameSize { + // need to free up the connection to be used again + _, err := io.CopyN(ioutil.Discard, f.r, int64(head.length)) + if err != nil { + return fmt.Errorf("error whilst trying to discard frame with invalid length: %v", err) + } + return ErrFrameTooBig + } + + if cap(f.readBuffer) >= head.length { + f.rbuf = f.readBuffer[:head.length] + } else { + f.readBuffer = make([]byte, head.length) + f.rbuf = f.readBuffer + } + + // assume the underlying reader takes care of timeouts and retries + n, err := io.ReadFull(f.r, f.rbuf) + if err != nil { + return fmt.Errorf("unable to read frame body: read %d/%d bytes: %v", n, head.length, err) + } + + if head.flags&flagCompress == flagCompress { + if f.compres == nil { + return NewErrProtocol("no compressor available with compressed frame body") + } + + f.rbuf, err = f.compres.Decode(f.rbuf) + if err != nil { + return err + } + } + + f.header = head + return nil +} + +func (f *framer) parseFrame() (frame frame, err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + err = r.(error) + } + }() + + if f.header.version.request() { + return nil, NewErrProtocol("got a request frame from server: %v", f.header.version) + } + + if f.header.flags&flagTracing == flagTracing { + f.readTrace() + } + + if f.header.flags&flagWarning == flagWarning { + f.header.warnings = f.readStringList() + } + + if f.header.flags&flagCustomPayload == flagCustomPayload { + f.header.customPayload = f.readBytesMap() + } + + // assumes that the frame body has been read into rbuf + switch f.header.op { + case opError: + frame = f.parseErrorFrame() + case opReady: + frame = f.parseReadyFrame() + case opResult: + frame, err = f.parseResultFrame() + case opSupported: + frame = f.parseSupportedFrame() + case opAuthenticate: + frame = f.parseAuthenticateFrame() + case opAuthChallenge: + frame = f.parseAuthChallengeFrame() + case opAuthSuccess: + frame = f.parseAuthSuccessFrame() + case opEvent: + frame = f.parseEventFrame() + default: + return nil, NewErrProtocol("unknown op in frame header: %s", f.header.op) + } + + return +} + +func (f *framer) parseErrorFrame() frame { + code := f.readInt() + msg := f.readString() + + errD := errorFrame{ + frameHeader: *f.header, + code: code, + message: msg, + } + + switch code { + case errUnavailable: + cl := f.readConsistency() + required := f.readInt() + alive := f.readInt() + return &RequestErrUnavailable{ + errorFrame: errD, + Consistency: cl, + Required: required, + Alive: alive, + } + case errWriteTimeout: + cl := f.readConsistency() + received := f.readInt() + blockfor := f.readInt() + writeType := f.readString() + return &RequestErrWriteTimeout{ + errorFrame: errD, + Consistency: cl, + Received: received, + BlockFor: blockfor, + WriteType: writeType, + } + case errReadTimeout: + cl := f.readConsistency() + received := f.readInt() + blockfor := f.readInt() + dataPresent := f.readByte() + return &RequestErrReadTimeout{ + errorFrame: errD, + Consistency: cl, + Received: received, + BlockFor: blockfor, + DataPresent: dataPresent, + } + case errAlreadyExists: + ks := f.readString() + table := f.readString() + return &RequestErrAlreadyExists{ + errorFrame: errD, + Keyspace: ks, + Table: table, + } + case errUnprepared: + stmtId := f.readShortBytes() + return &RequestErrUnprepared{ + errorFrame: errD, + StatementId: copyBytes(stmtId), // defensively copy + } + case errReadFailure: + res := &RequestErrReadFailure{ + errorFrame: errD, + } + res.Consistency = f.readConsistency() + res.Received = f.readInt() + res.BlockFor = f.readInt() + res.DataPresent = f.readByte() != 0 + return res + case errWriteFailure: + res := &RequestErrWriteFailure{ + errorFrame: errD, + } + res.Consistency = f.readConsistency() + res.Received = f.readInt() + res.BlockFor = f.readInt() + res.NumFailures = f.readInt() + res.WriteType = f.readString() + return res + case errFunctionFailure: + res := RequestErrFunctionFailure{ + errorFrame: errD, + } + res.Keyspace = f.readString() + res.Function = f.readString() + res.ArgTypes = f.readStringList() + return res + case errInvalid, errBootstrapping, errConfig, errCredentials, errOverloaded, + errProtocol, errServer, errSyntax, errTruncate, errUnauthorized: + // TODO(zariel): we should have some distinct types for these errors + return errD + default: + panic(fmt.Errorf("unknown error code: 0x%x", errD.code)) + } +} + +func (f *framer) writeHeader(flags byte, op frameOp, stream int) { + f.wbuf = f.wbuf[:0] + f.wbuf = append(f.wbuf, + f.proto, + flags, + ) + + if f.proto > protoVersion2 { + f.wbuf = append(f.wbuf, + byte(stream>>8), + byte(stream), + ) + } else { + f.wbuf = append(f.wbuf, + byte(stream), + ) + } + + // pad out length + f.wbuf = append(f.wbuf, + byte(op), + 0, + 0, + 0, + 0, + ) +} + +func (f *framer) setLength(length int) { + p := 4 + if f.proto > protoVersion2 { + p = 5 + } + + f.wbuf[p+0] = byte(length >> 24) + f.wbuf[p+1] = byte(length >> 16) + f.wbuf[p+2] = byte(length >> 8) + f.wbuf[p+3] = byte(length) +} + +func (f *framer) finishWrite() error { + if len(f.wbuf) > maxFrameSize { + // huge app frame, lets remove it so it doesn't bloat the heap + f.wbuf = make([]byte, defaultBufSize) + return ErrFrameTooBig + } + + if f.wbuf[1]&flagCompress == flagCompress { + if f.compres == nil { + panic("compress flag set with no compressor") + } + + // TODO: only compress frames which are big enough + compressed, err := f.compres.Encode(f.wbuf[f.headSize:]) + if err != nil { + return err + } + + f.wbuf = append(f.wbuf[:f.headSize], compressed...) + } + length := len(f.wbuf) - f.headSize + f.setLength(length) + + _, err := f.w.Write(f.wbuf) + if err != nil { + return err + } + + return nil +} + +func (f *framer) readTrace() { + f.traceID = f.readUUID().Bytes() +} + +type readyFrame struct { + frameHeader +} + +func (f *framer) parseReadyFrame() frame { + return &readyFrame{ + frameHeader: *f.header, + } +} + +type supportedFrame struct { + frameHeader + + supported map[string][]string +} + +// TODO: if we move the body buffer onto the frameHeader then we only need a single +// framer, and can move the methods onto the header. +func (f *framer) parseSupportedFrame() frame { + return &supportedFrame{ + frameHeader: *f.header, + + supported: f.readStringMultiMap(), + } +} + +type writeStartupFrame struct { + opts map[string]string +} + +func (w writeStartupFrame) String() string { + return fmt.Sprintf("[startup opts=%+v]", w.opts) +} + +func (w *writeStartupFrame) writeFrame(f *framer, streamID int) error { + f.writeHeader(f.flags&^flagCompress, opStartup, streamID) + f.writeStringMap(w.opts) + + return f.finishWrite() +} + +type writePrepareFrame struct { + statement string +} + +func (w *writePrepareFrame) writeFrame(f *framer, streamID int) error { + f.writeHeader(f.flags, opPrepare, streamID) + f.writeLongString(w.statement) + return f.finishWrite() +} + +func (f *framer) readTypeInfo() TypeInfo { + // TODO: factor this out so the same code paths can be used to parse custom + // types and other types, as much of the logic will be duplicated. + id := f.readShort() + + simple := NativeType{ + proto: f.proto, + typ: Type(id), + } + + if simple.typ == TypeCustom { + simple.custom = f.readString() + if cassType := getApacheCassandraType(simple.custom); cassType != TypeCustom { + simple.typ = cassType + } + } + + switch simple.typ { + case TypeTuple: + n := f.readShort() + tuple := TupleTypeInfo{ + NativeType: simple, + Elems: make([]TypeInfo, n), + } + + for i := 0; i < int(n); i++ { + tuple.Elems[i] = f.readTypeInfo() + } + + return tuple + + case TypeUDT: + udt := UDTTypeInfo{ + NativeType: simple, + } + udt.KeySpace = f.readString() + udt.Name = f.readString() + + n := f.readShort() + udt.Elements = make([]UDTField, n) + for i := 0; i < int(n); i++ { + field := &udt.Elements[i] + field.Name = f.readString() + field.Type = f.readTypeInfo() + } + + return udt + case TypeMap, TypeList, TypeSet: + collection := CollectionType{ + NativeType: simple, + } + + if simple.typ == TypeMap { + collection.Key = f.readTypeInfo() + } + + collection.Elem = f.readTypeInfo() + + return collection + } + + return simple +} + +type preparedMetadata struct { + resultMetadata + + // proto v4+ + pkeyColumns []int +} + +func (r preparedMetadata) String() string { + return fmt.Sprintf("[prepared flags=0x%x pkey=%v paging_state=% X columns=%v col_count=%d actual_col_count=%d]", r.flags, r.pkeyColumns, r.pagingState, r.columns, r.colCount, r.actualColCount) +} + +func (f *framer) parsePreparedMetadata() preparedMetadata { + // TODO: deduplicate this from parseMetadata + meta := preparedMetadata{} + + meta.flags = f.readInt() + meta.colCount = f.readInt() + if meta.colCount < 0 { + panic(fmt.Errorf("received negative column count: %d", meta.colCount)) + } + meta.actualColCount = meta.colCount + + if f.proto >= protoVersion4 { + pkeyCount := f.readInt() + pkeys := make([]int, pkeyCount) + for i := 0; i < pkeyCount; i++ { + pkeys[i] = int(f.readShort()) + } + meta.pkeyColumns = pkeys + } + + if meta.flags&flagHasMorePages == flagHasMorePages { + meta.pagingState = copyBytes(f.readBytes()) + } + + if meta.flags&flagNoMetaData == flagNoMetaData { + return meta + } + + var keyspace, table string + globalSpec := meta.flags&flagGlobalTableSpec == flagGlobalTableSpec + if globalSpec { + keyspace = f.readString() + table = f.readString() + } + + var cols []ColumnInfo + if meta.colCount < 1000 { + // preallocate columninfo to avoid excess copying + cols = make([]ColumnInfo, meta.colCount) + for i := 0; i < meta.colCount; i++ { + f.readCol(&cols[i], &meta.resultMetadata, globalSpec, keyspace, table) + } + } else { + // use append, huge number of columns usually indicates a corrupt frame or + // just a huge row. + for i := 0; i < meta.colCount; i++ { + var col ColumnInfo + f.readCol(&col, &meta.resultMetadata, globalSpec, keyspace, table) + cols = append(cols, col) + } + } + + meta.columns = cols + + return meta +} + +type resultMetadata struct { + flags int + + // only if flagPageState + pagingState []byte + + columns []ColumnInfo + colCount int + + // this is a count of the total number of columns which can be scanned, + // it is at minimum len(columns) but may be larger, for instance when a column + // is a UDT or tuple. + actualColCount int +} + +func (r resultMetadata) String() string { + return fmt.Sprintf("[metadata flags=0x%x paging_state=% X columns=%v]", r.flags, r.pagingState, r.columns) +} + +func (f *framer) readCol(col *ColumnInfo, meta *resultMetadata, globalSpec bool, keyspace, table string) { + if !globalSpec { + col.Keyspace = f.readString() + col.Table = f.readString() + } else { + col.Keyspace = keyspace + col.Table = table + } + + col.Name = f.readString() + col.TypeInfo = f.readTypeInfo() + switch v := col.TypeInfo.(type) { + // maybe also UDT + case TupleTypeInfo: + // -1 because we already included the tuple column + meta.actualColCount += len(v.Elems) - 1 + } +} + +func (f *framer) parseResultMetadata() resultMetadata { + var meta resultMetadata + + meta.flags = f.readInt() + meta.colCount = f.readInt() + if meta.colCount < 0 { + panic(fmt.Errorf("received negative column count: %d", meta.colCount)) + } + meta.actualColCount = meta.colCount + + if meta.flags&flagHasMorePages == flagHasMorePages { + meta.pagingState = copyBytes(f.readBytes()) + } + + if meta.flags&flagNoMetaData == flagNoMetaData { + return meta + } + + var keyspace, table string + globalSpec := meta.flags&flagGlobalTableSpec == flagGlobalTableSpec + if globalSpec { + keyspace = f.readString() + table = f.readString() + } + + var cols []ColumnInfo + if meta.colCount < 1000 { + // preallocate columninfo to avoid excess copying + cols = make([]ColumnInfo, meta.colCount) + for i := 0; i < meta.colCount; i++ { + f.readCol(&cols[i], &meta, globalSpec, keyspace, table) + } + + } else { + // use append, huge number of columns usually indicates a corrupt frame or + // just a huge row. + for i := 0; i < meta.colCount; i++ { + var col ColumnInfo + f.readCol(&col, &meta, globalSpec, keyspace, table) + cols = append(cols, col) + } + } + + meta.columns = cols + + return meta +} + +type resultVoidFrame struct { + frameHeader +} + +func (f *resultVoidFrame) String() string { + return "[result_void]" +} + +func (f *framer) parseResultFrame() (frame, error) { + kind := f.readInt() + + switch kind { + case resultKindVoid: + return &resultVoidFrame{frameHeader: *f.header}, nil + case resultKindRows: + return f.parseResultRows(), nil + case resultKindKeyspace: + return f.parseResultSetKeyspace(), nil + case resultKindPrepared: + return f.parseResultPrepared(), nil + case resultKindSchemaChanged: + return f.parseResultSchemaChange(), nil + } + + return nil, NewErrProtocol("unknown result kind: %x", kind) +} + +type resultRowsFrame struct { + frameHeader + + meta resultMetadata + // dont parse the rows here as we only need to do it once + numRows int +} + +func (f *resultRowsFrame) String() string { + return fmt.Sprintf("[result_rows meta=%v]", f.meta) +} + +func (f *framer) parseResultRows() frame { + result := &resultRowsFrame{} + result.meta = f.parseResultMetadata() + + result.numRows = f.readInt() + if result.numRows < 0 { + panic(fmt.Errorf("invalid row_count in result frame: %d", result.numRows)) + } + + return result +} + +type resultKeyspaceFrame struct { + frameHeader + keyspace string +} + +func (r *resultKeyspaceFrame) String() string { + return fmt.Sprintf("[result_keyspace keyspace=%s]", r.keyspace) +} + +func (f *framer) parseResultSetKeyspace() frame { + return &resultKeyspaceFrame{ + frameHeader: *f.header, + keyspace: f.readString(), + } +} + +type resultPreparedFrame struct { + frameHeader + + preparedID []byte + reqMeta preparedMetadata + respMeta resultMetadata +} + +func (f *framer) parseResultPrepared() frame { + frame := &resultPreparedFrame{ + frameHeader: *f.header, + preparedID: f.readShortBytes(), + reqMeta: f.parsePreparedMetadata(), + } + + if f.proto < protoVersion2 { + return frame + } + + frame.respMeta = f.parseResultMetadata() + + return frame +} + +type schemaChangeKeyspace struct { + frameHeader + + change string + keyspace string +} + +func (f schemaChangeKeyspace) String() string { + return fmt.Sprintf("[event schema_change_keyspace change=%q keyspace=%q]", f.change, f.keyspace) +} + +type schemaChangeTable struct { + frameHeader + + change string + keyspace string + object string +} + +func (f schemaChangeTable) String() string { + return fmt.Sprintf("[event schema_change change=%q keyspace=%q object=%q]", f.change, f.keyspace, f.object) +} + +type schemaChangeType struct { + frameHeader + + change string + keyspace string + object string +} + +type schemaChangeFunction struct { + frameHeader + + change string + keyspace string + name string + args []string +} + +type schemaChangeAggregate struct { + frameHeader + + change string + keyspace string + name string + args []string +} + +func (f *framer) parseResultSchemaChange() frame { + if f.proto <= protoVersion2 { + change := f.readString() + keyspace := f.readString() + table := f.readString() + + if table != "" { + return &schemaChangeTable{ + frameHeader: *f.header, + change: change, + keyspace: keyspace, + object: table, + } + } else { + return &schemaChangeKeyspace{ + frameHeader: *f.header, + change: change, + keyspace: keyspace, + } + } + } else { + change := f.readString() + target := f.readString() + + // TODO: could just use a separate type for each target + switch target { + case "KEYSPACE": + frame := &schemaChangeKeyspace{ + frameHeader: *f.header, + change: change, + } + + frame.keyspace = f.readString() + + return frame + case "TABLE": + frame := &schemaChangeTable{ + frameHeader: *f.header, + change: change, + } + + frame.keyspace = f.readString() + frame.object = f.readString() + + return frame + case "TYPE": + frame := &schemaChangeType{ + frameHeader: *f.header, + change: change, + } + + frame.keyspace = f.readString() + frame.object = f.readString() + + return frame + case "FUNCTION": + frame := &schemaChangeFunction{ + frameHeader: *f.header, + change: change, + } + + frame.keyspace = f.readString() + frame.name = f.readString() + frame.args = f.readStringList() + + return frame + case "AGGREGATE": + frame := &schemaChangeAggregate{ + frameHeader: *f.header, + change: change, + } + + frame.keyspace = f.readString() + frame.name = f.readString() + frame.args = f.readStringList() + + return frame + default: + panic(fmt.Errorf("gocql: unknown SCHEMA_CHANGE target: %q change: %q", target, change)) + } + } + +} + +type authenticateFrame struct { + frameHeader + + class string +} + +func (a *authenticateFrame) String() string { + return fmt.Sprintf("[authenticate class=%q]", a.class) +} + +func (f *framer) parseAuthenticateFrame() frame { + return &authenticateFrame{ + frameHeader: *f.header, + class: f.readString(), + } +} + +type authSuccessFrame struct { + frameHeader + + data []byte +} + +func (a *authSuccessFrame) String() string { + return fmt.Sprintf("[auth_success data=%q]", a.data) +} + +func (f *framer) parseAuthSuccessFrame() frame { + return &authSuccessFrame{ + frameHeader: *f.header, + data: f.readBytes(), + } +} + +type authChallengeFrame struct { + frameHeader + + data []byte +} + +func (a *authChallengeFrame) String() string { + return fmt.Sprintf("[auth_challenge data=%q]", a.data) +} + +func (f *framer) parseAuthChallengeFrame() frame { + return &authChallengeFrame{ + frameHeader: *f.header, + data: f.readBytes(), + } +} + +type statusChangeEventFrame struct { + frameHeader + + change string + host net.IP + port int +} + +func (t statusChangeEventFrame) String() string { + return fmt.Sprintf("[status_change change=%s host=%v port=%v]", t.change, t.host, t.port) +} + +// essentially the same as statusChange +type topologyChangeEventFrame struct { + frameHeader + + change string + host net.IP + port int +} + +func (t topologyChangeEventFrame) String() string { + return fmt.Sprintf("[topology_change change=%s host=%v port=%v]", t.change, t.host, t.port) +} + +func (f *framer) parseEventFrame() frame { + eventType := f.readString() + + switch eventType { + case "TOPOLOGY_CHANGE": + frame := &topologyChangeEventFrame{frameHeader: *f.header} + frame.change = f.readString() + frame.host, frame.port = f.readInet() + + return frame + case "STATUS_CHANGE": + frame := &statusChangeEventFrame{frameHeader: *f.header} + frame.change = f.readString() + frame.host, frame.port = f.readInet() + + return frame + case "SCHEMA_CHANGE": + // this should work for all versions + return f.parseResultSchemaChange() + default: + panic(fmt.Errorf("gocql: unknown event type: %q", eventType)) + } + +} + +type writeAuthResponseFrame struct { + data []byte +} + +func (a *writeAuthResponseFrame) String() string { + return fmt.Sprintf("[auth_response data=%q]", a.data) +} + +func (a *writeAuthResponseFrame) writeFrame(framer *framer, streamID int) error { + return framer.writeAuthResponseFrame(streamID, a.data) +} + +func (f *framer) writeAuthResponseFrame(streamID int, data []byte) error { + f.writeHeader(f.flags, opAuthResponse, streamID) + f.writeBytes(data) + return f.finishWrite() +} + +type queryValues struct { + value []byte + + // optional name, will set With names for values flag + name string + isUnset bool +} + +type queryParams struct { + consistency Consistency + // v2+ + skipMeta bool + values []queryValues + pageSize int + pagingState []byte + serialConsistency SerialConsistency + // v3+ + defaultTimestamp bool + defaultTimestampValue int64 +} + +func (q queryParams) String() string { + return fmt.Sprintf("[query_params consistency=%v skip_meta=%v page_size=%d paging_state=%q serial_consistency=%v default_timestamp=%v values=%v]", + q.consistency, q.skipMeta, q.pageSize, q.pagingState, q.serialConsistency, q.defaultTimestamp, q.values) +} + +func (f *framer) writeQueryParams(opts *queryParams) { + f.writeConsistency(opts.consistency) + + if f.proto == protoVersion1 { + return + } + + var flags byte + if len(opts.values) > 0 { + flags |= flagValues + } + if opts.skipMeta { + flags |= flagSkipMetaData + } + if opts.pageSize > 0 { + flags |= flagPageSize + } + if len(opts.pagingState) > 0 { + flags |= flagWithPagingState + } + if opts.serialConsistency > 0 { + flags |= flagWithSerialConsistency + } + + names := false + + // protoV3 specific things + if f.proto > protoVersion2 { + if opts.defaultTimestamp { + flags |= flagDefaultTimestamp + } + + if len(opts.values) > 0 && opts.values[0].name != "" { + flags |= flagWithNameValues + names = true + } + } + + f.writeByte(flags) + + if n := len(opts.values); n > 0 { + f.writeShort(uint16(n)) + + for i := 0; i < n; i++ { + if names { + f.writeString(opts.values[i].name) + } + if opts.values[i].isUnset { + f.writeUnset() + } else { + f.writeBytes(opts.values[i].value) + } + } + } + + if opts.pageSize > 0 { + f.writeInt(int32(opts.pageSize)) + } + + if len(opts.pagingState) > 0 { + f.writeBytes(opts.pagingState) + } + + if opts.serialConsistency > 0 { + f.writeConsistency(Consistency(opts.serialConsistency)) + } + + if f.proto > protoVersion2 && opts.defaultTimestamp { + // timestamp in microseconds + var ts int64 + if opts.defaultTimestampValue != 0 { + ts = opts.defaultTimestampValue + } else { + ts = time.Now().UnixNano() / 1000 + } + f.writeLong(ts) + } +} + +type writeQueryFrame struct { + statement string + params queryParams +} + +func (w *writeQueryFrame) String() string { + return fmt.Sprintf("[query statement=%q params=%v]", w.statement, w.params) +} + +func (w *writeQueryFrame) writeFrame(framer *framer, streamID int) error { + return framer.writeQueryFrame(streamID, w.statement, &w.params) +} + +func (f *framer) writeQueryFrame(streamID int, statement string, params *queryParams) error { + f.writeHeader(f.flags, opQuery, streamID) + f.writeLongString(statement) + f.writeQueryParams(params) + + return f.finishWrite() +} + +type frameWriter interface { + writeFrame(framer *framer, streamID int) error +} + +type frameWriterFunc func(framer *framer, streamID int) error + +func (f frameWriterFunc) writeFrame(framer *framer, streamID int) error { + return f(framer, streamID) +} + +type writeExecuteFrame struct { + preparedID []byte + params queryParams +} + +func (e *writeExecuteFrame) String() string { + return fmt.Sprintf("[execute id=% X params=%v]", e.preparedID, &e.params) +} + +func (e *writeExecuteFrame) writeFrame(fr *framer, streamID int) error { + return fr.writeExecuteFrame(streamID, e.preparedID, &e.params) +} + +func (f *framer) writeExecuteFrame(streamID int, preparedID []byte, params *queryParams) error { + f.writeHeader(f.flags, opExecute, streamID) + f.writeShortBytes(preparedID) + if f.proto > protoVersion1 { + f.writeQueryParams(params) + } else { + n := len(params.values) + f.writeShort(uint16(n)) + for i := 0; i < n; i++ { + if params.values[i].isUnset { + f.writeUnset() + } else { + f.writeBytes(params.values[i].value) + } + } + f.writeConsistency(params.consistency) + } + + return f.finishWrite() +} + +// TODO: can we replace BatchStatemt with batchStatement? As they prety much +// duplicate each other +type batchStatment struct { + preparedID []byte + statement string + values []queryValues +} + +type writeBatchFrame struct { + typ BatchType + statements []batchStatment + consistency Consistency + + // v3+ + serialConsistency SerialConsistency + defaultTimestamp bool + defaultTimestampValue int64 +} + +func (w *writeBatchFrame) writeFrame(framer *framer, streamID int) error { + return framer.writeBatchFrame(streamID, w) +} + +func (f *framer) writeBatchFrame(streamID int, w *writeBatchFrame) error { + f.writeHeader(f.flags, opBatch, streamID) + f.writeByte(byte(w.typ)) + + n := len(w.statements) + f.writeShort(uint16(n)) + + var flags byte + + for i := 0; i < n; i++ { + b := &w.statements[i] + if len(b.preparedID) == 0 { + f.writeByte(0) + f.writeLongString(b.statement) + } else { + f.writeByte(1) + f.writeShortBytes(b.preparedID) + } + + f.writeShort(uint16(len(b.values))) + for j := range b.values { + col := b.values[j] + if f.proto > protoVersion2 && col.name != "" { + // TODO: move this check into the caller and set a flag on writeBatchFrame + // to indicate using named values + if f.proto <= protoVersion5 { + return fmt.Errorf("gocql: named query values are not supported in batches, please see https://issues.apache.org/jira/browse/CASSANDRA-10246") + } + flags |= flagWithNameValues + f.writeString(col.name) + } + if col.isUnset { + f.writeUnset() + } else { + f.writeBytes(col.value) + } + } + } + + f.writeConsistency(w.consistency) + + if f.proto > protoVersion2 { + if w.serialConsistency > 0 { + flags |= flagWithSerialConsistency + } + if w.defaultTimestamp { + flags |= flagDefaultTimestamp + } + + f.writeByte(flags) + + if w.serialConsistency > 0 { + f.writeConsistency(Consistency(w.serialConsistency)) + } + + if w.defaultTimestamp { + var ts int64 + if w.defaultTimestampValue != 0 { + ts = w.defaultTimestampValue + } else { + ts = time.Now().UnixNano() / 1000 + } + f.writeLong(ts) + } + } + + return f.finishWrite() +} + +type writeOptionsFrame struct{} + +func (w *writeOptionsFrame) writeFrame(framer *framer, streamID int) error { + return framer.writeOptionsFrame(streamID, w) +} + +func (f *framer) writeOptionsFrame(stream int, _ *writeOptionsFrame) error { + f.writeHeader(f.flags, opOptions, stream) + return f.finishWrite() +} + +type writeRegisterFrame struct { + events []string +} + +func (w *writeRegisterFrame) writeFrame(framer *framer, streamID int) error { + return framer.writeRegisterFrame(streamID, w) +} + +func (f *framer) writeRegisterFrame(streamID int, w *writeRegisterFrame) error { + f.writeHeader(f.flags, opRegister, streamID) + f.writeStringList(w.events) + + return f.finishWrite() +} + +func (f *framer) readByte() byte { + if len(f.rbuf) < 1 { + panic(fmt.Errorf("not enough bytes in buffer to read byte require 1 got: %d", len(f.rbuf))) + } + + b := f.rbuf[0] + f.rbuf = f.rbuf[1:] + return b +} + +func (f *framer) readInt() (n int) { + if len(f.rbuf) < 4 { + panic(fmt.Errorf("not enough bytes in buffer to read int require 4 got: %d", len(f.rbuf))) + } + + n = int(int32(f.rbuf[0])<<24 | int32(f.rbuf[1])<<16 | int32(f.rbuf[2])<<8 | int32(f.rbuf[3])) + f.rbuf = f.rbuf[4:] + return +} + +func (f *framer) readShort() (n uint16) { + if len(f.rbuf) < 2 { + panic(fmt.Errorf("not enough bytes in buffer to read short require 2 got: %d", len(f.rbuf))) + } + n = uint16(f.rbuf[0])<<8 | uint16(f.rbuf[1]) + f.rbuf = f.rbuf[2:] + return +} + +func (f *framer) readLong() (n int64) { + if len(f.rbuf) < 8 { + panic(fmt.Errorf("not enough bytes in buffer to read long require 8 got: %d", len(f.rbuf))) + } + n = int64(f.rbuf[0])<<56 | int64(f.rbuf[1])<<48 | int64(f.rbuf[2])<<40 | int64(f.rbuf[3])<<32 | + int64(f.rbuf[4])<<24 | int64(f.rbuf[5])<<16 | int64(f.rbuf[6])<<8 | int64(f.rbuf[7]) + f.rbuf = f.rbuf[8:] + return +} + +func (f *framer) readString() (s string) { + size := f.readShort() + + if len(f.rbuf) < int(size) { + panic(fmt.Errorf("not enough bytes in buffer to read string require %d got: %d", size, len(f.rbuf))) + } + + s = string(f.rbuf[:size]) + f.rbuf = f.rbuf[size:] + return +} + +func (f *framer) readLongString() (s string) { + size := f.readInt() + + if len(f.rbuf) < size { + panic(fmt.Errorf("not enough bytes in buffer to read long string require %d got: %d", size, len(f.rbuf))) + } + + s = string(f.rbuf[:size]) + f.rbuf = f.rbuf[size:] + return +} + +func (f *framer) readUUID() *UUID { + if len(f.rbuf) < 16 { + panic(fmt.Errorf("not enough bytes in buffer to read uuid require %d got: %d", 16, len(f.rbuf))) + } + + // TODO: how to handle this error, if it is a uuid, then sureley, problems? + u, _ := UUIDFromBytes(f.rbuf[:16]) + f.rbuf = f.rbuf[16:] + return &u +} + +func (f *framer) readStringList() []string { + size := f.readShort() + + l := make([]string, size) + for i := 0; i < int(size); i++ { + l[i] = f.readString() + } + + return l +} + +func (f *framer) readBytesInternal() ([]byte, error) { + size := f.readInt() + if size < 0 { + return nil, nil + } + + if len(f.rbuf) < size { + return nil, fmt.Errorf("not enough bytes in buffer to read bytes require %d got: %d", size, len(f.rbuf)) + } + + l := f.rbuf[:size] + f.rbuf = f.rbuf[size:] + + return l, nil +} + +func (f *framer) readBytes() []byte { + l, err := f.readBytesInternal() + if err != nil { + panic(err) + } + + return l +} + +func (f *framer) readShortBytes() []byte { + size := f.readShort() + if len(f.rbuf) < int(size) { + panic(fmt.Errorf("not enough bytes in buffer to read short bytes: require %d got %d", size, len(f.rbuf))) + } + + l := f.rbuf[:size] + f.rbuf = f.rbuf[size:] + + return l +} + +func (f *framer) readInet() (net.IP, int) { + if len(f.rbuf) < 1 { + panic(fmt.Errorf("not enough bytes in buffer to read inet size require %d got: %d", 1, len(f.rbuf))) + } + + size := f.rbuf[0] + f.rbuf = f.rbuf[1:] + + if !(size == 4 || size == 16) { + panic(fmt.Errorf("invalid IP size: %d", size)) + } + + if len(f.rbuf) < 1 { + panic(fmt.Errorf("not enough bytes in buffer to read inet require %d got: %d", size, len(f.rbuf))) + } + + ip := make([]byte, size) + copy(ip, f.rbuf[:size]) + f.rbuf = f.rbuf[size:] + + port := f.readInt() + return net.IP(ip), port +} + +func (f *framer) readConsistency() Consistency { + return Consistency(f.readShort()) +} + +func (f *framer) readStringMap() map[string]string { + size := f.readShort() + m := make(map[string]string, size) + + for i := 0; i < int(size); i++ { + k := f.readString() + v := f.readString() + m[k] = v + } + + return m +} + +func (f *framer) readBytesMap() map[string][]byte { + size := f.readShort() + m := make(map[string][]byte, size) + + for i := 0; i < int(size); i++ { + k := f.readString() + v := f.readBytes() + m[k] = v + } + + return m +} + +func (f *framer) readStringMultiMap() map[string][]string { + size := f.readShort() + m := make(map[string][]string, size) + + for i := 0; i < int(size); i++ { + k := f.readString() + v := f.readStringList() + m[k] = v + } + + return m +} + +func (f *framer) writeByte(b byte) { + f.wbuf = append(f.wbuf, b) +} + +func appendBytes(p []byte, d []byte) []byte { + if d == nil { + return appendInt(p, -1) + } + p = appendInt(p, int32(len(d))) + p = append(p, d...) + return p +} + +func appendShort(p []byte, n uint16) []byte { + return append(p, + byte(n>>8), + byte(n), + ) +} + +func appendInt(p []byte, n int32) []byte { + return append(p, byte(n>>24), + byte(n>>16), + byte(n>>8), + byte(n)) +} + +func appendLong(p []byte, n int64) []byte { + return append(p, + byte(n>>56), + byte(n>>48), + byte(n>>40), + byte(n>>32), + byte(n>>24), + byte(n>>16), + byte(n>>8), + byte(n), + ) +} + +// these are protocol level binary types +func (f *framer) writeInt(n int32) { + f.wbuf = appendInt(f.wbuf, n) +} + +func (f *framer) writeShort(n uint16) { + f.wbuf = appendShort(f.wbuf, n) +} + +func (f *framer) writeLong(n int64) { + f.wbuf = appendLong(f.wbuf, n) +} + +func (f *framer) writeString(s string) { + f.writeShort(uint16(len(s))) + f.wbuf = append(f.wbuf, s...) +} + +func (f *framer) writeLongString(s string) { + f.writeInt(int32(len(s))) + f.wbuf = append(f.wbuf, s...) +} + +func (f *framer) writeUUID(u *UUID) { + f.wbuf = append(f.wbuf, u[:]...) +} + +func (f *framer) writeStringList(l []string) { + f.writeShort(uint16(len(l))) + for _, s := range l { + f.writeString(s) + } +} + +func (f *framer) writeUnset() { + // Protocol version 4 specifies that bind variables do not require having a + // value when executing a statement. Bind variables without a value are + // called 'unset'. The 'unset' bind variable is serialized as the int + // value '-2' without following bytes. + f.writeInt(-2) +} + +func (f *framer) writeBytes(p []byte) { + // TODO: handle null case correctly, + // [bytes] A [int] n, followed by n bytes if n >= 0. If n < 0, + // no byte should follow and the value represented is `null`. + if p == nil { + f.writeInt(-1) + } else { + f.writeInt(int32(len(p))) + f.wbuf = append(f.wbuf, p...) + } +} + +func (f *framer) writeShortBytes(p []byte) { + f.writeShort(uint16(len(p))) + f.wbuf = append(f.wbuf, p...) +} + +func (f *framer) writeInet(ip net.IP, port int) { + f.wbuf = append(f.wbuf, + byte(len(ip)), + ) + + f.wbuf = append(f.wbuf, + []byte(ip)..., + ) + + f.writeInt(int32(port)) +} + +func (f *framer) writeConsistency(cons Consistency) { + f.writeShort(uint16(cons)) +} + +func (f *framer) writeStringMap(m map[string]string) { + f.writeShort(uint16(len(m))) + for k, v := range m { + f.writeString(k) + f.writeString(v) + } +} diff --git a/vendor/github.com/gocql/gocql/fuzz.go b/vendor/github.com/gocql/gocql/fuzz.go new file mode 100644 index 0000000..3606f93 --- /dev/null +++ b/vendor/github.com/gocql/gocql/fuzz.go @@ -0,0 +1,33 @@ +// +build gofuzz + +package gocql + +import "bytes" + +func Fuzz(data []byte) int { + var bw bytes.Buffer + + r := bytes.NewReader(data) + + head, err := readHeader(r, make([]byte, 9)) + if err != nil { + return 0 + } + + framer := newFramer(r, &bw, nil, byte(head.version)) + err = framer.readFrame(&head) + if err != nil { + return 0 + } + + frame, err := framer.parseFrame() + if err != nil { + return 0 + } + + if frame != nil { + return 1 + } + + return 2 +} diff --git a/vendor/github.com/gocql/gocql/go.mod b/vendor/github.com/gocql/gocql/go.mod new file mode 100644 index 0000000..a3c3805 --- /dev/null +++ b/vendor/github.com/gocql/gocql/go.mod @@ -0,0 +1,7 @@ +module github.com/gocql/gocql + +require ( + github.com/golang/snappy v0.0.0-20170215233205-553a64147049 + github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed + gopkg.in/inf.v0 v0.9.1 +) diff --git a/vendor/github.com/gocql/gocql/go.modverify b/vendor/github.com/gocql/gocql/go.modverify new file mode 100644 index 0000000..fa9fc60 --- /dev/null +++ b/vendor/github.com/gocql/gocql/go.modverify @@ -0,0 +1,3 @@ +github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= diff --git a/vendor/github.com/gocql/gocql/helpers.go b/vendor/github.com/gocql/gocql/helpers.go new file mode 100644 index 0000000..1208979 --- /dev/null +++ b/vendor/github.com/gocql/gocql/helpers.go @@ -0,0 +1,365 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "fmt" + "math/big" + "reflect" + "strings" + "time" + + "gopkg.in/inf.v0" +) + +type RowData struct { + Columns []string + Values []interface{} +} + +func goType(t TypeInfo) reflect.Type { + switch t.Type() { + case TypeVarchar, TypeAscii, TypeInet, TypeText: + return reflect.TypeOf(*new(string)) + case TypeBigInt, TypeCounter: + return reflect.TypeOf(*new(int64)) + case TypeTimestamp: + return reflect.TypeOf(*new(time.Time)) + case TypeBlob: + return reflect.TypeOf(*new([]byte)) + case TypeBoolean: + return reflect.TypeOf(*new(bool)) + case TypeFloat: + return reflect.TypeOf(*new(float32)) + case TypeDouble: + return reflect.TypeOf(*new(float64)) + case TypeInt: + return reflect.TypeOf(*new(int)) + case TypeSmallInt: + return reflect.TypeOf(*new(int16)) + case TypeTinyInt: + return reflect.TypeOf(*new(int8)) + case TypeDecimal: + return reflect.TypeOf(*new(*inf.Dec)) + case TypeUUID, TypeTimeUUID: + return reflect.TypeOf(*new(UUID)) + case TypeList, TypeSet: + return reflect.SliceOf(goType(t.(CollectionType).Elem)) + case TypeMap: + return reflect.MapOf(goType(t.(CollectionType).Key), goType(t.(CollectionType).Elem)) + case TypeVarint: + return reflect.TypeOf(*new(*big.Int)) + case TypeTuple: + // what can we do here? all there is to do is to make a list of interface{} + tuple := t.(TupleTypeInfo) + return reflect.TypeOf(make([]interface{}, len(tuple.Elems))) + case TypeUDT: + return reflect.TypeOf(make(map[string]interface{})) + case TypeDate: + return reflect.TypeOf(*new(time.Time)) + default: + return nil + } +} + +func dereference(i interface{}) interface{} { + return reflect.Indirect(reflect.ValueOf(i)).Interface() +} + +func getCassandraBaseType(name string) Type { + switch name { + case "ascii": + return TypeAscii + case "bigint": + return TypeBigInt + case "blob": + return TypeBlob + case "boolean": + return TypeBoolean + case "counter": + return TypeCounter + case "decimal": + return TypeDecimal + case "double": + return TypeDouble + case "float": + return TypeFloat + case "int": + return TypeInt + case "timestamp": + return TypeTimestamp + case "uuid": + return TypeUUID + case "varchar": + return TypeVarchar + case "text": + return TypeText + case "varint": + return TypeVarint + case "timeuuid": + return TypeTimeUUID + case "inet": + return TypeInet + case "MapType": + return TypeMap + case "ListType": + return TypeList + case "SetType": + return TypeSet + case "TupleType": + return TypeTuple + default: + return TypeCustom + } +} + +func getCassandraType(name string) TypeInfo { + if strings.HasPrefix(name, "frozen<") { + return getCassandraType(strings.TrimPrefix(name[:len(name)-1], "frozen<")) + } else if strings.HasPrefix(name, "set<") { + return CollectionType{ + NativeType: NativeType{typ: TypeSet}, + Elem: getCassandraType(strings.TrimPrefix(name[:len(name)-1], "set<")), + } + } else if strings.HasPrefix(name, "list<") { + return CollectionType{ + NativeType: NativeType{typ: TypeList}, + Elem: getCassandraType(strings.TrimPrefix(name[:len(name)-1], "list<")), + } + } else if strings.HasPrefix(name, "map<") { + names := strings.Split(strings.TrimPrefix(name[:len(name)-1], "map<"), ", ") + if len(names) != 2 { + panic(fmt.Sprintf("invalid map type: %v", name)) + } + + return CollectionType{ + NativeType: NativeType{typ: TypeMap}, + Key: getCassandraType(names[0]), + Elem: getCassandraType(names[1]), + } + } else if strings.HasPrefix(name, "tuple<") { + names := strings.Split(strings.TrimPrefix(name[:len(name)-1], "tuple<"), ", ") + types := make([]TypeInfo, len(names)) + + for i, name := range names { + types[i] = getCassandraType(name) + } + + return TupleTypeInfo{ + NativeType: NativeType{typ: TypeTuple}, + Elems: types, + } + } else { + return NativeType{ + typ: getCassandraBaseType(name), + } + } +} + +func getApacheCassandraType(class string) Type { + switch strings.TrimPrefix(class, apacheCassandraTypePrefix) { + case "AsciiType": + return TypeAscii + case "LongType": + return TypeBigInt + case "BytesType": + return TypeBlob + case "BooleanType": + return TypeBoolean + case "CounterColumnType": + return TypeCounter + case "DecimalType": + return TypeDecimal + case "DoubleType": + return TypeDouble + case "FloatType": + return TypeFloat + case "Int32Type": + return TypeInt + case "ShortType": + return TypeSmallInt + case "ByteType": + return TypeTinyInt + case "DateType", "TimestampType": + return TypeTimestamp + case "UUIDType", "LexicalUUIDType": + return TypeUUID + case "UTF8Type": + return TypeVarchar + case "IntegerType": + return TypeVarint + case "TimeUUIDType": + return TypeTimeUUID + case "InetAddressType": + return TypeInet + case "MapType": + return TypeMap + case "ListType": + return TypeList + case "SetType": + return TypeSet + case "TupleType": + return TypeTuple + default: + return TypeCustom + } +} + +func typeCanBeNull(typ TypeInfo) bool { + switch typ.(type) { + case CollectionType, UDTTypeInfo, TupleTypeInfo: + return false + } + + return true +} + +func (r *RowData) rowMap(m map[string]interface{}) { + for i, column := range r.Columns { + val := dereference(r.Values[i]) + if valVal := reflect.ValueOf(val); valVal.Kind() == reflect.Slice { + valCopy := reflect.MakeSlice(valVal.Type(), valVal.Len(), valVal.Cap()) + reflect.Copy(valCopy, valVal) + m[column] = valCopy.Interface() + } else { + m[column] = val + } + } +} + +// TupeColumnName will return the column name of a tuple value in a column named +// c at index n. It should be used if a specific element within a tuple is needed +// to be extracted from a map returned from SliceMap or MapScan. +func TupleColumnName(c string, n int) string { + return fmt.Sprintf("%s[%d]", c, n) +} + +func (iter *Iter) RowData() (RowData, error) { + if iter.err != nil { + return RowData{}, iter.err + } + + columns := make([]string, 0, len(iter.Columns())) + values := make([]interface{}, 0, len(iter.Columns())) + + for _, column := range iter.Columns() { + if c, ok := column.TypeInfo.(TupleTypeInfo); !ok { + val := column.TypeInfo.New() + columns = append(columns, column.Name) + values = append(values, val) + } else { + for i, elem := range c.Elems { + columns = append(columns, TupleColumnName(column.Name, i)) + values = append(values, elem.New()) + } + } + } + + rowData := RowData{ + Columns: columns, + Values: values, + } + + return rowData, nil +} + +// TODO(zariel): is it worth exporting this? +func (iter *Iter) rowMap() (map[string]interface{}, error) { + if iter.err != nil { + return nil, iter.err + } + + rowData, _ := iter.RowData() + iter.Scan(rowData.Values...) + m := make(map[string]interface{}, len(rowData.Columns)) + rowData.rowMap(m) + return m, nil +} + +// SliceMap is a helper function to make the API easier to use +// returns the data from the query in the form of []map[string]interface{} +func (iter *Iter) SliceMap() ([]map[string]interface{}, error) { + if iter.err != nil { + return nil, iter.err + } + + // Not checking for the error because we just did + rowData, _ := iter.RowData() + dataToReturn := make([]map[string]interface{}, 0) + for iter.Scan(rowData.Values...) { + m := make(map[string]interface{}, len(rowData.Columns)) + rowData.rowMap(m) + dataToReturn = append(dataToReturn, m) + } + if iter.err != nil { + return nil, iter.err + } + return dataToReturn, nil +} + +// MapScan takes a map[string]interface{} and populates it with a row +// that is returned from cassandra. +// +// Each call to MapScan() must be called with a new map object. +// During the call to MapScan() any pointers in the existing map +// are replaced with non pointer types before the call returns +// +// iter := session.Query(`SELECT * FROM mytable`).Iter() +// for { +// // New map each iteration +// row = make(map[string]interface{}) +// if !iter.MapScan(row) { +// break +// } +// // Do things with row +// if fullname, ok := row["fullname"]; ok { +// fmt.Printf("Full Name: %s\n", fullname) +// } +// } +// +// You can also pass pointers in the map before each call +// +// var fullName FullName // Implements gocql.Unmarshaler and gocql.Marshaler interfaces +// var address net.IP +// var age int +// iter := session.Query(`SELECT * FROM scan_map_table`).Iter() +// for { +// // New map each iteration +// row := map[string]interface{}{ +// "fullname": &fullName, +// "age": &age, +// "address": &address, +// } +// if !iter.MapScan(row) { +// break +// } +// fmt.Printf("First: %s Age: %d Address: %q\n", fullName.FirstName, age, address) +// } +func (iter *Iter) MapScan(m map[string]interface{}) bool { + if iter.err != nil { + return false + } + + // Not checking for the error because we just did + rowData, _ := iter.RowData() + + for i, col := range rowData.Columns { + if dest, ok := m[col]; ok { + rowData.Values[i] = dest + } + } + + if iter.Scan(rowData.Values...) { + rowData.rowMap(m) + return true + } + return false +} + +func copyBytes(p []byte) []byte { + b := make([]byte, len(p)) + copy(b, p) + return b +} diff --git a/vendor/github.com/gocql/gocql/host_source.go b/vendor/github.com/gocql/gocql/host_source.go new file mode 100644 index 0000000..988324c --- /dev/null +++ b/vendor/github.com/gocql/gocql/host_source.go @@ -0,0 +1,692 @@ +package gocql + +import ( + "errors" + "fmt" + "net" + "strconv" + "strings" + "sync" + "time" +) + +type nodeState int32 + +func (n nodeState) String() string { + if n == NodeUp { + return "UP" + } else if n == NodeDown { + return "DOWN" + } + return fmt.Sprintf("UNKNOWN_%d", n) +} + +const ( + NodeUp nodeState = iota + NodeDown +) + +type cassVersion struct { + Major, Minor, Patch int +} + +func (c *cassVersion) Set(v string) error { + if v == "" { + return nil + } + + return c.UnmarshalCQL(nil, []byte(v)) +} + +func (c *cassVersion) UnmarshalCQL(info TypeInfo, data []byte) error { + return c.unmarshal(data) +} + +func (c *cassVersion) unmarshal(data []byte) error { + version := strings.TrimSuffix(string(data), "-SNAPSHOT") + version = strings.TrimPrefix(version, "v") + v := strings.Split(version, ".") + + if len(v) < 2 { + return fmt.Errorf("invalid version string: %s", data) + } + + var err error + c.Major, err = strconv.Atoi(v[0]) + if err != nil { + return fmt.Errorf("invalid major version %v: %v", v[0], err) + } + + c.Minor, err = strconv.Atoi(v[1]) + if err != nil { + return fmt.Errorf("invalid minor version %v: %v", v[1], err) + } + + if len(v) > 2 { + c.Patch, err = strconv.Atoi(v[2]) + if err != nil { + return fmt.Errorf("invalid patch version %v: %v", v[2], err) + } + } + + return nil +} + +func (c cassVersion) Before(major, minor, patch int) bool { + if c.Major > major { + return true + } else if c.Minor > minor { + return true + } else if c.Patch > patch { + return true + } + return false +} + +func (c cassVersion) String() string { + return fmt.Sprintf("v%d.%d.%d", c.Major, c.Minor, c.Patch) +} + +func (c cassVersion) nodeUpDelay() time.Duration { + if c.Major >= 2 && c.Minor >= 2 { + // CASSANDRA-8236 + return 0 + } + + return 10 * time.Second +} + +type HostInfo struct { + // TODO(zariel): reduce locking maybe, not all values will change, but to ensure + // that we are thread safe use a mutex to access all fields. + mu sync.RWMutex + peer net.IP + broadcastAddress net.IP + listenAddress net.IP + rpcAddress net.IP + preferredIP net.IP + connectAddress net.IP + port int + dataCenter string + rack string + hostId string + workload string + graph bool + dseVersion string + partitioner string + clusterName string + version cassVersion + state nodeState + tokens []string +} + +func (h *HostInfo) Equal(host *HostInfo) bool { + if h == host { + // prevent rlock reentry + return true + } + + return h.ConnectAddress().Equal(host.ConnectAddress()) +} + +func (h *HostInfo) Peer() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + return h.peer +} + +func (h *HostInfo) setPeer(peer net.IP) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.peer = peer + return h +} + +func (h *HostInfo) invalidConnectAddr() bool { + h.mu.RLock() + defer h.mu.RUnlock() + addr, _ := h.connectAddressLocked() + return !validIpAddr(addr) +} + +func validIpAddr(addr net.IP) bool { + return addr != nil && !addr.IsUnspecified() +} + +func (h *HostInfo) connectAddressLocked() (net.IP, string) { + if validIpAddr(h.connectAddress) { + return h.connectAddress, "connect_address" + } else if validIpAddr(h.rpcAddress) { + return h.rpcAddress, "rpc_adress" + } else if validIpAddr(h.preferredIP) { + // where does perferred_ip get set? + return h.preferredIP, "preferred_ip" + } else if validIpAddr(h.broadcastAddress) { + return h.broadcastAddress, "broadcast_address" + } else if validIpAddr(h.peer) { + return h.peer, "peer" + } + return net.IPv4zero, "invalid" +} + +// Returns the address that should be used to connect to the host. +// If you wish to override this, use an AddressTranslator or +// use a HostFilter to SetConnectAddress() +func (h *HostInfo) ConnectAddress() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + + if addr, _ := h.connectAddressLocked(); validIpAddr(addr) { + return addr + } + panic(fmt.Sprintf("no valid connect address for host: %v. Is your cluster configured correctly?", h)) +} + +func (h *HostInfo) SetConnectAddress(address net.IP) *HostInfo { + // TODO(zariel): should this not be exported? + h.mu.Lock() + defer h.mu.Unlock() + h.connectAddress = address + return h +} + +func (h *HostInfo) BroadcastAddress() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + return h.broadcastAddress +} + +func (h *HostInfo) ListenAddress() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + return h.listenAddress +} + +func (h *HostInfo) RPCAddress() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + return h.rpcAddress +} + +func (h *HostInfo) PreferredIP() net.IP { + h.mu.RLock() + defer h.mu.RUnlock() + return h.preferredIP +} + +func (h *HostInfo) DataCenter() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.dataCenter +} + +func (h *HostInfo) setDataCenter(dataCenter string) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.dataCenter = dataCenter + return h +} + +func (h *HostInfo) Rack() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.rack +} + +func (h *HostInfo) setRack(rack string) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.rack = rack + return h +} + +func (h *HostInfo) HostID() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.hostId +} + +func (h *HostInfo) setHostID(hostID string) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.hostId = hostID + return h +} + +func (h *HostInfo) WorkLoad() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.workload +} + +func (h *HostInfo) Graph() bool { + h.mu.RLock() + defer h.mu.RUnlock() + return h.graph +} + +func (h *HostInfo) DSEVersion() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.dseVersion +} + +func (h *HostInfo) Partitioner() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.partitioner +} + +func (h *HostInfo) ClusterName() string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.clusterName +} + +func (h *HostInfo) Version() cassVersion { + h.mu.RLock() + defer h.mu.RUnlock() + return h.version +} + +func (h *HostInfo) setVersion(major, minor, patch int) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.version = cassVersion{major, minor, patch} + return h +} + +func (h *HostInfo) State() nodeState { + h.mu.RLock() + defer h.mu.RUnlock() + return h.state +} + +func (h *HostInfo) setState(state nodeState) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.state = state + return h +} + +func (h *HostInfo) Tokens() []string { + h.mu.RLock() + defer h.mu.RUnlock() + return h.tokens +} + +func (h *HostInfo) setTokens(tokens []string) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.tokens = tokens + return h +} + +func (h *HostInfo) Port() int { + h.mu.RLock() + defer h.mu.RUnlock() + return h.port +} + +func (h *HostInfo) setPort(port int) *HostInfo { + h.mu.Lock() + defer h.mu.Unlock() + h.port = port + return h +} + +func (h *HostInfo) update(from *HostInfo) { + if h == from { + return + } + + h.mu.Lock() + defer h.mu.Unlock() + + from.mu.RLock() + defer from.mu.RUnlock() + + // autogenerated do not update + if h.peer == nil { + h.peer = from.peer + } + if h.broadcastAddress == nil { + h.broadcastAddress = from.broadcastAddress + } + if h.listenAddress == nil { + h.listenAddress = from.listenAddress + } + if h.rpcAddress == nil { + h.rpcAddress = from.rpcAddress + } + if h.preferredIP == nil { + h.preferredIP = from.preferredIP + } + if h.connectAddress == nil { + h.connectAddress = from.connectAddress + } + if h.port == 0 { + h.port = from.port + } + if h.dataCenter == "" { + h.dataCenter = from.dataCenter + } + if h.rack == "" { + h.rack = from.rack + } + if h.hostId == "" { + h.hostId = from.hostId + } + if h.workload == "" { + h.workload = from.workload + } + if h.dseVersion == "" { + h.dseVersion = from.dseVersion + } + if h.partitioner == "" { + h.partitioner = from.partitioner + } + if h.clusterName == "" { + h.clusterName = from.clusterName + } + if h.version == (cassVersion{}) { + h.version = from.version + } + if h.tokens == nil { + h.tokens = from.tokens + } +} + +func (h *HostInfo) IsUp() bool { + return h != nil && h.State() == NodeUp +} + +func (h *HostInfo) String() string { + h.mu.RLock() + defer h.mu.RUnlock() + + connectAddr, source := h.connectAddressLocked() + return fmt.Sprintf("[HostInfo connectAddress=%q peer=%q rpc_address=%q broadcast_address=%q "+ + "preferred_ip=%q connect_addr=%q connect_addr_source=%q "+ + "port=%d data_centre=%q rack=%q host_id=%q version=%q state=%s num_tokens=%d]", + h.connectAddress, h.peer, h.rpcAddress, h.broadcastAddress, h.preferredIP, + connectAddr, source, + h.port, h.dataCenter, h.rack, h.hostId, h.version, h.state, len(h.tokens)) +} + +// Polls system.peers at a specific interval to find new hosts +type ringDescriber struct { + session *Session + mu sync.Mutex + prevHosts []*HostInfo + prevPartitioner string +} + +// Returns true if we are using system_schema.keyspaces instead of system.schema_keyspaces +func checkSystemSchema(control *controlConn) (bool, error) { + iter := control.query("SELECT * FROM system_schema.keyspaces") + if err := iter.err; err != nil { + if errf, ok := err.(*errorFrame); ok { + if errf.code == errSyntax { + return false, nil + } + } + + return false, err + } + + return true, nil +} + +// Given a map that represents a row from either system.local or system.peers +// return as much information as we can in *HostInfo +func (s *Session) hostInfoFromMap(row map[string]interface{}, port int) (*HostInfo, error) { + const assertErrorMsg = "Assertion failed for %s" + var ok bool + + // Default to our connected port if the cluster doesn't have port information + host := HostInfo{ + port: port, + } + + for key, value := range row { + switch key { + case "data_center": + host.dataCenter, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "data_center") + } + case "rack": + host.rack, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "rack") + } + case "host_id": + hostId, ok := value.(UUID) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "host_id") + } + host.hostId = hostId.String() + case "release_version": + version, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "release_version") + } + host.version.Set(version) + case "peer": + ip, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "peer") + } + host.peer = net.ParseIP(ip) + case "cluster_name": + host.clusterName, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "cluster_name") + } + case "partitioner": + host.partitioner, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "partitioner") + } + case "broadcast_address": + ip, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "broadcast_address") + } + host.broadcastAddress = net.ParseIP(ip) + case "preferred_ip": + ip, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "preferred_ip") + } + host.preferredIP = net.ParseIP(ip) + case "rpc_address": + ip, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "rpc_address") + } + host.rpcAddress = net.ParseIP(ip) + case "listen_address": + ip, ok := value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "listen_address") + } + host.listenAddress = net.ParseIP(ip) + case "workload": + host.workload, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "workload") + } + case "graph": + host.graph, ok = value.(bool) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "graph") + } + case "tokens": + host.tokens, ok = value.([]string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "tokens") + } + case "dse_version": + host.dseVersion, ok = value.(string) + if !ok { + return nil, fmt.Errorf(assertErrorMsg, "dse_version") + } + } + // TODO(thrawn01): Add 'port'? once CASSANDRA-7544 is complete + // Not sure what the port field will be called until the JIRA issue is complete + } + + ip, port := s.cfg.translateAddressPort(host.ConnectAddress(), host.port) + host.connectAddress = ip + host.port = port + + return &host, nil +} + +// Ask the control node for host info on all it's known peers +func (r *ringDescriber) getClusterPeerInfo() ([]*HostInfo, error) { + var hosts []*HostInfo + iter := r.session.control.withConnHost(func(ch *connHost) *Iter { + hosts = append(hosts, ch.host) + return ch.conn.query("SELECT * FROM system.peers") + }) + + if iter == nil { + return nil, errNoControl + } + + rows, err := iter.SliceMap() + if err != nil { + // TODO(zariel): make typed error + return nil, fmt.Errorf("unable to fetch peer host info: %s", err) + } + + for _, row := range rows { + // extract all available info about the peer + host, err := r.session.hostInfoFromMap(row, r.session.cfg.Port) + if err != nil { + return nil, err + } else if !isValidPeer(host) { + // If it's not a valid peer + Logger.Printf("Found invalid peer '%s' "+ + "Likely due to a gossip or snitch issue, this host will be ignored", host) + continue + } + + hosts = append(hosts, host) + } + + return hosts, nil +} + +// Return true if the host is a valid peer +func isValidPeer(host *HostInfo) bool { + return !(len(host.RPCAddress()) == 0 || + host.hostId == "" || + host.dataCenter == "" || + host.rack == "" || + len(host.tokens) == 0) +} + +// Return a list of hosts the cluster knows about +func (r *ringDescriber) GetHosts() ([]*HostInfo, string, error) { + r.mu.Lock() + defer r.mu.Unlock() + + hosts, err := r.getClusterPeerInfo() + if err != nil { + return r.prevHosts, r.prevPartitioner, err + } + + var partitioner string + if len(hosts) > 0 { + partitioner = hosts[0].Partitioner() + } + + return hosts, partitioner, nil +} + +// Given an ip/port return HostInfo for the specified ip/port +func (r *ringDescriber) getHostInfo(ip net.IP, port int) (*HostInfo, error) { + var host *HostInfo + iter := r.session.control.withConnHost(func(ch *connHost) *Iter { + if ch.host.ConnectAddress().Equal(ip) { + host = ch.host + return nil + } + + return ch.conn.query("SELECT * FROM system.peers") + }) + + if iter != nil { + rows, err := iter.SliceMap() + if err != nil { + return nil, err + } + + for _, row := range rows { + h, err := r.session.hostInfoFromMap(row, port) + if err != nil { + return nil, err + } + + if h.ConnectAddress().Equal(ip) { + host = h + break + } + } + + if host == nil { + return nil, errors.New("host not found in peers table") + } + } + + if host == nil { + return nil, errors.New("unable to fetch host info: invalid control connection") + } else if host.invalidConnectAddr() { + return nil, fmt.Errorf("host ConnectAddress invalid ip=%v: %v", ip, host) + } + + return host, nil +} + +func (r *ringDescriber) refreshRing() error { + // if we have 0 hosts this will return the previous list of hosts to + // attempt to reconnect to the cluster otherwise we would never find + // downed hosts again, could possibly have an optimisation to only + // try to add new hosts if GetHosts didnt error and the hosts didnt change. + hosts, partitioner, err := r.GetHosts() + if err != nil { + return err + } + + prevHosts := r.session.ring.currentHosts() + + // TODO: move this to session + for _, h := range hosts { + if filter := r.session.cfg.HostFilter; filter != nil && !filter.Accept(h) { + continue + } + + if host, ok := r.session.ring.addHostIfMissing(h); !ok { + r.session.pool.addHost(h) + r.session.policy.AddHost(h) + } else { + host.update(h) + } + delete(prevHosts, h.ConnectAddress().String()) + } + + // TODO(zariel): it may be worth having a mutex covering the overall ring state + // in a session so that everything sees a consistent state. Becuase as is today + // events can come in and due to ordering an UP host could be removed from the cluster + for _, host := range prevHosts { + r.session.removeHost(host) + } + + r.session.metadata.setPartitioner(partitioner) + r.session.policy.SetPartitioner(partitioner) + return nil +} diff --git a/vendor/github.com/gocql/gocql/host_source_gen.go b/vendor/github.com/gocql/gocql/host_source_gen.go new file mode 100644 index 0000000..c82193c --- /dev/null +++ b/vendor/github.com/gocql/gocql/host_source_gen.go @@ -0,0 +1,45 @@ +// +build genhostinfo + +package main + +import ( + "fmt" + "reflect" + "sync" + + "github.com/gocql/gocql" +) + +func gen(clause, field string) { + fmt.Printf("if h.%s == %s {\n", field, clause) + fmt.Printf("\th.%s = from.%s\n", field, field) + fmt.Println("}") +} + +func main() { + t := reflect.ValueOf(&gocql.HostInfo{}).Elem().Type() + mu := reflect.TypeOf(sync.RWMutex{}) + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type == mu { + continue + } + + switch f.Type.Kind() { + case reflect.Slice: + gen("nil", f.Name) + case reflect.String: + gen(`""`, f.Name) + case reflect.Int: + gen("0", f.Name) + case reflect.Struct: + gen("("+f.Type.Name()+"{})", f.Name) + case reflect.Bool, reflect.Int32: + continue + default: + panic(fmt.Sprintf("unknown field: %s", f)) + } + } + +} diff --git a/vendor/github.com/gocql/gocql/install_test_deps.sh b/vendor/github.com/gocql/gocql/install_test_deps.sh new file mode 100755 index 0000000..77fac8d --- /dev/null +++ b/vendor/github.com/gocql/gocql/install_test_deps.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# This is not supposed to be an error-prone script; just a convenience. + +# Install CCM +pip install --user cql PyYAML six +git clone https://github.com/pcmanus/ccm.git +pushd ccm +./setup.py install --user +popd + +if [ "$1" != "gocql/gocql" ]; then + USER=$(echo $1 | cut -f1 -d'/') + cd ../.. + mv ${USER} gocql +fi diff --git a/vendor/github.com/gocql/gocql/integration.sh b/vendor/github.com/gocql/gocql/integration.sh new file mode 100755 index 0000000..0a614c8 --- /dev/null +++ b/vendor/github.com/gocql/gocql/integration.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +set -eux + +function run_tests() { + local clusterSize=3 + local version=$1 + local auth=$2 + + if [ "$auth" = true ]; then + clusterSize=1 + fi + + local keypath="$(pwd)/testdata/pki" + + local conf=( + "client_encryption_options.enabled: true" + "client_encryption_options.keystore: $keypath/.keystore" + "client_encryption_options.keystore_password: cassandra" + "client_encryption_options.require_client_auth: true" + "client_encryption_options.truststore: $keypath/.truststore" + "client_encryption_options.truststore_password: cassandra" + "concurrent_reads: 2" + "concurrent_writes: 2" + "rpc_server_type: sync" + "rpc_min_threads: 2" + "rpc_max_threads: 2" + "write_request_timeout_in_ms: 5000" + "read_request_timeout_in_ms: 5000" + ) + + ccm remove test || true + + ccm create test -v $version -n $clusterSize -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" + ccm updateconf "${conf[@]}" + + if [ "$auth" = true ] + then + ccm updateconf 'authenticator: PasswordAuthenticator' 'authorizer: CassandraAuthorizer' + rm -rf $HOME/.ccm/test/node1/data/system_auth + fi + + local proto=2 + if [[ $version == 1.2.* ]]; then + proto=1 + elif [[ $version == 2.0.* ]]; then + proto=2 + elif [[ $version == 2.1.* ]]; then + proto=3 + elif [[ $version == 2.2.* || $version == 3.0.* ]]; then + proto=4 + ccm updateconf 'enable_user_defined_functions: true' + elif [[ $version == 3.*.* ]]; then + proto=4 + ccm updateconf 'enable_user_defined_functions: true' + fi + + sleep 1s + + ccm list + ccm start --wait-for-binary-proto + ccm status + ccm node1 nodetool status + + local args="-gocql.timeout=60s -runssl -proto=$proto -rf=3 -clusterSize=$clusterSize -autowait=2000ms -compressor=snappy -gocql.cversion=$version -cluster=$(ccm liveset) ./..." + + go test -v -tags unit -race + + if [ "$auth" = true ] + then + sleep 30s + go test -run=TestAuthentication -tags "integration gocql_debug" -timeout=15s -runauth $args + else + sleep 1s + go test -tags "integration gocql_debug" -timeout=5m -race $args + + ccm clear + ccm start + sleep 1s + + go test -tags "ccm gocql_debug" -timeout=5m -race $args + fi + + ccm remove +} + +run_tests $1 $2 diff --git a/vendor/github.com/gocql/gocql/internal/lru/lru.go b/vendor/github.com/gocql/gocql/internal/lru/lru.go new file mode 100644 index 0000000..14ca1f4 --- /dev/null +++ b/vendor/github.com/gocql/gocql/internal/lru/lru.go @@ -0,0 +1,127 @@ +/* +Copyright 2015 To gocql authors +Copyright 2013 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package lru implements an LRU cache. +package lru + +import "container/list" + +// Cache is an LRU cache. It is not safe for concurrent access. +// +// This cache has been forked from github.com/golang/groupcache/lru, but +// specialized with string keys to avoid the allocations caused by wrapping them +// in interface{}. +type Cache struct { + // MaxEntries is the maximum number of cache entries before + // an item is evicted. Zero means no limit. + MaxEntries int + + // OnEvicted optionally specifies a callback function to be + // executed when an entry is purged from the cache. + OnEvicted func(key string, value interface{}) + + ll *list.List + cache map[string]*list.Element +} + +type entry struct { + key string + value interface{} +} + +// New creates a new Cache. +// If maxEntries is zero, the cache has no limit and it's assumed +// that eviction is done by the caller. +func New(maxEntries int) *Cache { + return &Cache{ + MaxEntries: maxEntries, + ll: list.New(), + cache: make(map[string]*list.Element), + } +} + +// Add adds a value to the cache. +func (c *Cache) Add(key string, value interface{}) { + if c.cache == nil { + c.cache = make(map[string]*list.Element) + c.ll = list.New() + } + if ee, ok := c.cache[key]; ok { + c.ll.MoveToFront(ee) + ee.Value.(*entry).value = value + return + } + ele := c.ll.PushFront(&entry{key, value}) + c.cache[key] = ele + if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { + c.RemoveOldest() + } +} + +// Get looks up a key's value from the cache. +func (c *Cache) Get(key string) (value interface{}, ok bool) { + if c.cache == nil { + return + } + if ele, hit := c.cache[key]; hit { + c.ll.MoveToFront(ele) + return ele.Value.(*entry).value, true + } + return +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key string) bool { + if c.cache == nil { + return false + } + + if ele, hit := c.cache[key]; hit { + c.removeElement(ele) + return true + } + + return false +} + +// RemoveOldest removes the oldest item from the cache. +func (c *Cache) RemoveOldest() { + if c.cache == nil { + return + } + ele := c.ll.Back() + if ele != nil { + c.removeElement(ele) + } +} + +func (c *Cache) removeElement(e *list.Element) { + c.ll.Remove(e) + kv := e.Value.(*entry) + delete(c.cache, kv.key) + if c.OnEvicted != nil { + c.OnEvicted(kv.key, kv.value) + } +} + +// Len returns the number of items in the cache. +func (c *Cache) Len() int { + if c.cache == nil { + return 0 + } + return c.ll.Len() +} diff --git a/vendor/github.com/gocql/gocql/internal/murmur/murmur.go b/vendor/github.com/gocql/gocql/internal/murmur/murmur.go new file mode 100644 index 0000000..d006cc0 --- /dev/null +++ b/vendor/github.com/gocql/gocql/internal/murmur/murmur.go @@ -0,0 +1,135 @@ +package murmur + +const ( + c1 int64 = -8663945395140668459 // 0x87c37b91114253d5 + c2 int64 = 5545529020109919103 // 0x4cf5ad432745937f + fmix1 int64 = -49064778989728563 // 0xff51afd7ed558ccd + fmix2 int64 = -4265267296055464877 // 0xc4ceb9fe1a85ec53 +) + +func fmix(n int64) int64 { + // cast to unsigned for logical right bitshift (to match C* MM3 implementation) + n ^= int64(uint64(n) >> 33) + n *= fmix1 + n ^= int64(uint64(n) >> 33) + n *= fmix2 + n ^= int64(uint64(n) >> 33) + + return n +} + +func block(p byte) int64 { + return int64(int8(p)) +} + +func rotl(x int64, r uint8) int64 { + // cast to unsigned for logical right bitshift (to match C* MM3 implementation) + return (x << r) | (int64)((uint64(x) >> (64 - r))) +} + +func Murmur3H1(data []byte) int64 { + length := len(data) + + var h1, h2, k1, k2 int64 + + // body + nBlocks := length / 16 + for i := 0; i < nBlocks; i++ { + k1, k2 = getBlock(data, i) + + k1 *= c1 + k1 = rotl(k1, 31) + k1 *= c2 + h1 ^= k1 + + h1 = rotl(h1, 27) + h1 += h2 + h1 = h1*5 + 0x52dce729 + + k2 *= c2 + k2 = rotl(k2, 33) + k2 *= c1 + h2 ^= k2 + + h2 = rotl(h2, 31) + h2 += h1 + h2 = h2*5 + 0x38495ab5 + } + + // tail + tail := data[nBlocks*16:] + k1 = 0 + k2 = 0 + switch length & 15 { + case 15: + k2 ^= block(tail[14]) << 48 + fallthrough + case 14: + k2 ^= block(tail[13]) << 40 + fallthrough + case 13: + k2 ^= block(tail[12]) << 32 + fallthrough + case 12: + k2 ^= block(tail[11]) << 24 + fallthrough + case 11: + k2 ^= block(tail[10]) << 16 + fallthrough + case 10: + k2 ^= block(tail[9]) << 8 + fallthrough + case 9: + k2 ^= block(tail[8]) + + k2 *= c2 + k2 = rotl(k2, 33) + k2 *= c1 + h2 ^= k2 + + fallthrough + case 8: + k1 ^= block(tail[7]) << 56 + fallthrough + case 7: + k1 ^= block(tail[6]) << 48 + fallthrough + case 6: + k1 ^= block(tail[5]) << 40 + fallthrough + case 5: + k1 ^= block(tail[4]) << 32 + fallthrough + case 4: + k1 ^= block(tail[3]) << 24 + fallthrough + case 3: + k1 ^= block(tail[2]) << 16 + fallthrough + case 2: + k1 ^= block(tail[1]) << 8 + fallthrough + case 1: + k1 ^= block(tail[0]) + + k1 *= c1 + k1 = rotl(k1, 31) + k1 *= c2 + h1 ^= k1 + } + + h1 ^= int64(length) + h2 ^= int64(length) + + h1 += h2 + h2 += h1 + + h1 = fmix(h1) + h2 = fmix(h2) + + h1 += h2 + // the following is extraneous since h2 is discarded + // h2 += h1 + + return h1 +} diff --git a/vendor/github.com/gocql/gocql/internal/murmur/murmur_appengine.go b/vendor/github.com/gocql/gocql/internal/murmur/murmur_appengine.go new file mode 100644 index 0000000..fd9ab5c --- /dev/null +++ b/vendor/github.com/gocql/gocql/internal/murmur/murmur_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package murmur + +import "encoding/binary" + +func getBlock(data []byte, n int) (int64, int64) { + k1 := binary.LittleEndian.Int64(data[n*16:]) + k2 := binary.LittleEndian.Int64(data[(n*16)+8:]) + return k1, k2 +} diff --git a/vendor/github.com/gocql/gocql/internal/murmur/murmur_unsafe.go b/vendor/github.com/gocql/gocql/internal/murmur/murmur_unsafe.go new file mode 100644 index 0000000..501537c --- /dev/null +++ b/vendor/github.com/gocql/gocql/internal/murmur/murmur_unsafe.go @@ -0,0 +1,15 @@ +// +build !appengine + +package murmur + +import ( + "unsafe" +) + +func getBlock(data []byte, n int) (int64, int64) { + block := (*[2]int64)(unsafe.Pointer(&data[n*16])) + + k1 := block[0] + k2 := block[1] + return k1, k2 +} diff --git a/vendor/github.com/gocql/gocql/internal/streams/streams.go b/vendor/github.com/gocql/gocql/internal/streams/streams.go new file mode 100644 index 0000000..ae1ea97 --- /dev/null +++ b/vendor/github.com/gocql/gocql/internal/streams/streams.go @@ -0,0 +1,140 @@ +package streams + +import ( + "math" + "strconv" + "sync/atomic" +) + +const bucketBits = 64 + +// IDGenerator tracks and allocates streams which are in use. +type IDGenerator struct { + NumStreams int + inuseStreams int32 + numBuckets uint32 + + // streams is a bitset where each bit represents a stream, a 1 implies in use + streams []uint64 + offset uint32 +} + +func New(protocol int) *IDGenerator { + maxStreams := 128 + if protocol > 2 { + maxStreams = 32768 + } + + buckets := maxStreams / 64 + // reserve stream 0 + streams := make([]uint64, buckets) + streams[0] = 1 << 63 + + return &IDGenerator{ + NumStreams: maxStreams, + streams: streams, + numBuckets: uint32(buckets), + offset: uint32(buckets) - 1, + } +} + +func streamFromBucket(bucket, streamInBucket int) int { + return (bucket * bucketBits) + streamInBucket +} + +func (s *IDGenerator) GetStream() (int, bool) { + // based closely on the java-driver stream ID generator + // avoid false sharing subsequent requests. + offset := atomic.LoadUint32(&s.offset) + for !atomic.CompareAndSwapUint32(&s.offset, offset, (offset+1)%s.numBuckets) { + offset = atomic.LoadUint32(&s.offset) + } + offset = (offset + 1) % s.numBuckets + + for i := uint32(0); i < s.numBuckets; i++ { + pos := int((i + offset) % s.numBuckets) + + bucket := atomic.LoadUint64(&s.streams[pos]) + if bucket == math.MaxUint64 { + // all streams in use + continue + } + + for j := 0; j < bucketBits; j++ { + mask := uint64(1 << streamOffset(j)) + for bucket&mask == 0 { + if atomic.CompareAndSwapUint64(&s.streams[pos], bucket, bucket|mask) { + atomic.AddInt32(&s.inuseStreams, 1) + return streamFromBucket(int(pos), j), true + } + bucket = atomic.LoadUint64(&s.streams[pos]) + } + } + } + + return 0, false +} + +func bitfmt(b uint64) string { + return strconv.FormatUint(b, 16) +} + +// returns the bucket offset of a given stream +func bucketOffset(i int) int { + return i / bucketBits +} + +func streamOffset(stream int) uint64 { + return bucketBits - uint64(stream%bucketBits) - 1 +} + +func isSet(bits uint64, stream int) bool { + return bits>>streamOffset(stream)&1 == 1 +} + +func (s *IDGenerator) isSet(stream int) bool { + bits := atomic.LoadUint64(&s.streams[bucketOffset(stream)]) + return isSet(bits, stream) +} + +func (s *IDGenerator) String() string { + size := s.numBuckets * (bucketBits + 1) + buf := make([]byte, 0, size) + for i := 0; i < int(s.numBuckets); i++ { + bits := atomic.LoadUint64(&s.streams[i]) + buf = append(buf, bitfmt(bits)...) + buf = append(buf, ' ') + } + return string(buf[:size-1 : size-1]) +} + +func (s *IDGenerator) Clear(stream int) (inuse bool) { + offset := bucketOffset(stream) + bucket := atomic.LoadUint64(&s.streams[offset]) + + mask := uint64(1) << streamOffset(stream) + if bucket&mask != mask { + // already cleared + return false + } + + for !atomic.CompareAndSwapUint64(&s.streams[offset], bucket, bucket & ^mask) { + bucket = atomic.LoadUint64(&s.streams[offset]) + if bucket&mask != mask { + // already cleared + return false + } + } + + // TODO: make this account for 0 stream being reserved + if atomic.AddInt32(&s.inuseStreams, -1) < 0 { + // TODO(zariel): remove this + panic("negative streams inuse") + } + + return true +} + +func (s *IDGenerator) Available() int { + return s.NumStreams - int(atomic.LoadInt32(&s.inuseStreams)) - 1 +} diff --git a/vendor/github.com/gocql/gocql/logger.go b/vendor/github.com/gocql/gocql/logger.go new file mode 100644 index 0000000..bd16d41 --- /dev/null +++ b/vendor/github.com/gocql/gocql/logger.go @@ -0,0 +1,30 @@ +package gocql + +import ( + "bytes" + "fmt" + "log" +) + +type StdLogger interface { + Print(v ...interface{}) + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} + +type testLogger struct { + capture bytes.Buffer +} + +func (l *testLogger) Print(v ...interface{}) { fmt.Fprint(&l.capture, v...) } +func (l *testLogger) Printf(format string, v ...interface{}) { fmt.Fprintf(&l.capture, format, v...) } +func (l *testLogger) Println(v ...interface{}) { fmt.Fprintln(&l.capture, v...) } +func (l *testLogger) String() string { return l.capture.String() } + +type defaultLogger struct{} + +func (l *defaultLogger) Print(v ...interface{}) { log.Print(v...) } +func (l *defaultLogger) Printf(format string, v ...interface{}) { log.Printf(format, v...) } +func (l *defaultLogger) Println(v ...interface{}) { log.Println(v...) } + +var Logger StdLogger = &defaultLogger{} diff --git a/vendor/github.com/gocql/gocql/marshal.go b/vendor/github.com/gocql/gocql/marshal.go new file mode 100644 index 0000000..fce258f --- /dev/null +++ b/vendor/github.com/gocql/gocql/marshal.go @@ -0,0 +1,2216 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "math" + "math/big" + "net" + "reflect" + "strconv" + "strings" + "time" + + "gopkg.in/inf.v0" +) + +var ( + bigOne = big.NewInt(1) + emptyValue reflect.Value +) + +var ( + ErrorUDTUnavailable = errors.New("UDT are not available on protocols less than 3, please update config") +) + +// Marshaler is the interface implemented by objects that can marshal +// themselves into values understood by Cassandra. +type Marshaler interface { + MarshalCQL(info TypeInfo) ([]byte, error) +} + +// Unmarshaler is the interface implemented by objects that can unmarshal +// a Cassandra specific description of themselves. +type Unmarshaler interface { + UnmarshalCQL(info TypeInfo, data []byte) error +} + +// Marshal returns the CQL encoding of the value for the Cassandra +// internal type described by the info parameter. +func Marshal(info TypeInfo, value interface{}) ([]byte, error) { + if info.Version() < protoVersion1 { + panic("protocol version not set") + } + + if valueRef := reflect.ValueOf(value); valueRef.Kind() == reflect.Ptr { + if valueRef.IsNil() { + return nil, nil + } else if v, ok := value.(Marshaler); ok { + return v.MarshalCQL(info) + } else { + return Marshal(info, valueRef.Elem().Interface()) + } + } + + if v, ok := value.(Marshaler); ok { + return v.MarshalCQL(info) + } + + switch info.Type() { + case TypeVarchar, TypeAscii, TypeBlob, TypeText: + return marshalVarchar(info, value) + case TypeBoolean: + return marshalBool(info, value) + case TypeTinyInt: + return marshalTinyInt(info, value) + case TypeSmallInt: + return marshalSmallInt(info, value) + case TypeInt: + return marshalInt(info, value) + case TypeBigInt, TypeCounter: + return marshalBigInt(info, value) + case TypeFloat: + return marshalFloat(info, value) + case TypeDouble: + return marshalDouble(info, value) + case TypeDecimal: + return marshalDecimal(info, value) + case TypeTimestamp, TypeTime: + return marshalTimestamp(info, value) + case TypeList, TypeSet: + return marshalList(info, value) + case TypeMap: + return marshalMap(info, value) + case TypeUUID, TypeTimeUUID: + return marshalUUID(info, value) + case TypeVarint: + return marshalVarint(info, value) + case TypeInet: + return marshalInet(info, value) + case TypeTuple: + return marshalTuple(info, value) + case TypeUDT: + return marshalUDT(info, value) + case TypeDate: + return marshalDate(info, value) + } + + // detect protocol 2 UDT + if strings.HasPrefix(info.Custom(), "org.apache.cassandra.db.marshal.UserType") && info.Version() < 3 { + return nil, ErrorUDTUnavailable + } + + // TODO(tux21b): add the remaining types + return nil, fmt.Errorf("can not marshal %T into %s", value, info) +} + +// Unmarshal parses the CQL encoded data based on the info parameter that +// describes the Cassandra internal data type and stores the result in the +// value pointed by value. +func Unmarshal(info TypeInfo, data []byte, value interface{}) error { + if v, ok := value.(Unmarshaler); ok { + return v.UnmarshalCQL(info, data) + } + + if isNullableValue(value) { + return unmarshalNullable(info, data, value) + } + + switch info.Type() { + case TypeVarchar, TypeAscii, TypeBlob, TypeText: + return unmarshalVarchar(info, data, value) + case TypeBoolean: + return unmarshalBool(info, data, value) + case TypeInt: + return unmarshalInt(info, data, value) + case TypeBigInt, TypeCounter: + return unmarshalBigInt(info, data, value) + case TypeVarint: + return unmarshalVarint(info, data, value) + case TypeSmallInt: + return unmarshalSmallInt(info, data, value) + case TypeTinyInt: + return unmarshalTinyInt(info, data, value) + case TypeFloat: + return unmarshalFloat(info, data, value) + case TypeDouble: + return unmarshalDouble(info, data, value) + case TypeDecimal: + return unmarshalDecimal(info, data, value) + case TypeTimestamp, TypeTime: + return unmarshalTimestamp(info, data, value) + case TypeList, TypeSet: + return unmarshalList(info, data, value) + case TypeMap: + return unmarshalMap(info, data, value) + case TypeTimeUUID: + return unmarshalTimeUUID(info, data, value) + case TypeUUID: + return unmarshalUUID(info, data, value) + case TypeInet: + return unmarshalInet(info, data, value) + case TypeTuple: + return unmarshalTuple(info, data, value) + case TypeUDT: + return unmarshalUDT(info, data, value) + case TypeDate: + return unmarshalDate(info, data, value) + } + + // detect protocol 2 UDT + if strings.HasPrefix(info.Custom(), "org.apache.cassandra.db.marshal.UserType") && info.Version() < 3 { + return ErrorUDTUnavailable + } + + // TODO(tux21b): add the remaining types + return fmt.Errorf("can not unmarshal %s into %T", info, value) +} + +func isNullableValue(value interface{}) bool { + v := reflect.ValueOf(value) + return v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Ptr +} + +func isNullData(info TypeInfo, data []byte) bool { + return data == nil +} + +func unmarshalNullable(info TypeInfo, data []byte, value interface{}) error { + valueRef := reflect.ValueOf(value) + + if isNullData(info, data) { + nilValue := reflect.Zero(valueRef.Type().Elem()) + valueRef.Elem().Set(nilValue) + return nil + } + + newValue := reflect.New(valueRef.Type().Elem().Elem()) + valueRef.Elem().Set(newValue) + return Unmarshal(info, data, newValue.Interface()) +} + +func marshalVarchar(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case string: + return []byte(v), nil + case []byte: + return v, nil + } + + if value == nil { + return nil, nil + } + + rv := reflect.ValueOf(value) + t := rv.Type() + k := t.Kind() + switch { + case k == reflect.String: + return []byte(rv.String()), nil + case k == reflect.Slice && t.Elem().Kind() == reflect.Uint8: + return rv.Bytes(), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalVarchar(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *string: + *v = string(data) + return nil + case *[]byte: + if data != nil { + *v = copyBytes(data) + } else { + *v = nil + } + return nil + } + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + t := rv.Type() + k := t.Kind() + switch { + case k == reflect.String: + rv.SetString(string(data)) + return nil + case k == reflect.Slice && t.Elem().Kind() == reflect.Uint8: + var dataCopy []byte + if data != nil { + dataCopy = make([]byte, len(data)) + copy(dataCopy, data) + } + rv.SetBytes(dataCopy) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func marshalSmallInt(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int16: + return encShort(v), nil + case uint16: + return encShort(int16(v)), nil + case int8: + return encShort(int16(v)), nil + case uint8: + return encShort(int16(v)), nil + case int: + if v > math.MaxInt16 || v < math.MinInt16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case int32: + if v > math.MaxInt16 || v < math.MinInt16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case int64: + if v > math.MaxInt16 || v < math.MinInt16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case uint: + if v > math.MaxUint16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case uint32: + if v > math.MaxUint16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case uint64: + if v > math.MaxUint16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case string: + n, err := strconv.ParseInt(v, 10, 16) + if err != nil { + return nil, marshalErrorf("can not marshal %T into %s: %v", value, info, err) + } + return encShort(int16(n)), nil + } + + if value == nil { + return nil, nil + } + + switch rv := reflect.ValueOf(value); rv.Type().Kind() { + case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: + v := rv.Int() + if v > math.MaxInt16 || v < math.MinInt16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: + v := rv.Uint() + if v > math.MaxUint16 { + return nil, marshalErrorf("marshal smallint: value %d out of range", v) + } + return encShort(int16(v)), nil + case reflect.Ptr: + if rv.IsNil() { + return nil, nil + } + } + + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func marshalTinyInt(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int8: + return []byte{byte(v)}, nil + case uint8: + return []byte{byte(v)}, nil + case int16: + if v > math.MaxInt8 || v < math.MinInt8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case uint16: + if v > math.MaxUint8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case int: + if v > math.MaxInt8 || v < math.MinInt8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case int32: + if v > math.MaxInt8 || v < math.MinInt8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case int64: + if v > math.MaxInt8 || v < math.MinInt8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case uint: + if v > math.MaxUint8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case uint32: + if v > math.MaxUint8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case uint64: + if v > math.MaxUint8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case string: + n, err := strconv.ParseInt(v, 10, 8) + if err != nil { + return nil, marshalErrorf("can not marshal %T into %s: %v", value, info, err) + } + return []byte{byte(n)}, nil + } + + if value == nil { + return nil, nil + } + + switch rv := reflect.ValueOf(value); rv.Type().Kind() { + case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: + v := rv.Int() + if v > math.MaxInt8 || v < math.MinInt8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: + v := rv.Uint() + if v > math.MaxUint8 { + return nil, marshalErrorf("marshal tinyint: value %d out of range", v) + } + return []byte{byte(v)}, nil + case reflect.Ptr: + if rv.IsNil() { + return nil, nil + } + } + + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func marshalInt(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int: + if v > math.MaxInt32 || v < math.MinInt32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case uint: + if v > math.MaxUint32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case int64: + if v > math.MaxInt32 || v < math.MinInt32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case uint64: + if v > math.MaxUint32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case int32: + return encInt(v), nil + case uint32: + return encInt(int32(v)), nil + case int16: + return encInt(int32(v)), nil + case uint16: + return encInt(int32(v)), nil + case int8: + return encInt(int32(v)), nil + case uint8: + return encInt(int32(v)), nil + case string: + i, err := strconv.ParseInt(v, 10, 32) + if err != nil { + return nil, marshalErrorf("can not marshal string to int: %s", err) + } + return encInt(int32(i)), nil + } + + if value == nil { + return nil, nil + } + + switch rv := reflect.ValueOf(value); rv.Type().Kind() { + case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: + v := rv.Int() + if v > math.MaxInt32 || v < math.MinInt32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: + v := rv.Uint() + if v > math.MaxInt32 { + return nil, marshalErrorf("marshal int: value %d out of range", v) + } + return encInt(int32(v)), nil + case reflect.Ptr: + if rv.IsNil() { + return nil, nil + } + } + + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func encInt(x int32) []byte { + return []byte{byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x)} +} + +func decInt(x []byte) int32 { + if len(x) != 4 { + return 0 + } + return int32(x[0])<<24 | int32(x[1])<<16 | int32(x[2])<<8 | int32(x[3]) +} + +func encShort(x int16) []byte { + p := make([]byte, 2) + p[0] = byte(x >> 8) + p[1] = byte(x) + return p +} + +func decShort(p []byte) int16 { + if len(p) != 2 { + return 0 + } + return int16(p[0])<<8 | int16(p[1]) +} + +func decTiny(p []byte) int8 { + if len(p) != 1 { + return 0 + } + return int8(p[0]) +} + +func marshalBigInt(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int: + return encBigInt(int64(v)), nil + case uint: + if uint64(v) > math.MaxInt64 { + return nil, marshalErrorf("marshal bigint: value %d out of range", v) + } + return encBigInt(int64(v)), nil + case int64: + return encBigInt(v), nil + case uint64: + return encBigInt(int64(v)), nil + case int32: + return encBigInt(int64(v)), nil + case uint32: + return encBigInt(int64(v)), nil + case int16: + return encBigInt(int64(v)), nil + case uint16: + return encBigInt(int64(v)), nil + case int8: + return encBigInt(int64(v)), nil + case uint8: + return encBigInt(int64(v)), nil + case big.Int: + return encBigInt2C(&v), nil + case string: + i, err := strconv.ParseInt(value.(string), 10, 64) + if err != nil { + return nil, marshalErrorf("can not marshal string to bigint: %s", err) + } + return encBigInt(i), nil + } + + if value == nil { + return nil, nil + } + + rv := reflect.ValueOf(value) + switch rv.Type().Kind() { + case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: + v := rv.Int() + return encBigInt(v), nil + case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: + v := rv.Uint() + if v > math.MaxInt64 { + return nil, marshalErrorf("marshal bigint: value %d out of range", v) + } + return encBigInt(int64(v)), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func encBigInt(x int64) []byte { + return []byte{byte(x >> 56), byte(x >> 48), byte(x >> 40), byte(x >> 32), + byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x)} +} + +func bytesToInt64(data []byte) (ret int64) { + for i := range data { + ret |= int64(data[i]) << (8 * uint(len(data)-i-1)) + } + return ret +} + +func bytesToUint64(data []byte) (ret uint64) { + for i := range data { + ret |= uint64(data[i]) << (8 * uint(len(data)-i-1)) + } + return ret +} + +func unmarshalBigInt(info TypeInfo, data []byte, value interface{}) error { + return unmarshalIntlike(info, decBigInt(data), data, value) +} + +func unmarshalInt(info TypeInfo, data []byte, value interface{}) error { + return unmarshalIntlike(info, int64(decInt(data)), data, value) +} + +func unmarshalSmallInt(info TypeInfo, data []byte, value interface{}) error { + return unmarshalIntlike(info, int64(decShort(data)), data, value) +} + +func unmarshalTinyInt(info TypeInfo, data []byte, value interface{}) error { + return unmarshalIntlike(info, int64(decTiny(data)), data, value) +} + +func unmarshalVarint(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case *big.Int: + return unmarshalIntlike(info, 0, data, value) + case *uint64: + if len(data) == 9 && data[0] == 0 { + *v = bytesToUint64(data[1:]) + return nil + } + } + + if len(data) > 8 { + return unmarshalErrorf("unmarshal int: varint value %v out of range for %T (use big.Int)", data, value) + } + + int64Val := bytesToInt64(data) + if len(data) > 0 && len(data) < 8 && data[0]&0x80 > 0 { + int64Val -= (1 << uint(len(data)*8)) + } + return unmarshalIntlike(info, int64Val, data, value) +} + +func marshalVarint(info TypeInfo, value interface{}) ([]byte, error) { + var ( + retBytes []byte + err error + ) + + switch v := value.(type) { + case unsetColumn: + return nil, nil + case uint64: + if v > uint64(math.MaxInt64) { + retBytes = make([]byte, 9) + binary.BigEndian.PutUint64(retBytes[1:], v) + } else { + retBytes = make([]byte, 8) + binary.BigEndian.PutUint64(retBytes, v) + } + default: + retBytes, err = marshalBigInt(info, value) + } + + if err == nil { + // trim down to most significant byte + i := 0 + for ; i < len(retBytes)-1; i++ { + b0 := retBytes[i] + if b0 != 0 && b0 != 0xFF { + break + } + + b1 := retBytes[i+1] + if b0 == 0 && b1 != 0 { + if b1&0x80 == 0 { + i++ + } + break + } + + if b0 == 0xFF && b1 != 0xFF { + if b1&0x80 > 0 { + i++ + } + break + } + } + retBytes = retBytes[i:] + } + + return retBytes, err +} + +func unmarshalIntlike(info TypeInfo, int64Val int64, data []byte, value interface{}) error { + switch v := value.(type) { + case *int: + if ^uint(0) == math.MaxUint32 && (int64Val < math.MinInt32 || int64Val > math.MaxInt32) { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + *v = int(int64Val) + return nil + case *uint: + unitVal := uint64(int64Val) + if ^uint(0) == math.MaxUint32 && unitVal > math.MaxUint32 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", unitVal, *v) + } + switch info.Type() { + case TypeInt: + *v = uint(unitVal) & 0xFFFFFFFF + case TypeSmallInt: + *v = uint(unitVal) & 0xFFFF + case TypeTinyInt: + *v = uint(unitVal) & 0xFF + default: + *v = uint(unitVal) + } + return nil + case *int64: + *v = int64Val + return nil + case *uint64: + switch info.Type() { + case TypeInt: + *v = uint64(int64Val) & 0xFFFFFFFF + case TypeSmallInt: + *v = uint64(int64Val) & 0xFFFF + case TypeTinyInt: + *v = uint64(int64Val) & 0xFF + default: + *v = uint64(int64Val) + } + return nil + case *int32: + if int64Val < math.MinInt32 || int64Val > math.MaxInt32 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + *v = int32(int64Val) + return nil + case *uint32: + if int64Val > math.MaxUint32 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + switch info.Type() { + case TypeSmallInt: + *v = uint32(int64Val) & 0xFFFF + case TypeTinyInt: + *v = uint32(int64Val) & 0xFF + default: + *v = uint32(int64Val) & 0xFFFFFFFF + } + return nil + case *int16: + if int64Val < math.MinInt16 || int64Val > math.MaxInt16 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + *v = int16(int64Val) + return nil + case *uint16: + if int64Val > math.MaxUint16 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + switch info.Type() { + case TypeTinyInt: + *v = uint16(int64Val) & 0xFF + default: + *v = uint16(int64Val) & 0xFFFF + } + return nil + case *int8: + if int64Val < math.MinInt8 || int64Val > math.MaxInt8 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + *v = int8(int64Val) + return nil + case *uint8: + if int64Val > math.MaxUint8 { + return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v) + } + *v = uint8(int64Val) & 0xFF + return nil + case *big.Int: + decBigInt2C(data, v) + return nil + case *string: + *v = strconv.FormatInt(int64Val, 10) + return nil + } + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + + switch rv.Type().Kind() { + case reflect.Int: + if ^uint(0) == math.MaxUint32 && (int64Val < math.MinInt32 || int64Val > math.MaxInt32) { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetInt(int64Val) + return nil + case reflect.Int64: + rv.SetInt(int64Val) + return nil + case reflect.Int32: + if int64Val < math.MinInt32 || int64Val > math.MaxInt32 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetInt(int64Val) + return nil + case reflect.Int16: + if int64Val < math.MinInt16 || int64Val > math.MaxInt16 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetInt(int64Val) + return nil + case reflect.Int8: + if int64Val < math.MinInt8 || int64Val > math.MaxInt8 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetInt(int64Val) + return nil + case reflect.Uint: + if int64Val < 0 || (^uint(0) == math.MaxUint32 && int64Val > math.MaxUint32) { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetUint(uint64(int64Val)) + return nil + case reflect.Uint64: + if int64Val < 0 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetUint(uint64(int64Val)) + return nil + case reflect.Uint32: + if int64Val < 0 || int64Val > math.MaxUint32 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetUint(uint64(int64Val)) + return nil + case reflect.Uint16: + if int64Val < 0 || int64Val > math.MaxUint16 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetUint(uint64(int64Val)) + return nil + case reflect.Uint8: + if int64Val < 0 || int64Val > math.MaxUint8 { + return unmarshalErrorf("unmarshal int: value %d out of range", int64Val) + } + rv.SetUint(uint64(int64Val)) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func decBigInt(data []byte) int64 { + if len(data) != 8 { + return 0 + } + return int64(data[0])<<56 | int64(data[1])<<48 | + int64(data[2])<<40 | int64(data[3])<<32 | + int64(data[4])<<24 | int64(data[5])<<16 | + int64(data[6])<<8 | int64(data[7]) +} + +func marshalBool(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case bool: + return encBool(v), nil + } + + if value == nil { + return nil, nil + } + + rv := reflect.ValueOf(value) + switch rv.Type().Kind() { + case reflect.Bool: + return encBool(rv.Bool()), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func encBool(v bool) []byte { + if v { + return []byte{1} + } + return []byte{0} +} + +func unmarshalBool(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *bool: + *v = decBool(data) + return nil + } + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + switch rv.Type().Kind() { + case reflect.Bool: + rv.SetBool(decBool(data)) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func decBool(v []byte) bool { + if len(v) == 0 { + return false + } + return v[0] != 0 +} + +func marshalFloat(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case float32: + return encInt(int32(math.Float32bits(v))), nil + } + + if value == nil { + return nil, nil + } + + rv := reflect.ValueOf(value) + switch rv.Type().Kind() { + case reflect.Float32: + return encInt(int32(math.Float32bits(float32(rv.Float())))), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalFloat(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *float32: + *v = math.Float32frombits(uint32(decInt(data))) + return nil + } + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + switch rv.Type().Kind() { + case reflect.Float32: + rv.SetFloat(float64(math.Float32frombits(uint32(decInt(data))))) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func marshalDouble(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case float64: + return encBigInt(int64(math.Float64bits(v))), nil + } + if value == nil { + return nil, nil + } + rv := reflect.ValueOf(value) + switch rv.Type().Kind() { + case reflect.Float64: + return encBigInt(int64(math.Float64bits(rv.Float()))), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalDouble(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *float64: + *v = math.Float64frombits(uint64(decBigInt(data))) + return nil + } + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + switch rv.Type().Kind() { + case reflect.Float64: + rv.SetFloat(math.Float64frombits(uint64(decBigInt(data)))) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func marshalDecimal(info TypeInfo, value interface{}) ([]byte, error) { + if value == nil { + return nil, nil + } + + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case inf.Dec: + unscaled := encBigInt2C(v.UnscaledBig()) + if unscaled == nil { + return nil, marshalErrorf("can not marshal %T into %s", value, info) + } + + buf := make([]byte, 4+len(unscaled)) + copy(buf[0:4], encInt(int32(v.Scale()))) + copy(buf[4:], unscaled) + return buf, nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalDecimal(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *inf.Dec: + scale := decInt(data[0:4]) + unscaled := decBigInt2C(data[4:], nil) + *v = *inf.NewDecBig(unscaled, inf.Scale(scale)) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +// decBigInt2C sets the value of n to the big-endian two's complement +// value stored in the given data. If data[0]&80 != 0, the number +// is negative. If data is empty, the result will be 0. +func decBigInt2C(data []byte, n *big.Int) *big.Int { + if n == nil { + n = new(big.Int) + } + n.SetBytes(data) + if len(data) > 0 && data[0]&0x80 > 0 { + n.Sub(n, new(big.Int).Lsh(bigOne, uint(len(data))*8)) + } + return n +} + +// encBigInt2C returns the big-endian two's complement +// form of n. +func encBigInt2C(n *big.Int) []byte { + switch n.Sign() { + case 0: + return []byte{0} + case 1: + b := n.Bytes() + if b[0]&0x80 > 0 { + b = append([]byte{0}, b...) + } + return b + case -1: + length := uint(n.BitLen()/8+1) * 8 + b := new(big.Int).Add(n, new(big.Int).Lsh(bigOne, length)).Bytes() + // When the most significant bit is on a byte + // boundary, we can get some extra significant + // bits, so strip them off when that happens. + if len(b) >= 2 && b[0] == 0xff && b[1]&0x80 != 0 { + b = b[1:] + } + return b + } + return nil +} + +func marshalTimestamp(info TypeInfo, value interface{}) ([]byte, error) { + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int64: + return encBigInt(v), nil + case time.Time: + if v.IsZero() { + return []byte{}, nil + } + x := int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6) + return encBigInt(x), nil + case time.Duration: + return encBigInt(v.Nanoseconds()), nil + } + + if value == nil { + return nil, nil + } + + rv := reflect.ValueOf(value) + switch rv.Type().Kind() { + case reflect.Int64: + return encBigInt(rv.Int()), nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalTimestamp(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *int64: + *v = decBigInt(data) + return nil + case *time.Time: + if len(data) == 0 { + *v = time.Time{} + return nil + } + x := decBigInt(data) + sec := x / 1000 + nsec := (x - sec*1000) * 1000000 + *v = time.Unix(sec, nsec).In(time.UTC) + return nil + case *time.Duration: + *v = time.Duration(decBigInt(data)) + } + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + switch rv.Type().Kind() { + case reflect.Int64: + rv.SetInt(decBigInt(data)) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func marshalDate(info TypeInfo, value interface{}) ([]byte, error) { + var timestamp int64 + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, nil + case int64: + timestamp = v + x := timestamp/86400000 + int64(1<<31) + return encInt(int32(x)), nil + case time.Time: + if v.IsZero() { + return []byte{}, nil + } + timestamp = int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6) + x := timestamp/86400000 + int64(1<<31) + return encInt(int32(x)), nil + case *time.Time: + if v.IsZero() { + return []byte{}, nil + } + timestamp = int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6) + x := timestamp/86400000 + int64(1<<31) + return encInt(int32(x)), nil + case string: + if v == "" { + return []byte{}, nil + } + t, err := time.Parse("2006-01-02", v) + if err != nil { + return nil, marshalErrorf("can not marshal %T into %s, date layout must be '2006-01-02'", value, info) + } + timestamp = int64(t.UTC().Unix()*1e3) + int64(t.UTC().Nanosecond()/1e6) + x := timestamp/86400000 + int64(1<<31) + return encInt(int32(x)), nil + } + + if value == nil { + return nil, nil + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalDate(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *time.Time: + if len(data) == 0 { + *v = time.Time{} + return nil + } + var origin uint32 = 1 << 31 + var current uint32 = binary.BigEndian.Uint32(data) + timestamp := (int64(current) - int64(origin)) * 86400000 + *v = time.Unix(0, timestamp*int64(time.Millisecond)).In(time.UTC) + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func writeCollectionSize(info CollectionType, n int, buf *bytes.Buffer) error { + if info.proto > protoVersion2 { + if n > math.MaxInt32 { + return marshalErrorf("marshal: collection too large") + } + + buf.WriteByte(byte(n >> 24)) + buf.WriteByte(byte(n >> 16)) + buf.WriteByte(byte(n >> 8)) + buf.WriteByte(byte(n)) + } else { + if n > math.MaxUint16 { + return marshalErrorf("marshal: collection too large") + } + + buf.WriteByte(byte(n >> 8)) + buf.WriteByte(byte(n)) + } + + return nil +} + +func marshalList(info TypeInfo, value interface{}) ([]byte, error) { + listInfo, ok := info.(CollectionType) + if !ok { + return nil, marshalErrorf("marshal: can not marshal non collection type into list") + } + + if value == nil { + return nil, nil + } else if _, ok := value.(unsetColumn); ok { + return nil, nil + } + + rv := reflect.ValueOf(value) + t := rv.Type() + k := t.Kind() + if k == reflect.Slice && rv.IsNil() { + return nil, nil + } + + switch k { + case reflect.Slice, reflect.Array: + buf := &bytes.Buffer{} + n := rv.Len() + + if err := writeCollectionSize(listInfo, n, buf); err != nil { + return nil, err + } + + for i := 0; i < n; i++ { + item, err := Marshal(listInfo.Elem, rv.Index(i).Interface()) + if err != nil { + return nil, err + } + if err := writeCollectionSize(listInfo, len(item), buf); err != nil { + return nil, err + } + buf.Write(item) + } + return buf.Bytes(), nil + case reflect.Map: + elem := t.Elem() + if elem.Kind() == reflect.Struct && elem.NumField() == 0 { + rkeys := rv.MapKeys() + keys := make([]interface{}, len(rkeys)) + for i := 0; i < len(keys); i++ { + keys[i] = rkeys[i].Interface() + } + return marshalList(listInfo, keys) + } + } + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func readCollectionSize(info CollectionType, data []byte) (size, read int) { + if info.proto > protoVersion2 { + size = int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + read = 4 + } else { + size = int(data[0])<<8 | int(data[1]) + read = 2 + } + return +} + +func unmarshalList(info TypeInfo, data []byte, value interface{}) error { + listInfo, ok := info.(CollectionType) + if !ok { + return unmarshalErrorf("unmarshal: can not unmarshal none collection type into list") + } + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + t := rv.Type() + k := t.Kind() + + switch k { + case reflect.Slice, reflect.Array: + if data == nil { + if k == reflect.Array { + return unmarshalErrorf("unmarshal list: can not store nil in array value") + } + if rv.IsNil() { + return nil + } + rv.Set(reflect.Zero(t)) + return nil + } + if len(data) < 2 { + return unmarshalErrorf("unmarshal list: unexpected eof") + } + n, p := readCollectionSize(listInfo, data) + data = data[p:] + if k == reflect.Array { + if rv.Len() != n { + return unmarshalErrorf("unmarshal list: array with wrong size") + } + } else { + rv.Set(reflect.MakeSlice(t, n, n)) + } + for i := 0; i < n; i++ { + if len(data) < 2 { + return unmarshalErrorf("unmarshal list: unexpected eof") + } + m, p := readCollectionSize(listInfo, data) + data = data[p:] + if err := Unmarshal(listInfo.Elem, data[:m], rv.Index(i).Addr().Interface()); err != nil { + return err + } + data = data[m:] + } + return nil + } + return unmarshalErrorf("can not unmarshal %s into %T", info, value) +} + +func marshalMap(info TypeInfo, value interface{}) ([]byte, error) { + mapInfo, ok := info.(CollectionType) + if !ok { + return nil, marshalErrorf("marshal: can not marshal none collection type into map") + } + + if value == nil { + return nil, nil + } else if _, ok := value.(unsetColumn); ok { + return nil, nil + } + + rv := reflect.ValueOf(value) + if rv.IsNil() { + return nil, nil + } + + t := rv.Type() + if t.Kind() != reflect.Map { + return nil, marshalErrorf("can not marshal %T into %s", value, info) + } + + buf := &bytes.Buffer{} + n := rv.Len() + + if err := writeCollectionSize(mapInfo, n, buf); err != nil { + return nil, err + } + + keys := rv.MapKeys() + for _, key := range keys { + item, err := Marshal(mapInfo.Key, key.Interface()) + if err != nil { + return nil, err + } + if err := writeCollectionSize(mapInfo, len(item), buf); err != nil { + return nil, err + } + buf.Write(item) + + item, err = Marshal(mapInfo.Elem, rv.MapIndex(key).Interface()) + if err != nil { + return nil, err + } + if err := writeCollectionSize(mapInfo, len(item), buf); err != nil { + return nil, err + } + buf.Write(item) + } + return buf.Bytes(), nil +} + +func unmarshalMap(info TypeInfo, data []byte, value interface{}) error { + mapInfo, ok := info.(CollectionType) + if !ok { + return unmarshalErrorf("unmarshal: can not unmarshal none collection type into map") + } + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + rv = rv.Elem() + t := rv.Type() + if t.Kind() != reflect.Map { + return unmarshalErrorf("can not unmarshal %s into %T", info, value) + } + if data == nil { + rv.Set(reflect.Zero(t)) + return nil + } + rv.Set(reflect.MakeMap(t)) + if len(data) < 2 { + return unmarshalErrorf("unmarshal map: unexpected eof") + } + n, p := readCollectionSize(mapInfo, data) + data = data[p:] + for i := 0; i < n; i++ { + if len(data) < 2 { + return unmarshalErrorf("unmarshal list: unexpected eof") + } + m, p := readCollectionSize(mapInfo, data) + data = data[p:] + key := reflect.New(t.Key()) + if err := Unmarshal(mapInfo.Key, data[:m], key.Interface()); err != nil { + return err + } + data = data[m:] + + m, p = readCollectionSize(mapInfo, data) + data = data[p:] + val := reflect.New(t.Elem()) + if err := Unmarshal(mapInfo.Elem, data[:m], val.Interface()); err != nil { + return err + } + data = data[m:] + + rv.SetMapIndex(key.Elem(), val.Elem()) + } + return nil +} + +func marshalUUID(info TypeInfo, value interface{}) ([]byte, error) { + switch val := value.(type) { + case unsetColumn: + return nil, nil + case UUID: + return val.Bytes(), nil + case []byte: + if len(val) != 16 { + return nil, marshalErrorf("can not marshal []byte %d bytes long into %s, must be exactly 16 bytes long", len(val), info) + } + return val, nil + case string: + b, err := ParseUUID(val) + if err != nil { + return nil, err + } + return b[:], nil + } + + if value == nil { + return nil, nil + } + + return nil, marshalErrorf("can not marshal %T into %s", value, info) +} + +func unmarshalUUID(info TypeInfo, data []byte, value interface{}) error { + if data == nil || len(data) == 0 { + switch v := value.(type) { + case *string: + *v = "" + case *[]byte: + *v = nil + case *UUID: + *v = UUID{} + default: + return unmarshalErrorf("can not unmarshal X %s into %T", info, value) + } + + return nil + } + + u, err := UUIDFromBytes(data) + if err != nil { + return unmarshalErrorf("Unable to parse UUID: %s", err) + } + + switch v := value.(type) { + case *string: + *v = u.String() + return nil + case *[]byte: + *v = u[:] + return nil + case *UUID: + *v = u + return nil + } + return unmarshalErrorf("can not unmarshal X %s into %T", info, value) +} + +func unmarshalTimeUUID(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *time.Time: + id, err := UUIDFromBytes(data) + if err != nil { + return err + } else if id.Version() != 1 { + return unmarshalErrorf("invalid timeuuid") + } + *v = id.Time() + return nil + default: + return unmarshalUUID(info, data, value) + } +} + +func marshalInet(info TypeInfo, value interface{}) ([]byte, error) { + // we return either the 4 or 16 byte representation of an + // ip address here otherwise the db value will be prefixed + // with the remaining byte values e.g. ::ffff:127.0.0.1 and not 127.0.0.1 + switch val := value.(type) { + case unsetColumn: + return nil, nil + case net.IP: + t := val.To4() + if t == nil { + return val.To16(), nil + } + return t, nil + case string: + b := net.ParseIP(val) + if b != nil { + t := b.To4() + if t == nil { + return b.To16(), nil + } + return t, nil + } + return nil, marshalErrorf("cannot marshal. invalid ip string %s", val) + } + + if value == nil { + return nil, nil + } + + return nil, marshalErrorf("cannot marshal %T into %s", value, info) +} + +func unmarshalInet(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case *net.IP: + if x := len(data); !(x == 4 || x == 16) { + return unmarshalErrorf("cannot unmarshal %s into %T: invalid sized IP: got %d bytes not 4 or 16", info, value, x) + } + buf := copyBytes(data) + ip := net.IP(buf) + if v4 := ip.To4(); v4 != nil { + *v = v4 + return nil + } + *v = ip + return nil + case *string: + if len(data) == 0 { + *v = "" + return nil + } + ip := net.IP(data) + if v4 := ip.To4(); v4 != nil { + *v = v4.String() + return nil + } + *v = ip.String() + return nil + } + return unmarshalErrorf("cannot unmarshal %s into %T", info, value) +} + +func marshalTuple(info TypeInfo, value interface{}) ([]byte, error) { + tuple := info.(TupleTypeInfo) + switch v := value.(type) { + case unsetColumn: + return nil, unmarshalErrorf("Invalid request: UnsetValue is unsupported for tuples") + case []interface{}: + if len(v) != len(tuple.Elems) { + return nil, unmarshalErrorf("cannont marshal tuple: wrong number of elements") + } + + var buf []byte + for i, elem := range v { + data, err := Marshal(tuple.Elems[i], elem) + if err != nil { + return nil, err + } + + n := len(data) + buf = appendInt(buf, int32(n)) + buf = append(buf, data...) + } + + return buf, nil + } + + rv := reflect.ValueOf(value) + t := rv.Type() + k := t.Kind() + + switch k { + case reflect.Struct: + if v := t.NumField(); v != len(tuple.Elems) { + return nil, marshalErrorf("can not marshal tuple into struct %v, not enough fields have %d need %d", t, v, len(tuple.Elems)) + } + + var buf []byte + for i, elem := range tuple.Elems { + data, err := Marshal(elem, rv.Field(i).Interface()) + if err != nil { + return nil, err + } + + n := len(data) + buf = appendInt(buf, int32(n)) + buf = append(buf, data...) + } + + return buf, nil + case reflect.Slice, reflect.Array: + size := rv.Len() + if size != len(tuple.Elems) { + return nil, marshalErrorf("can not marshal tuple into %v of length %d need %d elements", k, size, len(tuple.Elems)) + } + + var buf []byte + for i, elem := range tuple.Elems { + data, err := Marshal(elem, rv.Index(i).Interface()) + if err != nil { + return nil, err + } + + n := len(data) + buf = appendInt(buf, int32(n)) + buf = append(buf, data...) + } + + return buf, nil + } + + return nil, marshalErrorf("cannot marshal %T into %s", value, tuple) +} + +func readBytes(p []byte) ([]byte, []byte) { + // TODO: really should use a framer + size := readInt(p) + p = p[4:] + if size < 0 { + return nil, p + } + return p[:size], p[size:] +} + +// currently only support unmarshal into a list of values, this makes it possible +// to support tuples without changing the query API. In the future this can be extend +// to allow unmarshalling into custom tuple types. +func unmarshalTuple(info TypeInfo, data []byte, value interface{}) error { + if v, ok := value.(Unmarshaler); ok { + return v.UnmarshalCQL(info, data) + } + + tuple := info.(TupleTypeInfo) + switch v := value.(type) { + case []interface{}: + for i, elem := range tuple.Elems { + // each element inside data is a [bytes] + var p []byte + p, data = readBytes(data) + + err := Unmarshal(elem, p, v[i]) + if err != nil { + return err + } + } + + return nil + } + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + + rv = rv.Elem() + t := rv.Type() + k := t.Kind() + + switch k { + case reflect.Struct: + if v := t.NumField(); v != len(tuple.Elems) { + return unmarshalErrorf("can not unmarshal tuple into struct %v, not enough fields have %d need %d", t, v, len(tuple.Elems)) + } + + for i, elem := range tuple.Elems { + m := readInt(data) + data = data[4:] + + v := elem.New() + if err := Unmarshal(elem, data[:m], v); err != nil { + return err + } + rv.Field(i).Set(reflect.ValueOf(v).Elem()) + + data = data[m:] + } + + return nil + case reflect.Slice, reflect.Array: + if k == reflect.Array { + size := rv.Len() + if size != len(tuple.Elems) { + return unmarshalErrorf("can not unmarshal tuple into array of length %d need %d elements", size, len(tuple.Elems)) + } + } else { + rv.Set(reflect.MakeSlice(t, len(tuple.Elems), len(tuple.Elems))) + } + + for i, elem := range tuple.Elems { + m := readInt(data) + data = data[4:] + + v := elem.New() + if err := Unmarshal(elem, data[:m], v); err != nil { + return err + } + rv.Index(i).Set(reflect.ValueOf(v).Elem()) + + data = data[m:] + } + + return nil + } + + return unmarshalErrorf("cannot unmarshal %s into %T", info, value) +} + +// UDTMarshaler is an interface which should be implemented by users wishing to +// handle encoding UDT types to sent to Cassandra. Note: due to current implentations +// methods defined for this interface must be value receivers not pointer receivers. +type UDTMarshaler interface { + // MarshalUDT will be called for each field in the the UDT returned by Cassandra, + // the implementor should marshal the type to return by for example calling + // Marshal. + MarshalUDT(name string, info TypeInfo) ([]byte, error) +} + +// UDTUnmarshaler should be implemented by users wanting to implement custom +// UDT unmarshaling. +type UDTUnmarshaler interface { + // UnmarshalUDT will be called for each field in the UDT return by Cassandra, + // the implementor should unmarshal the data into the value of their chosing, + // for example by calling Unmarshal. + UnmarshalUDT(name string, info TypeInfo, data []byte) error +} + +func marshalUDT(info TypeInfo, value interface{}) ([]byte, error) { + udt := info.(UDTTypeInfo) + + switch v := value.(type) { + case Marshaler: + return v.MarshalCQL(info) + case unsetColumn: + return nil, unmarshalErrorf("Invalid request: UnsetValue is unsupported for user defined types") + case UDTMarshaler: + var buf []byte + for _, e := range udt.Elements { + data, err := v.MarshalUDT(e.Name, e.Type) + if err != nil { + return nil, err + } + + buf = appendBytes(buf, data) + } + + return buf, nil + case map[string]interface{}: + var buf []byte + for _, e := range udt.Elements { + val, ok := v[e.Name] + if !ok { + continue + } + + data, err := Marshal(e.Type, val) + if err != nil { + return nil, err + } + + buf = appendBytes(buf, data) + } + + return buf, nil + } + + k := reflect.ValueOf(value) + if k.Kind() == reflect.Ptr { + if k.IsNil() { + return nil, marshalErrorf("cannot marshal %T into %s", value, info) + } + k = k.Elem() + } + + if k.Kind() != reflect.Struct || !k.IsValid() { + return nil, marshalErrorf("cannot marshal %T into %s", value, info) + } + + fields := make(map[string]reflect.Value) + t := reflect.TypeOf(value) + for i := 0; i < t.NumField(); i++ { + sf := t.Field(i) + + if tag := sf.Tag.Get("cql"); tag != "" { + fields[tag] = k.Field(i) + } + } + + var buf []byte + for _, e := range udt.Elements { + f, ok := fields[e.Name] + if !ok { + f = k.FieldByName(e.Name) + } + + var data []byte + if f.IsValid() && f.CanInterface() { + var err error + data, err = Marshal(e.Type, f.Interface()) + if err != nil { + return nil, err + } + } + + buf = appendBytes(buf, data) + } + + return buf, nil +} + +func unmarshalUDT(info TypeInfo, data []byte, value interface{}) error { + switch v := value.(type) { + case Unmarshaler: + return v.UnmarshalCQL(info, data) + case UDTUnmarshaler: + udt := info.(UDTTypeInfo) + + for _, e := range udt.Elements { + if len(data) == 0 { + return nil + } + + var p []byte + p, data = readBytes(data) + + if err := v.UnmarshalUDT(e.Name, e.Type, p); err != nil { + return err + } + } + + return nil + case *map[string]interface{}: + udt := info.(UDTTypeInfo) + + rv := reflect.ValueOf(value) + if rv.Kind() != reflect.Ptr { + return unmarshalErrorf("can not unmarshal into non-pointer %T", value) + } + + rv = rv.Elem() + t := rv.Type() + if t.Kind() != reflect.Map { + return unmarshalErrorf("can not unmarshal %s into %T", info, value) + } else if data == nil { + rv.Set(reflect.Zero(t)) + return nil + } + + rv.Set(reflect.MakeMap(t)) + m := *v + + for _, e := range udt.Elements { + if len(data) == 0 { + return nil + } + + val := reflect.New(goType(e.Type)) + + var p []byte + p, data = readBytes(data) + + if err := Unmarshal(e.Type, p, val.Interface()); err != nil { + return err + } + + m[e.Name] = val.Elem().Interface() + } + + return nil + } + + k := reflect.ValueOf(value).Elem() + if k.Kind() != reflect.Struct || !k.IsValid() { + return unmarshalErrorf("cannot unmarshal %s into %T", info, value) + } + + if len(data) == 0 { + if k.CanSet() { + k.Set(reflect.Zero(k.Type())) + } + + return nil + } + + t := k.Type() + fields := make(map[string]reflect.Value, t.NumField()) + for i := 0; i < t.NumField(); i++ { + sf := t.Field(i) + + if tag := sf.Tag.Get("cql"); tag != "" { + fields[tag] = k.Field(i) + } + } + + udt := info.(UDTTypeInfo) + for _, e := range udt.Elements { + if len(data) < 4 { + // UDT def does not match the column value + return nil + } + + var p []byte + p, data = readBytes(data) + + f, ok := fields[e.Name] + if !ok { + f = k.FieldByName(e.Name) + if f == emptyValue { + // skip fields which exist in the UDT but not in + // the struct passed in + continue + } + } + + if !f.IsValid() || !f.CanAddr() { + return unmarshalErrorf("cannot unmarshal %s into %T: field %v is not valid", info, value, e.Name) + } + + fk := f.Addr().Interface() + if err := Unmarshal(e.Type, p, fk); err != nil { + return err + } + } + + return nil +} + +// TypeInfo describes a Cassandra specific data type. +type TypeInfo interface { + Type() Type + Version() byte + Custom() string + + // New creates a pointer to an empty version of whatever type + // is referenced by the TypeInfo receiver + New() interface{} +} + +type NativeType struct { + proto byte + typ Type + custom string // only used for TypeCustom +} + +func NewNativeType(proto byte, typ Type, custom string) NativeType { + return NativeType{proto, typ, custom} +} + +func (t NativeType) New() interface{} { + return reflect.New(goType(t)).Interface() +} + +func (s NativeType) Type() Type { + return s.typ +} + +func (s NativeType) Version() byte { + return s.proto +} + +func (s NativeType) Custom() string { + return s.custom +} + +func (s NativeType) String() string { + switch s.typ { + case TypeCustom: + return fmt.Sprintf("%s(%s)", s.typ, s.custom) + default: + return s.typ.String() + } +} + +type CollectionType struct { + NativeType + Key TypeInfo // only used for TypeMap + Elem TypeInfo // only used for TypeMap, TypeList and TypeSet +} + +func (t CollectionType) New() interface{} { + return reflect.New(goType(t)).Interface() +} + +func (c CollectionType) String() string { + switch c.typ { + case TypeMap: + return fmt.Sprintf("%s(%s, %s)", c.typ, c.Key, c.Elem) + case TypeList, TypeSet: + return fmt.Sprintf("%s(%s)", c.typ, c.Elem) + case TypeCustom: + return fmt.Sprintf("%s(%s)", c.typ, c.custom) + default: + return c.typ.String() + } +} + +type TupleTypeInfo struct { + NativeType + Elems []TypeInfo +} + +func (t TupleTypeInfo) String() string { + var buf bytes.Buffer + buf.WriteString(fmt.Sprintf("%s(", t.typ)) + for _, elem := range t.Elems { + buf.WriteString(fmt.Sprintf("%s, ", elem)) + } + buf.Truncate(buf.Len() - 2) + buf.WriteByte(')') + return buf.String() +} + +func (t TupleTypeInfo) New() interface{} { + return reflect.New(goType(t)).Interface() +} + +type UDTField struct { + Name string + Type TypeInfo +} + +type UDTTypeInfo struct { + NativeType + KeySpace string + Name string + Elements []UDTField +} + +func (u UDTTypeInfo) New() interface{} { + return reflect.New(goType(u)).Interface() +} + +func (u UDTTypeInfo) String() string { + buf := &bytes.Buffer{} + + fmt.Fprintf(buf, "%s.%s{", u.KeySpace, u.Name) + first := true + for _, e := range u.Elements { + if !first { + fmt.Fprint(buf, ",") + } else { + first = false + } + + fmt.Fprintf(buf, "%s=%v", e.Name, e.Type) + } + fmt.Fprint(buf, "}") + + return buf.String() +} + +// String returns a human readable name for the Cassandra datatype +// described by t. +// Type is the identifier of a Cassandra internal datatype. +type Type int + +const ( + TypeCustom Type = 0x0000 + TypeAscii Type = 0x0001 + TypeBigInt Type = 0x0002 + TypeBlob Type = 0x0003 + TypeBoolean Type = 0x0004 + TypeCounter Type = 0x0005 + TypeDecimal Type = 0x0006 + TypeDouble Type = 0x0007 + TypeFloat Type = 0x0008 + TypeInt Type = 0x0009 + TypeText Type = 0x000A + TypeTimestamp Type = 0x000B + TypeUUID Type = 0x000C + TypeVarchar Type = 0x000D + TypeVarint Type = 0x000E + TypeTimeUUID Type = 0x000F + TypeInet Type = 0x0010 + TypeDate Type = 0x0011 + TypeTime Type = 0x0012 + TypeSmallInt Type = 0x0013 + TypeTinyInt Type = 0x0014 + TypeList Type = 0x0020 + TypeMap Type = 0x0021 + TypeSet Type = 0x0022 + TypeUDT Type = 0x0030 + TypeTuple Type = 0x0031 +) + +// String returns the name of the identifier. +func (t Type) String() string { + switch t { + case TypeCustom: + return "custom" + case TypeAscii: + return "ascii" + case TypeBigInt: + return "bigint" + case TypeBlob: + return "blob" + case TypeBoolean: + return "boolean" + case TypeCounter: + return "counter" + case TypeDecimal: + return "decimal" + case TypeDouble: + return "double" + case TypeFloat: + return "float" + case TypeInt: + return "int" + case TypeText: + return "text" + case TypeTimestamp: + return "timestamp" + case TypeUUID: + return "uuid" + case TypeVarchar: + return "varchar" + case TypeTimeUUID: + return "timeuuid" + case TypeInet: + return "inet" + case TypeDate: + return "date" + case TypeTime: + return "time" + case TypeSmallInt: + return "smallint" + case TypeTinyInt: + return "tinyint" + case TypeList: + return "list" + case TypeMap: + return "map" + case TypeSet: + return "set" + case TypeVarint: + return "varint" + case TypeTuple: + return "tuple" + default: + return fmt.Sprintf("unknown_type_%d", t) + } +} + +type MarshalError string + +func (m MarshalError) Error() string { + return string(m) +} + +func marshalErrorf(format string, args ...interface{}) MarshalError { + return MarshalError(fmt.Sprintf(format, args...)) +} + +type UnmarshalError string + +func (m UnmarshalError) Error() string { + return string(m) +} + +func unmarshalErrorf(format string, args ...interface{}) UnmarshalError { + return UnmarshalError(fmt.Sprintf(format, args...)) +} diff --git a/vendor/github.com/gocql/gocql/metadata.go b/vendor/github.com/gocql/gocql/metadata.go new file mode 100644 index 0000000..db496a6 --- /dev/null +++ b/vendor/github.com/gocql/gocql/metadata.go @@ -0,0 +1,1100 @@ +// Copyright (c) 2015 The gocql 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 gocql + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "strconv" + "strings" + "sync" +) + +// schema metadata for a keyspace +type KeyspaceMetadata struct { + Name string + DurableWrites bool + StrategyClass string + StrategyOptions map[string]interface{} + Tables map[string]*TableMetadata +} + +// schema metadata for a table (a.k.a. column family) +type TableMetadata struct { + Keyspace string + Name string + KeyValidator string + Comparator string + DefaultValidator string + KeyAliases []string + ColumnAliases []string + ValueAlias string + PartitionKey []*ColumnMetadata + ClusteringColumns []*ColumnMetadata + Columns map[string]*ColumnMetadata + OrderedColumns []string +} + +// schema metadata for a column +type ColumnMetadata struct { + Keyspace string + Table string + Name string + ComponentIndex int + Kind ColumnKind + Validator string + Type TypeInfo + ClusteringOrder string + Order ColumnOrder + Index ColumnIndexMetadata +} + +// the ordering of the column with regard to its comparator +type ColumnOrder bool + +const ( + ASC ColumnOrder = false + DESC = true +) + +type ColumnIndexMetadata struct { + Name string + Type string + Options map[string]interface{} +} + +type ColumnKind int + +const ( + ColumnUnkownKind ColumnKind = iota + ColumnPartitionKey + ColumnClusteringKey + ColumnRegular + ColumnCompact + ColumnStatic +) + +func (c ColumnKind) String() string { + switch c { + case ColumnPartitionKey: + return "partition_key" + case ColumnClusteringKey: + return "clustering_key" + case ColumnRegular: + return "regular" + case ColumnCompact: + return "compact" + case ColumnStatic: + return "static" + default: + return fmt.Sprintf("unknown_column_%d", c) + } +} + +func (c *ColumnKind) UnmarshalCQL(typ TypeInfo, p []byte) error { + if typ.Type() != TypeVarchar { + return unmarshalErrorf("unable to marshall %s into ColumnKind, expected Varchar", typ) + } + + kind, err := columnKindFromSchema(string(p)) + if err != nil { + return err + } + *c = kind + + return nil +} + +func columnKindFromSchema(kind string) (ColumnKind, error) { + switch kind { + case "partition_key": + return ColumnPartitionKey, nil + case "clustering_key", "clustering": + return ColumnClusteringKey, nil + case "regular": + return ColumnRegular, nil + case "compact_value": + return ColumnCompact, nil + case "static": + return ColumnStatic, nil + default: + return -1, fmt.Errorf("unknown column kind: %q", kind) + } +} + +// default alias values +const ( + DEFAULT_KEY_ALIAS = "key" + DEFAULT_COLUMN_ALIAS = "column" + DEFAULT_VALUE_ALIAS = "value" +) + +// queries the cluster for schema information for a specific keyspace +type schemaDescriber struct { + session *Session + mu sync.Mutex + + cache map[string]*KeyspaceMetadata +} + +// creates a session bound schema describer which will query and cache +// keyspace metadata +func newSchemaDescriber(session *Session) *schemaDescriber { + return &schemaDescriber{ + session: session, + cache: map[string]*KeyspaceMetadata{}, + } +} + +// returns the cached KeyspaceMetadata held by the describer for the named +// keyspace. +func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) { + s.mu.Lock() + defer s.mu.Unlock() + + metadata, found := s.cache[keyspaceName] + if !found { + // refresh the cache for this keyspace + err := s.refreshSchema(keyspaceName) + if err != nil { + return nil, err + } + + metadata = s.cache[keyspaceName] + } + + return metadata, nil +} + +// clears the already cached keyspace metadata +func (s *schemaDescriber) clearSchema(keyspaceName string) { + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.cache, keyspaceName) +} + +// forcibly updates the current KeyspaceMetadata held by the schema describer +// for a given named keyspace. +func (s *schemaDescriber) refreshSchema(keyspaceName string) error { + var err error + + // query the system keyspace for schema data + // TODO retrieve concurrently + keyspace, err := getKeyspaceMetadata(s.session, keyspaceName) + if err != nil { + return err + } + tables, err := getTableMetadata(s.session, keyspaceName) + if err != nil { + return err + } + columns, err := getColumnMetadata(s.session, keyspaceName) + if err != nil { + return err + } + + // organize the schema data + compileMetadata(s.session.cfg.ProtoVersion, keyspace, tables, columns) + + // update the cache + s.cache[keyspaceName] = keyspace + + return nil +} + +// "compiles" derived information about keyspace, table, and column metadata +// for a keyspace from the basic queried metadata objects returned by +// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively; +// Links the metadata objects together and derives the column composition of +// the partition key and clustering key for a table. +func compileMetadata( + protoVersion int, + keyspace *KeyspaceMetadata, + tables []TableMetadata, + columns []ColumnMetadata, +) { + keyspace.Tables = make(map[string]*TableMetadata) + for i := range tables { + tables[i].Columns = make(map[string]*ColumnMetadata) + + keyspace.Tables[tables[i].Name] = &tables[i] + } + + // add columns from the schema data + for i := range columns { + col := &columns[i] + // decode the validator for TypeInfo and order + if col.ClusteringOrder != "" { // Cassandra 3.x+ + col.Type = getCassandraType(col.Validator) + col.Order = ASC + if col.ClusteringOrder == "desc" { + col.Order = DESC + } + } else { + validatorParsed := parseType(col.Validator) + col.Type = validatorParsed.types[0] + col.Order = ASC + if validatorParsed.reversed[0] { + col.Order = DESC + } + } + + table, ok := keyspace.Tables[col.Table] + if !ok { + // if the schema is being updated we will race between seeing + // the metadata be complete. Potentially we should check for + // schema versions before and after reading the metadata and + // if they dont match try again. + continue + } + + table.Columns[col.Name] = col + table.OrderedColumns = append(table.OrderedColumns, col.Name) + } + + if protoVersion == protoVersion1 { + compileV1Metadata(tables) + } else { + compileV2Metadata(tables) + } +} + +// Compiles derived information from TableMetadata which have had +// ColumnMetadata added already. V1 protocol does not return as much +// column metadata as V2+ (because V1 doesn't support the "type" column in the +// system.schema_columns table) so determining PartitionKey and ClusterColumns +// is more complex. +func compileV1Metadata(tables []TableMetadata) { + for i := range tables { + table := &tables[i] + + // decode the key validator + keyValidatorParsed := parseType(table.KeyValidator) + // decode the comparator + comparatorParsed := parseType(table.Comparator) + + // the partition key length is the same as the number of types in the + // key validator + table.PartitionKey = make([]*ColumnMetadata, len(keyValidatorParsed.types)) + + // V1 protocol only returns "regular" columns from + // system.schema_columns (there is no type field for columns) + // so the alias information is used to + // create the partition key and clustering columns + + // construct the partition key from the alias + for i := range table.PartitionKey { + var alias string + if len(table.KeyAliases) > i { + alias = table.KeyAliases[i] + } else if i == 0 { + alias = DEFAULT_KEY_ALIAS + } else { + alias = DEFAULT_KEY_ALIAS + strconv.Itoa(i+1) + } + + column := &ColumnMetadata{ + Keyspace: table.Keyspace, + Table: table.Name, + Name: alias, + Type: keyValidatorParsed.types[i], + Kind: ColumnPartitionKey, + ComponentIndex: i, + } + + table.PartitionKey[i] = column + table.Columns[alias] = column + } + + // determine the number of clustering columns + size := len(comparatorParsed.types) + if comparatorParsed.isComposite { + if len(comparatorParsed.collections) != 0 || + (len(table.ColumnAliases) == size-1 && + comparatorParsed.types[size-1].Type() == TypeVarchar) { + size = size - 1 + } + } else { + if !(len(table.ColumnAliases) != 0 || len(table.Columns) == 0) { + size = 0 + } + } + + table.ClusteringColumns = make([]*ColumnMetadata, size) + + for i := range table.ClusteringColumns { + var alias string + if len(table.ColumnAliases) > i { + alias = table.ColumnAliases[i] + } else if i == 0 { + alias = DEFAULT_COLUMN_ALIAS + } else { + alias = DEFAULT_COLUMN_ALIAS + strconv.Itoa(i+1) + } + + order := ASC + if comparatorParsed.reversed[i] { + order = DESC + } + + column := &ColumnMetadata{ + Keyspace: table.Keyspace, + Table: table.Name, + Name: alias, + Type: comparatorParsed.types[i], + Order: order, + Kind: ColumnClusteringKey, + ComponentIndex: i, + } + + table.ClusteringColumns[i] = column + table.Columns[alias] = column + } + + if size != len(comparatorParsed.types)-1 { + alias := DEFAULT_VALUE_ALIAS + if len(table.ValueAlias) > 0 { + alias = table.ValueAlias + } + // decode the default validator + defaultValidatorParsed := parseType(table.DefaultValidator) + column := &ColumnMetadata{ + Keyspace: table.Keyspace, + Table: table.Name, + Name: alias, + Type: defaultValidatorParsed.types[0], + Kind: ColumnRegular, + } + table.Columns[alias] = column + } + } +} + +// The simpler compile case for V2+ protocol +func compileV2Metadata(tables []TableMetadata) { + for i := range tables { + table := &tables[i] + + clusteringColumnCount := componentColumnCountOfType(table.Columns, ColumnClusteringKey) + table.ClusteringColumns = make([]*ColumnMetadata, clusteringColumnCount) + + if table.KeyValidator != "" { + keyValidatorParsed := parseType(table.KeyValidator) + table.PartitionKey = make([]*ColumnMetadata, len(keyValidatorParsed.types)) + } else { // Cassandra 3.x+ + partitionKeyCount := componentColumnCountOfType(table.Columns, ColumnPartitionKey) + table.PartitionKey = make([]*ColumnMetadata, partitionKeyCount) + } + + for _, columnName := range table.OrderedColumns { + column := table.Columns[columnName] + if column.Kind == ColumnPartitionKey { + table.PartitionKey[column.ComponentIndex] = column + } else if column.Kind == ColumnClusteringKey { + table.ClusteringColumns[column.ComponentIndex] = column + } + } + } +} + +// returns the count of coluns with the given "kind" value. +func componentColumnCountOfType(columns map[string]*ColumnMetadata, kind ColumnKind) int { + maxComponentIndex := -1 + for _, column := range columns { + if column.Kind == kind && column.ComponentIndex > maxComponentIndex { + maxComponentIndex = column.ComponentIndex + } + } + return maxComponentIndex + 1 +} + +// query only for the keyspace metadata for the specified keyspace from system.schema_keyspace +func getKeyspaceMetadata(session *Session, keyspaceName string) (*KeyspaceMetadata, error) { + keyspace := &KeyspaceMetadata{Name: keyspaceName} + + if session.useSystemSchema { // Cassandra 3.x+ + const stmt = ` + SELECT durable_writes, replication + FROM system_schema.keyspaces + WHERE keyspace_name = ?` + + var replication map[string]string + + iter := session.control.query(stmt, keyspaceName) + if iter.NumRows() == 0 { + return nil, ErrKeyspaceDoesNotExist + } + iter.Scan(&keyspace.DurableWrites, &replication) + err := iter.Close() + if err != nil { + return nil, fmt.Errorf("Error querying keyspace schema: %v", err) + } + + keyspace.StrategyClass = replication["class"] + delete(replication, "class") + + keyspace.StrategyOptions = make(map[string]interface{}, len(replication)) + for k, v := range replication { + keyspace.StrategyOptions[k] = v + } + } else { + + const stmt = ` + SELECT durable_writes, strategy_class, strategy_options + FROM system.schema_keyspaces + WHERE keyspace_name = ?` + + var strategyOptionsJSON []byte + + iter := session.control.query(stmt, keyspaceName) + if iter.NumRows() == 0 { + return nil, ErrKeyspaceDoesNotExist + } + iter.Scan(&keyspace.DurableWrites, &keyspace.StrategyClass, &strategyOptionsJSON) + err := iter.Close() + if err != nil { + return nil, fmt.Errorf("Error querying keyspace schema: %v", err) + } + + err = json.Unmarshal(strategyOptionsJSON, &keyspace.StrategyOptions) + if err != nil { + return nil, fmt.Errorf( + "Invalid JSON value '%s' as strategy_options for in keyspace '%s': %v", + strategyOptionsJSON, keyspace.Name, err, + ) + } + } + + return keyspace, nil +} + +// query for only the table metadata in the specified keyspace from system.schema_columnfamilies +func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, error) { + + var ( + iter *Iter + scan func(iter *Iter, table *TableMetadata) bool + stmt string + + keyAliasesJSON []byte + columnAliasesJSON []byte + ) + + if session.useSystemSchema { // Cassandra 3.x+ + stmt = ` + SELECT + table_name + FROM system_schema.tables + WHERE keyspace_name = ?` + + switchIter := func() *Iter { + iter.Close() + stmt = ` + SELECT + view_name + FROM system_schema.views + WHERE keyspace_name = ?` + iter = session.control.query(stmt, keyspaceName) + return iter + } + + scan = func(iter *Iter, table *TableMetadata) bool { + r := iter.Scan( + &table.Name, + ) + if !r { + iter = switchIter() + if iter != nil { + switchIter = func() *Iter { return nil } + r = iter.Scan(&table.Name) + } + } + return r + } + } else if session.cfg.ProtoVersion == protoVersion1 { + // we have key aliases + stmt = ` + SELECT + columnfamily_name, + key_validator, + comparator, + default_validator, + key_aliases, + column_aliases, + value_alias + FROM system.schema_columnfamilies + WHERE keyspace_name = ?` + + scan = func(iter *Iter, table *TableMetadata) bool { + return iter.Scan( + &table.Name, + &table.KeyValidator, + &table.Comparator, + &table.DefaultValidator, + &keyAliasesJSON, + &columnAliasesJSON, + &table.ValueAlias, + ) + } + } else { + stmt = ` + SELECT + columnfamily_name, + key_validator, + comparator, + default_validator + FROM system.schema_columnfamilies + WHERE keyspace_name = ?` + + scan = func(iter *Iter, table *TableMetadata) bool { + return iter.Scan( + &table.Name, + &table.KeyValidator, + &table.Comparator, + &table.DefaultValidator, + ) + } + } + + iter = session.control.query(stmt, keyspaceName) + + tables := []TableMetadata{} + table := TableMetadata{Keyspace: keyspaceName} + + for scan(iter, &table) { + var err error + + // decode the key aliases + if keyAliasesJSON != nil { + table.KeyAliases = []string{} + err = json.Unmarshal(keyAliasesJSON, &table.KeyAliases) + if err != nil { + iter.Close() + return nil, fmt.Errorf( + "Invalid JSON value '%s' as key_aliases for in table '%s': %v", + keyAliasesJSON, table.Name, err, + ) + } + } + + // decode the column aliases + if columnAliasesJSON != nil { + table.ColumnAliases = []string{} + err = json.Unmarshal(columnAliasesJSON, &table.ColumnAliases) + if err != nil { + iter.Close() + return nil, fmt.Errorf( + "Invalid JSON value '%s' as column_aliases for in table '%s': %v", + columnAliasesJSON, table.Name, err, + ) + } + } + + tables = append(tables, table) + table = TableMetadata{Keyspace: keyspaceName} + } + + err := iter.Close() + if err != nil && err != ErrNotFound { + return nil, fmt.Errorf("Error querying table schema: %v", err) + } + + return tables, nil +} + +func (s *Session) scanColumnMetadataV1(keyspace string) ([]ColumnMetadata, error) { + // V1 does not support the type column, and all returned rows are + // of kind "regular". + const stmt = ` + SELECT + columnfamily_name, + column_name, + component_index, + validator, + index_name, + index_type, + index_options + FROM system.schema_columns + WHERE keyspace_name = ?` + + var columns []ColumnMetadata + + rows := s.control.query(stmt, keyspace).Scanner() + for rows.Next() { + var ( + column = ColumnMetadata{Keyspace: keyspace} + indexOptionsJSON []byte + ) + + // all columns returned by V1 are regular + column.Kind = ColumnRegular + + err := rows.Scan(&column.Table, + &column.Name, + &column.ComponentIndex, + &column.Validator, + &column.Index.Name, + &column.Index.Type, + &indexOptionsJSON) + + if err != nil { + return nil, err + } + + if len(indexOptionsJSON) > 0 { + err := json.Unmarshal(indexOptionsJSON, &column.Index.Options) + if err != nil { + return nil, fmt.Errorf( + "Invalid JSON value '%s' as index_options for column '%s' in table '%s': %v", + indexOptionsJSON, + column.Name, + column.Table, + err) + } + } + + columns = append(columns, column) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return columns, nil +} + +func (s *Session) scanColumnMetadataV2(keyspace string) ([]ColumnMetadata, error) { + // V2+ supports the type column + const stmt = ` + SELECT + columnfamily_name, + column_name, + component_index, + validator, + index_name, + index_type, + index_options, + type + FROM system.schema_columns + WHERE keyspace_name = ?` + + var columns []ColumnMetadata + + rows := s.control.query(stmt, keyspace).Scanner() + for rows.Next() { + var ( + column = ColumnMetadata{Keyspace: keyspace} + indexOptionsJSON []byte + ) + + err := rows.Scan(&column.Table, + &column.Name, + &column.ComponentIndex, + &column.Validator, + &column.Index.Name, + &column.Index.Type, + &indexOptionsJSON, + &column.Kind, + ) + + if err != nil { + return nil, err + } + + if len(indexOptionsJSON) > 0 { + err := json.Unmarshal(indexOptionsJSON, &column.Index.Options) + if err != nil { + return nil, fmt.Errorf( + "Invalid JSON value '%s' as index_options for column '%s' in table '%s': %v", + indexOptionsJSON, + column.Name, + column.Table, + err) + } + } + + columns = append(columns, column) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return columns, nil + +} + +func (s *Session) scanColumnMetadataSystem(keyspace string) ([]ColumnMetadata, error) { + const stmt = ` + SELECT + table_name, + column_name, + clustering_order, + type, + kind, + position + FROM system_schema.columns + WHERE keyspace_name = ?` + + var columns []ColumnMetadata + + rows := s.control.query(stmt, keyspace).Scanner() + for rows.Next() { + column := ColumnMetadata{Keyspace: keyspace} + + err := rows.Scan(&column.Table, + &column.Name, + &column.ClusteringOrder, + &column.Validator, + &column.Kind, + &column.ComponentIndex, + ) + + if err != nil { + return nil, err + } + + columns = append(columns, column) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + // TODO(zariel): get column index info from system_schema.indexes + + return columns, nil +} + +// query for only the column metadata in the specified keyspace from system.schema_columns +func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata, error) { + var ( + columns []ColumnMetadata + err error + ) + + // Deal with differences in protocol versions + if session.cfg.ProtoVersion == 1 { + columns, err = session.scanColumnMetadataV1(keyspaceName) + } else if session.useSystemSchema { // Cassandra 3.x+ + columns, err = session.scanColumnMetadataSystem(keyspaceName) + } else { + columns, err = session.scanColumnMetadataV2(keyspaceName) + } + + if err != nil && err != ErrNotFound { + return nil, fmt.Errorf("Error querying column schema: %v", err) + } + + return columns, nil +} + +// type definition parser state +type typeParser struct { + input string + index int +} + +// the type definition parser result +type typeParserResult struct { + isComposite bool + types []TypeInfo + reversed []bool + collections map[string]TypeInfo +} + +// Parse the type definition used for validator and comparator schema data +func parseType(def string) typeParserResult { + parser := &typeParser{input: def} + return parser.parse() +} + +const ( + REVERSED_TYPE = "org.apache.cassandra.db.marshal.ReversedType" + COMPOSITE_TYPE = "org.apache.cassandra.db.marshal.CompositeType" + COLLECTION_TYPE = "org.apache.cassandra.db.marshal.ColumnToCollectionType" + LIST_TYPE = "org.apache.cassandra.db.marshal.ListType" + SET_TYPE = "org.apache.cassandra.db.marshal.SetType" + MAP_TYPE = "org.apache.cassandra.db.marshal.MapType" +) + +// represents a class specification in the type def AST +type typeParserClassNode struct { + name string + params []typeParserParamNode + // this is the segment of the input string that defined this node + input string +} + +// represents a class parameter in the type def AST +type typeParserParamNode struct { + name *string + class typeParserClassNode +} + +func (t *typeParser) parse() typeParserResult { + // parse the AST + ast, ok := t.parseClassNode() + if !ok { + // treat this is a custom type + return typeParserResult{ + isComposite: false, + types: []TypeInfo{ + NativeType{ + typ: TypeCustom, + custom: t.input, + }, + }, + reversed: []bool{false}, + collections: nil, + } + } + + // interpret the AST + if strings.HasPrefix(ast.name, COMPOSITE_TYPE) { + count := len(ast.params) + + // look for a collections param + last := ast.params[count-1] + collections := map[string]TypeInfo{} + if strings.HasPrefix(last.class.name, COLLECTION_TYPE) { + count-- + + for _, param := range last.class.params { + // decode the name + var name string + decoded, err := hex.DecodeString(*param.name) + if err != nil { + Logger.Printf( + "Error parsing type '%s', contains collection name '%s' with an invalid format: %v", + t.input, + *param.name, + err, + ) + // just use the provided name + name = *param.name + } else { + name = string(decoded) + } + collections[name] = param.class.asTypeInfo() + } + } + + types := make([]TypeInfo, count) + reversed := make([]bool, count) + + for i, param := range ast.params[:count] { + class := param.class + reversed[i] = strings.HasPrefix(class.name, REVERSED_TYPE) + if reversed[i] { + class = class.params[0].class + } + types[i] = class.asTypeInfo() + } + + return typeParserResult{ + isComposite: true, + types: types, + reversed: reversed, + collections: collections, + } + } else { + // not composite, so one type + class := *ast + reversed := strings.HasPrefix(class.name, REVERSED_TYPE) + if reversed { + class = class.params[0].class + } + typeInfo := class.asTypeInfo() + + return typeParserResult{ + isComposite: false, + types: []TypeInfo{typeInfo}, + reversed: []bool{reversed}, + } + } +} + +func (class *typeParserClassNode) asTypeInfo() TypeInfo { + if strings.HasPrefix(class.name, LIST_TYPE) { + elem := class.params[0].class.asTypeInfo() + return CollectionType{ + NativeType: NativeType{ + typ: TypeList, + }, + Elem: elem, + } + } + if strings.HasPrefix(class.name, SET_TYPE) { + elem := class.params[0].class.asTypeInfo() + return CollectionType{ + NativeType: NativeType{ + typ: TypeSet, + }, + Elem: elem, + } + } + if strings.HasPrefix(class.name, MAP_TYPE) { + key := class.params[0].class.asTypeInfo() + elem := class.params[1].class.asTypeInfo() + return CollectionType{ + NativeType: NativeType{ + typ: TypeMap, + }, + Key: key, + Elem: elem, + } + } + + // must be a simple type or custom type + info := NativeType{typ: getApacheCassandraType(class.name)} + if info.typ == TypeCustom { + // add the entire class definition + info.custom = class.input + } + return info +} + +// CLASS := ID [ PARAMS ] +func (t *typeParser) parseClassNode() (node *typeParserClassNode, ok bool) { + t.skipWhitespace() + + startIndex := t.index + + name, ok := t.nextIdentifier() + if !ok { + return nil, false + } + + params, ok := t.parseParamNodes() + if !ok { + return nil, false + } + + endIndex := t.index + + node = &typeParserClassNode{ + name: name, + params: params, + input: t.input[startIndex:endIndex], + } + return node, true +} + +// PARAMS := "(" PARAM { "," PARAM } ")" +// PARAM := [ PARAM_NAME ":" ] CLASS +// PARAM_NAME := ID +func (t *typeParser) parseParamNodes() (params []typeParserParamNode, ok bool) { + t.skipWhitespace() + + // the params are optional + if t.index == len(t.input) || t.input[t.index] != '(' { + return nil, true + } + + params = []typeParserParamNode{} + + // consume the '(' + t.index++ + + t.skipWhitespace() + + for t.input[t.index] != ')' { + // look for a named param, but if no colon, then we want to backup + backupIndex := t.index + + // name will be a hex encoded version of a utf-8 string + name, ok := t.nextIdentifier() + if !ok { + return nil, false + } + hasName := true + + // TODO handle '=>' used for DynamicCompositeType + + t.skipWhitespace() + + if t.input[t.index] == ':' { + // there is a name for this parameter + + // consume the ':' + t.index++ + + t.skipWhitespace() + } else { + // no name, backup + hasName = false + t.index = backupIndex + } + + // parse the next full parameter + classNode, ok := t.parseClassNode() + if !ok { + return nil, false + } + + if hasName { + params = append( + params, + typeParserParamNode{name: &name, class: *classNode}, + ) + } else { + params = append( + params, + typeParserParamNode{class: *classNode}, + ) + } + + t.skipWhitespace() + + if t.input[t.index] == ',' { + // consume the comma + t.index++ + + t.skipWhitespace() + } + } + + // consume the ')' + t.index++ + + return params, true +} + +func (t *typeParser) skipWhitespace() { + for t.index < len(t.input) && isWhitespaceChar(t.input[t.index]) { + t.index++ + } +} + +func isWhitespaceChar(c byte) bool { + return c == ' ' || c == '\n' || c == '\t' +} + +// ID := LETTER { LETTER } +// LETTER := "0"..."9" | "a"..."z" | "A"..."Z" | "-" | "+" | "." | "_" | "&" +func (t *typeParser) nextIdentifier() (id string, found bool) { + startIndex := t.index + for t.index < len(t.input) && isIdentifierChar(t.input[t.index]) { + t.index++ + } + if startIndex == t.index { + return "", false + } + return t.input[startIndex:t.index], true +} + +func isIdentifierChar(c byte) bool { + return (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '-' || + c == '+' || + c == '.' || + c == '_' || + c == '&' +} diff --git a/vendor/github.com/gocql/gocql/policies.go b/vendor/github.com/gocql/gocql/policies.go new file mode 100644 index 0000000..5f074fe --- /dev/null +++ b/vendor/github.com/gocql/gocql/policies.go @@ -0,0 +1,854 @@ +// Copyright (c) 2012 The gocql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +//This file will be the future home for more policies +package gocql + +import ( + "fmt" + "math" + "math/rand" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/hailocab/go-hostpool" +) + +// cowHostList implements a copy on write host list, its equivalent type is []*HostInfo +type cowHostList struct { + list atomic.Value + mu sync.Mutex +} + +func (c *cowHostList) String() string { + return fmt.Sprintf("%+v", c.get()) +} + +func (c *cowHostList) get() []*HostInfo { + // TODO(zariel): should we replace this with []*HostInfo? + l, ok := c.list.Load().(*[]*HostInfo) + if !ok { + return nil + } + return *l +} + +func (c *cowHostList) set(list []*HostInfo) { + c.mu.Lock() + c.list.Store(&list) + c.mu.Unlock() +} + +// add will add a host if it not already in the list +func (c *cowHostList) add(host *HostInfo) bool { + c.mu.Lock() + l := c.get() + + if n := len(l); n == 0 { + l = []*HostInfo{host} + } else { + newL := make([]*HostInfo, n+1) + for i := 0; i < n; i++ { + if host.Equal(l[i]) { + c.mu.Unlock() + return false + } + newL[i] = l[i] + } + newL[n] = host + l = newL + } + + c.list.Store(&l) + c.mu.Unlock() + return true +} + +func (c *cowHostList) update(host *HostInfo) { + c.mu.Lock() + l := c.get() + + if len(l) == 0 { + c.mu.Unlock() + return + } + + found := false + newL := make([]*HostInfo, len(l)) + for i := range l { + if host.Equal(l[i]) { + newL[i] = host + found = true + } else { + newL[i] = l[i] + } + } + + if found { + c.list.Store(&newL) + } + + c.mu.Unlock() +} + +func (c *cowHostList) remove(ip net.IP) bool { + c.mu.Lock() + l := c.get() + size := len(l) + if size == 0 { + c.mu.Unlock() + return false + } + + found := false + newL := make([]*HostInfo, 0, size) + for i := 0; i < len(l); i++ { + if !l[i].ConnectAddress().Equal(ip) { + newL = append(newL, l[i]) + } else { + found = true + } + } + + if !found { + c.mu.Unlock() + return false + } + + newL = newL[:size-1 : size-1] + c.list.Store(&newL) + c.mu.Unlock() + + return true +} + +// RetryableQuery is an interface that represents a query or batch statement that +// exposes the correct functions for the retry policy logic to evaluate correctly. +type RetryableQuery interface { + Attempts() int + SetConsistency(c Consistency) + GetConsistency() Consistency +} + +type RetryType uint16 + +const ( + Retry RetryType = 0x00 // retry on same connection + RetryNextHost RetryType = 0x01 // retry on another connection + Ignore RetryType = 0x02 // ignore error and return result + Rethrow RetryType = 0x03 // raise error and stop retrying +) + +// RetryPolicy interface is used by gocql to determine if a query can be attempted +// again after a retryable error has been received. The interface allows gocql +// users to implement their own logic to determine if a query can be attempted +// again. +// +// See SimpleRetryPolicy as an example of implementing and using a RetryPolicy +// interface. +type RetryPolicy interface { + Attempt(RetryableQuery) bool + GetRetryType(error) RetryType +} + +// SimpleRetryPolicy has simple logic for attempting a query a fixed number of times. +// +// See below for examples of usage: +// +// //Assign to the cluster +// cluster.RetryPolicy = &gocql.SimpleRetryPolicy{NumRetries: 3} +// +// //Assign to a query +// query.RetryPolicy(&gocql.SimpleRetryPolicy{NumRetries: 1}) +// +type SimpleRetryPolicy struct { + NumRetries int //Number of times to retry a query +} + +// Attempt tells gocql to attempt the query again based on query.Attempts being less +// than the NumRetries defined in the policy. +func (s *SimpleRetryPolicy) Attempt(q RetryableQuery) bool { + return q.Attempts() <= s.NumRetries +} + +func (s *SimpleRetryPolicy) GetRetryType(err error) RetryType { + return RetryNextHost +} + +// ExponentialBackoffRetryPolicy sleeps between attempts +type ExponentialBackoffRetryPolicy struct { + NumRetries int + Min, Max time.Duration +} + +func (e *ExponentialBackoffRetryPolicy) Attempt(q RetryableQuery) bool { + if q.Attempts() > e.NumRetries { + return false + } + time.Sleep(e.napTime(q.Attempts())) + return true +} + +// used to calculate exponentially growing time +func getExponentialTime(min time.Duration, max time.Duration, attempts int) time.Duration { + if min <= 0 { + min = 100 * time.Millisecond + } + if max <= 0 { + max = 10 * time.Second + } + minFloat := float64(min) + napDuration := minFloat * math.Pow(2, float64(attempts-1)) + // add some jitter + napDuration += rand.Float64()*minFloat - (minFloat / 2) + if napDuration > float64(max) { + return time.Duration(max) + } + return time.Duration(napDuration) +} + +func (e *ExponentialBackoffRetryPolicy) GetRetryType(err error) RetryType { + return RetryNextHost +} + +// DowngradingConsistencyRetryPolicy: Next retry will be with the next consistency level +// provided in the slice +// +// On a read timeout: the operation is retried with the next provided consistency +// level. +// +// On a write timeout: if the operation is an :attr:`~.UNLOGGED_BATCH` +// and at least one replica acknowledged the write, the operation is +// retried with the next consistency level. Furthermore, for other +// write types, if at least one replica acknowledged the write, the +// timeout is ignored. +// +// On an unavailable exception: if at least one replica is alive, the +// operation is retried with the next provided consistency level. + +type DowngradingConsistencyRetryPolicy struct { + ConsistencyLevelsToTry []Consistency +} + +func (d *DowngradingConsistencyRetryPolicy) Attempt(q RetryableQuery) bool { + currentAttempt := q.Attempts() + + if currentAttempt > len(d.ConsistencyLevelsToTry) { + return false + } else if currentAttempt > 0 { + q.SetConsistency(d.ConsistencyLevelsToTry[currentAttempt-1]) + if gocqlDebug { + Logger.Printf("%T: set consistency to %q\n", + d, + d.ConsistencyLevelsToTry[currentAttempt-1]) + } + } + return true +} + +func (d *DowngradingConsistencyRetryPolicy) GetRetryType(err error) RetryType { + switch t := err.(type) { + case *RequestErrUnavailable: + if t.Alive > 0 { + return Retry + } + return Rethrow + case *RequestErrWriteTimeout: + if t.WriteType == "SIMPLE" || t.WriteType == "BATCH" || t.WriteType == "COUNTER" { + if t.Received > 0 { + return Ignore + } + return Rethrow + } + if t.WriteType == "UNLOGGED_BATCH" { + return Retry + } + return Rethrow + case *RequestErrReadTimeout: + return Retry + default: + return RetryNextHost + } +} + +func (e *ExponentialBackoffRetryPolicy) napTime(attempts int) time.Duration { + return getExponentialTime(e.Min, e.Max, attempts) +} + +type HostStateNotifier interface { + AddHost(host *HostInfo) + RemoveHost(host *HostInfo) + HostUp(host *HostInfo) + HostDown(host *HostInfo) +} + +type KeyspaceUpdateEvent struct { + Keyspace string + Change string +} + +// HostSelectionPolicy is an interface for selecting +// the most appropriate host to execute a given query. +type HostSelectionPolicy interface { + HostStateNotifier + SetPartitioner + KeyspaceChanged(KeyspaceUpdateEvent) + Init(*Session) + IsLocal(host *HostInfo) bool + //Pick returns an iteration function over selected hosts + Pick(ExecutableQuery) NextHost +} + +// SelectedHost is an interface returned when picking a host from a host +// selection policy. +type SelectedHost interface { + Info() *HostInfo + Mark(error) +} + +type selectedHost HostInfo + +func (host *selectedHost) Info() *HostInfo { + return (*HostInfo)(host) +} + +func (host *selectedHost) Mark(err error) {} + +// NextHost is an iteration function over picked hosts +type NextHost func() SelectedHost + +// RoundRobinHostPolicy is a round-robin load balancing policy, where each host +// is tried sequentially for each query. +func RoundRobinHostPolicy() HostSelectionPolicy { + return &roundRobinHostPolicy{} +} + +type roundRobinHostPolicy struct { + hosts cowHostList + pos uint32 + mu sync.RWMutex +} + +func (r *roundRobinHostPolicy) IsLocal(*HostInfo) bool { return true } +func (r *roundRobinHostPolicy) KeyspaceChanged(KeyspaceUpdateEvent) {} +func (r *roundRobinHostPolicy) SetPartitioner(partitioner string) {} +func (r *roundRobinHostPolicy) Init(*Session) {} + +func (r *roundRobinHostPolicy) Pick(qry ExecutableQuery) NextHost { + // i is used to limit the number of attempts to find a host + // to the number of hosts known to this policy + var i int + return func() SelectedHost { + hosts := r.hosts.get() + if len(hosts) == 0 { + return nil + } + + // always increment pos to evenly distribute traffic in case of + // failures + pos := atomic.AddUint32(&r.pos, 1) - 1 + if i >= len(hosts) { + return nil + } + host := hosts[(pos)%uint32(len(hosts))] + i++ + return (*selectedHost)(host) + } +} + +func (r *roundRobinHostPolicy) AddHost(host *HostInfo) { + r.hosts.add(host) +} + +func (r *roundRobinHostPolicy) RemoveHost(host *HostInfo) { + r.hosts.remove(host.ConnectAddress()) +} + +func (r *roundRobinHostPolicy) HostUp(host *HostInfo) { + r.AddHost(host) +} + +func (r *roundRobinHostPolicy) HostDown(host *HostInfo) { + r.RemoveHost(host) +} + +func ShuffleReplicas() func(*tokenAwareHostPolicy) { + return func(t *tokenAwareHostPolicy) { + t.shuffleReplicas = true + } +} + +// TokenAwareHostPolicy is a token aware host selection policy, where hosts are +// selected based on the partition key, so queries are sent to the host which +// owns the partition. Fallback is used when routing information is not available. +func TokenAwareHostPolicy(fallback HostSelectionPolicy, opts ...func(*tokenAwareHostPolicy)) HostSelectionPolicy { + p := &tokenAwareHostPolicy{fallback: fallback} + for _, opt := range opts { + opt(p) + } + return p +} + +type keyspaceMeta struct { + replicas map[string]map[token][]*HostInfo +} + +type tokenAwareHostPolicy struct { + hosts cowHostList + mu sync.RWMutex + partitioner string + fallback HostSelectionPolicy + session *Session + + tokenRing atomic.Value // *tokenRing + keyspaces atomic.Value // *keyspaceMeta + + shuffleReplicas bool +} + +func (t *tokenAwareHostPolicy) Init(s *Session) { + t.session = s +} + +func (t *tokenAwareHostPolicy) IsLocal(host *HostInfo) bool { + return t.fallback.IsLocal(host) +} + +func (t *tokenAwareHostPolicy) KeyspaceChanged(update KeyspaceUpdateEvent) { + meta, _ := t.keyspaces.Load().(*keyspaceMeta) + var size = 1 + if meta != nil { + size = len(meta.replicas) + } + + newMeta := &keyspaceMeta{ + replicas: make(map[string]map[token][]*HostInfo, size), + } + + ks, err := t.session.KeyspaceMetadata(update.Keyspace) + if err == nil { + strat := getStrategy(ks) + tr := t.tokenRing.Load().(*tokenRing) + if tr != nil { + newMeta.replicas[update.Keyspace] = strat.replicaMap(t.hosts.get(), tr.tokens) + } + } + + if meta != nil { + for ks, replicas := range meta.replicas { + if ks != update.Keyspace { + newMeta.replicas[ks] = replicas + } + } + } + + t.keyspaces.Store(newMeta) +} + +func (t *tokenAwareHostPolicy) SetPartitioner(partitioner string) { + t.mu.Lock() + defer t.mu.Unlock() + + if t.partitioner != partitioner { + t.fallback.SetPartitioner(partitioner) + t.partitioner = partitioner + + t.resetTokenRing(partitioner) + } +} + +func (t *tokenAwareHostPolicy) AddHost(host *HostInfo) { + t.hosts.add(host) + t.fallback.AddHost(host) + + t.mu.RLock() + partitioner := t.partitioner + t.mu.RUnlock() + t.resetTokenRing(partitioner) +} + +func (t *tokenAwareHostPolicy) RemoveHost(host *HostInfo) { + t.hosts.remove(host.ConnectAddress()) + t.fallback.RemoveHost(host) + + t.mu.RLock() + partitioner := t.partitioner + t.mu.RUnlock() + t.resetTokenRing(partitioner) +} + +func (t *tokenAwareHostPolicy) HostUp(host *HostInfo) { + // TODO: need to avoid doing all the work on AddHost on hostup/down + // because it now expensive to calculate the replica map for each + // token + t.AddHost(host) +} + +func (t *tokenAwareHostPolicy) HostDown(host *HostInfo) { + t.RemoveHost(host) +} + +func (t *tokenAwareHostPolicy) resetTokenRing(partitioner string) { + if partitioner == "" { + // partitioner not yet set + return + } + + // create a new token ring + hosts := t.hosts.get() + tokenRing, err := newTokenRing(partitioner, hosts) + if err != nil { + Logger.Printf("Unable to update the token ring due to error: %s", err) + return + } + + // replace the token ring + t.tokenRing.Store(tokenRing) +} + +func (t *tokenAwareHostPolicy) getReplicas(keyspace string, token token) ([]*HostInfo, bool) { + meta, _ := t.keyspaces.Load().(*keyspaceMeta) + if meta == nil { + return nil, false + } + tokens, ok := meta.replicas[keyspace][token] + return tokens, ok +} + +func (t *tokenAwareHostPolicy) Pick(qry ExecutableQuery) NextHost { + if qry == nil { + return t.fallback.Pick(qry) + } + + routingKey, err := qry.GetRoutingKey() + if err != nil { + return t.fallback.Pick(qry) + } else if routingKey == nil { + return t.fallback.Pick(qry) + } + + tr, _ := t.tokenRing.Load().(*tokenRing) + if tr == nil { + return t.fallback.Pick(qry) + } + + token := tr.partitioner.Hash(routingKey) + primaryEndpoint := tr.GetHostForToken(token) + + if primaryEndpoint == nil || token == nil { + return t.fallback.Pick(qry) + } + + replicas, ok := t.getReplicas(qry.Keyspace(), token) + if !ok { + replicas = []*HostInfo{primaryEndpoint} + } else if t.shuffleReplicas { + replicas = shuffleHosts(replicas) + } + + var ( + fallbackIter NextHost + i int + ) + + used := make(map[*HostInfo]bool, len(replicas)) + return func() SelectedHost { + for i < len(replicas) { + h := replicas[i] + i++ + + if h.IsUp() && t.fallback.IsLocal(h) { + used[h] = true + return (*selectedHost)(h) + } + } + + if fallbackIter == nil { + // fallback + fallbackIter = t.fallback.Pick(qry) + } + + // filter the token aware selected hosts from the fallback hosts + for fallbackHost := fallbackIter(); fallbackHost != nil; fallbackHost = fallbackIter() { + if !used[fallbackHost.Info()] { + return fallbackHost + } + } + return nil + } +} + +// HostPoolHostPolicy is a host policy which uses the bitly/go-hostpool library +// to distribute queries between hosts and prevent sending queries to +// unresponsive hosts. When creating the host pool that is passed to the policy +// use an empty slice of hosts as the hostpool will be populated later by gocql. +// See below for examples of usage: +// +// // Create host selection policy using a simple host pool +// cluster.PoolConfig.HostSelectionPolicy = HostPoolHostPolicy(hostpool.New(nil)) +// +// // Create host selection policy using an epsilon greedy pool +// cluster.PoolConfig.HostSelectionPolicy = HostPoolHostPolicy( +// hostpool.NewEpsilonGreedy(nil, 0, &hostpool.LinearEpsilonValueCalculator{}), +// ) +// +func HostPoolHostPolicy(hp hostpool.HostPool) HostSelectionPolicy { + return &hostPoolHostPolicy{hostMap: map[string]*HostInfo{}, hp: hp} +} + +type hostPoolHostPolicy struct { + hp hostpool.HostPool + mu sync.RWMutex + hostMap map[string]*HostInfo +} + +func (r *hostPoolHostPolicy) Init(*Session) {} +func (r *hostPoolHostPolicy) KeyspaceChanged(KeyspaceUpdateEvent) {} +func (r *hostPoolHostPolicy) SetPartitioner(string) {} +func (r *hostPoolHostPolicy) IsLocal(*HostInfo) bool { return true } + +func (r *hostPoolHostPolicy) SetHosts(hosts []*HostInfo) { + peers := make([]string, len(hosts)) + hostMap := make(map[string]*HostInfo, len(hosts)) + + for i, host := range hosts { + ip := host.ConnectAddress().String() + peers[i] = ip + hostMap[ip] = host + } + + r.mu.Lock() + r.hp.SetHosts(peers) + r.hostMap = hostMap + r.mu.Unlock() +} + +func (r *hostPoolHostPolicy) AddHost(host *HostInfo) { + ip := host.ConnectAddress().String() + + r.mu.Lock() + defer r.mu.Unlock() + + // If the host addr is present and isn't nil return + if h, ok := r.hostMap[ip]; ok && h != nil { + return + } + // otherwise, add the host to the map + r.hostMap[ip] = host + // and construct a new peer list to give to the HostPool + hosts := make([]string, 0, len(r.hostMap)) + for addr := range r.hostMap { + hosts = append(hosts, addr) + } + + r.hp.SetHosts(hosts) +} + +func (r *hostPoolHostPolicy) RemoveHost(host *HostInfo) { + ip := host.ConnectAddress().String() + + r.mu.Lock() + defer r.mu.Unlock() + + if _, ok := r.hostMap[ip]; !ok { + return + } + + delete(r.hostMap, ip) + hosts := make([]string, 0, len(r.hostMap)) + for _, host := range r.hostMap { + hosts = append(hosts, host.ConnectAddress().String()) + } + + r.hp.SetHosts(hosts) +} + +func (r *hostPoolHostPolicy) HostUp(host *HostInfo) { + r.AddHost(host) +} + +func (r *hostPoolHostPolicy) HostDown(host *HostInfo) { + r.RemoveHost(host) +} + +func (r *hostPoolHostPolicy) Pick(qry ExecutableQuery) NextHost { + return func() SelectedHost { + r.mu.RLock() + defer r.mu.RUnlock() + + if len(r.hostMap) == 0 { + return nil + } + + hostR := r.hp.Get() + host, ok := r.hostMap[hostR.Host()] + if !ok { + return nil + } + + return selectedHostPoolHost{ + policy: r, + info: host, + hostR: hostR, + } + } +} + +// selectedHostPoolHost is a host returned by the hostPoolHostPolicy and +// implements the SelectedHost interface +type selectedHostPoolHost struct { + policy *hostPoolHostPolicy + info *HostInfo + hostR hostpool.HostPoolResponse +} + +func (host selectedHostPoolHost) Info() *HostInfo { + return host.info +} + +func (host selectedHostPoolHost) Mark(err error) { + ip := host.info.ConnectAddress().String() + + host.policy.mu.RLock() + defer host.policy.mu.RUnlock() + + if _, ok := host.policy.hostMap[ip]; !ok { + // host was removed between pick and mark + return + } + + host.hostR.Mark(err) +} + +type dcAwareRR struct { + local string + pos uint32 + mu sync.RWMutex + localHosts cowHostList + remoteHosts cowHostList +} + +// DCAwareRoundRobinPolicy is a host selection policies which will prioritize and +// return hosts which are in the local datacentre before returning hosts in all +// other datercentres +func DCAwareRoundRobinPolicy(localDC string) HostSelectionPolicy { + return &dcAwareRR{local: localDC} +} + +func (d *dcAwareRR) Init(*Session) {} +func (d *dcAwareRR) KeyspaceChanged(KeyspaceUpdateEvent) {} +func (d *dcAwareRR) SetPartitioner(p string) {} + +func (d *dcAwareRR) IsLocal(host *HostInfo) bool { + return host.DataCenter() == d.local +} + +func (d *dcAwareRR) AddHost(host *HostInfo) { + if host.DataCenter() == d.local { + d.localHosts.add(host) + } else { + d.remoteHosts.add(host) + } +} + +func (d *dcAwareRR) RemoveHost(host *HostInfo) { + if host.DataCenter() == d.local { + d.localHosts.remove(host.ConnectAddress()) + } else { + d.remoteHosts.remove(host.ConnectAddress()) + } +} + +func (d *dcAwareRR) HostUp(host *HostInfo) { d.AddHost(host) } +func (d *dcAwareRR) HostDown(host *HostInfo) { d.RemoveHost(host) } + +func (d *dcAwareRR) Pick(q ExecutableQuery) NextHost { + var i int + return func() SelectedHost { + var hosts []*HostInfo + localHosts := d.localHosts.get() + remoteHosts := d.remoteHosts.get() + if len(localHosts) != 0 { + hosts = localHosts + } else { + hosts = remoteHosts + } + if len(hosts) == 0 { + return nil + } + + // always increment pos to evenly distribute traffic in case of + // failures + pos := atomic.AddUint32(&d.pos, 1) - 1 + if i >= len(localHosts)+len(remoteHosts) { + return nil + } + host := hosts[(pos)%uint32(len(hosts))] + i++ + return (*selectedHost)(host) + } +} + +// ConvictionPolicy interface is used by gocql to determine if a host should be +// marked as DOWN based on the error and host info +type ConvictionPolicy interface { + // Implementations should return `true` if the host should be convicted, `false` otherwise. + AddFailure(error error, host *HostInfo) bool + //Implementations should clear out any convictions or state regarding the host. + Reset(host *HostInfo) +} + +// SimpleConvictionPolicy implements a ConvictionPolicy which convicts all hosts +// regardless of error +type SimpleConvictionPolicy struct { +} + +func (e *SimpleConvictionPolicy) AddFailure(error error, host *HostInfo) bool { + return true +} + +func (e *SimpleConvictionPolicy) Reset(host *HostInfo) {} + +// ReconnectionPolicy interface is used by gocql to determine if reconnection +// can be attempted after connection error. The interface allows gocql users +// to implement their own logic to determine how to attempt reconnection. +// +type ReconnectionPolicy interface { + GetInterval(currentRetry int) time.Duration + GetMaxRetries() int +} + +// ConstantReconnectionPolicy has simple logic for returning a fixed reconnection interval. +// +// Examples of usage: +// +// cluster.ReconnectionPolicy = &gocql.ConstantReconnectionPolicy{MaxRetries: 10, Interval: 8 * time.Second} +// +type ConstantReconnectionPolicy struct { + MaxRetries int + Interval time.Duration +} + +func (c *ConstantReconnectionPolicy) GetInterval(currentRetry int) time.Duration { + return c.Interval +} + +func (c *ConstantReconnectionPolicy) GetMaxRetries() int { + return c.MaxRetries +} + +// ExponentialReconnectionPolicy returns a growing reconnection interval. +type ExponentialReconnectionPolicy struct { + MaxRetries int + InitialInterval time.Duration +} + +func (e *ExponentialReconnectionPolicy) GetInterval(currentRetry int) time.Duration { + return getExponentialTime(e.InitialInterval, math.MaxInt16*time.Second, e.GetMaxRetries()) +} + +func (e *ExponentialReconnectionPolicy) GetMaxRetries() int { + return e.MaxRetries +} diff --git a/vendor/github.com/gocql/gocql/prepared_cache.go b/vendor/github.com/gocql/gocql/prepared_cache.go new file mode 100644 index 0000000..3c012a4 --- /dev/null +++ b/vendor/github.com/gocql/gocql/prepared_cache.go @@ -0,0 +1,64 @@ +package gocql + +import ( + "github.com/gocql/gocql/internal/lru" + "sync" +) + +const defaultMaxPreparedStmts = 1000 + +// preparedLRU is the prepared statement cache +type preparedLRU struct { + mu sync.Mutex + lru *lru.Cache +} + +// Max adjusts the maximum size of the cache and cleans up the oldest records if +// the new max is lower than the previous value. Not concurrency safe. +func (p *preparedLRU) max(max int) { + p.mu.Lock() + defer p.mu.Unlock() + + for p.lru.Len() > max { + p.lru.RemoveOldest() + } + p.lru.MaxEntries = max +} + +func (p *preparedLRU) clear() { + p.mu.Lock() + defer p.mu.Unlock() + + for p.lru.Len() > 0 { + p.lru.RemoveOldest() + } +} + +func (p *preparedLRU) add(key string, val *inflightPrepare) { + p.mu.Lock() + defer p.mu.Unlock() + p.lru.Add(key, val) +} + +func (p *preparedLRU) remove(key string) bool { + p.mu.Lock() + defer p.mu.Unlock() + return p.lru.Remove(key) +} + +func (p *preparedLRU) execIfMissing(key string, fn func(lru *lru.Cache) *inflightPrepare) (*inflightPrepare, bool) { + p.mu.Lock() + defer p.mu.Unlock() + + val, ok := p.lru.Get(key) + if ok { + return val.(*inflightPrepare), true + } + + return fn(p.lru), false +} + +func (p *preparedLRU) keyFor(addr, keyspace, statement string) string { + // TODO: maybe use []byte for keys? + return addr + keyspace + statement +} diff --git a/vendor/github.com/gocql/gocql/query_executor.go b/vendor/github.com/gocql/gocql/query_executor.go new file mode 100644 index 0000000..01c8efe --- /dev/null +++ b/vendor/github.com/gocql/gocql/query_executor.go @@ -0,0 +1,99 @@ +package gocql + +import ( + "time" +) + +type ExecutableQuery interface { + execute(conn *Conn) *Iter + attempt(keyspace string, end, start time.Time, iter *Iter, host *HostInfo) + retryPolicy() RetryPolicy + GetRoutingKey() ([]byte, error) + Keyspace() string + RetryableQuery +} + +type queryExecutor struct { + pool *policyConnPool + policy HostSelectionPolicy +} + +func (q *queryExecutor) attemptQuery(qry ExecutableQuery, conn *Conn) *Iter { + start := time.Now() + iter := qry.execute(conn) + end := time.Now() + + qry.attempt(q.pool.keyspace, end, start, iter, conn.host) + + return iter +} + +func (q *queryExecutor) executeQuery(qry ExecutableQuery) (*Iter, error) { + rt := qry.retryPolicy() + hostIter := q.policy.Pick(qry) + + var iter *Iter + for hostResponse := hostIter(); hostResponse != nil; hostResponse = hostIter() { + host := hostResponse.Info() + if host == nil || !host.IsUp() { + continue + } + + pool, ok := q.pool.getPool(host) + if !ok { + continue + } + + conn := pool.Pick() + if conn == nil { + continue + } + + iter = q.attemptQuery(qry, conn) + // Update host + hostResponse.Mark(iter.err) + + if rt == nil { + iter.host = host + break + } + + switch rt.GetRetryType(iter.err) { + case Retry: + for rt.Attempt(qry) { + iter = q.attemptQuery(qry, conn) + hostResponse.Mark(iter.err) + if iter.err == nil { + iter.host = host + return iter, nil + } + if rt.GetRetryType(iter.err) != Retry { + break + } + } + case Rethrow: + return nil, iter.err + case Ignore: + return iter, nil + case RetryNextHost: + default: + } + + // Exit for loop if the query was successful + if iter.err == nil { + iter.host = host + return iter, nil + } + + if !rt.Attempt(qry) { + // What do here? Should we just return an error here? + break + } + } + + if iter == nil { + return nil, ErrNoConnections + } + + return iter, nil +} diff --git a/vendor/github.com/gocql/gocql/ring.go b/vendor/github.com/gocql/gocql/ring.go new file mode 100644 index 0000000..856afae --- /dev/null +++ b/vendor/github.com/gocql/gocql/ring.go @@ -0,0 +1,152 @@ +package gocql + +import ( + "fmt" + "net" + "sync" + "sync/atomic" +) + +type ring struct { + // endpoints are the set of endpoints which the driver will attempt to connect + // to in the case it can not reach any of its hosts. They are also used to boot + // strap the initial connection. + endpoints []*HostInfo + + // hosts are the set of all hosts in the cassandra ring that we know of + mu sync.RWMutex + hosts map[string]*HostInfo + + hostList []*HostInfo + pos uint32 + + // TODO: we should store the ring metadata here also. +} + +func (r *ring) rrHost() *HostInfo { + // TODO: should we filter hosts that get used here? These hosts will be used + // for the control connection, should we also provide an iterator? + r.mu.RLock() + defer r.mu.RUnlock() + if len(r.hostList) == 0 { + return nil + } + + pos := int(atomic.AddUint32(&r.pos, 1) - 1) + return r.hostList[pos%len(r.hostList)] +} + +func (r *ring) getHost(ip net.IP) *HostInfo { + r.mu.RLock() + host := r.hosts[ip.String()] + r.mu.RUnlock() + return host +} + +func (r *ring) allHosts() []*HostInfo { + r.mu.RLock() + hosts := make([]*HostInfo, 0, len(r.hosts)) + for _, host := range r.hosts { + hosts = append(hosts, host) + } + r.mu.RUnlock() + return hosts +} + +func (r *ring) currentHosts() map[string]*HostInfo { + r.mu.RLock() + hosts := make(map[string]*HostInfo, len(r.hosts)) + for k, v := range r.hosts { + hosts[k] = v + } + r.mu.RUnlock() + return hosts +} + +func (r *ring) addHost(host *HostInfo) bool { + // TODO(zariel): key all host info by HostID instead of + // ip addresses + if host.invalidConnectAddr() { + panic(fmt.Sprintf("invalid host: %v", host)) + } + ip := host.ConnectAddress().String() + + r.mu.Lock() + if r.hosts == nil { + r.hosts = make(map[string]*HostInfo) + } + + _, ok := r.hosts[ip] + if !ok { + r.hostList = append(r.hostList, host) + } + + r.hosts[ip] = host + r.mu.Unlock() + return ok +} + +func (r *ring) addOrUpdate(host *HostInfo) *HostInfo { + if existingHost, ok := r.addHostIfMissing(host); ok { + existingHost.update(host) + host = existingHost + } + return host +} + +func (r *ring) addHostIfMissing(host *HostInfo) (*HostInfo, bool) { + if host.invalidConnectAddr() { + panic(fmt.Sprintf("invalid host: %v", host)) + } + ip := host.ConnectAddress().String() + + r.mu.Lock() + if r.hosts == nil { + r.hosts = make(map[string]*HostInfo) + } + + existing, ok := r.hosts[ip] + if !ok { + r.hosts[ip] = host + existing = host + r.hostList = append(r.hostList, host) + } + r.mu.Unlock() + return existing, ok +} + +func (r *ring) removeHost(ip net.IP) bool { + r.mu.Lock() + if r.hosts == nil { + r.hosts = make(map[string]*HostInfo) + } + + k := ip.String() + _, ok := r.hosts[k] + if ok { + for i, host := range r.hostList { + if host.ConnectAddress().Equal(ip) { + r.hostList = append(r.hostList[:i], r.hostList[i+1:]...) + break + } + } + } + delete(r.hosts, k) + r.mu.Unlock() + return ok +} + +type clusterMetadata struct { + mu sync.RWMutex + partitioner string +} + +func (c *clusterMetadata) setPartitioner(partitioner string) { + c.mu.Lock() + defer c.mu.Unlock() + + if c.partitioner != partitioner { + // TODO: update other things now + c.partitioner = partitioner + } +} diff --git a/vendor/github.com/gocql/gocql/session.go b/vendor/github.com/gocql/gocql/session.go new file mode 100644 index 0000000..7d81046 --- /dev/null +++ b/vendor/github.com/gocql/gocql/session.go @@ -0,0 +1,1787 @@ +// Copyright (c) 2012 The gocql 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 gocql + +import ( + "bytes" + "context" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "strings" + "sync" + "sync/atomic" + "time" + "unicode" + + "github.com/gocql/gocql/internal/lru" +) + +// Session is the interface used by users to interact with the database. +// +// It's safe for concurrent use by multiple goroutines and a typical usage +// scenario is to have one global session object to interact with the +// whole Cassandra cluster. +// +// This type extends the Node interface by adding a convinient query builder +// and automatically sets a default consistency level on all operations +// that do not have a consistency level set. +type Session struct { + cons Consistency + pageSize int + prefetch float64 + routingKeyInfoCache routingKeyInfoLRU + schemaDescriber *schemaDescriber + trace Tracer + queryObserver QueryObserver + batchObserver BatchObserver + connectObserver ConnectObserver + frameObserver FrameHeaderObserver + hostSource *ringDescriber + stmtsLRU *preparedLRU + + connCfg *ConnConfig + + executor *queryExecutor + pool *policyConnPool + policy HostSelectionPolicy + + ring ring + metadata clusterMetadata + + mu sync.RWMutex + + control *controlConn + + // event handlers + nodeEvents *eventDebouncer + schemaEvents *eventDebouncer + + // ring metadata + hosts []HostInfo + useSystemSchema bool + + cfg ClusterConfig + + quit chan struct{} + + closeMu sync.RWMutex + isClosed bool +} + +var queryPool = &sync.Pool{ + New: func() interface{} { + return new(Query) + }, +} + +func addrsToHosts(addrs []string, defaultPort int) ([]*HostInfo, error) { + var hosts []*HostInfo + for _, hostport := range addrs { + resolvedHosts, err := hostInfo(hostport, defaultPort) + if err != nil { + // Try other hosts if unable to resolve DNS name + if _, ok := err.(*net.DNSError); ok { + Logger.Printf("gocql: dns error: %v\n", err) + continue + } + return nil, err + } + + hosts = append(hosts, resolvedHosts...) + } + if len(hosts) == 0 { + return nil, errors.New("failed to resolve any of the provided hostnames") + } + return hosts, nil +} + +// NewSession wraps an existing Node. +func NewSession(cfg ClusterConfig) (*Session, error) { + // Check that hosts in the ClusterConfig is not empty + if len(cfg.Hosts) < 1 { + return nil, ErrNoHosts + } + + s := &Session{ + cons: cfg.Consistency, + prefetch: 0.25, + cfg: cfg, + pageSize: cfg.PageSize, + stmtsLRU: &preparedLRU{lru: lru.New(cfg.MaxPreparedStmts)}, + quit: make(chan struct{}), + connectObserver: cfg.ConnectObserver, + } + + s.schemaDescriber = newSchemaDescriber(s) + + s.nodeEvents = newEventDebouncer("NodeEvents", s.handleNodeEvent) + s.schemaEvents = newEventDebouncer("SchemaEvents", s.handleSchemaEvent) + + s.routingKeyInfoCache.lru = lru.New(cfg.MaxRoutingKeyInfo) + + s.hostSource = &ringDescriber{session: s} + + if cfg.PoolConfig.HostSelectionPolicy == nil { + cfg.PoolConfig.HostSelectionPolicy = RoundRobinHostPolicy() + } + s.pool = cfg.PoolConfig.buildPool(s) + + s.policy = cfg.PoolConfig.HostSelectionPolicy + s.policy.Init(s) + + s.executor = &queryExecutor{ + pool: s.pool, + policy: cfg.PoolConfig.HostSelectionPolicy, + } + + s.queryObserver = cfg.QueryObserver + s.batchObserver = cfg.BatchObserver + s.connectObserver = cfg.ConnectObserver + s.frameObserver = cfg.FrameHeaderObserver + + //Check the TLS Config before trying to connect to anything external + connCfg, err := connConfig(&s.cfg) + if err != nil { + //TODO: Return a typed error + return nil, fmt.Errorf("gocql: unable to create session: %v", err) + } + s.connCfg = connCfg + + if err := s.init(); err != nil { + s.Close() + if err == ErrNoConnectionsStarted { + //This error used to be generated inside NewSession & returned directly + //Forward it on up to be backwards compatible + return nil, ErrNoConnectionsStarted + } else { + // TODO(zariel): dont wrap this error in fmt.Errorf, return a typed error + return nil, fmt.Errorf("gocql: unable to create session: %v", err) + } + } + + return s, nil +} + +func (s *Session) init() error { + hosts, err := addrsToHosts(s.cfg.Hosts, s.cfg.Port) + if err != nil { + return err + } + s.ring.endpoints = hosts + + if !s.cfg.disableControlConn { + s.control = createControlConn(s) + if s.cfg.ProtoVersion == 0 { + proto, err := s.control.discoverProtocol(hosts) + if err != nil { + return fmt.Errorf("unable to discover protocol version: %v", err) + } else if proto == 0 { + return errors.New("unable to discovery protocol version") + } + + // TODO(zariel): we really only need this in 1 place + s.cfg.ProtoVersion = proto + s.connCfg.ProtoVersion = proto + } + + if err := s.control.connect(hosts); err != nil { + return err + } + + if !s.cfg.DisableInitialHostLookup { + var partitioner string + newHosts, partitioner, err := s.hostSource.GetHosts() + if err != nil { + return err + } + s.policy.SetPartitioner(partitioner) + filteredHosts := make([]*HostInfo, 0, len(newHosts)) + for _, host := range newHosts { + if !s.cfg.filterHost(host) { + filteredHosts = append(filteredHosts, host) + } + } + hosts = append(hosts, filteredHosts...) + } + } + + hostMap := make(map[string]*HostInfo, len(hosts)) + for _, host := range hosts { + hostMap[host.ConnectAddress().String()] = host + } + + for _, host := range hostMap { + host = s.ring.addOrUpdate(host) + s.addNewNode(host) + } + + // TODO(zariel): we probably dont need this any more as we verify that we + // can connect to one of the endpoints supplied by using the control conn. + // See if there are any connections in the pool + if s.cfg.ReconnectInterval > 0 { + go s.reconnectDownedHosts(s.cfg.ReconnectInterval) + } + + // If we disable the initial host lookup, we need to still check if the + // cluster is using the newer system schema or not... however, if control + // connection is disable, we really have no choice, so we just make our + // best guess... + if !s.cfg.disableControlConn && s.cfg.DisableInitialHostLookup { + newer, _ := checkSystemSchema(s.control) + s.useSystemSchema = newer + } else { + host := s.ring.rrHost() + s.useSystemSchema = host.Version().Major >= 3 + } + + if s.pool.Size() == 0 { + return ErrNoConnectionsStarted + } + + return nil +} + +func (s *Session) reconnectDownedHosts(intv time.Duration) { + reconnectTicker := time.NewTicker(intv) + defer reconnectTicker.Stop() + + for { + select { + case <-reconnectTicker.C: + hosts := s.ring.allHosts() + + // Print session.ring for debug. + if gocqlDebug { + buf := bytes.NewBufferString("Session.ring:") + for _, h := range hosts { + buf.WriteString("[" + h.ConnectAddress().String() + ":" + h.State().String() + "]") + } + Logger.Println(buf.String()) + } + + for _, h := range hosts { + if h.IsUp() { + continue + } + s.handleNodeUp(h.ConnectAddress(), h.Port(), true) + } + case <-s.quit: + return + } + } +} + +// SetConsistency sets the default consistency level for this session. This +// setting can also be changed on a per-query basis and the default value +// is Quorum. +func (s *Session) SetConsistency(cons Consistency) { + s.mu.Lock() + s.cons = cons + s.mu.Unlock() +} + +// SetPageSize sets the default page size for this session. A value <= 0 will +// disable paging. This setting can also be changed on a per-query basis. +func (s *Session) SetPageSize(n int) { + s.mu.Lock() + s.pageSize = n + s.mu.Unlock() +} + +// SetPrefetch sets the default threshold for pre-fetching new pages. If +// there are only p*pageSize rows remaining, the next page will be requested +// automatically. This value can also be changed on a per-query basis and +// the default value is 0.25. +func (s *Session) SetPrefetch(p float64) { + s.mu.Lock() + s.prefetch = p + s.mu.Unlock() +} + +// SetTrace sets the default tracer for this session. This setting can also +// be changed on a per-query basis. +func (s *Session) SetTrace(trace Tracer) { + s.mu.Lock() + s.trace = trace + s.mu.Unlock() +} + +// Query generates a new query object for interacting with the database. +// Further details of the query may be tweaked using the resulting query +// value before the query is executed. Query is automatically prepared +// if it has not previously been executed. +func (s *Session) Query(stmt string, values ...interface{}) *Query { + qry := queryPool.Get().(*Query) + qry.session = s + qry.stmt = stmt + qry.values = values + qry.defaultsFromSession() + return qry +} + +type QueryInfo struct { + Id []byte + Args []ColumnInfo + Rval []ColumnInfo + PKeyColumns []int +} + +// Bind generates a new query object based on the query statement passed in. +// The query is automatically prepared if it has not previously been executed. +// The binding callback allows the application to define which query argument +// values will be marshalled as part of the query execution. +// During execution, the meta data of the prepared query will be routed to the +// binding callback, which is responsible for producing the query argument values. +func (s *Session) Bind(stmt string, b func(q *QueryInfo) ([]interface{}, error)) *Query { + qry := queryPool.Get().(*Query) + qry.session = s + qry.stmt = stmt + qry.binding = b + qry.defaultsFromSession() + return qry +} + +// Close closes all connections. The session is unusable after this +// operation. +func (s *Session) Close() { + + s.closeMu.Lock() + defer s.closeMu.Unlock() + if s.isClosed { + return + } + s.isClosed = true + + if s.pool != nil { + s.pool.Close() + } + + if s.control != nil { + s.control.close() + } + + if s.nodeEvents != nil { + s.nodeEvents.stop() + } + + if s.schemaEvents != nil { + s.schemaEvents.stop() + } + + if s.quit != nil { + close(s.quit) + } +} + +func (s *Session) Closed() bool { + s.closeMu.RLock() + closed := s.isClosed + s.closeMu.RUnlock() + return closed +} + +func (s *Session) executeQuery(qry *Query) (it *Iter) { + // fail fast + if s.Closed() { + return &Iter{err: ErrSessionClosed} + } + + iter, err := s.executor.executeQuery(qry) + if err != nil { + return &Iter{err: err} + } + if iter == nil { + panic("nil iter") + } + + return iter +} + +func (s *Session) removeHost(h *HostInfo) { + s.policy.RemoveHost(h) + s.pool.removeHost(h.ConnectAddress()) + s.ring.removeHost(h.ConnectAddress()) +} + +// KeyspaceMetadata returns the schema metadata for the keyspace specified. Returns an error if the keyspace does not exist. +func (s *Session) KeyspaceMetadata(keyspace string) (*KeyspaceMetadata, error) { + // fail fast + if s.Closed() { + return nil, ErrSessionClosed + } else if keyspace == "" { + return nil, ErrNoKeyspace + } + + return s.schemaDescriber.getSchema(keyspace) +} + +func (s *Session) getConn() *Conn { + hosts := s.ring.allHosts() + for _, host := range hosts { + if !host.IsUp() { + continue + } + + pool, ok := s.pool.getPool(host) + if !ok { + continue + } else if conn := pool.Pick(); conn != nil { + return conn + } + } + + return nil +} + +// returns routing key indexes and type info +func (s *Session) routingKeyInfo(ctx context.Context, stmt string) (*routingKeyInfo, error) { + s.routingKeyInfoCache.mu.Lock() + + entry, cached := s.routingKeyInfoCache.lru.Get(stmt) + if cached { + // done accessing the cache + s.routingKeyInfoCache.mu.Unlock() + // the entry is an inflight struct similar to that used by + // Conn to prepare statements + inflight := entry.(*inflightCachedEntry) + + // wait for any inflight work + inflight.wg.Wait() + + if inflight.err != nil { + return nil, inflight.err + } + + key, _ := inflight.value.(*routingKeyInfo) + + return key, nil + } + + // create a new inflight entry while the data is created + inflight := new(inflightCachedEntry) + inflight.wg.Add(1) + defer inflight.wg.Done() + s.routingKeyInfoCache.lru.Add(stmt, inflight) + s.routingKeyInfoCache.mu.Unlock() + + var ( + info *preparedStatment + partitionKey []*ColumnMetadata + ) + + conn := s.getConn() + if conn == nil { + // TODO: better error? + inflight.err = errors.New("gocql: unable to fetch prepared info: no connection available") + return nil, inflight.err + } + + // get the query info for the statement + info, inflight.err = conn.prepareStatement(ctx, stmt, nil) + if inflight.err != nil { + // don't cache this error + s.routingKeyInfoCache.Remove(stmt) + return nil, inflight.err + } + + // TODO: it would be nice to mark hosts here but as we are not using the policies + // to fetch hosts we cant + + if info.request.colCount == 0 { + // no arguments, no routing key, and no error + return nil, nil + } + + if len(info.request.pkeyColumns) > 0 { + // proto v4 dont need to calculate primary key columns + types := make([]TypeInfo, len(info.request.pkeyColumns)) + for i, col := range info.request.pkeyColumns { + types[i] = info.request.columns[col].TypeInfo + } + + routingKeyInfo := &routingKeyInfo{ + indexes: info.request.pkeyColumns, + types: types, + } + + inflight.value = routingKeyInfo + return routingKeyInfo, nil + } + + // get the table metadata + table := info.request.columns[0].Table + + var keyspaceMetadata *KeyspaceMetadata + keyspaceMetadata, inflight.err = s.KeyspaceMetadata(info.request.columns[0].Keyspace) + if inflight.err != nil { + // don't cache this error + s.routingKeyInfoCache.Remove(stmt) + return nil, inflight.err + } + + tableMetadata, found := keyspaceMetadata.Tables[table] + if !found { + // unlikely that the statement could be prepared and the metadata for + // the table couldn't be found, but this may indicate either a bug + // in the metadata code, or that the table was just dropped. + inflight.err = ErrNoMetadata + // don't cache this error + s.routingKeyInfoCache.Remove(stmt) + return nil, inflight.err + } + + partitionKey = tableMetadata.PartitionKey + + size := len(partitionKey) + routingKeyInfo := &routingKeyInfo{ + indexes: make([]int, size), + types: make([]TypeInfo, size), + } + + for keyIndex, keyColumn := range partitionKey { + // set an indicator for checking if the mapping is missing + routingKeyInfo.indexes[keyIndex] = -1 + + // find the column in the query info + for argIndex, boundColumn := range info.request.columns { + if keyColumn.Name == boundColumn.Name { + // there may be many such bound columns, pick the first + routingKeyInfo.indexes[keyIndex] = argIndex + routingKeyInfo.types[keyIndex] = boundColumn.TypeInfo + break + } + } + + if routingKeyInfo.indexes[keyIndex] == -1 { + // missing a routing key column mapping + // no routing key, and no error + return nil, nil + } + } + + // cache this result + inflight.value = routingKeyInfo + + return routingKeyInfo, nil +} + +func (b *Batch) execute(conn *Conn) *Iter { + return conn.executeBatch(b) +} + +func (s *Session) executeBatch(batch *Batch) *Iter { + // fail fast + if s.Closed() { + return &Iter{err: ErrSessionClosed} + } + + // Prevent the execution of the batch if greater than the limit + // Currently batches have a limit of 65536 queries. + // https://datastax-oss.atlassian.net/browse/JAVA-229 + if batch.Size() > BatchSizeMaximum { + return &Iter{err: ErrTooManyStmts} + } + + iter, err := s.executor.executeQuery(batch) + if err != nil { + return &Iter{err: err} + } + + return iter +} + +// ExecuteBatch executes a batch operation and returns nil if successful +// otherwise an error is returned describing the failure. +func (s *Session) ExecuteBatch(batch *Batch) error { + iter := s.executeBatch(batch) + return iter.Close() +} + +// ExecuteBatchCAS executes a batch operation and returns true if successful and +// an iterator (to scan aditional rows if more than one conditional statement) +// was sent. +// Further scans on the interator must also remember to include +// the applied boolean as the first argument to *Iter.Scan +func (s *Session) ExecuteBatchCAS(batch *Batch, dest ...interface{}) (applied bool, iter *Iter, err error) { + iter = s.executeBatch(batch) + if err := iter.checkErrAndNotFound(); err != nil { + iter.Close() + return false, nil, err + } + + if len(iter.Columns()) > 1 { + dest = append([]interface{}{&applied}, dest...) + iter.Scan(dest...) + } else { + iter.Scan(&applied) + } + + return applied, iter, nil +} + +// MapExecuteBatchCAS executes a batch operation much like ExecuteBatchCAS, +// however it accepts a map rather than a list of arguments for the initial +// scan. +func (s *Session) MapExecuteBatchCAS(batch *Batch, dest map[string]interface{}) (applied bool, iter *Iter, err error) { + iter = s.executeBatch(batch) + if err := iter.checkErrAndNotFound(); err != nil { + iter.Close() + return false, nil, err + } + iter.MapScan(dest) + applied = dest["[applied]"].(bool) + delete(dest, "[applied]") + + // we usually close here, but instead of closing, just returin an error + // if MapScan failed. Although Close just returns err, using Close + // here might be confusing as we are not actually closing the iter + return applied, iter, iter.err +} + +func (s *Session) connect(host *HostInfo, errorHandler ConnErrorHandler) (*Conn, error) { + if s.connectObserver != nil { + obs := ObservedConnect{ + Host: host, + Start: time.Now(), + } + conn, err := s.dial(host, s.connCfg, errorHandler) + obs.End = time.Now() + obs.Err = err + s.connectObserver.ObserveConnect(obs) + return conn, err + } + return s.dial(host, s.connCfg, errorHandler) +} + +// Query represents a CQL statement that can be executed. +type Query struct { + stmt string + values []interface{} + cons Consistency + pageSize int + routingKey []byte + routingKeyBuffer []byte + pageState []byte + prefetch float64 + trace Tracer + observer QueryObserver + session *Session + rt RetryPolicy + binding func(q *QueryInfo) ([]interface{}, error) + attempts int + totalLatency int64 + serialCons SerialConsistency + defaultTimestamp bool + defaultTimestampValue int64 + disableSkipMetadata bool + context context.Context + idempotent bool + + disableAutoPage bool +} + +func (q *Query) defaultsFromSession() { + s := q.session + + s.mu.RLock() + q.cons = s.cons + q.pageSize = s.pageSize + q.trace = s.trace + q.observer = s.queryObserver + q.prefetch = s.prefetch + q.rt = s.cfg.RetryPolicy + q.serialCons = s.cfg.SerialConsistency + q.defaultTimestamp = s.cfg.DefaultTimestamp + q.idempotent = s.cfg.DefaultIdempotence + s.mu.RUnlock() +} + +// Statement returns the statement that was used to generate this query. +func (q Query) Statement() string { + return q.stmt +} + +// String implements the stringer interface. +func (q Query) String() string { + return fmt.Sprintf("[query statement=%q values=%+v consistency=%s]", q.stmt, q.values, q.cons) +} + +//Attempts returns the number of times the query was executed. +func (q *Query) Attempts() int { + return q.attempts +} + +//Latency returns the average amount of nanoseconds per attempt of the query. +func (q *Query) Latency() int64 { + if q.attempts > 0 { + return q.totalLatency / int64(q.attempts) + } + return 0 +} + +// Consistency sets the consistency level for this query. If no consistency +// level have been set, the default consistency level of the cluster +// is used. +func (q *Query) Consistency(c Consistency) *Query { + q.cons = c + return q +} + +// GetConsistency returns the currently configured consistency level for +// the query. +func (q *Query) GetConsistency() Consistency { + return q.cons +} + +// Same as Consistency but without a return value +func (q *Query) SetConsistency(c Consistency) { + q.cons = c +} + +// Trace enables tracing of this query. Look at the documentation of the +// Tracer interface to learn more about tracing. +func (q *Query) Trace(trace Tracer) *Query { + q.trace = trace + return q +} + +// Observer enables query-level observer on this query. +// The provided observer will be called every time this query is executed. +func (q *Query) Observer(observer QueryObserver) *Query { + q.observer = observer + return q +} + +// PageSize will tell the iterator to fetch the result in pages of size n. +// This is useful for iterating over large result sets, but setting the +// page size too low might decrease the performance. This feature is only +// available in Cassandra 2 and onwards. +func (q *Query) PageSize(n int) *Query { + q.pageSize = n + return q +} + +// DefaultTimestamp will enable the with default timestamp flag on the query. +// If enable, this will replace the server side assigned +// timestamp as default timestamp. Note that a timestamp in the query itself +// will still override this timestamp. This is entirely optional. +// +// Only available on protocol >= 3 +func (q *Query) DefaultTimestamp(enable bool) *Query { + q.defaultTimestamp = enable + return q +} + +// WithTimestamp will enable the with default timestamp flag on the query +// like DefaultTimestamp does. But also allows to define value for timestamp. +// It works the same way as USING TIMESTAMP in the query itself, but +// should not break prepared query optimization +// +// Only available on protocol >= 3 +func (q *Query) WithTimestamp(timestamp int64) *Query { + q.DefaultTimestamp(true) + q.defaultTimestampValue = timestamp + return q +} + +// RoutingKey sets the routing key to use when a token aware connection +// pool is used to optimize the routing of this query. +func (q *Query) RoutingKey(routingKey []byte) *Query { + q.routingKey = routingKey + return q +} + +// WithContext will set the context to use during a query, it will be used to +// timeout when waiting for responses from Cassandra. +func (q *Query) WithContext(ctx context.Context) *Query { + q.context = ctx + return q +} + +func (q *Query) execute(conn *Conn) *Iter { + return conn.executeQuery(q) +} + +func (q *Query) attempt(keyspace string, end, start time.Time, iter *Iter, host *HostInfo) { + q.attempts++ + q.totalLatency += end.Sub(start).Nanoseconds() + // TODO: track latencies per host and things as well instead of just total + + if q.observer != nil { + q.observer.ObserveQuery(q.context, ObservedQuery{ + Keyspace: keyspace, + Statement: q.stmt, + Start: start, + End: end, + Rows: iter.numRows, + Host: host, + Err: iter.err, + }) + } +} + +func (q *Query) retryPolicy() RetryPolicy { + return q.rt +} + +// Keyspace returns the keyspace the query will be executed against. +func (q *Query) Keyspace() string { + if q.session == nil { + return "" + } + // TODO(chbannis): this should be parsed from the query or we should let + // this be set by users. + return q.session.cfg.Keyspace +} + +// GetRoutingKey gets the routing key to use for routing this query. If +// a routing key has not been explicitly set, then the routing key will +// be constructed if possible using the keyspace's schema and the query +// info for this query statement. If the routing key cannot be determined +// then nil will be returned with no error. On any error condition, +// an error description will be returned. +func (q *Query) GetRoutingKey() ([]byte, error) { + if q.routingKey != nil { + return q.routingKey, nil + } else if q.binding != nil && len(q.values) == 0 { + // If this query was created using session.Bind we wont have the query + // values yet, so we have to pass down to the next policy. + // TODO: Remove this and handle this case + return nil, nil + } + + // try to determine the routing key + routingKeyInfo, err := q.session.routingKeyInfo(q.context, q.stmt) + if err != nil { + return nil, err + } + + if routingKeyInfo == nil { + return nil, nil + } + + if len(routingKeyInfo.indexes) == 1 { + // single column routing key + routingKey, err := Marshal( + routingKeyInfo.types[0], + q.values[routingKeyInfo.indexes[0]], + ) + if err != nil { + return nil, err + } + return routingKey, nil + } + + // We allocate that buffer only once, so that further re-bind/exec of the + // same query don't allocate more memory. + if q.routingKeyBuffer == nil { + q.routingKeyBuffer = make([]byte, 0, 256) + } + + // composite routing key + buf := bytes.NewBuffer(q.routingKeyBuffer) + for i := range routingKeyInfo.indexes { + encoded, err := Marshal( + routingKeyInfo.types[i], + q.values[routingKeyInfo.indexes[i]], + ) + if err != nil { + return nil, err + } + lenBuf := []byte{0x00, 0x00} + binary.BigEndian.PutUint16(lenBuf, uint16(len(encoded))) + buf.Write(lenBuf) + buf.Write(encoded) + buf.WriteByte(0x00) + } + routingKey := buf.Bytes() + return routingKey, nil +} + +func (q *Query) shouldPrepare() bool { + + stmt := strings.TrimLeftFunc(strings.TrimRightFunc(q.stmt, func(r rune) bool { + return unicode.IsSpace(r) || r == ';' + }), unicode.IsSpace) + + var stmtType string + if n := strings.IndexFunc(stmt, unicode.IsSpace); n >= 0 { + stmtType = strings.ToLower(stmt[:n]) + } + if stmtType == "begin" { + if n := strings.LastIndexFunc(stmt, unicode.IsSpace); n >= 0 { + stmtType = strings.ToLower(stmt[n+1:]) + } + } + switch stmtType { + case "select", "insert", "update", "delete", "batch": + return true + } + return false +} + +// SetPrefetch sets the default threshold for pre-fetching new pages. If +// there are only p*pageSize rows remaining, the next page will be requested +// automatically. +func (q *Query) Prefetch(p float64) *Query { + q.prefetch = p + return q +} + +// RetryPolicy sets the policy to use when retrying the query. +func (q *Query) RetryPolicy(r RetryPolicy) *Query { + q.rt = r + return q +} + +func (q *Query) IsIdempotent() bool { + return q.idempotent +} + +// Idempontent marks the query as being idempontent or not depending on +// the value. +func (q *Query) Idempontent(value bool) *Query { + q.idempotent = value + return q +} + +// Bind sets query arguments of query. This can also be used to rebind new query arguments +// to an existing query instance. +func (q *Query) Bind(v ...interface{}) *Query { + q.values = v + return q +} + +// SerialConsistency sets the consistency level for the +// serial phase of conditional updates. That consistency can only be +// either SERIAL or LOCAL_SERIAL and if not present, it defaults to +// SERIAL. This option will be ignored for anything else that a +// conditional update/insert. +func (q *Query) SerialConsistency(cons SerialConsistency) *Query { + q.serialCons = cons + return q +} + +// PageState sets the paging state for the query to resume paging from a specific +// point in time. Setting this will disable to query paging for this query, and +// must be used for all subsequent pages. +func (q *Query) PageState(state []byte) *Query { + q.pageState = state + q.disableAutoPage = true + return q +} + +// NoSkipMetadata will override the internal result metadata cache so that the driver does not +// send skip_metadata for queries, this means that the result will always contain +// the metadata to parse the rows and will not reuse the metadata from the prepared +// staement. This should only be used to work around cassandra bugs, such as when using +// CAS operations which do not end in Cas. +// +// See https://issues.apache.org/jira/browse/CASSANDRA-11099 +// https://github.com/gocql/gocql/issues/612 +func (q *Query) NoSkipMetadata() *Query { + q.disableSkipMetadata = true + return q +} + +// Exec executes the query without returning any rows. +func (q *Query) Exec() error { + return q.Iter().Close() +} + +func isUseStatement(stmt string) bool { + if len(stmt) < 3 { + return false + } + + return strings.EqualFold(stmt[0:3], "use") +} + +// Iter executes the query and returns an iterator capable of iterating +// over all results. +func (q *Query) Iter() *Iter { + if isUseStatement(q.stmt) { + return &Iter{err: ErrUseStmt} + } + return q.session.executeQuery(q) +} + +// MapScan executes the query, copies the columns of the first selected +// row into the map pointed at by m and discards the rest. If no rows +// were selected, ErrNotFound is returned. +func (q *Query) MapScan(m map[string]interface{}) error { + iter := q.Iter() + if err := iter.checkErrAndNotFound(); err != nil { + return err + } + iter.MapScan(m) + return iter.Close() +} + +// Scan executes the query, copies the columns of the first selected +// row into the values pointed at by dest and discards the rest. If no rows +// were selected, ErrNotFound is returned. +func (q *Query) Scan(dest ...interface{}) error { + iter := q.Iter() + if err := iter.checkErrAndNotFound(); err != nil { + return err + } + iter.Scan(dest...) + return iter.Close() +} + +// ScanCAS executes a lightweight transaction (i.e. an UPDATE or INSERT +// statement containing an IF clause). If the transaction fails because +// the existing values did not match, the previous values will be stored +// in dest. +func (q *Query) ScanCAS(dest ...interface{}) (applied bool, err error) { + q.disableSkipMetadata = true + iter := q.Iter() + if err := iter.checkErrAndNotFound(); err != nil { + return false, err + } + if len(iter.Columns()) > 1 { + dest = append([]interface{}{&applied}, dest...) + iter.Scan(dest...) + } else { + iter.Scan(&applied) + } + return applied, iter.Close() +} + +// MapScanCAS executes a lightweight transaction (i.e. an UPDATE or INSERT +// statement containing an IF clause). If the transaction fails because +// the existing values did not match, the previous values will be stored +// in dest map. +// +// As for INSERT .. IF NOT EXISTS, previous values will be returned as if +// SELECT * FROM. So using ScanCAS with INSERT is inherently prone to +// column mismatching. MapScanCAS is added to capture them safely. +func (q *Query) MapScanCAS(dest map[string]interface{}) (applied bool, err error) { + q.disableSkipMetadata = true + iter := q.Iter() + if err := iter.checkErrAndNotFound(); err != nil { + return false, err + } + iter.MapScan(dest) + applied = dest["[applied]"].(bool) + delete(dest, "[applied]") + + return applied, iter.Close() +} + +// Release releases a query back into a pool of queries. Released Queries +// cannot be reused. +// +// Example: +// qry := session.Query("SELECT * FROM my_table") +// qry.Exec() +// qry.Release() +func (q *Query) Release() { + q.reset() + queryPool.Put(q) +} + +// reset zeroes out all fields of a query so that it can be safely pooled. +func (q *Query) reset() { + *q = Query{} +} + +// Iter represents an iterator that can be used to iterate over all rows that +// were returned by a query. The iterator might send additional queries to the +// database during the iteration if paging was enabled. +type Iter struct { + err error + pos int + meta resultMetadata + numRows int + next *nextIter + host *HostInfo + + framer *framer + closed int32 +} + +// Host returns the host which the query was sent to. +func (iter *Iter) Host() *HostInfo { + return iter.host +} + +// Columns returns the name and type of the selected columns. +func (iter *Iter) Columns() []ColumnInfo { + return iter.meta.columns +} + +type Scanner interface { + // Next advances the row pointer to point at the next row, the row is valid until + // the next call of Next. It returns true if there is a row which is available to be + // scanned into with Scan. + // Next must be called before every call to Scan. + Next() bool + + // Scan copies the current row's columns into dest. If the length of dest does not equal + // the number of columns returned in the row an error is returned. If an error is encountered + // when unmarshalling a column into the value in dest an error is returned and the row is invalidated + // until the next call to Next. + // Next must be called before calling Scan, if it is not an error is returned. + Scan(...interface{}) error + + // Err returns the if there was one during iteration that resulted in iteration being unable to complete. + // Err will also release resources held by the iterator, the Scanner should not used after being called. + Err() error +} + +type iterScanner struct { + iter *Iter + cols [][]byte + valid bool +} + +func (is *iterScanner) Next() bool { + iter := is.iter + if iter.err != nil { + return false + } + + if iter.pos >= iter.numRows { + if iter.next != nil { + is.iter = iter.next.fetch() + return is.Next() + } + return false + } + + for i := 0; i < len(is.cols); i++ { + col, err := iter.readColumn() + if err != nil { + iter.err = err + return false + } + is.cols[i] = col + } + iter.pos++ + is.valid = true + + return true +} + +func scanColumn(p []byte, col ColumnInfo, dest []interface{}) (int, error) { + if dest[0] == nil { + return 1, nil + } + + if col.TypeInfo.Type() == TypeTuple { + // this will panic, actually a bug, please report + tuple := col.TypeInfo.(TupleTypeInfo) + + count := len(tuple.Elems) + // here we pass in a slice of the struct which has the number number of + // values as elements in the tuple + if err := Unmarshal(col.TypeInfo, p, dest[:count]); err != nil { + return 0, err + } + return count, nil + } else { + if err := Unmarshal(col.TypeInfo, p, dest[0]); err != nil { + return 0, err + } + return 1, nil + } +} + +func (is *iterScanner) Scan(dest ...interface{}) error { + if !is.valid { + return errors.New("gocql: Scan called without calling Next") + } + + iter := is.iter + // currently only support scanning into an expand tuple, such that its the same + // as scanning in more values from a single column + if len(dest) != iter.meta.actualColCount { + return fmt.Errorf("gocql: not enough columns to scan into: have %d want %d", len(dest), iter.meta.actualColCount) + } + + // i is the current position in dest, could posible replace it and just use + // slices of dest + i := 0 + var err error + for _, col := range iter.meta.columns { + var n int + n, err = scanColumn(is.cols[i], col, dest[i:]) + if err != nil { + break + } + i += n + } + + is.valid = false + return err +} + +func (is *iterScanner) Err() error { + iter := is.iter + is.iter = nil + is.cols = nil + is.valid = false + return iter.Close() +} + +// Scanner returns a row Scanner which provides an interface to scan rows in a manner which is +// similar to database/sql. The iter should NOT be used again after calling this method. +func (iter *Iter) Scanner() Scanner { + if iter == nil { + return nil + } + + return &iterScanner{iter: iter, cols: make([][]byte, len(iter.meta.columns))} +} + +func (iter *Iter) readColumn() ([]byte, error) { + return iter.framer.readBytesInternal() +} + +// Scan consumes the next row of the iterator and copies the columns of the +// current row into the values pointed at by dest. Use nil as a dest value +// to skip the corresponding column. Scan might send additional queries +// to the database to retrieve the next set of rows if paging was enabled. +// +// Scan returns true if the row was successfully unmarshaled or false if the +// end of the result set was reached or if an error occurred. Close should +// be called afterwards to retrieve any potential errors. +func (iter *Iter) Scan(dest ...interface{}) bool { + if iter.err != nil { + return false + } + + if iter.pos >= iter.numRows { + if iter.next != nil { + *iter = *iter.next.fetch() + return iter.Scan(dest...) + } + return false + } + + if iter.next != nil && iter.pos == iter.next.pos { + go iter.next.fetch() + } + + // currently only support scanning into an expand tuple, such that its the same + // as scanning in more values from a single column + if len(dest) != iter.meta.actualColCount { + iter.err = fmt.Errorf("gocql: not enough columns to scan into: have %d want %d", len(dest), iter.meta.actualColCount) + return false + } + + // i is the current position in dest, could posible replace it and just use + // slices of dest + i := 0 + for _, col := range iter.meta.columns { + colBytes, err := iter.readColumn() + if err != nil { + iter.err = err + return false + } + + n, err := scanColumn(colBytes, col, dest[i:]) + if err != nil { + iter.err = err + return false + } + i += n + } + + iter.pos++ + return true +} + +// GetCustomPayload returns any parsed custom payload results if given in the +// response from Cassandra. Note that the result is not a copy. +// +// This additional feature of CQL Protocol v4 +// allows additional results and query information to be returned by +// custom QueryHandlers running in your C* cluster. +// See https://datastax.github.io/java-driver/manual/custom_payloads/ +func (iter *Iter) GetCustomPayload() map[string][]byte { + return iter.framer.header.customPayload +} + +// Warnings returns any warnings generated if given in the response from Cassandra. +// +// This is only available starting with CQL Protocol v4. +func (iter *Iter) Warnings() []string { + if iter.framer != nil { + return iter.framer.header.warnings + } + return nil +} + +// Close closes the iterator and returns any errors that happened during +// the query or the iteration. +func (iter *Iter) Close() error { + if atomic.CompareAndSwapInt32(&iter.closed, 0, 1) { + if iter.framer != nil { + iter.framer = nil + } + } + + return iter.err +} + +// WillSwitchPage detects if iterator reached end of current page +// and the next page is available. +func (iter *Iter) WillSwitchPage() bool { + return iter.pos >= iter.numRows && iter.next != nil +} + +// checkErrAndNotFound handle error and NotFound in one method. +func (iter *Iter) checkErrAndNotFound() error { + if iter.err != nil { + return iter.err + } else if iter.numRows == 0 { + return ErrNotFound + } + return nil +} + +// PageState return the current paging state for a query which can be used for +// subsequent quries to resume paging this point. +func (iter *Iter) PageState() []byte { + return iter.meta.pagingState +} + +// NumRows returns the number of rows in this pagination, it will update when new +// pages are fetched, it is not the value of the total number of rows this iter +// will return unless there is only a single page returned. +func (iter *Iter) NumRows() int { + return iter.numRows +} + +type nextIter struct { + qry Query + pos int + once sync.Once + next *Iter + conn *Conn +} + +func (n *nextIter) fetch() *Iter { + n.once.Do(func() { + iter := n.qry.session.executor.attemptQuery(&n.qry, n.conn) + if iter != nil && iter.err == nil { + n.next = iter + } else { + n.next = n.qry.session.executeQuery(&n.qry) + } + }) + return n.next +} + +type Batch struct { + Type BatchType + Entries []BatchEntry + Cons Consistency + rt RetryPolicy + observer BatchObserver + attempts int + totalLatency int64 + serialCons SerialConsistency + defaultTimestamp bool + defaultTimestampValue int64 + context context.Context + keyspace string +} + +// NewBatch creates a new batch operation without defaults from the cluster +// +// Depreicated: use session.NewBatch instead +func NewBatch(typ BatchType) *Batch { + return &Batch{Type: typ} +} + +// NewBatch creates a new batch operation using defaults defined in the cluster +func (s *Session) NewBatch(typ BatchType) *Batch { + s.mu.RLock() + batch := &Batch{ + Type: typ, + rt: s.cfg.RetryPolicy, + serialCons: s.cfg.SerialConsistency, + observer: s.batchObserver, + Cons: s.cons, + defaultTimestamp: s.cfg.DefaultTimestamp, + keyspace: s.cfg.Keyspace, + } + s.mu.RUnlock() + return batch +} + +// Observer enables batch-level observer on this batch. +// The provided observer will be called every time this batched query is executed. +func (b *Batch) Observer(observer BatchObserver) *Batch { + b.observer = observer + return b +} + +func (b *Batch) Keyspace() string { + return b.keyspace +} + +// Attempts returns the number of attempts made to execute the batch. +func (b *Batch) Attempts() int { + return b.attempts +} + +//Latency returns the average number of nanoseconds to execute a single attempt of the batch. +func (b *Batch) Latency() int64 { + if b.attempts > 0 { + return b.totalLatency / int64(b.attempts) + } + return 0 +} + +// GetConsistency returns the currently configured consistency level for the batch +// operation. +func (b *Batch) GetConsistency() Consistency { + return b.Cons +} + +// SetConsistency sets the currently configured consistency level for the batch +// operation. +func (b *Batch) SetConsistency(c Consistency) { + b.Cons = c +} + +// Query adds the query to the batch operation +func (b *Batch) Query(stmt string, args ...interface{}) { + b.Entries = append(b.Entries, BatchEntry{Stmt: stmt, Args: args}) +} + +// Bind adds the query to the batch operation and correlates it with a binding callback +// that will be invoked when the batch is executed. The binding callback allows the application +// to define which query argument values will be marshalled as part of the batch execution. +func (b *Batch) Bind(stmt string, bind func(q *QueryInfo) ([]interface{}, error)) { + b.Entries = append(b.Entries, BatchEntry{Stmt: stmt, binding: bind}) +} + +func (b *Batch) retryPolicy() RetryPolicy { + return b.rt +} + +// RetryPolicy sets the retry policy to use when executing the batch operation +func (b *Batch) RetryPolicy(r RetryPolicy) *Batch { + b.rt = r + return b +} + +// WithContext will set the context to use during a query, it will be used to +// timeout when waiting for responses from Cassandra. +func (b *Batch) WithContext(ctx context.Context) *Batch { + b.context = ctx + return b +} + +// Size returns the number of batch statements to be executed by the batch operation. +func (b *Batch) Size() int { + return len(b.Entries) +} + +// SerialConsistency sets the consistency level for the +// serial phase of conditional updates. That consistency can only be +// either SERIAL or LOCAL_SERIAL and if not present, it defaults to +// SERIAL. This option will be ignored for anything else that a +// conditional update/insert. +// +// Only available for protocol 3 and above +func (b *Batch) SerialConsistency(cons SerialConsistency) *Batch { + b.serialCons = cons + return b +} + +// DefaultTimestamp will enable the with default timestamp flag on the query. +// If enable, this will replace the server side assigned +// timestamp as default timestamp. Note that a timestamp in the query itself +// will still override this timestamp. This is entirely optional. +// +// Only available on protocol >= 3 +func (b *Batch) DefaultTimestamp(enable bool) *Batch { + b.defaultTimestamp = enable + return b +} + +// WithTimestamp will enable the with default timestamp flag on the query +// like DefaultTimestamp does. But also allows to define value for timestamp. +// It works the same way as USING TIMESTAMP in the query itself, but +// should not break prepared query optimization +// +// Only available on protocol >= 3 +func (b *Batch) WithTimestamp(timestamp int64) *Batch { + b.DefaultTimestamp(true) + b.defaultTimestampValue = timestamp + return b +} + +func (b *Batch) attempt(keyspace string, end, start time.Time, iter *Iter, host *HostInfo) { + b.attempts++ + b.totalLatency += end.Sub(start).Nanoseconds() + // TODO: track latencies per host and things as well instead of just total + + if b.observer == nil { + return + } + + statements := make([]string, len(b.Entries)) + for i, entry := range b.Entries { + statements[i] = entry.Stmt + } + + b.observer.ObserveBatch(b.context, ObservedBatch{ + Keyspace: keyspace, + Statements: statements, + Start: start, + End: end, + // Rows not used in batch observations // TODO - might be able to support it when using BatchCAS + Host: host, + Err: iter.err, + }) +} + +func (b *Batch) GetRoutingKey() ([]byte, error) { + // TODO: use the first statement in the batch as the routing key? + return nil, nil +} + +type BatchType byte + +const ( + LoggedBatch BatchType = 0 + UnloggedBatch BatchType = 1 + CounterBatch BatchType = 2 +) + +type BatchEntry struct { + Stmt string + Args []interface{} + binding func(q *QueryInfo) ([]interface{}, error) +} + +type ColumnInfo struct { + Keyspace string + Table string + Name string + TypeInfo TypeInfo +} + +func (c ColumnInfo) String() string { + return fmt.Sprintf("[column keyspace=%s table=%s name=%s type=%v]", c.Keyspace, c.Table, c.Name, c.TypeInfo) +} + +// routing key indexes LRU cache +type routingKeyInfoLRU struct { + lru *lru.Cache + mu sync.Mutex +} + +type routingKeyInfo struct { + indexes []int + types []TypeInfo +} + +func (r *routingKeyInfo) String() string { + return fmt.Sprintf("routing key index=%v types=%v", r.indexes, r.types) +} + +func (r *routingKeyInfoLRU) Remove(key string) { + r.mu.Lock() + r.lru.Remove(key) + r.mu.Unlock() +} + +//Max adjusts the maximum size of the cache and cleans up the oldest records if +//the new max is lower than the previous value. Not concurrency safe. +func (r *routingKeyInfoLRU) Max(max int) { + r.mu.Lock() + for r.lru.Len() > max { + r.lru.RemoveOldest() + } + r.lru.MaxEntries = max + r.mu.Unlock() +} + +type inflightCachedEntry struct { + wg sync.WaitGroup + err error + value interface{} +} + +// Tracer is the interface implemented by query tracers. Tracers have the +// ability to obtain a detailed event log of all events that happened during +// the execution of a query from Cassandra. Gathering this information might +// be essential for debugging and optimizing queries, but this feature should +// not be used on production systems with very high load. +type Tracer interface { + Trace(traceId []byte) +} + +type traceWriter struct { + session *Session + w io.Writer + mu sync.Mutex +} + +// NewTraceWriter returns a simple Tracer implementation that outputs +// the event log in a textual format. +func NewTraceWriter(session *Session, w io.Writer) Tracer { + return &traceWriter{session: session, w: w} +} + +func (t *traceWriter) Trace(traceId []byte) { + var ( + coordinator string + duration int + ) + iter := t.session.control.query(`SELECT coordinator, duration + FROM system_traces.sessions + WHERE session_id = ?`, traceId) + + iter.Scan(&coordinator, &duration) + if err := iter.Close(); err != nil { + t.mu.Lock() + fmt.Fprintln(t.w, "Error:", err) + t.mu.Unlock() + return + } + + var ( + timestamp time.Time + activity string + source string + elapsed int + ) + + t.mu.Lock() + defer t.mu.Unlock() + + fmt.Fprintf(t.w, "Tracing session %016x (coordinator: %s, duration: %v):\n", + traceId, coordinator, time.Duration(duration)*time.Microsecond) + + iter = t.session.control.query(`SELECT event_id, activity, source, source_elapsed + FROM system_traces.events + WHERE session_id = ?`, traceId) + + for iter.Scan(×tamp, &activity, &source, &elapsed) { + fmt.Fprintf(t.w, "%s: %s (source: %s, elapsed: %d)\n", + timestamp.Format("2006/01/02 15:04:05.999999"), activity, source, elapsed) + } + + if err := iter.Close(); err != nil { + fmt.Fprintln(t.w, "Error:", err) + } +} + +type ObservedQuery struct { + Keyspace string + Statement string + + Start time.Time // time immediately before the query was called + End time.Time // time immediately after the query returned + + // Rows is the number of rows in the current iter. + // In paginated queries, rows from previous scans are not counted. + // Rows is not used in batch queries and remains at the default value + Rows int + + // Host is the informations about the host that performed the query + Host *HostInfo + + // Err is the error in the query. + // It only tracks network errors or errors of bad cassandra syntax, in particular selects with no match return nil error + Err error +} + +// QueryObserver is the interface implemented by query observers / stat collectors. +// +// Experimental, this interface and use may change +type QueryObserver interface { + // ObserveQuery gets called on every query to cassandra, including all queries in an iterator when paging is enabled. + // It doesn't get called if there is no query because the session is closed or there are no connections available. + // The error reported only shows query errors, i.e. if a SELECT is valid but finds no matches it will be nil. + ObserveQuery(context.Context, ObservedQuery) +} + +type ObservedBatch struct { + Keyspace string + Statements []string + + Start time.Time // time immediately before the batch query was called + End time.Time // time immediately after the batch query returned + + // Host is the informations about the host that performed the batch + Host *HostInfo + + // Err is the error in the batch query. + // It only tracks network errors or errors of bad cassandra syntax, in particular selects with no match return nil error + Err error +} + +// BatchObserver is the interface implemented by batch observers / stat collectors. +type BatchObserver interface { + // ObserveBatch gets called on every batch query to cassandra. + // It also gets called once for each query in a batch. + // It doesn't get called if there is no query because the session is closed or there are no connections available. + // The error reported only shows query errors, i.e. if a SELECT is valid but finds no matches it will be nil. + // Unlike QueryObserver.ObserveQuery it does no reporting on rows read. + ObserveBatch(context.Context, ObservedBatch) +} + +type ObservedConnect struct { + // Host is the information about the host about to connect + Host *HostInfo + + Start time.Time // time immediately before the dial is called + End time.Time // time immediately after the dial returned + + // Err is the connection error (if any) + Err error +} + +// ConnectObserver is the interface implemented by connect observers / stat collectors. +type ConnectObserver interface { + // ObserveConnect gets called when a new connection to cassandra is made. + ObserveConnect(ObservedConnect) +} + +type Error struct { + Code int + Message string +} + +func (e Error) Error() string { + return e.Message +} + +var ( + ErrNotFound = errors.New("not found") + ErrUnavailable = errors.New("unavailable") + ErrUnsupported = errors.New("feature not supported") + ErrTooManyStmts = errors.New("too many statements") + ErrUseStmt = errors.New("use statements aren't supported. Please see https://github.com/gocql/gocql for explanation.") + ErrSessionClosed = errors.New("session has been closed") + ErrNoConnections = errors.New("gocql: no hosts available in the pool") + ErrNoKeyspace = errors.New("no keyspace provided") + ErrKeyspaceDoesNotExist = errors.New("keyspace does not exist") + ErrNoMetadata = errors.New("no metadata available") +) + +type ErrProtocol struct{ error } + +func NewErrProtocol(format string, args ...interface{}) error { + return ErrProtocol{fmt.Errorf(format, args...)} +} + +// BatchSizeMaximum is the maximum number of statements a batch operation can have. +// This limit is set by cassandra and could change in the future. +const BatchSizeMaximum = 65535 diff --git a/vendor/github.com/gocql/gocql/token.go b/vendor/github.com/gocql/gocql/token.go new file mode 100644 index 0000000..bdfcceb --- /dev/null +++ b/vendor/github.com/gocql/gocql/token.go @@ -0,0 +1,220 @@ +// Copyright (c) 2015 The gocql 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 gocql + +import ( + "bytes" + "crypto/md5" + "fmt" + "math/big" + "sort" + "strconv" + "strings" + + "github.com/gocql/gocql/internal/murmur" +) + +// a token partitioner +type partitioner interface { + Name() string + Hash([]byte) token + ParseString(string) token +} + +// a token +type token interface { + fmt.Stringer + Less(token) bool +} + +// murmur3 partitioner and token +type murmur3Partitioner struct{} +type murmur3Token int64 + +func (p murmur3Partitioner) Name() string { + return "Murmur3Partitioner" +} + +func (p murmur3Partitioner) Hash(partitionKey []byte) token { + h1 := murmur.Murmur3H1(partitionKey) + return murmur3Token(h1) +} + +// murmur3 little-endian, 128-bit hash, but returns only h1 +func (p murmur3Partitioner) ParseString(str string) token { + val, _ := strconv.ParseInt(str, 10, 64) + return murmur3Token(val) +} + +func (m murmur3Token) String() string { + return strconv.FormatInt(int64(m), 10) +} + +func (m murmur3Token) Less(token token) bool { + return m < token.(murmur3Token) +} + +// order preserving partitioner and token +type orderedPartitioner struct{} +type orderedToken string + +func (p orderedPartitioner) Name() string { + return "OrderedPartitioner" +} + +func (p orderedPartitioner) Hash(partitionKey []byte) token { + // the partition key is the token + return orderedToken(partitionKey) +} + +func (p orderedPartitioner) ParseString(str string) token { + return orderedToken(str) +} + +func (o orderedToken) String() string { + return string(o) +} + +func (o orderedToken) Less(token token) bool { + return o < token.(orderedToken) +} + +// random partitioner and token +type randomPartitioner struct{} +type randomToken big.Int + +func (r randomPartitioner) Name() string { + return "RandomPartitioner" +} + +// 2 ** 128 +var maxHashInt, _ = new(big.Int).SetString("340282366920938463463374607431768211456", 10) + +func (p randomPartitioner) Hash(partitionKey []byte) token { + sum := md5.Sum(partitionKey) + val := new(big.Int) + val.SetBytes(sum[:]) + if sum[0] > 127 { + val.Sub(val, maxHashInt) + val.Abs(val) + } + + return (*randomToken)(val) +} + +func (p randomPartitioner) ParseString(str string) token { + val := new(big.Int) + val.SetString(str, 10) + return (*randomToken)(val) +} + +func (r *randomToken) String() string { + return (*big.Int)(r).String() +} + +func (r *randomToken) Less(token token) bool { + return -1 == (*big.Int)(r).Cmp((*big.Int)(token.(*randomToken))) +} + +type hostToken struct { + token token + host *HostInfo +} + +func (ht hostToken) String() string { + return fmt.Sprintf("{token=%v host=%v}", ht.token, ht.host.HostID()) +} + +// a data structure for organizing the relationship between tokens and hosts +type tokenRing struct { + partitioner partitioner + tokens []hostToken +} + +func newTokenRing(partitioner string, hosts []*HostInfo) (*tokenRing, error) { + tokenRing := &tokenRing{} + + if strings.HasSuffix(partitioner, "Murmur3Partitioner") { + tokenRing.partitioner = murmur3Partitioner{} + } else if strings.HasSuffix(partitioner, "OrderedPartitioner") { + tokenRing.partitioner = orderedPartitioner{} + } else if strings.HasSuffix(partitioner, "RandomPartitioner") { + tokenRing.partitioner = randomPartitioner{} + } else { + return nil, fmt.Errorf("Unsupported partitioner '%s'", partitioner) + } + + for _, host := range hosts { + for _, strToken := range host.Tokens() { + token := tokenRing.partitioner.ParseString(strToken) + tokenRing.tokens = append(tokenRing.tokens, hostToken{token, host}) + } + } + + sort.Sort(tokenRing) + + return tokenRing, nil +} + +func (t *tokenRing) Len() int { + return len(t.tokens) +} + +func (t *tokenRing) Less(i, j int) bool { + return t.tokens[i].token.Less(t.tokens[j].token) +} + +func (t *tokenRing) Swap(i, j int) { + t.tokens[i], t.tokens[j] = t.tokens[j], t.tokens[i] +} + +func (t *tokenRing) String() string { + buf := &bytes.Buffer{} + buf.WriteString("TokenRing(") + if t.partitioner != nil { + buf.WriteString(t.partitioner.Name()) + } + buf.WriteString("){") + sep := "" + for i, th := range t.tokens { + buf.WriteString(sep) + sep = "," + buf.WriteString("\n\t[") + buf.WriteString(strconv.Itoa(i)) + buf.WriteString("]") + buf.WriteString(th.token.String()) + buf.WriteString(":") + buf.WriteString(th.host.ConnectAddress().String()) + } + buf.WriteString("\n}") + return string(buf.Bytes()) +} + +func (t *tokenRing) GetHostForPartitionKey(partitionKey []byte) *HostInfo { + if t == nil { + return nil + } + + token := t.partitioner.Hash(partitionKey) + return t.GetHostForToken(token) +} + +func (t *tokenRing) GetHostForToken(token token) *HostInfo { + if t == nil || len(t.tokens) == 0 { + return nil + } + + // find the primary replica + ringIndex := sort.Search(len(t.tokens), func(i int) bool { + return !t.tokens[i].token.Less(token) + }) + + if ringIndex == len(t.tokens) { + // wrap around to the first in the ring + ringIndex = 0 + } + + return t.tokens[ringIndex].host +} diff --git a/vendor/github.com/gocql/gocql/topology.go b/vendor/github.com/gocql/gocql/topology.go new file mode 100644 index 0000000..735dc9d --- /dev/null +++ b/vendor/github.com/gocql/gocql/topology.go @@ -0,0 +1,212 @@ +package gocql + +import ( + "fmt" + "strconv" + "strings" +) + +type placementStrategy interface { + replicaMap(hosts []*HostInfo, tokens []hostToken) map[token][]*HostInfo + replicationFactor(dc string) int +} + +func getReplicationFactorFromOpts(keyspace string, val interface{}) int { + // TODO: dont really want to panic here, but is better + // than spamming + switch v := val.(type) { + case int: + if v <= 0 { + panic(fmt.Sprintf("invalid replication_factor %d. Is the %q keyspace configured correctly?", v, keyspace)) + } + return v + case string: + n, err := strconv.Atoi(v) + if err != nil { + panic(fmt.Sprintf("invalid replication_factor. Is the %q keyspace configured correctly? %v", keyspace, err)) + } else if n <= 0 { + panic(fmt.Sprintf("invalid replication_factor %d. Is the %q keyspace configured correctly?", n, keyspace)) + } + return n + default: + panic(fmt.Sprintf("unkown replication_factor type %T", v)) + } +} + +func getStrategy(ks *KeyspaceMetadata) placementStrategy { + switch { + case strings.Contains(ks.StrategyClass, "SimpleStrategy"): + return &simpleStrategy{rf: getReplicationFactorFromOpts(ks.Name, ks.StrategyOptions["replication_factor"])} + case strings.Contains(ks.StrategyClass, "NetworkTopologyStrategy"): + dcs := make(map[string]int) + for dc, rf := range ks.StrategyOptions { + if dc == "class" { + continue + } + + dcs[dc] = getReplicationFactorFromOpts(ks.Name+":dc="+dc, rf) + } + return &networkTopology{dcs: dcs} + default: + // TODO: handle unknown replicas and just return the primary host for a token + panic(fmt.Sprintf("unsupported strategy class: %v", ks.StrategyClass)) + } +} + +type simpleStrategy struct { + rf int +} + +func (s *simpleStrategy) replicationFactor(dc string) int { + return s.rf +} + +func (s *simpleStrategy) replicaMap(_ []*HostInfo, tokens []hostToken) map[token][]*HostInfo { + tokenRing := make(map[token][]*HostInfo, len(tokens)) + + for i, th := range tokens { + replicas := make([]*HostInfo, 0, s.rf) + for j := 0; j < len(tokens) && len(replicas) < s.rf; j++ { + // TODO: need to ensure we dont add the same hosts twice + h := tokens[(i+j)%len(tokens)] + replicas = append(replicas, h.host) + } + tokenRing[th.token] = replicas + } + + return tokenRing +} + +type networkTopology struct { + dcs map[string]int +} + +func (n *networkTopology) replicationFactor(dc string) int { + return n.dcs[dc] +} + +func (n *networkTopology) haveRF(replicaCounts map[string]int) bool { + if len(replicaCounts) != len(n.dcs) { + return false + } + + for dc, rf := range n.dcs { + if rf != replicaCounts[dc] { + return false + } + } + + return true +} + +func (n *networkTopology) replicaMap(hosts []*HostInfo, tokens []hostToken) map[token][]*HostInfo { + dcRacks := make(map[string]map[string]struct{}) + + for _, h := range hosts { + dc := h.DataCenter() + rack := h.Rack() + + racks, ok := dcRacks[dc] + if !ok { + racks = make(map[string]struct{}) + dcRacks[dc] = racks + } + racks[rack] = struct{}{} + } + + tokenRing := make(map[token][]*HostInfo, len(tokens)) + + var totalRF int + for _, rf := range n.dcs { + totalRF += rf + } + + for i, th := range tokens { + // number of replicas per dc + // TODO: recycle these + replicasInDC := make(map[string]int, len(n.dcs)) + // dc -> racks + seenDCRacks := make(map[string]map[string]struct{}, len(n.dcs)) + // skipped hosts in a dc + skipped := make(map[string][]*HostInfo, len(n.dcs)) + + replicas := make([]*HostInfo, 0, totalRF) + for j := 0; j < len(tokens) && !n.haveRF(replicasInDC); j++ { + // TODO: ensure we dont add the same host twice + h := tokens[(i+j)%len(tokens)].host + + dc := h.DataCenter() + rack := h.Rack() + + rf, ok := n.dcs[dc] + if !ok { + // skip this DC, dont know about it + continue + } else if replicasInDC[dc] >= rf { + if replicasInDC[dc] > rf { + panic(fmt.Sprintf("replica overflow. rf=%d have=%d in dc %q", rf, replicasInDC[dc], dc)) + } + + // have enough replicas in this DC + continue + } else if _, ok := dcRacks[dc][rack]; !ok { + // dont know about this rack + continue + } else if len(replicas) >= totalRF { + if replicasInDC[dc] > rf { + panic(fmt.Sprintf("replica overflow. total rf=%d have=%d", totalRF, len(replicas))) + } + + // we now have enough replicas + break + } + + racks := seenDCRacks[dc] + if _, ok := racks[rack]; ok && len(racks) == len(dcRacks[dc]) { + // we have been through all the racks and dont have RF yet, add this + replicas = append(replicas, h) + replicasInDC[dc]++ + } else if !ok { + if racks == nil { + racks = make(map[string]struct{}, 1) + seenDCRacks[dc] = racks + } + + // new rack + racks[rack] = struct{}{} + replicas = append(replicas, h) + replicasInDC[dc]++ + + if len(racks) == len(dcRacks[dc]) { + // if we have been through all the racks, drain the rest of the skipped + // hosts until we have RF. The next iteration will skip in the block + // above + skippedHosts := skipped[dc] + var k int + for ; k < len(skippedHosts) && replicasInDC[dc] < rf; k++ { + sh := skippedHosts[k] + replicas = append(replicas, sh) + replicasInDC[dc]++ + } + skipped[dc] = skippedHosts[k:] + } + } else { + // already seen this rack, keep hold of this host incase + // we dont get enough for rf + skipped[dc] = append(skipped[dc], h) + } + } + + if len(replicas) == 0 || replicas[0] != th.host { + panic("first replica is not the primary replica for the token") + } + + tokenRing[th.token] = replicas + } + + if len(tokenRing) != len(tokens) { + panic(fmt.Sprintf("token map different size to token ring: got %d expected %d", len(tokenRing), len(tokens))) + } + + return tokenRing +} diff --git a/vendor/github.com/gocql/gocql/uuid.go b/vendor/github.com/gocql/gocql/uuid.go new file mode 100644 index 0000000..7ca4c08 --- /dev/null +++ b/vendor/github.com/gocql/gocql/uuid.go @@ -0,0 +1,272 @@ +// Copyright (c) 2012 The gocql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The uuid package can be used to generate and parse universally unique +// identifiers, a standardized format in the form of a 128 bit number. +// +// http://tools.ietf.org/html/rfc4122 +package gocql + +import ( + "crypto/rand" + "errors" + "fmt" + "io" + "net" + "strings" + "sync/atomic" + "time" +) + +type UUID [16]byte + +var hardwareAddr []byte +var clockSeq uint32 + +const ( + VariantNCSCompat = 0 + VariantIETF = 2 + VariantMicrosoft = 6 + VariantFuture = 7 +) + +func init() { + if interfaces, err := net.Interfaces(); err == nil { + for _, i := range interfaces { + if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 { + hardwareAddr = i.HardwareAddr + break + } + } + } + if hardwareAddr == nil { + // If we failed to obtain the MAC address of the current computer, + // we will use a randomly generated 6 byte sequence instead and set + // the multicast bit as recommended in RFC 4122. + hardwareAddr = make([]byte, 6) + _, err := io.ReadFull(rand.Reader, hardwareAddr) + if err != nil { + panic(err) + } + hardwareAddr[0] = hardwareAddr[0] | 0x01 + } + + // initialize the clock sequence with a random number + var clockSeqRand [2]byte + io.ReadFull(rand.Reader, clockSeqRand[:]) + clockSeq = uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0]) +} + +// ParseUUID parses a 32 digit hexadecimal number (that might contain hypens) +// representing an UUID. +func ParseUUID(input string) (UUID, error) { + var u UUID + j := 0 + for _, r := range input { + switch { + case r == '-' && j&1 == 0: + continue + case r >= '0' && r <= '9' && j < 32: + u[j/2] |= byte(r-'0') << uint(4-j&1*4) + case r >= 'a' && r <= 'f' && j < 32: + u[j/2] |= byte(r-'a'+10) << uint(4-j&1*4) + case r >= 'A' && r <= 'F' && j < 32: + u[j/2] |= byte(r-'A'+10) << uint(4-j&1*4) + default: + return UUID{}, fmt.Errorf("invalid UUID %q", input) + } + j += 1 + } + if j != 32 { + return UUID{}, fmt.Errorf("invalid UUID %q", input) + } + return u, nil +} + +// UUIDFromBytes converts a raw byte slice to an UUID. +func UUIDFromBytes(input []byte) (UUID, error) { + var u UUID + if len(input) != 16 { + return u, errors.New("UUIDs must be exactly 16 bytes long") + } + + copy(u[:], input) + return u, nil +} + +// RandomUUID generates a totally random UUID (version 4) as described in +// RFC 4122. +func RandomUUID() (UUID, error) { + var u UUID + _, err := io.ReadFull(rand.Reader, u[:]) + if err != nil { + return u, err + } + u[6] &= 0x0F // clear version + u[6] |= 0x40 // set version to 4 (random uuid) + u[8] &= 0x3F // clear variant + u[8] |= 0x80 // set to IETF variant + return u, nil +} + +var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix() + +// TimeUUID generates a new time based UUID (version 1) using the current +// time as the timestamp. +func TimeUUID() UUID { + return UUIDFromTime(time.Now()) +} + +// UUIDFromTime generates a new time based UUID (version 1) as described in +// RFC 4122. This UUID contains the MAC address of the node that generated +// the UUID, the given timestamp and a sequence number. +func UUIDFromTime(aTime time.Time) UUID { + utcTime := aTime.In(time.UTC) + t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100) + clock := atomic.AddUint32(&clockSeq, 1) + + return TimeUUIDWith(t, clock, hardwareAddr) +} + +// TimeUUIDWith generates a new time based UUID (version 1) as described in +// RFC4122 with given parameters. t is the number of 100's of nanoseconds +// since 15 Oct 1582 (60bits). clock is the number of clock sequence (14bits). +// node is a slice to gurarantee the uniqueness of the UUID (up to 6bytes). +// Note: calling this function does not increment the static clock sequence. +func TimeUUIDWith(t int64, clock uint32, node []byte) UUID { + var u UUID + + u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t) + u[4], u[5] = byte(t>>40), byte(t>>32) + u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48) + + u[8] = byte(clock >> 8) + u[9] = byte(clock) + + copy(u[10:], node) + + u[6] |= 0x10 // set version to 1 (time based uuid) + u[8] &= 0x3F // clear variant + u[8] |= 0x80 // set to IETF variant + + return u +} + +// String returns the UUID in it's canonical form, a 32 digit hexadecimal +// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func (u UUID) String() string { + var offsets = [...]int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} + const hexString = "0123456789abcdef" + r := make([]byte, 36) + for i, b := range u { + r[offsets[i]] = hexString[b>>4] + r[offsets[i]+1] = hexString[b&0xF] + } + r[8] = '-' + r[13] = '-' + r[18] = '-' + r[23] = '-' + return string(r) + +} + +// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits +// (16 bytes) long. +func (u UUID) Bytes() []byte { + return u[:] +} + +// Variant returns the variant of this UUID. This package will only generate +// UUIDs in the IETF variant. +func (u UUID) Variant() int { + x := u[8] + if x&0x80 == 0 { + return VariantNCSCompat + } + if x&0x40 == 0 { + return VariantIETF + } + if x&0x20 == 0 { + return VariantMicrosoft + } + return VariantFuture +} + +// Version extracts the version of this UUID variant. The RFC 4122 describes +// five kinds of UUIDs. +func (u UUID) Version() int { + return int(u[6] & 0xF0 >> 4) +} + +// Node extracts the MAC address of the node who generated this UUID. It will +// return nil if the UUID is not a time based UUID (version 1). +func (u UUID) Node() []byte { + if u.Version() != 1 { + return nil + } + return u[10:] +} + +// Clock extracts the clock sequence of this UUID. It will return zero if the +// UUID is not a time based UUID (version 1). +func (u UUID) Clock() uint32 { + if u.Version() != 1 { + return 0 + } + + // Clock sequence is the lower 14bits of u[8:10] + return uint32(u[8]&0x3F)<<8 | uint32(u[9]) +} + +// Timestamp extracts the timestamp information from a time based UUID +// (version 1). +func (u UUID) Timestamp() int64 { + if u.Version() != 1 { + return 0 + } + return int64(uint64(u[0])<<24|uint64(u[1])<<16| + uint64(u[2])<<8|uint64(u[3])) + + int64(uint64(u[4])<<40|uint64(u[5])<<32) + + int64(uint64(u[6]&0x0F)<<56|uint64(u[7])<<48) +} + +// Time is like Timestamp, except that it returns a time.Time. +func (u UUID) Time() time.Time { + if u.Version() != 1 { + return time.Time{} + } + t := u.Timestamp() + sec := t / 1e7 + nsec := (t % 1e7) * 100 + return time.Unix(sec+timeBase, nsec).UTC() +} + +// Marshaling for JSON +func (u UUID) MarshalJSON() ([]byte, error) { + return []byte(`"` + u.String() + `"`), nil +} + +// Unmarshaling for JSON +func (u *UUID) UnmarshalJSON(data []byte) error { + str := strings.Trim(string(data), `"`) + if len(str) > 36 { + return fmt.Errorf("invalid JSON UUID %s", str) + } + + parsed, err := ParseUUID(str) + if err == nil { + copy(u[:], parsed[:]) + } + + return err +} + +func (u UUID) MarshalText() ([]byte, error) { + return []byte(u.String()), nil +} + +func (u *UUID) UnmarshalText(text []byte) (err error) { + *u, err = ParseUUID(string(text)) + return +} diff --git a/vendor/github.com/gogo/protobuf/AUTHORS b/vendor/github.com/gogo/protobuf/AUTHORS new file mode 100644 index 0000000..3d97fc7 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of GoGo authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS file, which +# lists people. For example, employees are listed in CONTRIBUTORS, +# but not in AUTHORS, because the employer holds the copyright. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +# Please keep the list sorted. + +Sendgrid, Inc +Vastech SA (PTY) LTD +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/CONTRIBUTORS b/vendor/github.com/gogo/protobuf/CONTRIBUTORS new file mode 100644 index 0000000..1b4f6c2 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/CONTRIBUTORS @@ -0,0 +1,23 @@ +Anton Povarov +Brian Goff +Clayton Coleman +Denis Smirnov +DongYun Kang +Dwayne Schultz +Georg Apitz +Gustav Paul +Johan Brandhorst +John Shahid +John Tuley +Laurent +Patrick Lee +Peter Edge +Roger Johansson +Sam Nguyen +Sergio Arbeo +Stephen J Day +Tamir Duberstein +Todd Eisenberger +Tormod Erevik Lea +Vyacheslav Kim +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS b/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS new file mode 100644 index 0000000..b368efb --- /dev/null +++ b/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS @@ -0,0 +1,5 @@ +The contributors to the Go protobuf repository: + +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. \ No newline at end of file diff --git a/vendor/github.com/gogo/protobuf/LICENSE b/vendor/github.com/gogo/protobuf/LICENSE new file mode 100644 index 0000000..7be0cc7 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/LICENSE @@ -0,0 +1,36 @@ +Protocol Buffers for Go with Gadgets + +Copyright (c) 2013, The GoGo Authors. All rights reserved. +http://github.com/gogo/protobuf + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +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/vendor/github.com/gogo/protobuf/proto/Makefile b/vendor/github.com/gogo/protobuf/proto/Makefile new file mode 100644 index 0000000..41c7175 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# 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. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc-min-version --version="3.0.0" --proto_path=.:../../../../:../protobuf --gogo_out=Mtestdata/test.proto=github.com/gogo/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. proto3_proto/proto3.proto + make diff --git a/vendor/github.com/gogo/protobuf/proto/clone.go b/vendor/github.com/gogo/protobuf/proto/clone.go new file mode 100644 index 0000000..5d4cba4 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/clone.go @@ -0,0 +1,234 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + + out := reflect.New(in.Type().Elem()) + // out is empty so a merge is a deep copy. + mergeStruct(out.Elem(), in.Elem()) + return out.Interface().(Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + // Explicit test prior to mergeStruct so that mistyped nils will fail + panic("proto: type mismatch") + } + if in.IsNil() { + // Merging nil into non-nil is a quiet no-op + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { + emOut := out.Addr().Interface().(extensionsBytes) + bIn := emIn.GetExtensions() + bOut := emOut.GetExtensions() + *bOut = append(*bOut, *bIn...) + } else if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/decode.go b/vendor/github.com/gogo/protobuf/proto/decode.go new file mode 100644 index 0000000..737f273 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode.go @@ -0,0 +1,978 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" + "os" + "reflect" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// The fundamental decoders that interpret bytes on the wire. +// Those that take integer types all return uint64 and are +// therefore of type valueDecoder. + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// These are not ValueDecoders: they produce an array of bytes or a string. +// bytes, embedded messages + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +// If the protocol buffer has extensions, and the field matches, add it as an extension. +// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. +func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { + oi := o.index + + err := o.skip(t, tag, wire) + if err != nil { + return err + } + + if !unrecField.IsValid() { + return nil + } + + ptr := structPointer_Bytes(base, unrecField) + + // Add the skipped field to struct field + obuf := o.buf + + o.buf = *ptr + o.EncodeVarint(uint64(tag<<3 | wire)) + *ptr = append(o.buf, obuf[oi:o.index]...) + + o.buf = obuf + + return nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +func (o *Buffer) skip(t reflect.Type, tag, wire int) error { + + var u uint64 + var err error + + switch wire { + case WireVarint: + _, err = o.DecodeVarint() + case WireFixed64: + _, err = o.DecodeFixed64() + case WireBytes: + _, err = o.DecodeRawBytes(false) + case WireFixed32: + _, err = o.DecodeFixed32() + case WireStartGroup: + for { + u, err = o.DecodeVarint() + if err != nil { + break + } + fwire := int(u & 0x7) + if fwire == WireEndGroup { + break + } + ftag := int(u >> 3) + err = o.skip(t, ftag, fwire) + if err != nil { + break + } + } + default: + err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) + } + return err +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The method should reset the receiver before +// decoding starts. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + return UnmarshalMerge(buf, pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +func (p *Buffer) DecodeGroup(pb Message) error { + typ, base, err := getbase(pb) + if err != nil { + return err + } + return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + typ, base, err := getbase(pb) + if err != nil { + return err + } + + err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) + + if collectStats { + stats.Decode++ + } + + return err +} + +// unmarshalType does the work of unmarshaling a structure. +func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { + var state errorState + required, reqFields := prop.reqCount, uint64(0) + + var err error + for err == nil && o.index < len(o.buf) { + oi := o.index + var u uint64 + u, err = o.DecodeVarint() + if err != nil { + break + } + wire := int(u & 0x7) + if wire == WireEndGroup { + if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } + return nil // input is satisfied + } + return fmt.Errorf("proto: %s: wiretype end group for non-group", st) + } + tag := int(u >> 3) + if tag <= 0 { + return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) + } + fieldnum, ok := prop.decoderTags.get(tag) + if !ok { + // Maybe it's an extension? + if prop.extendable { + if e, eok := structPointer_Interface(base, st).(extensionsBytes); eok { + if isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + ext := e.GetExtensions() + *ext = append(*ext, o.buf[oi:o.index]...) + } + continue + } + } else if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + extmap[int32(tag)] = ext + } + continue + } + } + // Maybe it's a oneof? + if prop.oneofUnmarshaler != nil { + m := structPointer_Interface(base, st).(Message) + // First return value indicates whether tag is a oneof field. + ok, err = prop.oneofUnmarshaler(m, tag, wire, o) + if err == ErrInternalBadWireType { + // Map the error to something more descriptive. + // Do the formatting here to save generated code space. + err = fmt.Errorf("bad wiretype for oneof field in %T", m) + } + if ok { + continue + } + } + err = o.skipAndSave(st, tag, wire, base, prop.unrecField) + continue + } + p := prop.Prop[fieldnum] + + if p.dec == nil { + fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) + continue + } + dec := p.dec + if wire != WireStartGroup && wire != p.WireType { + if wire == WireBytes && p.packedDec != nil { + // a packable field + dec = p.packedDec + } else { + err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) + continue + } + } + decErr := dec(o, p, base) + if decErr != nil && !state.shouldContinue(decErr, p) { + err = decErr + } + if err == nil && p.Required { + // Successfully decoded a required field. + if tag <= 64 { + // use bitmap for fields 1-64 to catch field reuse. + var mask uint64 = 1 << uint64(tag-1) + if reqFields&mask == 0 { + // new required field + reqFields |= mask + required-- + } + } else { + // This is imprecise. It can be fooled by a required field + // with a tag > 64 that is encoded twice; that's very rare. + // A fully correct implementation would require allocating + // a data structure, which we would like to avoid. + required-- + } + } + } + if err == nil { + if is_group { + return io.ErrUnexpectedEOF + } + if state.err != nil { + return state.err + } + if required > 0 { + // Not enough information to determine the exact field. If we use extra + // CPU, we could determine the field only if the missing required field + // has a tag <= 64 and we check reqFields. + return &RequiredNotSetError{"{Unknown}"} + } + } + return err +} + +// Individual type decoders +// For each, +// u is the decoded value, +// v is a pointer to the field (pointer) in the struct + +// Sizes of the pools to allocate inside the Buffer. +// The goal is modest amortization and allocation +// on at least 16-byte boundaries. +const ( + boolPoolSize = 16 + uint32PoolSize = 8 + uint64PoolSize = 4 +) + +// Decode a bool. +func (o *Buffer) dec_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + if len(o.bools) == 0 { + o.bools = make([]bool, boolPoolSize) + } + o.bools[0] = u != 0 + *structPointer_Bool(base, p.field) = &o.bools[0] + o.bools = o.bools[1:] + return nil +} + +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + +// Decode an int32. +func (o *Buffer) dec_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) + return nil +} + +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + +// Decode an int64. +func (o *Buffer) dec_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, u) + return nil +} + +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + +// Decode a string. +func (o *Buffer) dec_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s + return nil +} + +// Decode a slice of bytes ([]byte). +func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + *structPointer_Bytes(base, p.field) = b + return nil +} + +// Decode a slice of bools ([]bool). +func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + v := structPointer_BoolSlice(base, p.field) + *v = append(*v, u != 0) + return nil +} + +// Decode a slice of bools ([]bool) in packed format. +func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { + v := structPointer_BoolSlice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded bools + fin := o.index + nb + if fin < o.index { + return errOverflow + } + + y := *v + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + y = append(y, u != 0) + } + + *v = y + return nil +} + +// Decode a slice of int32s ([]int32). +func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + structPointer_Word32Slice(base, p.field).Append(uint32(u)) + return nil +} + +// Decode a slice of int32s ([]int32) in packed format. +func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int32s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(uint32(u)) + } + return nil +} + +// Decode a slice of int64s ([]int64). +func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + + structPointer_Word64Slice(base, p.field).Append(u) + return nil +} + +// Decode a slice of int64s ([]int64) in packed format. +func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int64s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(u) + } + return nil +} + +// Decode a slice of strings ([]string). +func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + v := structPointer_StringSlice(base, p.field) + *v = append(*v, s) + return nil +} + +// Decode a slice of slice of bytes ([][]byte). +func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + v := structPointer_BytesSlice(base, p.field) + *v = append(*v, b) + return nil +} + +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + keyelem, valelem := keyptr.Elem(), valptr.Elem() + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) + } + + v.SetMapIndex(keyelem, valelem) + return nil +} + +// Decode a group. +func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + return o.unmarshalType(p.stype, p.sprop, true, bas) +} + +// Decode an embedded message. +func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := structPointer_Interface(bas, p.stype) + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of embedded messages. +func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, false, base) +} + +// Decode a slice of embedded groups. +func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, true, base) +} + +// Decode a slice of structs ([]*struct). +func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { + v := reflect.New(p.stype) + bas := toStructPointer(v) + structPointer_StructPointerSlice(base, p.field).Append(bas) + + if is_group { + err := o.unmarshalType(p.stype, p.sprop, is_group, bas) + return err + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := v.Interface() + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, bas) + + o.buf = obuf + o.index = oi + + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/decode_gogo.go b/vendor/github.com/gogo/protobuf/proto/decode_gogo.go new file mode 100644 index 0000000..6fb74de --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode_gogo.go @@ -0,0 +1,172 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "reflect" +) + +// Decode a reference to a struct pointer. +func (o *Buffer) dec_ref_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + panic("not supported, since this is a pointer receiver") + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + bas := structPointer_FieldPointer(base, p.field) + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of references to struct pointers ([]struct). +func (o *Buffer) dec_slice_ref_struct(p *Properties, is_group bool, base structPointer) error { + newBas := appendStructPointer(base, p.field, p.sstype) + + if is_group { + panic("not supported, maybe in future, if requested.") + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + panic("not supported, since this is not a pointer receiver.") + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, newBas) + + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of references to struct pointers. +func (o *Buffer) dec_slice_ref_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_ref_struct(p, false, base) +} + +func setPtrCustomType(base structPointer, f field, v interface{}) { + if v == nil { + return + } + structPointer_SetStructPointer(base, f, toStructPointer(reflect.ValueOf(v))) +} + +func setCustomType(base structPointer, f field, value interface{}) { + if value == nil { + return + } + v := reflect.ValueOf(value).Elem() + t := reflect.TypeOf(value).Elem() + kind := t.Kind() + switch kind { + case reflect.Slice: + slice := reflect.MakeSlice(t, v.Len(), v.Cap()) + reflect.Copy(slice, v) + oldHeader := structPointer_GetSliceHeader(base, f) + oldHeader.Data = slice.Pointer() + oldHeader.Len = v.Len() + oldHeader.Cap = v.Cap() + default: + size := reflect.TypeOf(value).Elem().Size() + structPointer_Copy(toStructPointer(reflect.ValueOf(value)), structPointer_Add(base, f), int(size)) + } +} + +func (o *Buffer) dec_custom_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype.Elem()).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + setPtrCustomType(base, p.field, custom) + return nil +} + +func (o *Buffer) dec_custom_ref_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + if custom != nil { + setCustomType(base, p.field, custom) + } + return nil +} + +// Decode a slice of bytes ([]byte) into a slice of custom types. +func (o *Buffer) dec_custom_slice_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype.Elem()).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + newBas := appendStructPointer(base, p.field, p.ctype) + + var zero field + setCustomType(newBas, zero, custom) + + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/discard.go b/vendor/github.com/gogo/protobuf/proto/discard.go new file mode 100644 index 0000000..bd0e3bb --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/discard.go @@ -0,0 +1,151 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "fmt" + "reflect" + "strings" +) + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + discardLegacy(m) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, ok := extendable(m); ok { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration.go b/vendor/github.com/gogo/protobuf/proto/duration.go new file mode 100644 index 0000000..93464c9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration.go @@ -0,0 +1,100 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Range of a Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid Duration +// may still be too large to fit into a time.Duration (the range of Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %#v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %#v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %#v: seconds and nanos have different signs", d) + } + return nil +} + +// DurationFromProto converts a Duration to a time.Duration. DurationFromProto +// returns an error if the Duration is invalid or is too large to be +// represented in a time.Duration. +func durationFromProto(p *duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a Duration. +func durationProto(d time.Duration) *duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration_gogo.go b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go new file mode 100644 index 0000000..18e2a5f --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go @@ -0,0 +1,203 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "reflect" + "time" +) + +var durationType = reflect.TypeOf((*time.Duration)(nil)).Elem() + +type duration struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *duration) Reset() { *m = duration{} } +func (*duration) ProtoMessage() {} +func (*duration) String() string { return "duration" } + +func init() { + RegisterType((*duration)(nil), "gogo.protobuf.proto.duration") +} + +func (o *Buffer) decDuration() (time.Duration, error) { + b, err := o.DecodeRawBytes(true) + if err != nil { + return 0, err + } + dproto := &duration{} + if err := Unmarshal(b, dproto); err != nil { + return 0, err + } + return durationFromProto(dproto) +} + +func (o *Buffer) dec_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, uint64(d)) + return nil +} + +func (o *Buffer) dec_ref_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, uint64(d)) + return nil +} + +func (o *Buffer) dec_slice_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))) + var zero field + setPtrCustomType(newBas, zero, &d) + return nil +} + +func (o *Buffer) dec_slice_ref_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + structPointer_Word64Slice(base, p.field).Append(uint64(d)) + return nil +} + +func size_duration(p *Properties, base structPointer) (n int) { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + dur := structPointer_Interface(structp, durationType).(*time.Duration) + d := durationProto(*dur) + size := Size(d) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_duration(p *Properties, base structPointer) error { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + dur := structPointer_Interface(structp, durationType).(*time.Duration) + d := durationProto(*dur) + data, err := Marshal(d) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_ref_duration(p *Properties, base structPointer) (n int) { + dur := structPointer_InterfaceAt(base, p.field, durationType).(*time.Duration) + d := durationProto(*dur) + size := Size(d) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_ref_duration(p *Properties, base structPointer) error { + dur := structPointer_InterfaceAt(base, p.field, durationType).(*time.Duration) + d := durationProto(*dur) + data, err := Marshal(d) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_slice_duration(p *Properties, base structPointer) (n int) { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))).(*[]*time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + if durs[i] == nil { + return 0 + } + dproto := durationProto(*durs[i]) + size := Size(dproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_duration(p *Properties, base structPointer) error { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))).(*[]*time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + if durs[i] == nil { + return errRepeatedHasNil + } + dproto := durationProto(*durs[i]) + data, err := Marshal(dproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_slice_ref_duration(p *Properties, base structPointer) (n int) { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(durationType)).(*[]time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + dproto := durationProto(durs[i]) + size := Size(dproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_ref_duration(p *Properties, base structPointer) error { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(durationType)).(*[]time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + dproto := durationProto(durs[i]) + data, err := Marshal(dproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode.go b/vendor/github.com/gogo/protobuf/proto/encode.go new file mode 100644 index 0000000..8b84d1b --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode.go @@ -0,0 +1,1362 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" + "sort" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + return sizeVarint(x) +} + +func sizeVarint(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +func sizeFixed64(x uint64) int { + return 8 +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +func sizeFixed32(x uint64) int { + return 4 +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +func sizeZigzag64(x uint64) int { + return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +func sizeZigzag32(x uint64) int { + return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +func sizeRawBytes(b []byte) int { + return sizeVarint(uint64(len(b))) + + len(b) +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +func sizeStringBytes(s string) int { + return sizeVarint(uint64(len(s))) + + len(s) +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, returning the data. +func Marshal(pb Message) ([]byte, error) { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + return m.Marshal() + } + p := NewBuffer(nil) + err := p.Marshal(pb) + if p.buf == nil && err == nil { + // Return a non-nil slice on success. + return []byte{}, nil + } + return p.buf, err +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + var state errorState + err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) + } + return err +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, writing the result to the +// Buffer. +func (p *Buffer) Marshal(pb Message) error { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + data, err := m.Marshal() + p.buf = append(p.buf, data...) + return err + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + err = p.enc_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Encode++ // Parens are to work around a goimports bug. + } + + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } + return err +} + +// Size returns the encoded size of a protocol buffer. +func Size(pb Message) (n int) { + // Can the object marshal itself? If so, Size is slow. + // TODO: add Size to Marshaler, or add a Sizer interface. + if m, ok := pb.(Marshaler); ok { + b, _ := m.Marshal() + return len(b) + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return 0 + } + if err == nil { + n = size_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Size++ // Parens are to work around a goimports bug. + } + + return +} + +// Individual type encoders. + +// Encode a bool. +func (o *Buffer) enc_bool(p *Properties, base structPointer) error { + v := *structPointer_Bool(base, p.field) + if v == nil { + return ErrNil + } + x := 0 + if *v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + +func size_bool(p *Properties, base structPointer) int { + v := *structPointer_Bool(base, p.field) + if v == nil { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +func size_proto3_bool(p *Properties, base structPointer) int { + v := *structPointer_BoolVal(base, p.field) + if !v && !p.oneof { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode an int32. +func (o *Buffer) enc_int32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a uint32. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := word32_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := word32_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode an int64. +func (o *Buffer) enc_int64(p *Properties, base structPointer) error { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return ErrNil + } + x := word64_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return 0 + } + x := word64_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +func size_proto3_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a string. +func (o *Buffer) enc_string(p *Properties, base structPointer) error { + v := *structPointer_String(base, p.field) + if v == nil { + return ErrNil + } + x := *v + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(x) + return nil +} + +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_string(p *Properties, base structPointer) (n int) { + v := *structPointer_String(base, p.field) + if v == nil { + return 0 + } + x := *v + n += len(p.tagcode) + n += sizeStringBytes(x) + return +} + +func size_proto3_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + if v == "" && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + +// Encode a message struct. +func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return state.err + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +func size_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a group struct. +func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { + var state errorState + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return ErrNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + err := o.enc_struct(p.sprop, b) + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return state.err +} + +func size_struct_group(p *Properties, base structPointer) (n int) { + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return 0 + } + + n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) + n += size_struct(p.sprop, b) + n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return +} + +// Encode a slice of bools ([]bool). +func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + for _, x := range s { + o.buf = append(o.buf, p.tagcode...) + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_bool(p *Properties, base structPointer) int { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + return l * (len(p.tagcode) + 1) // each bool takes exactly one byte +} + +// Encode a slice of bools ([]bool) in packed format. +func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(l)) // each bool takes exactly one byte + for _, x := range s { + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_packed_bool(p *Properties, base structPointer) (n int) { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeVarint(uint64(l)) + n += l // each bool takes exactly one byte + return +} + +// Encode a slice of bytes ([]byte). +func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func size_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +// Encode a slice of int32s ([]int32). +func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of int32s ([]int32) in packed format. +func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(buf, uint64(x)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + bufSize += p.valSize(uint64(x)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of uint32s ([]uint32). +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := s.Index(i) + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := s.Index(i) + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of uint32s ([]uint32) in packed format. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, uint64(s.Index(i))) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(uint64(s.Index(i))) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of int64s ([]int64). +func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, s.Index(i)) + } + return nil +} + +func size_slice_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + n += p.valSize(s.Index(i)) + } + return +} + +// Encode a slice of int64s ([]int64) in packed format. +func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, s.Index(i)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(s.Index(i)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of slice of bytes ([][]byte). +func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(ss[i]) + } + return nil +} + +func size_slice_slice_byte(p *Properties, base structPointer) (n int) { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return 0 + } + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeRawBytes(ss[i]) + } + return +} + +// Encode a slice of strings ([]string). +func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(ss[i]) + } + return nil +} + +func size_slice_string(p *Properties, base structPointer) (n int) { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeStringBytes(ss[i]) + } + return +} + +// Encode a slice of message structs ([]*struct). +func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + } + return state.err +} + +func size_slice_struct_message(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +// Encode a slice of group structs ([]*struct). +func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return errRepeatedHasNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + + err := o.enc_struct(p.sprop, b) + + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + } + return state.err +} + +func size_slice_struct_group(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) + n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return // return size up to this point + } + + n += size_struct(p.sprop, b) + } + return +} + +// Encode an extension map. +func (o *Buffer) enc_map(p *Properties, base structPointer) error { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { + return err + } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + + v, mu := exts.extensionsRead() + if v == nil { + return nil + } + + mu.Lock() + defer mu.Unlock() + if err := encodeExtensionsMap(v); err != nil { + return err + } + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { + // Fast-path for common cases: zero or one extensions. + if len(v) <= 1 { + for _, e := range v { + o.buf = append(o.buf, e.enc...) + } + return nil + } + + // Sort keys to provide a deterministic encoding. + keys := make([]int, 0, len(v)) + for k := range v { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + o.buf = append(o.buf, v[int32(k)].enc...) + } + return nil +} + +func size_map(p *Properties, base structPointer) int { + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) +} + +// Encode a map field. +func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { + var state errorState // XXX: or do we need to plumb this through? + + /* + A map defined as + map map_field = N; + is encoded in the same way as + message MapFieldEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapFieldEntry map_field = N; + */ + + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + if v.Len() == 0 { + return nil + } + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + enc := func() error { + if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { + return err + } + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { + return err + } + return nil + } + + // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + + keycopy.Set(key) + valcopy.Set(val) + + o.buf = append(o.buf, p.tagcode...) + if err := o.enc_len_thing(enc, &state); err != nil { + return err + } + } + return nil +} + +func size_new_map(p *Properties, base structPointer) int { + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + n := 0 + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + keycopy.Set(key) + valcopy.Set(val) + + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + } + return n +} + +// mapEncodeScratch returns a new reflect.Value matching the map's value type, +// and a structPointer suitable for passing to an encoder or sizer. +func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { + // Prepare addressable doubly-indirect placeholders for the key and value types. + // This is needed because the element-type encoders expect **T, but the map iteration produces T. + + keycopy = reflect.New(mapType.Key()).Elem() // addressable K + keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K + keyptr.Set(keycopy.Addr()) // + keybase = toStructPointer(keyptr.Addr()) // **K + + // Value types are more varied and require special handling. + switch mapType.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte + valbase = toStructPointer(valcopy.Addr()) + case reflect.Ptr: + // message; the generated field type is map[K]*Msg (so V is *Msg), + // so we only need one level of indirection. + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valbase = toStructPointer(valcopy.Addr()) + default: + // everything else + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V + valptr.Set(valcopy.Addr()) // + valbase = toStructPointer(valptr.Addr()) // **V + } + return +} + +// Encode a struct. +func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { + var state errorState + // Encode fields in tag order so that decoders may use optimizations + // that depend on the ordering. + // https://developers.google.com/protocol-buffers/docs/encoding#order + for _, i := range prop.order { + p := prop.Prop[i] + if p.enc != nil { + err := p.enc(o, p, base) + if err != nil { + if err == ErrNil { + if p.Required && state.err == nil { + state.err = &RequiredNotSetError{p.Name} + } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") + } else if !state.shouldContinue(err, p) { + return err + } + } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } + } + } + + // Do oneof fields. + if prop.oneofMarshaler != nil { + m := structPointer_Interface(base, prop.stype).(Message) + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { + return err + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } + if len(v) > 0 { + o.buf = append(o.buf, v...) + } + } + + return state.err +} + +func size_struct(prop *StructProperties, base structPointer) (n int) { + for _, i := range prop.order { + p := prop.Prop[i] + if p.size != nil { + n += p.size(p, base) + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + n += len(v) + } + + // Factor in any oneof fields. + if prop.oneofSizer != nil { + m := structPointer_Interface(base, prop.stype).(Message) + n += prop.oneofSizer(m) + } + + return +} + +var zeroes [20]byte // longer than any conceivable sizeVarint + +// Encode a struct, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { + return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) +} + +// Encode something, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { + iLen := len(o.buf) + o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length + iMsg := len(o.buf) + err := enc() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + lMsg := len(o.buf) - iMsg + lLen := sizeVarint(uint64(lMsg)) + switch x := lLen - (iMsg - iLen); { + case x > 0: // actual length is x bytes larger than the space we reserved + // Move msg x bytes right. + o.buf = append(o.buf, zeroes[:x]...) + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + case x < 0: // actual length is x bytes smaller than the space we reserved + // Move msg x bytes left. + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + o.buf = o.buf[:len(o.buf)+x] // x is negative + } + // Encode the length in the reserved space. + o.buf = o.buf[:iLen] + o.EncodeVarint(uint64(lMsg)) + o.buf = o.buf[:len(o.buf)+lMsg] + return state.err +} + +// errorState maintains the first error that occurs and updates that error +// with additional context. +type errorState struct { + err error +} + +// shouldContinue reports whether encoding should continue upon encountering the +// given error. If the error is RequiredNotSetError, shouldContinue returns true +// and, if this is the first appearance of that error, remembers it for future +// reporting. +// +// If prop is not nil, it may update any error with additional context about the +// field with the error. +func (s *errorState) shouldContinue(err error, prop *Properties) bool { + // Ignore unset required fields. + reqNotSet, ok := err.(*RequiredNotSetError) + if !ok { + return false + } + if s.err == nil { + if prop != nil { + err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} + } + s.err = err + } + return true +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode_gogo.go b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go new file mode 100644 index 0000000..32111b7 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go @@ -0,0 +1,350 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// http://github.com/golang/protobuf/ +// +// 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. + +package proto + +import ( + "reflect" +) + +func NewRequiredNotSetError(field string) *RequiredNotSetError { + return &RequiredNotSetError{field} +} + +type Sizer interface { + Size() int +} + +func (o *Buffer) enc_ext_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, s...) + return nil +} + +func size_ext_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return 0 + } + n += len(s) + return +} + +// Encode a reference to bool pointer. +func (o *Buffer) enc_ref_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + x := 0 + if v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_bool(p *Properties, base structPointer) int { + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode a reference to int32 pointer. +func (o *Buffer) enc_ref_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func (o *Buffer) enc_ref_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a reference to an int64 pointer. +func (o *Buffer) enc_ref_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_ref_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a reference to a string pointer. +func (o *Buffer) enc_ref_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_ref_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// Encode a reference to a message struct. +func (o *Buffer) enc_ref_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetRefStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +//TODO this is only copied, please fix this +func size_ref_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetRefStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a slice of references to message struct pointers ([]struct). +func (o *Buffer) enc_slice_ref_struct_message(p *Properties, base structPointer) error { + var state errorState + ss := structPointer_StructRefSlice(base, p.field, p.stype.Size()) + l := ss.Len() + for i := 0; i < l; i++ { + structp := ss.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + } + return state.err +} + +//TODO this is only copied, please fix this +func size_slice_ref_struct_message(p *Properties, base structPointer) (n int) { + ss := structPointer_StructRefSlice(base, p.field, p.stype.Size()) + l := ss.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := ss.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += len(p.tagcode) + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +func (o *Buffer) enc_custom_bytes(p *Properties, base structPointer) error { + i := structPointer_InterfaceRef(base, p.field, p.ctype) + if i == nil { + return ErrNil + } + custom := i.(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + if data == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_custom_bytes(p *Properties, base structPointer) (n int) { + n += len(p.tagcode) + i := structPointer_InterfaceRef(base, p.field, p.ctype) + if i == nil { + return 0 + } + custom := i.(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + return +} + +func (o *Buffer) enc_custom_ref_bytes(p *Properties, base structPointer) error { + custom := structPointer_InterfaceAt(base, p.field, p.ctype).(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + if data == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_custom_ref_bytes(p *Properties, base structPointer) (n int) { + n += len(p.tagcode) + i := structPointer_InterfaceAt(base, p.field, p.ctype) + if i == nil { + return 0 + } + custom := i.(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + return +} + +func (o *Buffer) enc_custom_slice_bytes(p *Properties, base structPointer) error { + inter := structPointer_InterfaceRef(base, p.field, p.ctype) + if inter == nil { + return ErrNil + } + slice := reflect.ValueOf(inter) + l := slice.Len() + for i := 0; i < l; i++ { + v := slice.Index(i) + custom := v.Interface().(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_custom_slice_bytes(p *Properties, base structPointer) (n int) { + inter := structPointer_InterfaceRef(base, p.field, p.ctype) + if inter == nil { + return 0 + } + slice := reflect.ValueOf(inter) + l := slice.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + v := slice.Index(i) + custom := v.Interface().(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + } + return +} diff --git a/vendor/github.com/gogo/protobuf/proto/equal.go b/vendor/github.com/gogo/protobuf/proto/equal.go new file mode 100644 index 0000000..2ed1cf5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + b1, ok := f1.Interface().(raw) + if ok { + b2 := f2.Interface().(raw) + // RawMessage + if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + return false + } + continue + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + if !bytes.Equal(u1, u2) { + return false + } + + return true +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + continue + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions.go b/vendor/github.com/gogo/protobuf/proto/extensions.go new file mode 100644 index 0000000..0dfcb53 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions.go @@ -0,0 +1,693 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +type extensionsBytes interface { + Message + ExtensionRangeArray() []ExtensionRange + GetExtensions() *[]byte +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +type extensionRange interface { + Message + ExtensionRangeArray() []ExtensionRange +} + +var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() +var extendableBytesType = reflect.TypeOf((*extensionsBytes)(nil)).Elem() +var extensionRangeType = reflect.TypeOf((*extensionRange)(nil)).Elem() + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + if ebase, ok := base.(extensionsBytes); ok { + clearExtension(base, id) + ext := ebase.GetExtensions() + *ext = append(*ext, b...) + return + } + epb, ok := extendable(base) + if !ok { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extensionRange, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { + for k, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + m[k] = e + } + return nil +} + +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) +} + +func extensionsMapSize(m map[int32]Extension) (n int) { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + n += props.size(props, toStructPointer(x)) + } + return +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + buf := *ext + o := 0 + for o < len(buf) { + tag, n := DecodeVarint(buf[o:]) + fieldNum := int32(tag >> 3) + if int32(fieldNum) == extension.Field { + return true + } + wireType := int(tag & 0x7) + o += n + l, err := size(buf[o:], wireType) + if err != nil { + return false + } + o += l + } + return false + } + // TODO: Check types, field numbers, etc.? + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() + return ok +} + +func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { + ext := pb.GetExtensions() + for offset < len(*ext) { + tag, n1 := DecodeVarint((*ext)[offset:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + n2, err := size((*ext)[offset+n1:], wireType) + if err != nil { + panic(err) + } + newOffset := offset + n1 + n2 + if fieldNum == theFieldNum { + *ext = append((*ext)[:offset], (*ext)[newOffset:]...) + return offset + } + offset = newOffset + } + return -1 +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + clearExtension(pb, extension.Field) +} + +func clearExtension(pb Message, fieldNum int32) { + if epb, doki := pb.(extensionsBytes); doki { + offset := 0 + for offset != -1 { + offset = deleteExtension(epb, fieldNum, offset) + } + return + } + epb, ok := extendable(pb) + if !ok { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, fieldNum) +} + +// GetExtension parses and returns the given extension of pb. +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + o := 0 + for o < len(*ext) { + tag, n := DecodeVarint((*ext)[o:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + l, err := size((*ext)[o+n:], wireType) + if err != nil { + return nil, err + } + if int32(fieldNum) == extension.Field { + v, err := decodeExtension((*ext)[o:o+n+l], extension) + if err != nil { + return nil, err + } + return v, nil + } + o += n + l + } + return defaultExtensionValue(extension) + } + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + o := NewBuffer(b) + + t := reflect.TypeOf(extension.ExtensionType) + + props := extensionProperties(extension) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate a "field" to store the pointer/slice itself; the + // pointer/slice will be stored here. We pass + // the address of this field to props.dec. + // This passes a zero field and a *t and lets props.dec + // interpret it as a *struct{ x t }. + value := reflect.New(t).Elem() + + for { + // Discard wire type and field number varint. It isn't needed. + if _, err := o.DecodeVarint(); err != nil { + return nil, err + } + + if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { + return nil, err + } + + if o.index >= len(o.buf) { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(pb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + if epb, doki := pb.(extensionsBytes); doki { + ClearExtension(pb, extension) + ext := epb.GetExtensions() + et := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + p := NewBuffer(nil) + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + *ext = append(*ext, p.buf...) + return nil + } + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + *ext = []byte{} + return + } + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go new file mode 100644 index 0000000..ea6478f --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go @@ -0,0 +1,294 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "sort" + "strings" + "sync" +) + +func GetBoolExtension(pb Message, extension *ExtensionDesc, ifnotset bool) bool { + if reflect.ValueOf(pb).IsNil() { + return ifnotset + } + value, err := GetExtension(pb, extension) + if err != nil { + return ifnotset + } + if value == nil { + return ifnotset + } + if value.(*bool) == nil { + return ifnotset + } + return *(value.(*bool)) +} + +func (this *Extension) Equal(that *Extension) bool { + return bytes.Equal(this.enc, that.enc) +} + +func (this *Extension) Compare(that *Extension) int { + return bytes.Compare(this.enc, that.enc) +} + +func SizeOfInternalExtension(m extendableProto) (n int) { + return SizeOfExtensionMap(m.extensionsWrite()) +} + +func SizeOfExtensionMap(m map[int32]Extension) (n int) { + return extensionsMapSize(m) +} + +type sortableMapElem struct { + field int32 + ext Extension +} + +func newSortableExtensionsFromMap(m map[int32]Extension) sortableExtensions { + s := make(sortableExtensions, 0, len(m)) + for k, v := range m { + s = append(s, &sortableMapElem{field: k, ext: v}) + } + return s +} + +type sortableExtensions []*sortableMapElem + +func (this sortableExtensions) Len() int { return len(this) } + +func (this sortableExtensions) Swap(i, j int) { this[i], this[j] = this[j], this[i] } + +func (this sortableExtensions) Less(i, j int) bool { return this[i].field < this[j].field } + +func (this sortableExtensions) String() string { + sort.Sort(this) + ss := make([]string, len(this)) + for i := range this { + ss[i] = fmt.Sprintf("%d: %v", this[i].field, this[i].ext) + } + return "map[" + strings.Join(ss, ",") + "]" +} + +func StringFromInternalExtension(m extendableProto) string { + return StringFromExtensionsMap(m.extensionsWrite()) +} + +func StringFromExtensionsMap(m map[int32]Extension) string { + return newSortableExtensionsFromMap(m).String() +} + +func StringFromExtensionsBytes(ext []byte) string { + m, err := BytesToExtensionsMap(ext) + if err != nil { + panic(err) + } + return StringFromExtensionsMap(m) +} + +func EncodeInternalExtension(m extendableProto, data []byte) (n int, err error) { + return EncodeExtensionMap(m.extensionsWrite(), data) +} + +func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) { + if err := encodeExtensionsMap(m); err != nil { + return 0, err + } + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + for _, k := range keys { + n += copy(data[n:], m[int32(k)].enc) + } + return n, nil +} + +func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) { + if m[id].value == nil || m[id].desc == nil { + return m[id].enc, nil + } + if err := encodeExtensionsMap(m); err != nil { + return nil, err + } + return m[id].enc, nil +} + +func size(buf []byte, wire int) (int, error) { + switch wire { + case WireVarint: + _, n := DecodeVarint(buf) + return n, nil + case WireFixed64: + return 8, nil + case WireBytes: + v, n := DecodeVarint(buf) + return int(v) + n, nil + case WireFixed32: + return 4, nil + case WireStartGroup: + offset := 0 + for { + u, n := DecodeVarint(buf[offset:]) + fwire := int(u & 0x7) + offset += n + if fwire == WireEndGroup { + return offset, nil + } + s, err := size(buf[offset:], wire) + if err != nil { + return 0, err + } + offset += s + } + } + return 0, fmt.Errorf("proto: can't get size for unknown wire type %d", wire) +} + +func BytesToExtensionsMap(buf []byte) (map[int32]Extension, error) { + m := make(map[int32]Extension) + i := 0 + for i < len(buf) { + tag, n := DecodeVarint(buf[i:]) + if n <= 0 { + return nil, fmt.Errorf("unable to decode varint") + } + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + l, err := size(buf[i+n:], wireType) + if err != nil { + return nil, err + } + end := i + int(l) + n + m[int32(fieldNum)] = Extension{enc: buf[i:end]} + i = end + } + return m, nil +} + +func NewExtension(e []byte) Extension { + ee := Extension{enc: make([]byte, len(e))} + copy(ee.enc, e) + return ee +} + +func AppendExtension(e Message, tag int32, buf []byte) { + if ee, eok := e.(extensionsBytes); eok { + ext := ee.GetExtensions() + *ext = append(*ext, buf...) + return + } + if ee, eok := e.(extendableProto); eok { + m := ee.extensionsWrite() + ext := m[int32(tag)] // may be missing + ext.enc = append(ext.enc, buf...) + m[int32(tag)] = ext + } +} + +func encodeExtension(e *Extension) error { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + return nil + } + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + return nil +} + +func (this Extension) GoString() string { + if this.enc == nil { + if err := encodeExtension(&this); err != nil { + panic(err) + } + } + return fmt.Sprintf("proto.NewExtension(%#v)", this.enc) +} + +func SetUnsafeExtension(pb Message, fieldNum int32, value interface{}) error { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return errors.New("proto: bad extension number; not in declared ranges") + } + return SetExtension(pb, desc, value) +} + +func GetUnsafeExtension(pb Message, fieldNum int32) (interface{}, error) { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return nil, fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return nil, fmt.Errorf("unregistered field number %d", fieldNum) + } + return GetExtension(pb, desc) +} + +func NewUnsafeXXX_InternalExtensions(m map[int32]Extension) XXX_InternalExtensions { + x := &XXX_InternalExtensions{ + p: new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }), + } + x.p.extensionMap = m + return *x +} + +func GetUnsafeExtensionsMap(extendable Message) map[int32]Extension { + pb := extendable.(extendableProto) + return pb.extensionsWrite() +} diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go new file mode 100644 index 0000000..c98d73d --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib.go @@ -0,0 +1,897 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/gogo/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/gogo/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + // pools of basic types to amortize allocation. + bools []bool + uint32s []uint32 + uint64s []uint64 + + // extra pools, only used with pointer_reflect.go + int32s []int32 + int64s []int64 + float32s []float32 + float64s []float64 +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + sindex := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = sindex +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// Map fields may have key types of non-float scalars, strings and enums. +// The easiest way to sort them in some deterministic order is to use fmt. +// If this turns out to be inefficient we can always consider other options, +// such as doing a Schwartzian transform. + +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{ + vs: vs, + // default Less function: textual comparison + less: func(a, b reflect.Value) bool { + return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) + }, + } + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; + // numeric keys are sorted numerically. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const GoGoProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const GoGoProtoPackageIsVersion1 = true diff --git a/vendor/github.com/gogo/protobuf/proto/lib_gogo.go b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go new file mode 100644 index 0000000..4b4f7c9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go @@ -0,0 +1,42 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "encoding/json" + "strconv" +) + +func MarshalJSONEnum(m map[int32]string, value int32) ([]byte, error) { + s, ok := m[value] + if !ok { + s = strconv.Itoa(int(value)) + } + return json.Marshal(s) +} diff --git a/vendor/github.com/gogo/protobuf/proto/message_set.go b/vendor/github.com/gogo/protobuf/proto/message_set.go new file mode 100644 index 0000000..fd982de --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/message_set.go @@ -0,0 +1,311 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + if ms.find(pb) != nil { + return true + } + return false +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + + // Sort extension IDs to provide a deterministic encoding. + // See also enc_map in encode.go. + ids := make([]int, 0, len(m)) + for id := range m { + ids = append(ids, int(id)) + } + sort.Ints(ids) + + ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + for _, id := range ids { + e := m[int32(id)] + // Remove the wire type and field number varint, as well as the length varint. + msg := skipVarint(skipVarint(e.enc)) + + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: Int32(int32(id)), + Message: msg, + }) + } + return Marshal(ms) +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go new file mode 100644 index 0000000..fb512e2 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go @@ -0,0 +1,484 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// +build appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "math" + "reflect" +) + +// A structPointer is a pointer to a struct. +type structPointer struct { + v reflect.Value +} + +// toStructPointer returns a structPointer equivalent to the given reflect value. +// The reflect value must itself be a pointer to a struct. +func toStructPointer(v reflect.Value) structPointer { + return structPointer{v} +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p.v.IsNil() +} + +// Interface returns the struct pointer as an interface value. +func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { + return p.v.Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// field returns the given field in the struct as a reflect value. +func structPointer_field(p structPointer, f field) reflect.Value { + // Special case: an extension map entry with a value of type T + // passes a *T to the struct-handling code with a zero field, + // expecting that it will be treated as equivalent to *struct{ X T }, + // which has the same memory layout. We have to handle that case + // specially, because reflect will panic if we call FieldByIndex on a + // non-struct. + if f == nil { + return p.v.Elem() + } + + return p.v.Elem().FieldByIndex(f) +} + +// ifield returns the given field in the struct as an interface value. +func structPointer_ifield(p structPointer, f field) interface{} { + return structPointer_field(p, f).Addr().Interface() +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return structPointer_ifield(p, f).(*[]byte) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return structPointer_ifield(p, f).(*[][]byte) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return structPointer_ifield(p, f).(**bool) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return structPointer_ifield(p, f).(*[]bool) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return structPointer_ifield(p, f).(**string) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return structPointer_ifield(p, f).(*[]string) +} + +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return structPointer_ifield(p, f).(*map[int32]Extension) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + structPointer_field(p, f).Set(q.v) +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return structPointer{structPointer_field(p, f)} +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { + return structPointerSlice{structPointer_field(p, f)} +} + +// A structPointerSlice represents the address of a slice of pointers to structs +// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. +type structPointerSlice struct { + v reflect.Value +} + +func (p structPointerSlice) Len() int { return p.v.Len() } +func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } +func (p structPointerSlice) Append(q structPointer) { + p.v.Set(reflect.Append(p.v, q.v)) +} + +var ( + int32Type = reflect.TypeOf(int32(0)) + uint32Type = reflect.TypeOf(uint32(0)) + float32Type = reflect.TypeOf(float32(0)) + int64Type = reflect.TypeOf(int64(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float64Type = reflect.TypeOf(float64(0)) +) + +// A word32 represents a field of type *int32, *uint32, *float32, or *enum. +// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. +type word32 struct { + v reflect.Value +} + +// IsNil reports whether p is nil. +func word32_IsNil(p word32) bool { + return p.v.IsNil() +} + +// Set sets p to point at a newly allocated word with bits set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + t := p.v.Type().Elem() + switch t { + case int32Type: + if len(o.int32s) == 0 { + o.int32s = make([]int32, uint32PoolSize) + } + o.int32s[0] = int32(x) + p.v.Set(reflect.ValueOf(&o.int32s[0])) + o.int32s = o.int32s[1:] + return + case uint32Type: + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + p.v.Set(reflect.ValueOf(&o.uint32s[0])) + o.uint32s = o.uint32s[1:] + return + case float32Type: + if len(o.float32s) == 0 { + o.float32s = make([]float32, uint32PoolSize) + } + o.float32s[0] = math.Float32frombits(x) + p.v.Set(reflect.ValueOf(&o.float32s[0])) + o.float32s = o.float32s[1:] + return + } + + // must be enum + p.v.Set(reflect.New(t)) + p.v.Elem().SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32_Get(p word32) uint32 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32{structPointer_field(p, f)} +} + +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + +// A word32Slice is a slice of 32-bit values. +// That is, v.Type() is []int32, []uint32, []float32, or []enum. +type word32Slice struct { + v reflect.Value +} + +func (p word32Slice) Append(x uint32) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int32: + elem.SetInt(int64(int32(x))) + case reflect.Uint32: + elem.SetUint(uint64(x)) + case reflect.Float32: + elem.SetFloat(float64(math.Float32frombits(x))) + } +} + +func (p word32Slice) Len() int { + return p.v.Len() +} + +func (p word32Slice) Index(i int) uint32 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) word32Slice { + return word32Slice{structPointer_field(p, f)} +} + +// word64 is like word32 but for 64-bit values. +type word64 struct { + v reflect.Value +} + +func word64_Set(p word64, o *Buffer, x uint64) { + t := p.v.Type().Elem() + switch t { + case int64Type: + if len(o.int64s) == 0 { + o.int64s = make([]int64, uint64PoolSize) + } + o.int64s[0] = int64(x) + p.v.Set(reflect.ValueOf(&o.int64s[0])) + o.int64s = o.int64s[1:] + return + case uint64Type: + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + p.v.Set(reflect.ValueOf(&o.uint64s[0])) + o.uint64s = o.uint64s[1:] + return + case float64Type: + if len(o.float64s) == 0 { + o.float64s = make([]float64, uint64PoolSize) + } + o.float64s[0] = math.Float64frombits(x) + p.v.Set(reflect.ValueOf(&o.float64s[0])) + o.float64s = o.float64s[1:] + return + } + panic("unreachable") +} + +func word64_IsNil(p word64) bool { + return p.v.IsNil() +} + +func word64_Get(p word64) uint64 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64{structPointer_field(p, f)} +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + +type word64Slice struct { + v reflect.Value +} + +func (p word64Slice) Append(x uint64) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int64: + elem.SetInt(int64(int64(x))) + case reflect.Uint64: + elem.SetUint(uint64(x)) + case reflect.Float64: + elem.SetFloat(float64(math.Float64frombits(x))) + } +} + +func (p word64Slice) Len() int { + return p.v.Len() +} + +func (p word64Slice) Index(i int) uint64 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return uint64(elem.Uint()) + case reflect.Float64: + return math.Float64bits(float64(elem.Float())) + } + panic("unreachable") +} + +func structPointer_Word64Slice(p structPointer, f field) word64Slice { + return word64Slice{structPointer_field(p, f)} +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go new file mode 100644 index 0000000..1763a5f --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go @@ -0,0 +1,85 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +// +build appengine js + +package proto + +import ( + "reflect" +) + +func structPointer_FieldPointer(p structPointer, f field) structPointer { + panic("not implemented") +} + +func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer { + panic("not implemented") +} + +func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} { + panic("not implemented") +} + +func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} { + panic("not implemented") +} + +func structPointer_GetRefStructPointer(p structPointer, f field) structPointer { + panic("not implemented") +} + +func structPointer_Add(p structPointer, size field) structPointer { + panic("not implemented") +} + +func structPointer_Len(p structPointer, f field) int { + panic("not implemented") +} + +func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader { + panic("not implemented") +} + +func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) { + panic("not implemented") +} + +func structPointer_StructRefSlice(p structPointer, f field, size uintptr) *structRefSlice { + panic("not implemented") +} + +type structRefSlice struct{} + +func (v *structRefSlice) Len() int { + panic("not implemented") +} + +func (v *structRefSlice) Index(i int) structPointer { + panic("not implemented") +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go new file mode 100644 index 0000000..6b5567d --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,270 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +// NOTE: These type_Foo functions would more idiomatically be methods, +// but Go does not allow methods on pointer types, and we must preserve +// some pointer type for the garbage collector. We use these +// funcs with clunky names as our poor approximation to methods. +// +// An alternative would be +// type structPointer struct { p unsafe.Pointer } +// but that does not registerize as well. + +// A structPointer is a pointer to a struct. +type structPointer unsafe.Pointer + +// toStructPointer returns a structPointer equivalent to the given reflect value. +func toStructPointer(v reflect.Value) structPointer { + return structPointer(unsafe.Pointer(v.Pointer())) +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p == nil +} + +// Interface returns the struct pointer, assumed to have element type t, +// as an interface value. +func structPointer_Interface(p structPointer, t reflect.Type) interface{} { + return reflect.NewAt(t, unsafe.Pointer(p)).Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != ^field(0) +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { + return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). +type structPointerSlice []structPointer + +func (v *structPointerSlice) Len() int { return len(*v) } +func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } +func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } + +// A word32 is the address of a "pointer to 32-bit value" field. +type word32 **uint32 + +// IsNil reports whether *v is nil. +func word32_IsNil(p word32) bool { + return *p == nil +} + +// Set sets *v to point at a newly allocated word set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + *p = &o.uint32s[0] + o.uint32s = o.uint32s[1:] +} + +// Get gets the value pointed at by *v. +func word32_Get(p word32) uint32 { + return **p +} + +// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Slice is a slice of 32-bit values. +type word32Slice []uint32 + +func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } +func (v *word32Slice) Len() int { return len(*v) } +func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } + +// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) *word32Slice { + return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// word64 is like word32 but for 64-bit values. +type word64 **uint64 + +func word64_Set(p word64, o *Buffer, x uint64) { + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + *p = &o.uint64s[0] + o.uint64s = o.uint64s[1:] +} + +func word64_IsNil(p word64) bool { + return *p == nil +} + +func word64_Get(p word64) uint64 { + return **p +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Slice is like word32Slice but for 64-bit values. +type word64Slice []uint64 + +func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } +func (v *word64Slice) Len() int { return len(*v) } +func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } + +func structPointer_Word64Slice(p structPointer, f field) *word64Slice { + return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go new file mode 100644 index 0000000..f156a29 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go @@ -0,0 +1,128 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} { + point := unsafe.Pointer(uintptr(p) + uintptr(f)) + r := reflect.NewAt(t, point) + return r.Interface() +} + +func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} { + point := unsafe.Pointer(uintptr(p) + uintptr(f)) + r := reflect.NewAt(t, point) + if r.Elem().IsNil() { + return nil + } + return r.Elem().Interface() +} + +func copyUintPtr(oldptr, newptr uintptr, size int) { + oldbytes := make([]byte, 0) + oldslice := (*reflect.SliceHeader)(unsafe.Pointer(&oldbytes)) + oldslice.Data = oldptr + oldslice.Len = size + oldslice.Cap = size + newbytes := make([]byte, 0) + newslice := (*reflect.SliceHeader)(unsafe.Pointer(&newbytes)) + newslice.Data = newptr + newslice.Len = size + newslice.Cap = size + copy(newbytes, oldbytes) +} + +func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) { + copyUintPtr(uintptr(oldptr), uintptr(newptr), size) +} + +func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer { + size := typ.Elem().Size() + + oldHeader := structPointer_GetSliceHeader(base, f) + oldSlice := reflect.NewAt(typ, unsafe.Pointer(oldHeader)).Elem() + newLen := oldHeader.Len + 1 + newSlice := reflect.MakeSlice(typ, newLen, newLen) + reflect.Copy(newSlice, oldSlice) + bas := toStructPointer(newSlice) + oldHeader.Data = uintptr(bas) + oldHeader.Len = newLen + oldHeader.Cap = newLen + + return structPointer(unsafe.Pointer(uintptr(unsafe.Pointer(bas)) + uintptr(uintptr(newLen-1)*size))) +} + +func structPointer_FieldPointer(p structPointer, f field) structPointer { + return structPointer(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_GetRefStructPointer(p structPointer, f field) structPointer { + return structPointer((*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader { + return (*reflect.SliceHeader)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_Add(p structPointer, size field) structPointer { + return structPointer(unsafe.Pointer(uintptr(p) + uintptr(size))) +} + +func structPointer_Len(p structPointer, f field) int { + return len(*(*[]interface{})(unsafe.Pointer(structPointer_GetRefStructPointer(p, f)))) +} + +func structPointer_StructRefSlice(p structPointer, f field, size uintptr) *structRefSlice { + return &structRefSlice{p: p, f: f, size: size} +} + +// A structRefSlice represents a slice of structs (themselves submessages or groups). +type structRefSlice struct { + p structPointer + f field + size uintptr +} + +func (v *structRefSlice) Len() int { + return structPointer_Len(v.p, v.f) +} + +func (v *structRefSlice) Index(i int) structPointer { + ss := structPointer_GetStructPointer(v.p, v.f) + ss1 := structPointer_GetRefStructPointer(ss, 0) + return structPointer_Add(ss1, field(uintptr(i)*v.size)) +} diff --git a/vendor/github.com/gogo/protobuf/proto/properties.go b/vendor/github.com/gogo/protobuf/proto/properties.go new file mode 100644 index 0000000..2a69e88 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties.go @@ -0,0 +1,971 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +const startSize = 10 // initial slice/string sizes + +// Encoders are defined in encode.go +// An encoder outputs the full representation of a field, including its +// tag and encoder type. +type encoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueEncoder encodes a single integer in a particular encoding. +type valueEncoder func(o *Buffer, x uint64) error + +// Sizers are defined in encode.go +// A sizer returns the encoded size of a field, including its tag and encoder +// type. +type sizer func(prop *Properties, base structPointer) int + +// A valueSizer returns the encoded size of a single integer in a particular +// encoding. +type valueSizer func(x uint64) int + +// Decoders are defined in decode.go +// A decoder creates a value from its wire representation. +// Unrecognized subelements are saved in unrec. +type decoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueDecoder decodes a single integer in a particular encoding. +type valueDecoder func(o *Buffer) (x uint64, err error) + +// A oneofMarshaler does the marshaling for all oneof fields in a message. +type oneofMarshaler func(Message, *Buffer) error + +// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. +type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) + +// A oneofSizer does the sizing for all oneof fields in a message. +type oneofSizer func(Message) int + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + unrecField field // field id of the XXX_unrecognized []byte field + extendable bool // is this an extendable proto + + oneofMarshaler oneofMarshaler + oneofUnmarshaler oneofUnmarshaler + oneofSizer oneofSizer + stype reflect.Type + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + CustomType string + CastType string + StdTime bool + StdDuration bool + + enc encoder + valEnc valueEncoder // set for bool and numeric types only + field field + tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) + tagbuf [8]byte + stype reflect.Type // set for struct types only + sstype reflect.Type // set for slices of structs types only + ctype reflect.Type // set for custom types only + sprop *StructProperties // set for struct types only + isMarshaler bool + isUnmarshaler bool + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + + size sizer + valSize valueSizer // set for bool and numeric types only + + dec decoder + valDec valueDecoder // set for bool and numeric types only + + // If this is a packable field, this will be the decoder for the packed version of the field. + packedDec decoder +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s = "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeVarint + p.valDec = (*Buffer).DecodeVarint + p.valSize = sizeVarint + case "fixed32": + p.WireType = WireFixed32 + p.valEnc = (*Buffer).EncodeFixed32 + p.valDec = (*Buffer).DecodeFixed32 + p.valSize = sizeFixed32 + case "fixed64": + p.WireType = WireFixed64 + p.valEnc = (*Buffer).EncodeFixed64 + p.valDec = (*Buffer).DecodeFixed64 + p.valSize = sizeFixed64 + case "zigzag32": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag32 + p.valDec = (*Buffer).DecodeZigzag32 + p.valSize = sizeZigzag32 + case "zigzag64": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag64 + p.valDec = (*Buffer).DecodeZigzag64 + p.valSize = sizeZigzag64 + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break + } + case strings.HasPrefix(f, "embedded="): + p.OrigName = strings.Split(f, "=")[1] + case strings.HasPrefix(f, "customtype="): + p.CustomType = strings.Split(f, "=")[1] + case strings.HasPrefix(f, "casttype="): + p.CastType = strings.Split(f, "=")[1] + case f == "stdtime": + p.StdTime = true + case f == "stdduration": + p.StdDuration = true + } + } +} + +func logNoSliceEnc(t1, t2 reflect.Type) { + fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// Initialize the fields for encoding and decoding. +func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + p.enc = nil + p.dec = nil + p.size = nil + isMap := typ.Kind() == reflect.Map + if len(p.CustomType) > 0 && !isMap { + p.setCustomEncAndDec(typ) + p.setTag(lockGetProp) + return + } + if p.StdTime && !isMap { + p.setTimeEncAndDec(typ) + p.setTag(lockGetProp) + return + } + if p.StdDuration && !isMap { + p.setDurationEncAndDec(typ) + p.setTag(lockGetProp) + return + } + switch t1 := typ; t1.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) + + // proto3 scalar types + + case reflect.Bool: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_proto3_bool + } else { + p.enc = (*Buffer).enc_ref_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_ref_bool + } + case reflect.Int32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_int32 + } else { + p.enc = (*Buffer).enc_ref_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_ref_int32 + } + case reflect.Uint32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_proto3_uint32 + } else { + p.enc = (*Buffer).enc_ref_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_ref_uint32 + } + case reflect.Int64, reflect.Uint64: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + } else { + p.enc = (*Buffer).enc_ref_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_ref_int64 + } + case reflect.Float32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_uint32 + } else { + p.enc = (*Buffer).enc_ref_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_ref_uint32 + } + case reflect.Float64: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + } else { + p.enc = (*Buffer).enc_ref_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_ref_int64 + } + case reflect.String: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_proto3_string + } else { + p.enc = (*Buffer).enc_ref_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_ref_string + } + case reflect.Struct: + p.stype = typ + p.isMarshaler = isMarshaler(typ) + p.isUnmarshaler = isUnmarshaler(typ) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_ref_struct_message + p.dec = (*Buffer).dec_ref_struct_message + p.size = size_ref_struct_message + } else { + fmt.Fprintf(os.Stderr, "proto: no coders for struct %T\n", typ) + } + + case reflect.Ptr: + switch t2 := t1.Elem(); t2.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) + break + case reflect.Bool: + p.enc = (*Buffer).enc_bool + p.dec = (*Buffer).dec_bool + p.size = size_bool + case reflect.Int32: + p.enc = (*Buffer).enc_int32 + p.dec = (*Buffer).dec_int32 + p.size = size_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_uint32 + p.dec = (*Buffer).dec_int32 // can reuse + p.size = size_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_int64 + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_int32 + p.size = size_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_int64 // can just treat them as bits + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.String: + p.enc = (*Buffer).enc_string + p.dec = (*Buffer).dec_string + p.size = size_string + case reflect.Struct: + p.stype = t1.Elem() + p.isMarshaler = isMarshaler(t1) + p.isUnmarshaler = isUnmarshaler(t1) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_struct_message + p.dec = (*Buffer).dec_struct_message + p.size = size_struct_message + } else { + p.enc = (*Buffer).enc_struct_group + p.dec = (*Buffer).dec_struct_group + p.size = size_struct_group + } + } + + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + default: + logNoSliceEnc(t1, t2) + break + case reflect.Bool: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_bool + p.size = size_slice_packed_bool + } else { + p.enc = (*Buffer).enc_slice_bool + p.size = size_slice_bool + } + p.dec = (*Buffer).dec_slice_bool + p.packedDec = (*Buffer).dec_slice_packed_bool + case reflect.Int32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int32 + p.size = size_slice_packed_int32 + } else { + p.enc = (*Buffer).enc_slice_int32 + p.size = size_slice_int32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Uint32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Int64, reflect.Uint64: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + case reflect.Uint8: + p.dec = (*Buffer).dec_slice_byte + if p.proto3 { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte + } + case reflect.Float32, reflect.Float64: + switch t2.Bits() { + case 32: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case 64: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + default: + logNoSliceEnc(t1, t2) + break + } + case reflect.String: + p.enc = (*Buffer).enc_slice_string + p.dec = (*Buffer).dec_slice_string + p.size = size_slice_string + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) + break + case reflect.Struct: + p.stype = t2.Elem() + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_slice_struct_message + p.dec = (*Buffer).dec_slice_struct_message + p.size = size_slice_struct_message + } else { + p.enc = (*Buffer).enc_slice_struct_group + p.dec = (*Buffer).dec_slice_struct_group + p.size = size_slice_struct_group + } + } + case reflect.Slice: + switch t2.Elem().Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) + break + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_slice_byte + p.dec = (*Buffer).dec_slice_slice_byte + p.size = size_slice_slice_byte + } + case reflect.Struct: + p.setSliceOfNonPointerStructs(t1) + } + + case reflect.Map: + p.enc = (*Buffer).enc_new_map + p.dec = (*Buffer).dec_new_map + p.size = size_new_map + + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + + p.mvalprop.CustomType = p.CustomType + p.mvalprop.StdDuration = p.StdDuration + p.mvalprop.StdTime = p.StdTime + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + p.setTag(lockGetProp) +} + +func (p *Properties) setTag(lockGetProp bool) { + // precalculate tag code + wire := p.WireType + if p.Packed { + wire = WireBytes + } + x := uint32(p.Tag)<<3 | uint32(wire) + i := 0 + for i = 0; x > 127; i++ { + p.tagbuf[i] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + p.tagbuf[i] = uint8(x) + p.tagcode = p.tagbuf[0 : i+1] + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +// isMarshaler reports whether type t implements Marshaler. +func isMarshaler(t reflect.Type) bool { + return t.Implements(marshalerType) +} + +// isUnmarshaler reports whether type t implements Unmarshaler. +func isUnmarshaler(t reflect.Type) bool { + return t.Implements(unmarshalerType) +} + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if f != nil { + p.field = toField(f) + } + if tag == "" { + return + } + p.Parse(tag) + p.setEncAndDec(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) || + reflect.PtrTo(t).Implements(extendableBytesType) + prop.unrecField = invalidField + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + isOneofMessage := false + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case + if len(f.Tag.Get("protobuf")) > 0 { + p.enc = (*Buffer).enc_ext_slice_byte + p.dec = nil // not needed + p.size = size_ext_slice_byte + } else { + p.enc = (*Buffer).enc_map + p.dec = nil // not needed + p.size = size_map + } + } else if f.Name == "XXX_unrecognized" { // special case + prop.unrecField = toField(&f) + } + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + isOneofMessage = true + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { + fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); isOneofMessage && ok { + var oots []interface{} + prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() + prop.stype = t + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// Return the Properties object for the x[0]'th field of the structure. +func propByIndex(t reflect.Type, x []int) *Properties { + if len(x) != 1 { + fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) + return nil + } + prop := GetProperties(t) + return prop.Prop[x[0]] +} + +// Get the address and type of a pointer to a struct from an interface. +func getbase(pb Message) (t reflect.Type, b structPointer, err error) { + if pb == nil { + err = ErrNil + return + } + // get the reflect type of the pointer to the struct. + t = reflect.TypeOf(pb) + // get the address of the struct. + value := reflect.ValueOf(pb) + b = toStructPointer(value) + return +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) +var enumStringMaps = make(map[string]map[int32]string) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap + if _, ok := enumStringMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumStringMaps[typeName] = unusedNameMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypes = make(map[string]reflect.Type) + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypes[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/gogo/protobuf/proto/properties_gogo.go b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go new file mode 100644 index 0000000..b6b7176 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go @@ -0,0 +1,111 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "fmt" + "os" + "reflect" +) + +func (p *Properties) setCustomEncAndDec(typ reflect.Type) { + p.ctype = typ + if p.Repeated { + p.enc = (*Buffer).enc_custom_slice_bytes + p.dec = (*Buffer).dec_custom_slice_bytes + p.size = size_custom_slice_bytes + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_custom_bytes + p.dec = (*Buffer).dec_custom_bytes + p.size = size_custom_bytes + } else { + p.enc = (*Buffer).enc_custom_ref_bytes + p.dec = (*Buffer).dec_custom_ref_bytes + p.size = size_custom_ref_bytes + } +} + +func (p *Properties) setDurationEncAndDec(typ reflect.Type) { + if p.Repeated { + if typ.Elem().Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_slice_duration + p.dec = (*Buffer).dec_slice_duration + p.size = size_slice_duration + } else { + p.enc = (*Buffer).enc_slice_ref_duration + p.dec = (*Buffer).dec_slice_ref_duration + p.size = size_slice_ref_duration + } + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_duration + p.dec = (*Buffer).dec_duration + p.size = size_duration + } else { + p.enc = (*Buffer).enc_ref_duration + p.dec = (*Buffer).dec_ref_duration + p.size = size_ref_duration + } +} + +func (p *Properties) setTimeEncAndDec(typ reflect.Type) { + if p.Repeated { + if typ.Elem().Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_slice_time + p.dec = (*Buffer).dec_slice_time + p.size = size_slice_time + } else { + p.enc = (*Buffer).enc_slice_ref_time + p.dec = (*Buffer).dec_slice_ref_time + p.size = size_slice_ref_time + } + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_time + p.dec = (*Buffer).dec_time + p.size = size_time + } else { + p.enc = (*Buffer).enc_ref_time + p.dec = (*Buffer).dec_ref_time + p.size = size_ref_time + } + +} + +func (p *Properties) setSliceOfNonPointerStructs(typ reflect.Type) { + t2 := typ.Elem() + p.sstype = typ + p.stype = t2 + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + p.enc = (*Buffer).enc_slice_ref_struct_message + p.dec = (*Buffer).dec_slice_ref_struct_message + p.size = size_slice_ref_struct_message + if p.Wire != "bytes" { + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T \n", typ, t2) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/skip_gogo.go b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go new file mode 100644 index 0000000..5a5fd93 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go @@ -0,0 +1,119 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "fmt" + "io" +) + +func Skip(data []byte) (n int, err error) { + l := len(data) + index := 0 + for index < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + index++ + if data[index-1] < 0x80 { + break + } + } + return index, nil + case 1: + index += 8 + return index, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + index += length + return index, nil + case 3: + for { + var innerWire uint64 + var start int = index + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := Skip(data[start:]) + if err != nil { + return 0, err + } + index = start + next + } + return index, nil + case 4: + return index, nil + case 5: + index += 4 + return index, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} diff --git a/vendor/github.com/gogo/protobuf/proto/text.go b/vendor/github.com/gogo/protobuf/proto/text.go new file mode 100644 index 0000000..f609d1d --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text.go @@ -0,0 +1,939 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" + "sync" + "time" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + gtNewline = []byte(">\n") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +// raw is the interface satisfied by RawMessage. +type raw interface { + Bytes() []byte +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, v, props); err != nil { + return err + } + } else if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if props.proto3 && fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if b, ok := fv.Interface().(raw); ok { + if err := writeRaw(w, b.Bytes()); err != nil { + return err + } + continue + } + + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, fv, props); err != nil { + return err + } + } else if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv + if pv.CanAddr() { + pv = sv.Addr() + } else { + pv = reflect.New(sv.Type()) + pv.Elem().Set(sv) + } + if pv.Type().Implements(extensionRangeType) { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeRaw writes an uninterpreted raw message. +func writeRaw(w *textWriter, b []byte) error { + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if err := writeUnknownStruct(w, b); err != nil { + return err + } + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + return nil +} + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + if props != nil { + if len(props.CustomType) > 0 { + custom, ok := v.Interface().(Marshaler) + if ok { + data, err := custom.Marshal() + if err != nil { + return err + } + if err := writeString(w, string(data)); err != nil { + return err + } + return nil + } + } else if len(props.CastType) > 0 { + if _, ok := v.Interface().(interface { + String() string + }); ok { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + _, err := fmt.Fprintf(w, "%d", v.Interface()) + return err + } + } + } else if props.StdTime { + t, ok := v.Interface().(time.Time) + if !ok { + return fmt.Errorf("stdtime is not time.Time, but %T", v.Interface()) + } + tproto, err := timestampProto(t) + if err != nil { + return err + } + propsCopy := *props // Make a copy so that this is goroutine-safe + propsCopy.StdTime = false + err = tm.writeAny(w, reflect.ValueOf(tproto), &propsCopy) + return err + } else if props.StdDuration { + d, ok := v.Interface().(time.Duration) + if !ok { + return fmt.Errorf("stdtime is not time.Duration, but %T", v.Interface()) + } + dproto := durationProto(d) + propsCopy := *props // Make a copy so that this is goroutine-safe + propsCopy.StdDuration = false + err := tm.writeAny(w, reflect.ValueOf(dproto), &propsCopy) + return err + } + } + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else if err := tm.writeStruct(w, v); err != nil { + return err + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, ferr := fmt.Fprintf(w, "/* %v */\n", err) + return ferr + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, werr := w.Write(endBraceNewline); werr != nil { + return werr + } + continue + } + if _, ferr := fmt.Fprint(w, tag); ferr != nil { + return ferr + } + if wire != WireStartGroup { + if err = w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err = w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + e := pv.Interface().(Message) + + var m map[int32]Extension + var mu sync.Locker + if em, ok := e.(extensionsBytes); ok { + eb := em.GetExtensions() + var err error + m, err = BytesToExtensionsMap(*eb) + if err != nil { + return err + } + mu = notLocker{} + } else if _, ok := e.(extendableProto); ok { + ep, _ := extendable(e) + m, mu = ep.extensionsRead() + if m == nil { + return nil + } + } + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(e, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/gogo/protobuf/proto/text_gogo.go b/vendor/github.com/gogo/protobuf/proto/text_gogo.go new file mode 100644 index 0000000..1d6c6aa --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_gogo.go @@ -0,0 +1,57 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "fmt" + "reflect" +) + +func (tm *TextMarshaler) writeEnum(w *textWriter, v reflect.Value, props *Properties) error { + m, ok := enumStringMaps[props.Enum] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + key := int32(0) + if v.Kind() == reflect.Ptr { + key = int32(v.Elem().Int()) + } else { + key = int32(v.Int()) + } + s, ok := m[key] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + _, err := fmt.Fprint(w, s) + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/text_parser.go b/vendor/github.com/gogo/protobuf/proto/text_parser.go new file mode 100644 index 0000000..f127672 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_parser.go @@ -0,0 +1,1013 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") + errBadHex = errors.New("proto: bad hexadecimal") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + base := 8 + ss := s[:2] + s = s[2:] + if r == 'x' || r == 'X' { + base = 16 + } else { + ss = string(r) + ss + } + i, err := strconv.ParseUint(ss, base, 8) + if err != nil { + return "", "", err + } + return string([]byte{byte(i)}), s, nil + case 'u', 'U': + n := 4 + if r == 'U' { + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) + } + + bs := make([]byte, n/2) + for i := 0; i < n; i += 2 { + a, ok1 := unhex(s[i]) + b, ok2 := unhex(s[i+1]) + if !ok1 || !ok2 { + return "", "", errBadHex + } + bs[i/2] = a<<4 | b + } + s = s[n:] + return string(bs), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Adapted from src/pkg/strconv/quote.go. +func unhex(b byte) (v byte, ok bool) { + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + if len(props.CustomType) > 0 { + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + tc := reflect.TypeOf(new(Marshaler)) + ok := t.Elem().Implements(tc.Elem()) + if ok { + fv := v + flen := fv.Len() + if flen == fv.Cap() { + nav := reflect.MakeSlice(v.Type(), flen, 2*flen+1) + reflect.Copy(nav, fv) + fv.Set(nav) + } + fv.SetLen(flen + 1) + + // Read one. + p.back() + return p.readAny(fv.Index(flen), props) + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + custom := reflect.New(props.ctype.Elem()).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.ValueOf(custom)) + } else { + custom := reflect.New(reflect.TypeOf(v.Interface())).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.Indirect(reflect.ValueOf(custom))) + } + return nil + } + if props.StdTime { + fv := v + p.back() + props.StdTime = false + tproto := ×tamp{} + err := p.readAny(reflect.ValueOf(tproto).Elem(), props) + props.StdTime = true + if err != nil { + return err + } + tim, err := timestampFromProto(tproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ts := fv.Interface().([]*time.Time) + ts = append(ts, &tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } else { + ts := fv.Interface().([]time.Time) + ts = append(ts, tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&tim)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&tim))) + } + return nil + } + if props.StdDuration { + fv := v + p.back() + props.StdDuration = false + dproto := &duration{} + err := p.readAny(reflect.ValueOf(dproto).Elem(), props) + props.StdDuration = true + if err != nil { + return err + } + dur, err := durationFromProto(dproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ds := fv.Interface().([]*time.Duration) + ds = append(ds, &dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } else { + ds := fv.Interface().([]time.Duration) + ds = append(ds, dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&dur)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&dur))) + } + return nil + } + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + ntok := p.next() + if ntok.err != nil { + return ntok.err + } + if ntok.value == "]" { + break + } + if ntok.value != "," { + return p.errorf("Expected ']' or ',' found %q", ntok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(x) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + err := um.UnmarshalText([]byte(s)) + return err + } + pb.Reset() + v := reflect.ValueOf(pb) + if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { + return pe + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp.go b/vendor/github.com/gogo/protobuf/proto/timestamp.go new file mode 100644 index 0000000..9324f65 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp.go @@ -0,0 +1,113 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %#v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %#v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %#v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// TimestampFromProto converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func timestampFromProto(ts *timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func timestampProto(t time.Time) (*timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := ×tamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go new file mode 100644 index 0000000..d427647 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go @@ -0,0 +1,229 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package proto + +import ( + "reflect" + "time" +) + +var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + +type timestamp struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *timestamp) Reset() { *m = timestamp{} } +func (*timestamp) ProtoMessage() {} +func (*timestamp) String() string { return "timestamp" } + +func init() { + RegisterType((*timestamp)(nil), "gogo.protobuf.proto.timestamp") +} + +func (o *Buffer) decTimestamp() (time.Time, error) { + b, err := o.DecodeRawBytes(true) + if err != nil { + return time.Time{}, err + } + tproto := ×tamp{} + if err := Unmarshal(b, tproto); err != nil { + return time.Time{}, err + } + return timestampFromProto(tproto) +} + +func (o *Buffer) dec_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + setPtrCustomType(base, p.field, &t) + return nil +} + +func (o *Buffer) dec_ref_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + setCustomType(base, p.field, &t) + return nil +} + +func (o *Buffer) dec_slice_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))) + var zero field + setPtrCustomType(newBas, zero, &t) + return nil +} + +func (o *Buffer) dec_slice_ref_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(timeType)) + var zero field + setCustomType(newBas, zero, &t) + return nil +} + +func size_time(p *Properties, base structPointer) (n int) { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + tim := structPointer_Interface(structp, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return 0 + } + size := Size(t) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_time(p *Properties, base structPointer) error { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + tim := structPointer_Interface(structp, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return err + } + data, err := Marshal(t) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_ref_time(p *Properties, base structPointer) (n int) { + tim := structPointer_InterfaceAt(base, p.field, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return 0 + } + size := Size(t) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_ref_time(p *Properties, base structPointer) error { + tim := structPointer_InterfaceAt(base, p.field, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return err + } + data, err := Marshal(t) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_slice_time(p *Properties, base structPointer) (n int) { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))).(*[]*time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + if tims[i] == nil { + return 0 + } + tproto, err := timestampProto(*tims[i]) + if err != nil { + return 0 + } + size := Size(tproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_time(p *Properties, base structPointer) error { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))).(*[]*time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + if tims[i] == nil { + return errRepeatedHasNil + } + tproto, err := timestampProto(*tims[i]) + if err != nil { + return err + } + data, err := Marshal(tproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_slice_ref_time(p *Properties, base structPointer) (n int) { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(timeType)).(*[]time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + tproto, err := timestampProto(tims[i]) + if err != nil { + return 0 + } + size := Size(tproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_ref_time(p *Properties, base structPointer) error { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(timeType)).(*[]time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + tproto, err := timestampProto(tims[i]) + if err != nil { + return err + } + data, err := Marshal(tproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go b/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go new file mode 100644 index 0000000..ceadde6 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go @@ -0,0 +1,101 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// 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. +// +// 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. + +package sortkeys + +import ( + "sort" +) + +func Strings(l []string) { + sort.Strings(l) +} + +func Float64s(l []float64) { + sort.Float64s(l) +} + +func Float32s(l []float32) { + sort.Sort(Float32Slice(l)) +} + +func Int64s(l []int64) { + sort.Sort(Int64Slice(l)) +} + +func Int32s(l []int32) { + sort.Sort(Int32Slice(l)) +} + +func Uint64s(l []uint64) { + sort.Sort(Uint64Slice(l)) +} + +func Uint32s(l []uint32) { + sort.Sort(Uint32Slice(l)) +} + +func Bools(l []bool) { + sort.Sort(BoolSlice(l)) +} + +type BoolSlice []bool + +func (p BoolSlice) Len() int { return len(p) } +func (p BoolSlice) Less(i, j int) bool { return p[j] } +func (p BoolSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Int64Slice []int64 + +func (p Int64Slice) Len() int { return len(p) } +func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Int32Slice []int32 + +func (p Int32Slice) Len() int { return len(p) } +func (p Int32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Int32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Uint64Slice []uint64 + +func (p Uint64Slice) Len() int { return len(p) } +func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Uint32Slice []uint32 + +func (p Uint32Slice) Len() int { return len(p) } +func (p Uint32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Float32Slice []float32 + +func (p Float32Slice) Len() int { return len(p) } +func (p Float32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Float32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/vendor/github.com/golang/glog/LICENSE b/vendor/github.com/golang/glog/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/vendor/github.com/golang/glog/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/glog/README b/vendor/github.com/golang/glog/README new file mode 100644 index 0000000..387b4eb --- /dev/null +++ b/vendor/github.com/golang/glog/README @@ -0,0 +1,44 @@ +glog +==== + +Leveled execution logs for Go. + +This is an efficient pure Go implementation of leveled logs in the +manner of the open source C++ package + https://github.com/google/glog + +By binding methods to booleans it is possible to use the log package +without paying the expense of evaluating the arguments to the log. +Through the -vmodule flag, the package also provides fine-grained +control over logging at the file level. + +The comment from glog.go introduces the ideas: + + Package glog implements logging analogous to the Google-internal + C++ INFO/ERROR/V setup. It provides functions Info, Warning, + Error, Fatal, plus formatting variants such as Infof. It + also provides V-style logging controlled by the -v and + -vmodule=file=2 flags. + + Basic examples: + + glog.Info("Prepare to repel boarders") + + glog.Fatalf("Initialization failed: %s", err) + + See the documentation for the V function for an explanation + of these examples: + + if glog.V(2) { + glog.Info("Starting transaction...") + } + + glog.V(2).Infoln("Processed", nItems, "elements") + + +The repository contains an open source version of the log package +used inside Google. The master copy of the source lives inside +Google, not here. The code in this repo is for export only and is not itself +under development. Feature requests will be ignored. + +Send bug reports to golang-nuts@googlegroups.com. diff --git a/vendor/github.com/golang/glog/glog.go b/vendor/github.com/golang/glog/glog.go new file mode 100644 index 0000000..54bd7af --- /dev/null +++ b/vendor/github.com/golang/glog/glog.go @@ -0,0 +1,1180 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup. +// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as +// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags. +// +// Basic examples: +// +// glog.Info("Prepare to repel boarders") +// +// glog.Fatalf("Initialization failed: %s", err) +// +// See the documentation for the V function for an explanation of these examples: +// +// if glog.V(2) { +// glog.Info("Starting transaction...") +// } +// +// glog.V(2).Infoln("Processed", nItems, "elements") +// +// Log output is buffered and written periodically using Flush. Programs +// should call Flush before exiting to guarantee all log output is written. +// +// By default, all log statements write to files in a temporary directory. +// This package provides several flags that modify this behavior. +// As a result, flag.Parse must be called before any logging is done. +// +// -logtostderr=false +// Logs are written to standard error instead of to files. +// -alsologtostderr=false +// Logs are written to standard error as well as to files. +// -stderrthreshold=ERROR +// Log events at or above this severity are logged to standard +// error as well as to files. +// -log_dir="" +// Log files will be written to this directory instead of the +// default temporary directory. +// +// Other flags provide aids to debugging. +// +// -log_backtrace_at="" +// When set to a file and line number holding a logging statement, +// such as +// -log_backtrace_at=gopherflakes.go:234 +// a stack trace will be written to the Info log whenever execution +// hits that statement. (Unlike with -vmodule, the ".go" must be +// present.) +// -v=0 +// Enable V-leveled logging at the specified level. +// -vmodule="" +// The syntax of the argument is a comma-separated list of pattern=N, +// where pattern is a literal file name (minus the ".go" suffix) or +// "glob" pattern and N is a V level. For instance, +// -vmodule=gopher*=3 +// sets the V level to 3 in all Go files whose names begin "gopher". +// +package glog + +import ( + "bufio" + "bytes" + "errors" + "flag" + "fmt" + "io" + stdLog "log" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +// severity identifies the sort of log: info, warning etc. It also implements +// the flag.Value interface. The -stderrthreshold flag is of type severity and +// should be modified only through the flag.Value interface. The values match +// the corresponding constants in C++. +type severity int32 // sync/atomic int32 + +// These constants identify the log levels in order of increasing severity. +// A message written to a high-severity log file is also written to each +// lower-severity log file. +const ( + infoLog severity = iota + warningLog + errorLog + fatalLog + numSeverity = 4 +) + +const severityChar = "IWEF" + +var severityName = []string{ + infoLog: "INFO", + warningLog: "WARNING", + errorLog: "ERROR", + fatalLog: "FATAL", +} + +// get returns the value of the severity. +func (s *severity) get() severity { + return severity(atomic.LoadInt32((*int32)(s))) +} + +// set sets the value of the severity. +func (s *severity) set(val severity) { + atomic.StoreInt32((*int32)(s), int32(val)) +} + +// String is part of the flag.Value interface. +func (s *severity) String() string { + return strconv.FormatInt(int64(*s), 10) +} + +// Get is part of the flag.Value interface. +func (s *severity) Get() interface{} { + return *s +} + +// Set is part of the flag.Value interface. +func (s *severity) Set(value string) error { + var threshold severity + // Is it a known name? + if v, ok := severityByName(value); ok { + threshold = v + } else { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + threshold = severity(v) + } + logging.stderrThreshold.set(threshold) + return nil +} + +func severityByName(s string) (severity, bool) { + s = strings.ToUpper(s) + for i, name := range severityName { + if name == s { + return severity(i), true + } + } + return 0, false +} + +// OutputStats tracks the number of output lines and bytes written. +type OutputStats struct { + lines int64 + bytes int64 +} + +// Lines returns the number of lines written. +func (s *OutputStats) Lines() int64 { + return atomic.LoadInt64(&s.lines) +} + +// Bytes returns the number of bytes written. +func (s *OutputStats) Bytes() int64 { + return atomic.LoadInt64(&s.bytes) +} + +// Stats tracks the number of lines of output and number of bytes +// per severity level. Values must be read with atomic.LoadInt64. +var Stats struct { + Info, Warning, Error OutputStats +} + +var severityStats = [numSeverity]*OutputStats{ + infoLog: &Stats.Info, + warningLog: &Stats.Warning, + errorLog: &Stats.Error, +} + +// Level is exported because it appears in the arguments to V and is +// the type of the v flag, which can be set programmatically. +// It's a distinct type because we want to discriminate it from logType. +// Variables of type level are only changed under logging.mu. +// The -v flag is read only with atomic ops, so the state of the logging +// module is consistent. + +// Level is treated as a sync/atomic int32. + +// Level specifies a level of verbosity for V logs. *Level implements +// flag.Value; the -v flag is of type Level and should be modified +// only through the flag.Value interface. +type Level int32 + +// get returns the value of the Level. +func (l *Level) get() Level { + return Level(atomic.LoadInt32((*int32)(l))) +} + +// set sets the value of the Level. +func (l *Level) set(val Level) { + atomic.StoreInt32((*int32)(l), int32(val)) +} + +// String is part of the flag.Value interface. +func (l *Level) String() string { + return strconv.FormatInt(int64(*l), 10) +} + +// Get is part of the flag.Value interface. +func (l *Level) Get() interface{} { + return *l +} + +// Set is part of the flag.Value interface. +func (l *Level) Set(value string) error { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(Level(v), logging.vmodule.filter, false) + return nil +} + +// moduleSpec represents the setting of the -vmodule flag. +type moduleSpec struct { + filter []modulePat +} + +// modulePat contains a filter for the -vmodule flag. +// It holds a verbosity level and a file pattern to match. +type modulePat struct { + pattern string + literal bool // The pattern is a literal string + level Level +} + +// match reports whether the file matches the pattern. It uses a string +// comparison if the pattern contains no metacharacters. +func (m *modulePat) match(file string) bool { + if m.literal { + return file == m.pattern + } + match, _ := filepath.Match(m.pattern, file) + return match +} + +func (m *moduleSpec) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + var b bytes.Buffer + for i, f := range m.filter { + if i > 0 { + b.WriteRune(',') + } + fmt.Fprintf(&b, "%s=%d", f.pattern, f.level) + } + return b.String() +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported. +func (m *moduleSpec) Get() interface{} { + return nil +} + +var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N") + +// Syntax: -vmodule=recordio=2,file=1,gfs*=3 +func (m *moduleSpec) Set(value string) error { + var filter []modulePat + for _, pat := range strings.Split(value, ",") { + if len(pat) == 0 { + // Empty strings such as from a trailing comma can be ignored. + continue + } + patLev := strings.Split(pat, "=") + if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 { + return errVmoduleSyntax + } + pattern := patLev[0] + v, err := strconv.Atoi(patLev[1]) + if err != nil { + return errors.New("syntax error: expect comma-separated list of filename=N") + } + if v < 0 { + return errors.New("negative value for vmodule level") + } + if v == 0 { + continue // Ignore. It's harmless but no point in paying the overhead. + } + // TODO: check syntax of filter? + filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)}) + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(logging.verbosity, filter, true) + return nil +} + +// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters +// that require filepath.Match to be called to match the pattern. +func isLiteral(pattern string) bool { + return !strings.ContainsAny(pattern, `\*?[]`) +} + +// traceLocation represents the setting of the -log_backtrace_at flag. +type traceLocation struct { + file string + line int +} + +// isSet reports whether the trace location has been specified. +// logging.mu is held. +func (t *traceLocation) isSet() bool { + return t.line > 0 +} + +// match reports whether the specified file and line matches the trace location. +// The argument file name is the full path, not the basename specified in the flag. +// logging.mu is held. +func (t *traceLocation) match(file string, line int) bool { + if t.line != line { + return false + } + if i := strings.LastIndex(file, "/"); i >= 0 { + file = file[i+1:] + } + return t.file == file +} + +func (t *traceLocation) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + return fmt.Sprintf("%s:%d", t.file, t.line) +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported +func (t *traceLocation) Get() interface{} { + return nil +} + +var errTraceSyntax = errors.New("syntax error: expect file.go:234") + +// Syntax: -log_backtrace_at=gopherflakes.go:234 +// Note that unlike vmodule the file extension is included here. +func (t *traceLocation) Set(value string) error { + if value == "" { + // Unset. + t.line = 0 + t.file = "" + } + fields := strings.Split(value, ":") + if len(fields) != 2 { + return errTraceSyntax + } + file, line := fields[0], fields[1] + if !strings.Contains(file, ".") { + return errTraceSyntax + } + v, err := strconv.Atoi(line) + if err != nil { + return errTraceSyntax + } + if v <= 0 { + return errors.New("negative or zero value for level") + } + logging.mu.Lock() + defer logging.mu.Unlock() + t.line = v + t.file = file + return nil +} + +// flushSyncWriter is the interface satisfied by logging destinations. +type flushSyncWriter interface { + Flush() error + Sync() error + io.Writer +} + +func init() { + flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files") + flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") + flag.Var(&logging.verbosity, "v", "log level for V logs") + flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr") + flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging") + flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace") + + // Default stderrThreshold is ERROR. + logging.stderrThreshold = errorLog + + logging.setVState(0, nil, false) + go logging.flushDaemon() +} + +// Flush flushes all pending log I/O. +func Flush() { + logging.lockAndFlushAll() +} + +// loggingT collects all the global state of the logging setup. +type loggingT struct { + // Boolean flags. Not handled atomically because the flag.Value interface + // does not let us avoid the =true, and that shorthand is necessary for + // compatibility. TODO: does this matter enough to fix? Seems unlikely. + toStderr bool // The -logtostderr flag. + alsoToStderr bool // The -alsologtostderr flag. + + // Level flag. Handled atomically. + stderrThreshold severity // The -stderrthreshold flag. + + // freeList is a list of byte buffers, maintained under freeListMu. + freeList *buffer + // freeListMu maintains the free list. It is separate from the main mutex + // so buffers can be grabbed and printed to without holding the main lock, + // for better parallelization. + freeListMu sync.Mutex + + // mu protects the remaining elements of this structure and is + // used to synchronize logging. + mu sync.Mutex + // file holds writer for each of the log types. + file [numSeverity]flushSyncWriter + // pcs is used in V to avoid an allocation when computing the caller's PC. + pcs [1]uintptr + // vmap is a cache of the V Level for each V() call site, identified by PC. + // It is wiped whenever the vmodule flag changes state. + vmap map[uintptr]Level + // filterLength stores the length of the vmodule filter chain. If greater + // than zero, it means vmodule is enabled. It may be read safely + // using sync.LoadInt32, but is only modified under mu. + filterLength int32 + // traceLocation is the state of the -log_backtrace_at flag. + traceLocation traceLocation + // These flags are modified only under lock, although verbosity may be fetched + // safely using atomic.LoadInt32. + vmodule moduleSpec // The state of the -vmodule flag. + verbosity Level // V logging level, the value of the -v flag/ +} + +// buffer holds a byte Buffer for reuse. The zero value is ready for use. +type buffer struct { + bytes.Buffer + tmp [64]byte // temporary byte array for creating headers. + next *buffer +} + +var logging loggingT + +// setVState sets a consistent state for V logging. +// l.mu is held. +func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) { + // Turn verbosity off so V will not fire while we are in transition. + logging.verbosity.set(0) + // Ditto for filter length. + atomic.StoreInt32(&logging.filterLength, 0) + + // Set the new filters and wipe the pc->Level map if the filter has changed. + if setFilter { + logging.vmodule.filter = filter + logging.vmap = make(map[uintptr]Level) + } + + // Things are consistent now, so enable filtering and verbosity. + // They are enabled in order opposite to that in V. + atomic.StoreInt32(&logging.filterLength, int32(len(filter))) + logging.verbosity.set(verbosity) +} + +// getBuffer returns a new, ready-to-use buffer. +func (l *loggingT) getBuffer() *buffer { + l.freeListMu.Lock() + b := l.freeList + if b != nil { + l.freeList = b.next + } + l.freeListMu.Unlock() + if b == nil { + b = new(buffer) + } else { + b.next = nil + b.Reset() + } + return b +} + +// putBuffer returns a buffer to the free list. +func (l *loggingT) putBuffer(b *buffer) { + if b.Len() >= 256 { + // Let big buffers die a natural death. + return + } + l.freeListMu.Lock() + b.next = l.freeList + l.freeList = b + l.freeListMu.Unlock() +} + +var timeNow = time.Now // Stubbed out for testing. + +/* +header formats a log header as defined by the C++ implementation. +It returns a buffer containing the formatted header and the user's file and line number. +The depth specifies how many stack frames above lives the source line to be identified in the log message. + +Log lines have this form: + Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +where the fields are defined as follows: + L A single character, representing the log level (eg 'I' for INFO) + mm The month (zero padded; ie May is '05') + dd The day (zero padded) + hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds + threadid The space-padded thread ID as returned by GetTID() + file The file name + line The line number + msg The user-supplied message +*/ +func (l *loggingT) header(s severity, depth int) (*buffer, string, int) { + _, file, line, ok := runtime.Caller(3 + depth) + if !ok { + file = "???" + line = 1 + } else { + slash := strings.LastIndex(file, "/") + if slash >= 0 { + file = file[slash+1:] + } + } + return l.formatHeader(s, file, line), file, line +} + +// formatHeader formats a log header using the provided file name and line number. +func (l *loggingT) formatHeader(s severity, file string, line int) *buffer { + now := timeNow() + if line < 0 { + line = 0 // not a real line number, but acceptable to someDigits + } + if s > fatalLog { + s = infoLog // for safety. + } + buf := l.getBuffer() + + // Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand. + // It's worth about 3X. Fprintf is hard. + _, month, day := now.Date() + hour, minute, second := now.Clock() + // Lmmdd hh:mm:ss.uuuuuu threadid file:line] + buf.tmp[0] = severityChar[s] + buf.twoDigits(1, int(month)) + buf.twoDigits(3, day) + buf.tmp[5] = ' ' + buf.twoDigits(6, hour) + buf.tmp[8] = ':' + buf.twoDigits(9, minute) + buf.tmp[11] = ':' + buf.twoDigits(12, second) + buf.tmp[14] = '.' + buf.nDigits(6, 15, now.Nanosecond()/1000, '0') + buf.tmp[21] = ' ' + buf.nDigits(7, 22, pid, ' ') // TODO: should be TID + buf.tmp[29] = ' ' + buf.Write(buf.tmp[:30]) + buf.WriteString(file) + buf.tmp[0] = ':' + n := buf.someDigits(1, line) + buf.tmp[n+1] = ']' + buf.tmp[n+2] = ' ' + buf.Write(buf.tmp[:n+3]) + return buf +} + +// Some custom tiny helper functions to print the log header efficiently. + +const digits = "0123456789" + +// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i]. +func (buf *buffer) twoDigits(i, d int) { + buf.tmp[i+1] = digits[d%10] + d /= 10 + buf.tmp[i] = digits[d%10] +} + +// nDigits formats an n-digit integer at buf.tmp[i], +// padding with pad on the left. +// It assumes d >= 0. +func (buf *buffer) nDigits(n, i, d int, pad byte) { + j := n - 1 + for ; j >= 0 && d > 0; j-- { + buf.tmp[i+j] = digits[d%10] + d /= 10 + } + for ; j >= 0; j-- { + buf.tmp[i+j] = pad + } +} + +// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i]. +func (buf *buffer) someDigits(i, d int) int { + // Print into the top, then copy down. We know there's space for at least + // a 10-digit number. + j := len(buf.tmp) + for { + j-- + buf.tmp[j] = digits[d%10] + d /= 10 + if d == 0 { + break + } + } + return copy(buf.tmp[i:], buf.tmp[j:]) +} + +func (l *loggingT) println(s severity, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintln(buf, args...) + l.output(s, buf, file, line, false) +} + +func (l *loggingT) print(s severity, args ...interface{}) { + l.printDepth(s, 1, args...) +} + +func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) { + buf, file, line := l.header(s, depth) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +func (l *loggingT) printf(s severity, format string, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintf(buf, format, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +// printWithFileLine behaves like print but uses the provided file and line number. If +// alsoLogToStderr is true, the log message always appears on standard error; it +// will also appear in the log file unless --logtostderr is set. +func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) { + buf := l.formatHeader(s, file, line) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, alsoToStderr) +} + +// output writes the data to the log files and releases the buffer. +func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) { + l.mu.Lock() + if l.traceLocation.isSet() { + if l.traceLocation.match(file, line) { + buf.Write(stacks(false)) + } + } + data := buf.Bytes() + if !flag.Parsed() { + os.Stderr.Write([]byte("ERROR: logging before flag.Parse: ")) + os.Stderr.Write(data) + } else if l.toStderr { + os.Stderr.Write(data) + } else { + if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { + os.Stderr.Write(data) + } + if l.file[s] == nil { + if err := l.createFiles(s); err != nil { + os.Stderr.Write(data) // Make sure the message appears somewhere. + l.exit(err) + } + } + switch s { + case fatalLog: + l.file[fatalLog].Write(data) + fallthrough + case errorLog: + l.file[errorLog].Write(data) + fallthrough + case warningLog: + l.file[warningLog].Write(data) + fallthrough + case infoLog: + l.file[infoLog].Write(data) + } + } + if s == fatalLog { + // If we got here via Exit rather than Fatal, print no stacks. + if atomic.LoadUint32(&fatalNoStacks) > 0 { + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(1) + } + // Dump all goroutine stacks before exiting. + // First, make sure we see the trace for the current goroutine on standard error. + // If -logtostderr has been specified, the loop below will do that anyway + // as the first stack in the full dump. + if !l.toStderr { + os.Stderr.Write(stacks(false)) + } + // Write the stack trace for all goroutines to the files. + trace := stacks(true) + logExitFunc = func(error) {} // If we get a write error, we'll still exit below. + for log := fatalLog; log >= infoLog; log-- { + if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set. + f.Write(trace) + } + } + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway. + } + l.putBuffer(buf) + l.mu.Unlock() + if stats := severityStats[s]; stats != nil { + atomic.AddInt64(&stats.lines, 1) + atomic.AddInt64(&stats.bytes, int64(len(data))) + } +} + +// timeoutFlush calls Flush and returns when it completes or after timeout +// elapses, whichever happens first. This is needed because the hooks invoked +// by Flush may deadlock when glog.Fatal is called from a hook that holds +// a lock. +func timeoutFlush(timeout time.Duration) { + done := make(chan bool, 1) + go func() { + Flush() // calls logging.lockAndFlushAll() + done <- true + }() + select { + case <-done: + case <-time.After(timeout): + fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout) + } +} + +// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines. +func stacks(all bool) []byte { + // We don't know how big the traces are, so grow a few times if they don't fit. Start large, though. + n := 10000 + if all { + n = 100000 + } + var trace []byte + for i := 0; i < 5; i++ { + trace = make([]byte, n) + nbytes := runtime.Stack(trace, all) + if nbytes < len(trace) { + return trace[:nbytes] + } + n *= 2 + } + return trace +} + +// logExitFunc provides a simple mechanism to override the default behavior +// of exiting on error. Used in testing and to guarantee we reach a required exit +// for fatal logs. Instead, exit could be a function rather than a method but that +// would make its use clumsier. +var logExitFunc func(error) + +// exit is called if there is trouble creating or writing log files. +// It flushes the logs and exits the program; there's no point in hanging around. +// l.mu is held. +func (l *loggingT) exit(err error) { + fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err) + // If logExitFunc is set, we do that instead of exiting. + if logExitFunc != nil { + logExitFunc(err) + return + } + l.flushAll() + os.Exit(2) +} + +// syncBuffer joins a bufio.Writer to its underlying file, providing access to the +// file's Sync method and providing a wrapper for the Write method that provides log +// file rotation. There are conflicting methods, so the file cannot be embedded. +// l.mu is held for all its methods. +type syncBuffer struct { + logger *loggingT + *bufio.Writer + file *os.File + sev severity + nbytes uint64 // The number of bytes written to this file +} + +func (sb *syncBuffer) Sync() error { + return sb.file.Sync() +} + +func (sb *syncBuffer) Write(p []byte) (n int, err error) { + if sb.nbytes+uint64(len(p)) >= MaxSize { + if err := sb.rotateFile(time.Now()); err != nil { + sb.logger.exit(err) + } + } + n, err = sb.Writer.Write(p) + sb.nbytes += uint64(n) + if err != nil { + sb.logger.exit(err) + } + return +} + +// rotateFile closes the syncBuffer's file and starts a new one. +func (sb *syncBuffer) rotateFile(now time.Time) error { + if sb.file != nil { + sb.Flush() + sb.file.Close() + } + var err error + sb.file, _, err = create(severityName[sb.sev], now) + sb.nbytes = 0 + if err != nil { + return err + } + + sb.Writer = bufio.NewWriterSize(sb.file, bufferSize) + + // Write header. + var buf bytes.Buffer + fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05")) + fmt.Fprintf(&buf, "Running on machine: %s\n", host) + fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH) + fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n") + n, err := sb.file.Write(buf.Bytes()) + sb.nbytes += uint64(n) + return err +} + +// bufferSize sizes the buffer associated with each log file. It's large +// so that log records can accumulate without the logging thread blocking +// on disk I/O. The flushDaemon will block instead. +const bufferSize = 256 * 1024 + +// createFiles creates all the log files for severity from sev down to infoLog. +// l.mu is held. +func (l *loggingT) createFiles(sev severity) error { + now := time.Now() + // Files are created in decreasing severity order, so as soon as we find one + // has already been created, we can stop. + for s := sev; s >= infoLog && l.file[s] == nil; s-- { + sb := &syncBuffer{ + logger: l, + sev: s, + } + if err := sb.rotateFile(now); err != nil { + return err + } + l.file[s] = sb + } + return nil +} + +const flushInterval = 30 * time.Second + +// flushDaemon periodically flushes the log file buffers. +func (l *loggingT) flushDaemon() { + for _ = range time.NewTicker(flushInterval).C { + l.lockAndFlushAll() + } +} + +// lockAndFlushAll is like flushAll but locks l.mu first. +func (l *loggingT) lockAndFlushAll() { + l.mu.Lock() + l.flushAll() + l.mu.Unlock() +} + +// flushAll flushes all the logs and attempts to "sync" their data to disk. +// l.mu is held. +func (l *loggingT) flushAll() { + // Flush from fatal down, in case there's trouble flushing. + for s := fatalLog; s >= infoLog; s-- { + file := l.file[s] + if file != nil { + file.Flush() // ignore error + file.Sync() // ignore error + } + } +} + +// CopyStandardLogTo arranges for messages written to the Go "log" package's +// default logs to also appear in the Google logs for the named and lower +// severities. Subsequent changes to the standard log's default output location +// or format may break this behavior. +// +// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not +// recognized, CopyStandardLogTo panics. +func CopyStandardLogTo(name string) { + sev, ok := severityByName(name) + if !ok { + panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name)) + } + // Set a log format that captures the user's file and line: + // d.go:23: message + stdLog.SetFlags(stdLog.Lshortfile) + stdLog.SetOutput(logBridge(sev)) +} + +// logBridge provides the Write method that enables CopyStandardLogTo to connect +// Go's standard logs to the logs provided by this package. +type logBridge severity + +// Write parses the standard logging line and passes its components to the +// logger for severity(lb). +func (lb logBridge) Write(b []byte) (n int, err error) { + var ( + file = "???" + line = 1 + text string + ) + // Split "d.go:23: message" into "d.go", "23", and "message". + if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 { + text = fmt.Sprintf("bad log format: %s", b) + } else { + file = string(parts[0]) + text = string(parts[2][1:]) // skip leading space + line, err = strconv.Atoi(string(parts[1])) + if err != nil { + text = fmt.Sprintf("bad line number: %s", b) + line = 1 + } + } + // printWithFileLine with alsoToStderr=true, so standard log messages + // always appear on standard error. + logging.printWithFileLine(severity(lb), file, line, true, text) + return len(b), nil +} + +// setV computes and remembers the V level for a given PC +// when vmodule is enabled. +// File pattern matching takes the basename of the file, stripped +// of its .go suffix, and uses filepath.Match, which is a little more +// general than the *? matching used in C++. +// l.mu is held. +func (l *loggingT) setV(pc uintptr) Level { + fn := runtime.FuncForPC(pc) + file, _ := fn.FileLine(pc) + // The file is something like /a/b/c/d.go. We want just the d. + if strings.HasSuffix(file, ".go") { + file = file[:len(file)-3] + } + if slash := strings.LastIndex(file, "/"); slash >= 0 { + file = file[slash+1:] + } + for _, filter := range l.vmodule.filter { + if filter.match(file) { + l.vmap[pc] = filter.level + return filter.level + } + } + l.vmap[pc] = 0 + return 0 +} + +// Verbose is a boolean type that implements Infof (like Printf) etc. +// See the documentation of V for more information. +type Verbose bool + +// V reports whether verbosity at the call site is at least the requested level. +// The returned value is a boolean of type Verbose, which implements Info, Infoln +// and Infof. These methods will write to the Info log if called. +// Thus, one may write either +// if glog.V(2) { glog.Info("log this") } +// or +// glog.V(2).Info("log this") +// The second form is shorter but the first is cheaper if logging is off because it does +// not evaluate its arguments. +// +// Whether an individual call to V generates a log record depends on the setting of +// the -v and --vmodule flags; both are off by default. If the level in the call to +// V is at least the value of -v, or of -vmodule for the source file containing the +// call, the V call will log. +func V(level Level) Verbose { + // This function tries hard to be cheap unless there's work to do. + // The fast path is two atomic loads and compares. + + // Here is a cheap but safe test to see if V logging is enabled globally. + if logging.verbosity.get() >= level { + return Verbose(true) + } + + // It's off globally but it vmodule may still be set. + // Here is another cheap but safe test to see if vmodule is enabled. + if atomic.LoadInt32(&logging.filterLength) > 0 { + // Now we need a proper lock to use the logging structure. The pcs field + // is shared so we must lock before accessing it. This is fairly expensive, + // but if V logging is enabled we're slow anyway. + logging.mu.Lock() + defer logging.mu.Unlock() + if runtime.Callers(2, logging.pcs[:]) == 0 { + return Verbose(false) + } + v, ok := logging.vmap[logging.pcs[0]] + if !ok { + v = logging.setV(logging.pcs[0]) + } + return Verbose(v >= level) + } + return Verbose(false) +} + +// Info is equivalent to the global Info function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Info(args ...interface{}) { + if v { + logging.print(infoLog, args...) + } +} + +// Infoln is equivalent to the global Infoln function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infoln(args ...interface{}) { + if v { + logging.println(infoLog, args...) + } +} + +// Infof is equivalent to the global Infof function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infof(format string, args ...interface{}) { + if v { + logging.printf(infoLog, format, args...) + } +} + +// Info logs to the INFO log. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Info(args ...interface{}) { + logging.print(infoLog, args...) +} + +// InfoDepth acts as Info but uses depth to determine which call frame to log. +// InfoDepth(0, "msg") is the same as Info("msg"). +func InfoDepth(depth int, args ...interface{}) { + logging.printDepth(infoLog, depth, args...) +} + +// Infoln logs to the INFO log. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Infoln(args ...interface{}) { + logging.println(infoLog, args...) +} + +// Infof logs to the INFO log. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Infof(format string, args ...interface{}) { + logging.printf(infoLog, format, args...) +} + +// Warning logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Warning(args ...interface{}) { + logging.print(warningLog, args...) +} + +// WarningDepth acts as Warning but uses depth to determine which call frame to log. +// WarningDepth(0, "msg") is the same as Warning("msg"). +func WarningDepth(depth int, args ...interface{}) { + logging.printDepth(warningLog, depth, args...) +} + +// Warningln logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Warningln(args ...interface{}) { + logging.println(warningLog, args...) +} + +// Warningf logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Warningf(format string, args ...interface{}) { + logging.printf(warningLog, format, args...) +} + +// Error logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Error(args ...interface{}) { + logging.print(errorLog, args...) +} + +// ErrorDepth acts as Error but uses depth to determine which call frame to log. +// ErrorDepth(0, "msg") is the same as Error("msg"). +func ErrorDepth(depth int, args ...interface{}) { + logging.printDepth(errorLog, depth, args...) +} + +// Errorln logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Errorln(args ...interface{}) { + logging.println(errorLog, args...) +} + +// Errorf logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Errorf(format string, args ...interface{}) { + logging.printf(errorLog, format, args...) +} + +// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Fatal(args ...interface{}) { + logging.print(fatalLog, args...) +} + +// FatalDepth acts as Fatal but uses depth to determine which call frame to log. +// FatalDepth(0, "msg") is the same as Fatal("msg"). +func FatalDepth(depth int, args ...interface{}) { + logging.printDepth(fatalLog, depth, args...) +} + +// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Fatalln(args ...interface{}) { + logging.println(fatalLog, args...) +} + +// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Fatalf(format string, args ...interface{}) { + logging.printf(fatalLog, format, args...) +} + +// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks. +// It allows Exit and relatives to use the Fatal logs. +var fatalNoStacks uint32 + +// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Exit(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.print(fatalLog, args...) +} + +// ExitDepth acts as Exit but uses depth to determine which call frame to log. +// ExitDepth(0, "msg") is the same as Exit("msg"). +func ExitDepth(depth int, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printDepth(fatalLog, depth, args...) +} + +// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +func Exitln(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.println(fatalLog, args...) +} + +// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Exitf(format string, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printf(fatalLog, format, args...) +} diff --git a/vendor/github.com/golang/glog/glog_file.go b/vendor/github.com/golang/glog/glog_file.go new file mode 100644 index 0000000..65075d2 --- /dev/null +++ b/vendor/github.com/golang/glog/glog_file.go @@ -0,0 +1,124 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// File I/O for logs. + +package glog + +import ( + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + "sync" + "time" +) + +// MaxSize is the maximum size of a log file in bytes. +var MaxSize uint64 = 1024 * 1024 * 1800 + +// logDirs lists the candidate directories for new log files. +var logDirs []string + +// If non-empty, overrides the choice of directory in which to write logs. +// See createLogDirs for the full list of possible destinations. +var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory") + +func createLogDirs() { + if *logDir != "" { + logDirs = append(logDirs, *logDir) + } + logDirs = append(logDirs, os.TempDir()) +} + +var ( + pid = os.Getpid() + program = filepath.Base(os.Args[0]) + host = "unknownhost" + userName = "unknownuser" +) + +func init() { + h, err := os.Hostname() + if err == nil { + host = shortHostname(h) + } + + current, err := user.Current() + if err == nil { + userName = current.Username + } + + // Sanitize userName since it may contain filepath separators on Windows. + userName = strings.Replace(userName, `\`, "_", -1) +} + +// shortHostname returns its argument, truncating at the first period. +// For instance, given "www.google.com" it returns "www". +func shortHostname(hostname string) string { + if i := strings.Index(hostname, "."); i >= 0 { + return hostname[:i] + } + return hostname +} + +// logName returns a new log file name containing tag, with start time t, and +// the name for the symlink for tag. +func logName(tag string, t time.Time) (name, link string) { + name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d", + program, + host, + userName, + tag, + t.Year(), + t.Month(), + t.Day(), + t.Hour(), + t.Minute(), + t.Second(), + pid) + return name, program + "." + tag +} + +var onceLogDirs sync.Once + +// create creates a new log file and returns the file and its filename, which +// contains tag ("INFO", "FATAL", etc.) and t. If the file is created +// successfully, create also attempts to update the symlink for that tag, ignoring +// errors. +func create(tag string, t time.Time) (f *os.File, filename string, err error) { + onceLogDirs.Do(createLogDirs) + if len(logDirs) == 0 { + return nil, "", errors.New("log: no log dirs") + } + name, link := logName(tag, t) + var lastErr error + for _, dir := range logDirs { + fname := filepath.Join(dir, name) + f, err := os.Create(fname) + if err == nil { + symlink := filepath.Join(dir, link) + os.Remove(symlink) // ignore err + os.Symlink(name, symlink) // ignore err + return f, fname, nil + } + lastErr = err + } + return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr) +} diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS new file mode 100644 index 0000000..15167cd --- /dev/null +++ b/vendor/github.com/golang/protobuf/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS new file mode 100644 index 0000000..1c4577e --- /dev/null +++ b/vendor/github.com/golang/protobuf/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE new file mode 100644 index 0000000..1b1b192 --- /dev/null +++ b/vendor/github.com/golang/protobuf/LICENSE @@ -0,0 +1,31 @@ +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +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/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go new file mode 100644 index 0000000..3cd3249 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -0,0 +1,253 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "fmt" + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(src Message) Message { + in := reflect.ValueOf(src) + if in.IsNil() { + return src + } + out := reflect.New(in.Type().Elem()) + dst := out.Interface().(Message) + Merge(dst, src) + return dst +} + +// Merger is the interface representing objects that can merge messages of the same type. +type Merger interface { + // Merge merges src into this message. + // Required and optional fields that are set in src will be set to that value in dst. + // Elements of repeated fields will be appended. + // + // Merge may panic if called with a different argument type than the receiver. + Merge(src Message) +} + +// generatedMerger is the custom merge method that generated protos will have. +// We must add this method since a generate Merge method will conflict with +// many existing protos that have a Merge data field already defined. +type generatedMerger interface { + XXX_Merge(src Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + if m, ok := dst.(Merger); ok { + m.Merge(src) + return + } + + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) + } + if in.IsNil() { + return // Merge from nil src is a noop + } + if m, ok := dst.(generatedMerger); ok { + m.XXX_Merge(src) + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go new file mode 100644 index 0000000..d9aa3c4 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -0,0 +1,428 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +// Unmarshal implementations should not clear the receiver. +// Any unmarshaled data should be merged into the receiver. +// Callers of Unmarshal that do not want to retain existing data +// should Reset the receiver before calling Unmarshal. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// newUnmarshaler is the interface representing objects that can +// unmarshal themselves. The semantics are identical to Unmarshaler. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newUnmarshaler interface { + XXX_Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +// StartGroup tag is already consumed. This function consumes +// EndGroup tag. +func (p *Buffer) DecodeGroup(pb Message) error { + b := p.buf[p.index:] + x, y := findEndGroup(b) + if x < 0 { + return io.ErrUnexpectedEOF + } + err := Unmarshal(b[:x], pb) + p.index += y + return err +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + err := u.XXX_Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + // Slow workaround for messages that aren't Unmarshalers. + // This includes some hand-coded .pb.go files and + // bootstrap protos. + // TODO: fix all of those and then add Unmarshal to + // the Message interface. Then: + // The cast above and code below can be deleted. + // The old unmarshaler can be deleted. + // Clients can call Unmarshal directly (can already do that, actually). + var info InternalMessageInfo + err := info.Unmarshal(pb, p.buf[p.index:]) + p.index = len(p.buf) + return err +} diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go new file mode 100644 index 0000000..dea2617 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/discard.go @@ -0,0 +1,350 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +type generatedDiscarder interface { + XXX_DiscardUnknown() +} + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + if m, ok := m.(generatedDiscarder); ok { + m.XXX_DiscardUnknown() + return + } + // TODO: Dynamically populate a InternalMessageInfo for legacy messages, + // but the master branch has no implementation for InternalMessageInfo, + // so it would be more work to replicate that approach. + discardLegacy(m) +} + +// DiscardUnknown recursively discards all unknown fields. +func (a *InternalMessageInfo) DiscardUnknown(m Message) { + di := atomicLoadDiscardInfo(&a.discard) + if di == nil { + di = getDiscardInfo(reflect.TypeOf(m).Elem()) + atomicStoreDiscardInfo(&a.discard, di) + } + di.discard(toPointer(&m)) +} + +type discardInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []discardFieldInfo + unrecognized field +} + +type discardFieldInfo struct { + field field // Offset of field, guaranteed to be valid + discard func(src pointer) +} + +var ( + discardInfoMap = map[reflect.Type]*discardInfo{} + discardInfoLock sync.Mutex +) + +func getDiscardInfo(t reflect.Type) *discardInfo { + discardInfoLock.Lock() + defer discardInfoLock.Unlock() + di := discardInfoMap[t] + if di == nil { + di = &discardInfo{typ: t} + discardInfoMap[t] = di + } + return di +} + +func (di *discardInfo) discard(src pointer) { + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&di.initialized) == 0 { + di.computeDiscardInfo() + } + + for _, fi := range di.fields { + sfp := src.offset(fi.field) + fi.discard(sfp) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { + // Ignore lock since DiscardUnknown is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + DiscardUnknown(m) + } + } + } + + if di.unrecognized.IsValid() { + *src.offset(di.unrecognized).toBytes() = nil + } +} + +func (di *discardInfo) computeDiscardInfo() { + di.lock.Lock() + defer di.lock.Unlock() + if di.initialized != 0 { + return + } + t := di.typ + n := t.NumField() + + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + dfi := discardFieldInfo{field: toField(&f)} + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) + case isSlice: // E.g., []*pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sps := src.getPointerSlice() + for _, sp := range sps { + if !sp.isNil() { + di.discard(sp) + } + } + } + default: // E.g., *pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sp := src.getPointer() + if !sp.isNil() { + di.discard(sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) + default: // E.g., map[K]V + if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) + dfi.discard = func(src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + DiscardUnknown(val.Interface().(Message)) + } + } + } else { + dfi.discard = func(pointer) {} // Noop + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) + default: // E.g., interface{} + // TODO: Make this faster? + dfi.discard = func(src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + DiscardUnknown(sv.Interface().(Message)) + } + } + } + } + default: + continue + } + di.fields = append(di.fields, dfi) + } + + di.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + di.unrecognized = toField(&f) + } + + atomic.StoreInt32(&di.initialized, 1) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(m); err == nil { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go new file mode 100644 index 0000000..c27d35f --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -0,0 +1,221 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + switch { + case x < 1<<7: + return 1 + case x < 1<<14: + return 2 + case x < 1<<21: + return 3 + case x < 1<<28: + return 4 + case x < 1<<35: + return 5 + case x < 1<<42: + return 6 + case x < 1<<49: + return 7 + case x < 1<<56: + return 8 + case x < 1<<63: + return 9 + } + return 10 +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + siz := Size(pb) + p.EncodeVarint(uint64(siz)) + return p.Marshal(pb) +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go new file mode 100644 index 0000000..d4db5a1 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + return bytes.Equal(u1, u2) +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 == nil && m2 == nil { + // Both have only encoded form. + if bytes.Equal(e1.enc, e2.enc) { + continue + } + // The bytes are different, but the extensions might still be + // equal. We need to decode them to compare. + } + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + // If both have only encoded form and the bytes are the same, + // it is handled above. We get here when the bytes are different. + // We don't know how to decode it, so just compare them as byte + // slices. + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + return false + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go new file mode 100644 index 0000000..816a3b9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -0,0 +1,543 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "io" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, error) { + switch p := p.(type) { + case extendableProto: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return p, nil + case extendableProtoV1: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return extensionAdapter{p}, nil + } + // Don't allocate a specific error containing %T: + // this is the hot path for Clone and MarshalText. + return nil, errNotExtendable +} + +var errNotExtendable = errors.New("proto: not an extendable proto.Message") + +func isNilPtr(x interface{}) bool { + v := reflect.ValueOf(x) + return v.Kind() == reflect.Ptr && v.IsNil() +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + epb, err := extendable(base) + if err != nil { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extendableProto, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + // TODO: Check types, field numbers, etc.? + epb, err := extendable(pb) + if err != nil { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok := extmap[extension.Field] + mu.Unlock() + return ok +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + epb, err := extendable(pb) + if err != nil { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, extension.Field) +} + +// GetExtension retrieves a proto2 extended field from pb. +// +// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), +// then GetExtension parses the encoded field and returns a Go value of the specified type. +// If the field is not present, then the default value is returned (if one is specified), +// otherwise ErrMissingExtension is reported. +// +// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), +// then GetExtension returns the raw encoded bytes of the field extension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + epb, err := extendable(pb) + if err != nil { + return nil, err + } + + if extension.ExtendedType != nil { + // can only check type if this is a complete descriptor + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + if extension.ExtensionType == nil { + // incomplete descriptor + return e.enc, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + if extension.ExtensionType == nil { + // incomplete descriptor, so no default + return nil, ErrMissingExtension + } + + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + unmarshal := typeUnmarshaler(t, extension.Tag) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate space to store the pointer/slice. + value := reflect.New(t).Elem() + + var err error + for { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + wire := int(x) & 7 + + b, err = unmarshal(b, valToPointer(value.Addr()), wire) + if err != nil { + return nil, err + } + + if len(b) == 0 { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + epb, err := extendable(pb) + if err != nil { + return nil, err + } + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(epb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, err := extendable(pb) + if err != nil { + return nil, err + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + epb, err := extendable(pb) + if err != nil { + return err + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + epb, err := extendable(pb) + if err != nil { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go new file mode 100644 index 0000000..0e2191b --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -0,0 +1,921 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/golang/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +var errInvalidUTF8 = errors.New("proto: invalid UTF-8 string") + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + deterministic bool +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +// SetDeterministic sets whether to use deterministic serialization. +// +// Deterministic serialization guarantees that for a given binary, equal +// messages will always be serialized to the same bytes. This implies: +// +// - Repeated serialization of a message will return the same bytes. +// - Different processes of the same binary (which may be executing on +// different machines) will serialize equal messages to the same bytes. +// +// Note that the deterministic serialization is NOT canonical across +// languages. It is not guaranteed to remain stable over time. It is unstable +// across different builds with schema changes due to unknown fields. +// Users who need canonical serialization (e.g., persistent storage in a +// canonical form, fingerprinting, etc.) should define their own +// canonicalization specification and implement their own serializer rather +// than relying on this API. +// +// If deterministic serialization is requested, map entries will be sorted +// by keys in lexographical order. This is an implementation detail and +// subject to change. +func (p *Buffer) SetDeterministic(deterministic bool) { + p.deterministic = deterministic +} + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + index := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = index +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// mapKeys returns a sort.Interface to be used for sorting the map keys. +// Map fields may have key types of non-float scalars, strings and enums. +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{vs: vs} + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + case reflect.Bool: + s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true + case reflect.String: + s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } + default: + panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion1 = true + +// InternalMessageInfo is a type used internally by generated .pb.go files. +// This type is not intended to be used by non-generated code. +// This type is not subject to any compatibility guarantee. +type InternalMessageInfo struct { + marshal *marshalInfo + unmarshal *unmarshalInfo + merge *mergeInfo + discard *discardInfo +} diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go new file mode 100644 index 0000000..3b6ca41 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -0,0 +1,314 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" + "sync" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + return ms.find(pb) != nil +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(exts interface{}) ([]byte, error) { + return marshalMessageSet(exts, false) +} + +// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal. +func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) { + switch exts := exts.(type) { + case *XXX_InternalExtensions: + var u marshalInfo + siz := u.sizeMessageSet(exts) + b := make([]byte, 0, siz) + return u.appendMessageSet(b, exts, deterministic) + + case map[int32]Extension: + // This is an old-style extension map. + // Wrap it in a new-style XXX_InternalExtensions. + ie := XXX_InternalExtensions{ + p: &struct { + mu sync.Mutex + extensionMap map[int32]Extension + }{ + extensionMap: exts, + }, + } + + var u marshalInfo + siz := u.sizeMessageSet(&ie) + b := make([]byte, 0, siz) + return u.appendMessageSet(b, &ie, deterministic) + + default: + return nil, errors.New("proto: not an extension map") + } +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + var mu sync.Locker + m, mu = exts.extensionsRead() + if m != nil { + // Keep the extensions map locked until we're done marshaling to prevent + // races between marshaling and unmarshaling the lazily-{en,de}coded + // values. + mu.Lock() + defer mu.Unlock() + } + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + + if i > 0 && b.Len() > 1 { + b.WriteByte(',') + } + + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go new file mode 100644 index 0000000..b6cad90 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -0,0 +1,357 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// +build purego appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "reflect" + "sync" +) + +const unsafeAllowed = false + +// A field identifies a field in a struct, accessible from a pointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// zeroField is a noop when calling pointer.offset. +var zeroField = field([]int{}) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// The pointer type is for the table-driven decoder. +// The implementation here uses a reflect.Value of pointer type to +// create a generic pointer. In pointer_unsafe.go we use unsafe +// instead of reflect to implement the same (but faster) interface. +type pointer struct { + v reflect.Value +} + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + return pointer{v: reflect.ValueOf(*i)} +} + +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + v := reflect.ValueOf(*i) + u := reflect.New(v.Type()) + u.Elem().Set(v) + return pointer{v: u} +} + +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{v: v} +} + +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} +} + +func (p pointer) isNil() bool { + return p.v.IsNil() +} + +// grow updates the slice s in place to make it one element longer. +// s must be addressable. +// Returns the (addressable) new element. +func grow(s reflect.Value) reflect.Value { + n, m := s.Len(), s.Cap() + if n < m { + s.SetLen(n + 1) + } else { + s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) + } + return s.Index(n) +} + +func (p pointer) toInt64() *int64 { + return p.v.Interface().(*int64) +} +func (p pointer) toInt64Ptr() **int64 { + return p.v.Interface().(**int64) +} +func (p pointer) toInt64Slice() *[]int64 { + return p.v.Interface().(*[]int64) +} + +var int32ptr = reflect.TypeOf((*int32)(nil)) + +func (p pointer) toInt32() *int32 { + return p.v.Convert(int32ptr).Interface().(*int32) +} + +// The toInt32Ptr/Slice methods don't work because of enums. +// Instead, we must use set/get methods for the int32ptr/slice case. +/* + func (p pointer) toInt32Ptr() **int32 { + return p.v.Interface().(**int32) +} + func (p pointer) toInt32Slice() *[]int32 { + return p.v.Interface().(*[]int32) +} +*/ +func (p pointer) getInt32Ptr() *int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().(*int32) + } + // an enum + return p.v.Elem().Convert(int32PtrType).Interface().(*int32) +} +func (p pointer) setInt32Ptr(v int32) { + // Allocate value in a *int32. Possibly convert that to a *enum. + // Then assign it to a **int32 or **enum. + // Note: we can convert *int32 to *enum, but we can't convert + // **int32 to **enum! + p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) +} + +// getInt32Slice copies []int32 from p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getInt32Slice() []int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().([]int32) + } + // an enum + // Allocate a []int32, then assign []enum's values into it. + // Note: we can't convert []enum to []int32. + slice := p.v.Elem() + s := make([]int32, slice.Len()) + for i := 0; i < slice.Len(); i++ { + s[i] = int32(slice.Index(i).Int()) + } + return s +} + +// setInt32Slice copies []int32 into p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setInt32Slice(v []int32) { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + p.v.Elem().Set(reflect.ValueOf(v)) + return + } + // an enum + // Allocate a []enum, then assign []int32's values into it. + // Note: we can't convert []enum to []int32. + slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) + for i, x := range v { + slice.Index(i).SetInt(int64(x)) + } + p.v.Elem().Set(slice) +} +func (p pointer) appendInt32Slice(v int32) { + grow(p.v.Elem()).SetInt(int64(v)) +} + +func (p pointer) toUint64() *uint64 { + return p.v.Interface().(*uint64) +} +func (p pointer) toUint64Ptr() **uint64 { + return p.v.Interface().(**uint64) +} +func (p pointer) toUint64Slice() *[]uint64 { + return p.v.Interface().(*[]uint64) +} +func (p pointer) toUint32() *uint32 { + return p.v.Interface().(*uint32) +} +func (p pointer) toUint32Ptr() **uint32 { + return p.v.Interface().(**uint32) +} +func (p pointer) toUint32Slice() *[]uint32 { + return p.v.Interface().(*[]uint32) +} +func (p pointer) toBool() *bool { + return p.v.Interface().(*bool) +} +func (p pointer) toBoolPtr() **bool { + return p.v.Interface().(**bool) +} +func (p pointer) toBoolSlice() *[]bool { + return p.v.Interface().(*[]bool) +} +func (p pointer) toFloat64() *float64 { + return p.v.Interface().(*float64) +} +func (p pointer) toFloat64Ptr() **float64 { + return p.v.Interface().(**float64) +} +func (p pointer) toFloat64Slice() *[]float64 { + return p.v.Interface().(*[]float64) +} +func (p pointer) toFloat32() *float32 { + return p.v.Interface().(*float32) +} +func (p pointer) toFloat32Ptr() **float32 { + return p.v.Interface().(**float32) +} +func (p pointer) toFloat32Slice() *[]float32 { + return p.v.Interface().(*[]float32) +} +func (p pointer) toString() *string { + return p.v.Interface().(*string) +} +func (p pointer) toStringPtr() **string { + return p.v.Interface().(**string) +} +func (p pointer) toStringSlice() *[]string { + return p.v.Interface().(*[]string) +} +func (p pointer) toBytes() *[]byte { + return p.v.Interface().(*[]byte) +} +func (p pointer) toBytesSlice() *[][]byte { + return p.v.Interface().(*[][]byte) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return p.v.Interface().(*XXX_InternalExtensions) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return p.v.Interface().(*map[int32]Extension) +} +func (p pointer) getPointer() pointer { + return pointer{v: p.v.Elem()} +} +func (p pointer) setPointer(q pointer) { + p.v.Elem().Set(q.v) +} +func (p pointer) appendPointer(q pointer) { + grow(p.v.Elem()).Set(q.v) +} + +// getPointerSlice copies []*T from p as a new []pointer. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getPointerSlice() []pointer { + if p.v.IsNil() { + return nil + } + n := p.v.Elem().Len() + s := make([]pointer, n) + for i := 0; i < n; i++ { + s[i] = pointer{v: p.v.Elem().Index(i)} + } + return s +} + +// setPointerSlice copies []pointer into p as a new []*T. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setPointerSlice(v []pointer) { + if v == nil { + p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) + return + } + s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) + for _, p := range v { + s = reflect.Append(s, p.v) + } + p.v.Elem().Set(s) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + if p.v.Elem().IsNil() { + return pointer{v: p.v.Elem()} + } + return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct +} + +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + // TODO: check that p.v.Type().Elem() == t? + return p.v +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} + +var atomicLock sync.Mutex diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go new file mode 100644 index 0000000..d55a335 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,308 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +// +build !purego,!appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "sync/atomic" + "unsafe" +) + +const unsafeAllowed = true + +// A field identifies a field in a struct, accessible from a pointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// zeroField is a noop when calling pointer.offset. +const zeroField = field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != invalidField +} + +// The pointer type below is for the new table-driven encoder/decoder. +// The implementation here uses unsafe.Pointer to create a generic pointer. +// In pointer_reflect.go we use reflect instead of unsafe to implement +// the same (but slower) interface. +type pointer struct { + p unsafe.Pointer +} + +// size of pointer +var ptrSize = unsafe.Sizeof(uintptr(0)) + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + // Super-tricky - read pointer out of data word of interface value. + // Saves ~25ns over the equivalent: + // return valToPointer(reflect.ValueOf(*i)) + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} +} + +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + // Super-tricky - read or get the address of data word of interface value. + if isptr { + // The interface is of pointer type, thus it is a direct interface. + // The data word is the pointer data itself. We take its address. + return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} + } + // The interface is not of pointer type. The data word is the pointer + // to the data. + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} +} + +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{p: unsafe.Pointer(v.Pointer())} +} + +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + // For safety, we should panic if !f.IsValid, however calling panic causes + // this to no longer be inlineable, which is a serious performance cost. + /* + if !f.IsValid() { + panic("invalid field") + } + */ + return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} +} + +func (p pointer) isNil() bool { + return p.p == nil +} + +func (p pointer) toInt64() *int64 { + return (*int64)(p.p) +} +func (p pointer) toInt64Ptr() **int64 { + return (**int64)(p.p) +} +func (p pointer) toInt64Slice() *[]int64 { + return (*[]int64)(p.p) +} +func (p pointer) toInt32() *int32 { + return (*int32)(p.p) +} + +// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. +/* + func (p pointer) toInt32Ptr() **int32 { + return (**int32)(p.p) + } + func (p pointer) toInt32Slice() *[]int32 { + return (*[]int32)(p.p) + } +*/ +func (p pointer) getInt32Ptr() *int32 { + return *(**int32)(p.p) +} +func (p pointer) setInt32Ptr(v int32) { + *(**int32)(p.p) = &v +} + +// getInt32Slice loads a []int32 from p. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getInt32Slice() []int32 { + return *(*[]int32)(p.p) +} + +// setInt32Slice stores a []int32 to p. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setInt32Slice(v []int32) { + *(*[]int32)(p.p) = v +} + +// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? +func (p pointer) appendInt32Slice(v int32) { + s := (*[]int32)(p.p) + *s = append(*s, v) +} + +func (p pointer) toUint64() *uint64 { + return (*uint64)(p.p) +} +func (p pointer) toUint64Ptr() **uint64 { + return (**uint64)(p.p) +} +func (p pointer) toUint64Slice() *[]uint64 { + return (*[]uint64)(p.p) +} +func (p pointer) toUint32() *uint32 { + return (*uint32)(p.p) +} +func (p pointer) toUint32Ptr() **uint32 { + return (**uint32)(p.p) +} +func (p pointer) toUint32Slice() *[]uint32 { + return (*[]uint32)(p.p) +} +func (p pointer) toBool() *bool { + return (*bool)(p.p) +} +func (p pointer) toBoolPtr() **bool { + return (**bool)(p.p) +} +func (p pointer) toBoolSlice() *[]bool { + return (*[]bool)(p.p) +} +func (p pointer) toFloat64() *float64 { + return (*float64)(p.p) +} +func (p pointer) toFloat64Ptr() **float64 { + return (**float64)(p.p) +} +func (p pointer) toFloat64Slice() *[]float64 { + return (*[]float64)(p.p) +} +func (p pointer) toFloat32() *float32 { + return (*float32)(p.p) +} +func (p pointer) toFloat32Ptr() **float32 { + return (**float32)(p.p) +} +func (p pointer) toFloat32Slice() *[]float32 { + return (*[]float32)(p.p) +} +func (p pointer) toString() *string { + return (*string)(p.p) +} +func (p pointer) toStringPtr() **string { + return (**string)(p.p) +} +func (p pointer) toStringSlice() *[]string { + return (*[]string)(p.p) +} +func (p pointer) toBytes() *[]byte { + return (*[]byte)(p.p) +} +func (p pointer) toBytesSlice() *[][]byte { + return (*[][]byte)(p.p) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(p.p) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return (*map[int32]Extension)(p.p) +} + +// getPointerSlice loads []*T from p as a []pointer. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getPointerSlice() []pointer { + // Super-tricky - p should point to a []*T where T is a + // message type. We load it as []pointer. + return *(*[]pointer)(p.p) +} + +// setPointerSlice stores []pointer into p as a []*T. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setPointerSlice(v []pointer) { + // Super-tricky - p should point to a []*T where T is a + // message type. We store it as []pointer. + *(*[]pointer)(p.p) = v +} + +// getPointer loads the pointer at p and returns it. +func (p pointer) getPointer() pointer { + return pointer{p: *(*unsafe.Pointer)(p.p)} +} + +// setPointer stores the pointer q at p. +func (p pointer) setPointer(q pointer) { + *(*unsafe.Pointer)(p.p) = q.p +} + +// append q to the slice pointed to by p. +func (p pointer) appendPointer(q pointer) { + s := (*[]unsafe.Pointer)(p.p) + *s = append(*s, q.p) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + // Super-tricky - read pointer out of data word of interface value. + return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} +} + +// asPointerTo returns a reflect.Value that is a pointer to an +// object of type t stored at p. +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + return reflect.NewAt(t, p.p) +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go new file mode 100644 index 0000000..f710ada --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -0,0 +1,544 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s += "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + case "fixed32": + p.WireType = WireFixed32 + case "fixed64": + p.WireType = WireFixed64 + case "zigzag32": + p.WireType = WireVarint + case "zigzag64": + p.WireType = WireVarint + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + +outer: + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break outer + } + } + } +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// setFieldProps initializes the field properties for submessages and maps. +func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + switch t1 := typ; t1.Kind() { + case reflect.Ptr: + if t1.Elem().Kind() == reflect.Struct { + p.stype = t1.Elem() + } + + case reflect.Slice: + if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { + p.stype = t2.Elem() + } + + case reflect.Map: + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() +) + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if tag == "" { + return + } + p.Parse(tag) + p.setFieldProps(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + var oots []interface{} + _, _, _, oots = om.XXX_OneofFuncs() + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers + protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypedNils[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { + // Generated code always calls RegisterType with nil x. + // This check is just for extra safety. + protoTypedNils[name] = x + } else { + protoTypedNils[name] = reflect.Zero(t).Interface().(Message) + } + revProtoTypes[t] = name +} + +// RegisterMapType is called from generated code and maps from the fully qualified +// proto name to the native map type of the proto map definition. +func RegisterMapType(x interface{}, name string) { + if reflect.TypeOf(x).Kind() != reflect.Map { + panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) + } + if _, ok := protoMapTypes[name]; ok { + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoMapTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +// The type is not guaranteed to implement proto.Message if the name refers to a +// map entry. +func MessageType(name string) reflect.Type { + if t, ok := protoTypedNils[name]; ok { + return reflect.TypeOf(t) + } + return protoMapTypes[name] +} + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go new file mode 100644 index 0000000..0f212b3 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_marshal.go @@ -0,0 +1,2681 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// a sizer takes a pointer to a field and the size of its tag, computes the size of +// the encoded data. +type sizer func(pointer, int) int + +// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), +// marshals the field to the end of the slice, returns the slice and error (if any). +type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) + +// marshalInfo is the information used for marshaling a message. +type marshalInfo struct { + typ reflect.Type + fields []*marshalFieldInfo + unrecognized field // offset of XXX_unrecognized + extensions field // offset of XXX_InternalExtensions + v1extensions field // offset of XXX_extensions + sizecache field // offset of XXX_sizecache + initialized int32 // 0 -- only typ is set, 1 -- fully initialized + messageset bool // uses message set wire format + hasmarshaler bool // has custom marshaler + sync.RWMutex // protect extElems map, also for initialization + extElems map[int32]*marshalElemInfo // info of extension elements +} + +// marshalFieldInfo is the information used for marshaling a field of a message. +type marshalFieldInfo struct { + field field + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isPointer bool + required bool // field is required + name string // name of the field, for error reporting + oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements +} + +// marshalElemInfo is the information used for marshaling an extension or oneof element. +type marshalElemInfo struct { + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) +} + +var ( + marshalInfoMap = map[reflect.Type]*marshalInfo{} + marshalInfoLock sync.Mutex +) + +// getMarshalInfo returns the information to marshal a given type of message. +// The info it returns may not necessarily initialized. +// t is the type of the message (NOT the pointer to it). +func getMarshalInfo(t reflect.Type) *marshalInfo { + marshalInfoLock.Lock() + u, ok := marshalInfoMap[t] + if !ok { + u = &marshalInfo{typ: t} + marshalInfoMap[t] = u + } + marshalInfoLock.Unlock() + return u +} + +// Size is the entry point from generated code, +// and should be ONLY called by generated code. +// It computes the size of encoded data of msg. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Size(msg Message) int { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return 0 + } + return u.size(ptr) +} + +// Marshal is the entry point from generated code, +// and should be ONLY called by generated code. +// It marshals msg to the end of b. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return b, ErrNil + } + return u.marshal(b, ptr, deterministic) +} + +func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { + // u := a.marshal, but atomically. + // We use an atomic here to ensure memory consistency. + u := atomicLoadMarshalInfo(&a.marshal) + if u == nil { + // Get marshal information from type of message. + t := reflect.ValueOf(msg).Type() + if t.Kind() != reflect.Ptr { + panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) + } + u = getMarshalInfo(t.Elem()) + // Store it in the cache for later users. + // a.marshal = u, but atomically. + atomicStoreMarshalInfo(&a.marshal, u) + } + return u +} + +// size is the main function to compute the size of the encoded data of a message. +// ptr is the pointer to the message. +func (u *marshalInfo) size(ptr pointer) int { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b, _ := m.Marshal() + return len(b) + } + + n := 0 + for _, f := range u.fields { + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + n += f.sizer(ptr.offset(f.field), f.tagsize) + } + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + n += u.sizeMessageSet(e) + } else { + n += u.sizeExtensions(e) + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + n += u.sizeV1Extensions(m) + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + n += len(s) + } + // cache the result for use in marshal + if u.sizecache.IsValid() { + atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) + } + return n +} + +// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), +// fall back to compute the size. +func (u *marshalInfo) cachedsize(ptr pointer) int { + if u.sizecache.IsValid() { + return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) + } + return u.size(ptr) +} + +// marshal is the main function to marshal a message. It takes a byte slice and appends +// the encoded data to the end of the slice, returns the slice and error (if any). +// ptr is the pointer to the message. +// If deterministic is true, map is marshaled in deterministic order. +func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b1, err := m.Marshal() + b = append(b, b1...) + return b, err + } + + var err, errreq error + // The old marshaler encodes extensions at beginning. + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + b, err = u.appendMessageSet(b, e, deterministic) + } else { + b, err = u.appendExtensions(b, e, deterministic) + } + if err != nil { + return b, err + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + b, err = u.appendV1Extensions(b, m, deterministic) + if err != nil { + return b, err + } + } + for _, f := range u.fields { + if f.required && errreq == nil { + if ptr.offset(f.field).getPointer().isNil() { + // Required field is not set. + // We record the error but keep going, to give a complete marshaling. + errreq = &RequiredNotSetError{f.name} + continue + } + } + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) + if err != nil { + if err1, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errreq == nil { + errreq = &RequiredNotSetError{f.name + "." + err1.field} + } + continue + } + if err == errRepeatedHasNil { + err = errors.New("proto: repeated field " + f.name + " has nil element") + } + return b, err + } + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + b = append(b, s...) + } + return b, errreq +} + +// computeMarshalInfo initializes the marshal info. +func (u *marshalInfo) computeMarshalInfo() { + u.Lock() + defer u.Unlock() + if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock + return + } + + t := u.typ + u.unrecognized = invalidField + u.extensions = invalidField + u.v1extensions = invalidField + u.sizecache = invalidField + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if reflect.PtrTo(t).Implements(marshalerType) { + u.hasmarshaler = true + atomic.StoreInt32(&u.initialized, 1) + return + } + + // get oneof implementers + var oneofImplementers []interface{} + if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + } + + n := t.NumField() + + // deal with XXX fields first + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if !strings.HasPrefix(f.Name, "XXX_") { + continue + } + switch f.Name { + case "XXX_sizecache": + u.sizecache = toField(&f) + case "XXX_unrecognized": + u.unrecognized = toField(&f) + case "XXX_InternalExtensions": + u.extensions = toField(&f) + u.messageset = f.Tag.Get("protobuf_messageset") == "1" + case "XXX_extensions": + u.v1extensions = toField(&f) + case "XXX_NoUnkeyedLiteral": + // nothing to do + default: + panic("unknown XXX field: " + f.Name) + } + n-- + } + + // normal fields + fields := make([]marshalFieldInfo, n) // batch allocation + u.fields = make([]*marshalFieldInfo, 0, n) + for i, j := 0, 0; i < t.NumField(); i++ { + f := t.Field(i) + + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + field := &fields[j] + j++ + field.name = f.Name + u.fields = append(u.fields, field) + if f.Tag.Get("protobuf_oneof") != "" { + field.computeOneofFieldInfo(&f, oneofImplementers) + continue + } + if f.Tag.Get("protobuf") == "" { + // field has no tag (not in generated message), ignore it + u.fields = u.fields[:len(u.fields)-1] + j-- + continue + } + field.computeMarshalFieldInfo(&f) + } + + // fields are marshaled in tag order on the wire. + sort.Sort(byTag(u.fields)) + + atomic.StoreInt32(&u.initialized, 1) +} + +// helper for sorting fields by tag +type byTag []*marshalFieldInfo + +func (a byTag) Len() int { return len(a) } +func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } + +// getExtElemInfo returns the information to marshal an extension element. +// The info it returns is initialized. +func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { + // get from cache first + u.RLock() + e, ok := u.extElems[desc.Field] + u.RUnlock() + if ok { + return e + } + + t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct + tags := strings.Split(desc.Tag, ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizer, marshaler := typeMarshaler(t, tags, false, false) + e = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + isptr: t.Kind() == reflect.Ptr, + } + + // update cache + u.Lock() + if u.extElems == nil { + u.extElems = make(map[int32]*marshalElemInfo) + } + u.extElems[desc.Field] = e + u.Unlock() + return e +} + +// computeMarshalFieldInfo fills up the information to marshal a field. +func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { + // parse protobuf tag of the field. + // tag has format of "bytes,49,opt,name=foo,def=hello!" + tags := strings.Split(f.Tag.Get("protobuf"), ",") + if tags[0] == "" { + return + } + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + if tags[2] == "req" { + fi.required = true + } + fi.setTag(f, tag, wt) + fi.setMarshaler(f, tags) +} + +func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { + fi.field = toField(f) + fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.isPointer = true + fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) + fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) + + ityp := f.Type // interface type + for _, o := range oneofImplementers { + t := reflect.TypeOf(o) + if !t.Implements(ityp) { + continue + } + sf := t.Elem().Field(0) // oneof implementer is a struct with a single field + tags := strings.Split(sf.Tag.Get("protobuf"), ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizer, marshaler := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value + fi.oneofElems[t.Elem()] = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + } + } +} + +type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) +} + +// wiretype returns the wire encoding of the type. +func wiretype(encoding string) uint64 { + switch encoding { + case "fixed32": + return WireFixed32 + case "fixed64": + return WireFixed64 + case "varint", "zigzag32", "zigzag64": + return WireVarint + case "bytes": + return WireBytes + case "group": + return WireStartGroup + } + panic("unknown wire type " + encoding) +} + +// setTag fills up the tag (in wire format) and its size in the info of a field. +func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { + fi.field = toField(f) + fi.wiretag = uint64(tag)<<3 | wt + fi.tagsize = SizeVarint(uint64(tag) << 3) +} + +// setMarshaler fills up the sizer and marshaler in the info of a field. +func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { + switch f.Type.Kind() { + case reflect.Map: + // map field + fi.isPointer = true + fi.sizer, fi.marshaler = makeMapMarshaler(f) + return + case reflect.Ptr, reflect.Slice: + fi.isPointer = true + } + fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) +} + +// typeMarshaler returns the sizer and marshaler of a given field. +// t is the type of the field. +// tags is the generated "protobuf" tag of the field. +// If nozero is true, zero value is not marshaled to the wire. +// If oneof is true, it is a oneof field. +func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { + encoding := tags[0] + + pointer := false + slice := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + packed := false + proto3 := false + for i := 2; i < len(tags); i++ { + if tags[i] == "packed" { + packed = true + } + if tags[i] == "proto3" { + proto3 = true + } + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return sizeBoolPtr, appendBoolPtr + } + if slice { + if packed { + return sizeBoolPackedSlice, appendBoolPackedSlice + } + return sizeBoolSlice, appendBoolSlice + } + if nozero { + return sizeBoolValueNoZero, appendBoolValueNoZero + } + return sizeBoolValue, appendBoolValue + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixed32Ptr, appendFixed32Ptr + } + if slice { + if packed { + return sizeFixed32PackedSlice, appendFixed32PackedSlice + } + return sizeFixed32Slice, appendFixed32Slice + } + if nozero { + return sizeFixed32ValueNoZero, appendFixed32ValueNoZero + } + return sizeFixed32Value, appendFixed32Value + case "varint": + if pointer { + return sizeVarint32Ptr, appendVarint32Ptr + } + if slice { + if packed { + return sizeVarint32PackedSlice, appendVarint32PackedSlice + } + return sizeVarint32Slice, appendVarint32Slice + } + if nozero { + return sizeVarint32ValueNoZero, appendVarint32ValueNoZero + } + return sizeVarint32Value, appendVarint32Value + } + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixedS32Ptr, appendFixedS32Ptr + } + if slice { + if packed { + return sizeFixedS32PackedSlice, appendFixedS32PackedSlice + } + return sizeFixedS32Slice, appendFixedS32Slice + } + if nozero { + return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero + } + return sizeFixedS32Value, appendFixedS32Value + case "varint": + if pointer { + return sizeVarintS32Ptr, appendVarintS32Ptr + } + if slice { + if packed { + return sizeVarintS32PackedSlice, appendVarintS32PackedSlice + } + return sizeVarintS32Slice, appendVarintS32Slice + } + if nozero { + return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero + } + return sizeVarintS32Value, appendVarintS32Value + case "zigzag32": + if pointer { + return sizeZigzag32Ptr, appendZigzag32Ptr + } + if slice { + if packed { + return sizeZigzag32PackedSlice, appendZigzag32PackedSlice + } + return sizeZigzag32Slice, appendZigzag32Slice + } + if nozero { + return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero + } + return sizeZigzag32Value, appendZigzag32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixed64Ptr, appendFixed64Ptr + } + if slice { + if packed { + return sizeFixed64PackedSlice, appendFixed64PackedSlice + } + return sizeFixed64Slice, appendFixed64Slice + } + if nozero { + return sizeFixed64ValueNoZero, appendFixed64ValueNoZero + } + return sizeFixed64Value, appendFixed64Value + case "varint": + if pointer { + return sizeVarint64Ptr, appendVarint64Ptr + } + if slice { + if packed { + return sizeVarint64PackedSlice, appendVarint64PackedSlice + } + return sizeVarint64Slice, appendVarint64Slice + } + if nozero { + return sizeVarint64ValueNoZero, appendVarint64ValueNoZero + } + return sizeVarint64Value, appendVarint64Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixedS64Ptr, appendFixedS64Ptr + } + if slice { + if packed { + return sizeFixedS64PackedSlice, appendFixedS64PackedSlice + } + return sizeFixedS64Slice, appendFixedS64Slice + } + if nozero { + return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero + } + return sizeFixedS64Value, appendFixedS64Value + case "varint": + if pointer { + return sizeVarintS64Ptr, appendVarintS64Ptr + } + if slice { + if packed { + return sizeVarintS64PackedSlice, appendVarintS64PackedSlice + } + return sizeVarintS64Slice, appendVarintS64Slice + } + if nozero { + return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero + } + return sizeVarintS64Value, appendVarintS64Value + case "zigzag64": + if pointer { + return sizeZigzag64Ptr, appendZigzag64Ptr + } + if slice { + if packed { + return sizeZigzag64PackedSlice, appendZigzag64PackedSlice + } + return sizeZigzag64Slice, appendZigzag64Slice + } + if nozero { + return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero + } + return sizeZigzag64Value, appendZigzag64Value + } + case reflect.Float32: + if pointer { + return sizeFloat32Ptr, appendFloat32Ptr + } + if slice { + if packed { + return sizeFloat32PackedSlice, appendFloat32PackedSlice + } + return sizeFloat32Slice, appendFloat32Slice + } + if nozero { + return sizeFloat32ValueNoZero, appendFloat32ValueNoZero + } + return sizeFloat32Value, appendFloat32Value + case reflect.Float64: + if pointer { + return sizeFloat64Ptr, appendFloat64Ptr + } + if slice { + if packed { + return sizeFloat64PackedSlice, appendFloat64PackedSlice + } + return sizeFloat64Slice, appendFloat64Slice + } + if nozero { + return sizeFloat64ValueNoZero, appendFloat64ValueNoZero + } + return sizeFloat64Value, appendFloat64Value + case reflect.String: + if pointer { + return sizeStringPtr, appendStringPtr + } + if slice { + return sizeStringSlice, appendStringSlice + } + if nozero { + return sizeStringValueNoZero, appendStringValueNoZero + } + return sizeStringValue, appendStringValue + case reflect.Slice: + if slice { + return sizeBytesSlice, appendBytesSlice + } + if oneof { + // Oneof bytes field may also have "proto3" tag. + // We want to marshal it as a oneof field. Do this + // check before the proto3 check. + return sizeBytesOneof, appendBytesOneof + } + if proto3 { + return sizeBytes3, appendBytes3 + } + return sizeBytes, appendBytes + case reflect.Struct: + switch encoding { + case "group": + if slice { + return makeGroupSliceMarshaler(getMarshalInfo(t)) + } + return makeGroupMarshaler(getMarshalInfo(t)) + case "bytes": + if slice { + return makeMessageSliceMarshaler(getMarshalInfo(t)) + } + return makeMessageMarshaler(getMarshalInfo(t)) + } + } + panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) +} + +// Below are functions to size/marshal a specific type of a field. +// They are stored in the field's info, and called by function pointers. +// They have type sizer or marshaler. + +func sizeFixed32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixedS32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFloat32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + return (4 + tagsize) * len(s) +} +func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixed64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFixedS64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFloat64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + return (8 + tagsize) * len(s) +} +func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeVarint32Value(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarint32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarint64Value(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + return SizeVarint(v) + tagsize +} +func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return SizeVarint(v) + tagsize +} +func sizeVarint64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return SizeVarint(*p) + tagsize +} +func sizeVarint64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(v) + tagsize + } + return n +} +func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize + } + return n +} +func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize + } + return n +} +func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeBoolValue(_ pointer, tagsize int) int { + return 1 + tagsize +} +func sizeBoolValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toBool() + if !v { + return 0 + } + return 1 + tagsize +} +func sizeBoolPtr(ptr pointer, tagsize int) int { + p := *ptr.toBoolPtr() + if p == nil { + return 0 + } + return 1 + tagsize +} +func sizeBoolSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + return (1 + tagsize) * len(s) +} +func sizeBoolPackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return 0 + } + return len(s) + SizeVarint(uint64(len(s))) + tagsize +} +func sizeStringValue(ptr pointer, tagsize int) int { + v := *ptr.toString() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toString() + if v == "" { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringPtr(ptr pointer, tagsize int) int { + p := *ptr.toStringPtr() + if p == nil { + return 0 + } + v := *p + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringSlice(ptr pointer, tagsize int) int { + s := *ptr.toStringSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} +func sizeBytes(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if v == nil { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytes3(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if len(v) == 0 { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesOneof(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesSlice(ptr pointer, tagsize int) int { + s := *ptr.toBytesSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} + +// appendFixed32 appends an encoded fixed32 to b. +func appendFixed32(b []byte, v uint32) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24)) + return b +} + +// appendFixed64 appends an encoded fixed64 to b. +func appendFixed64(b []byte, v uint64) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56)) + return b +} + +// appendVarint appends an encoded varint to b. +func appendVarint(b []byte, v uint64) []byte { + // TODO: make 1-byte (maybe 2-byte) case inline-able, once we + // have non-leaf inliner. + switch { + case v < 1<<7: + b = append(b, byte(v)) + case v < 1<<14: + b = append(b, + byte(v&0x7f|0x80), + byte(v>>7)) + case v < 1<<21: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte(v>>14)) + case v < 1<<28: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte(v>>21)) + case v < 1<<35: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte(v>>28)) + case v < 1<<42: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte(v>>35)) + case v < 1<<49: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte(v>>42)) + case v < 1<<56: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte(v>>49)) + case v < 1<<63: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte(v>>56)) + default: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte((v>>56)&0x7f|0x80), + 1) + } + return b +} + +func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, *p) + return b, nil +} +func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(*p)) + return b, nil +} +func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(*p)) + return b, nil +} +func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, *p) + return b, nil +} +func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(*p)) + return b, nil +} +func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(*p)) + return b, nil +} +func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, *p) + return b, nil +} +func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + } + return b, nil +} +func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, v) + } + return b, nil +} +func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + if !v { + return b, nil + } + b = appendVarint(b, wiretag) + b = append(b, 1) + return b, nil +} + +func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toBoolPtr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + if *p { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(len(s))) + for _, v := range s { + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + if v == "" { + return b, nil + } + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toStringSlice() + for _, v := range s { + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} +func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if v == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if len(v) == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBytesSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} + +// makeGroupMarshaler returns the sizer and marshaler for a group. +// u is the marshal info of the underlying message. +func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + return u.size(p) + 2*tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + var err error + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, p, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + return b, err + } +} + +// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. +// u is the marshal info of the underlying message. +func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + n += u.size(v) + 2*tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err, errreq error + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, v, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + if err != nil { + if _, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errreq == nil { + errreq = err + } + continue + } + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, errreq + } +} + +// makeMessageMarshaler returns the sizer and marshaler for a message field. +// u is the marshal info of the message. +func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.size(p) + return siz + SizeVarint(uint64(siz)) + tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(p) + b = appendVarint(b, uint64(siz)) + return u.marshal(b, p, deterministic) + } +} + +// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. +// u is the marshal info of the message. +func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + siz := u.size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err, errreq error + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(v) + b = appendVarint(b, uint64(siz)) + b, err = u.marshal(b, v, deterministic) + + if err != nil { + if _, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errreq == nil { + errreq = err + } + continue + } + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, errreq + } +} + +// makeMapMarshaler returns the sizer and marshaler for a map field. +// f is the pointer to the reflect data structure of the field. +func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { + // figure out key and value type + t := f.Type + keyType := t.Key() + valType := t.Elem() + keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") + valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") + keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map + valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map + keyWireTag := 1<<3 | wiretype(keyTags[0]) + valWireTag := 2<<3 | wiretype(valTags[0]) + + // We create an interface to get the addresses of the map key and value. + // If value is pointer-typed, the interface is a direct interface, the + // idata itself is the value. Otherwise, the idata is the pointer to the + // value. + // Key cannot be pointer-typed. + valIsPtr := valType.Kind() == reflect.Ptr + return func(ptr pointer, tagsize int) int { + m := ptr.asPointerTo(t).Elem() // the map + n := 0 + for _, k := range m.MapKeys() { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { + m := ptr.asPointerTo(t).Elem() // the map + var err error + keys := m.MapKeys() + if len(keys) > 1 && deterministic { + sort.Sort(mapKeys(keys)) + } + for _, k := range keys { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + b = appendVarint(b, tag) + siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + b = appendVarint(b, uint64(siz)) + b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) + if err != nil { + return b, err + } + b, err = valMarshaler(b, vaddr, valWireTag, deterministic) + if err != nil && err != ErrNil { // allow nil value in map + return b, err + } + } + return b, nil + } +} + +// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. +// fi is the marshal info of the field. +// f is the pointer to the reflect data structure of the field. +func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { + // Oneof field is an interface. We need to get the actual data type on the fly. + t := f.Type + return func(ptr pointer, _ int) int { + p := ptr.getInterfacePointer() + if p.isNil() { + return 0 + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + e := fi.oneofElems[telem] + return e.sizer(p, e.tagsize) + }, + func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { + p := ptr.getInterfacePointer() + if p.isNil() { + return b, nil + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { + return b, errOneofHasNil + } + e := fi.oneofElems[telem] + return e.marshaler(b, p, e.wiretag, deterministic) + } +} + +// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. +func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + mu.Unlock() + return n +} + +// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. +func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if err != nil { + return b, err + } + } + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + // Not sure this is required, but the old code does it. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if err != nil { + return b, err + } + } + return b, nil +} + +// message set format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } + +// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field +// in message set format (above). +func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for id, e := range m { + n += 2 // start group, end group. tag = 1 (size=1) + n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + siz := len(msgWithLen) + n += siz + 1 // message, tag = 3 (size=1) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, 1) // message, tag = 3 (size=1) + } + mu.Unlock() + return n +} + +// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) +// to the end of byte slice b. +func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for id, e := range m { + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + if err != nil { + return b, err + } + b = append(b, 1<<3|WireEndGroup) + } + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, id := range keys { + e := m[int32(id)] + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + b = append(b, 1<<3|WireEndGroup) + if err != nil { + return b, err + } + } + return b, nil +} + +// sizeV1Extensions computes the size of encoded data for a V1-API extension field. +func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { + if m == nil { + return 0 + } + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + return n +} + +// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. +func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { + if m == nil { + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + var err error + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if err != nil { + return b, err + } + } + return b, nil +} + +// newMarshaler is the interface representing objects that can marshal themselves. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newMarshaler interface { + XXX_Size() int + XXX_Marshal(b []byte, deterministic bool) ([]byte, error) +} + +// Size returns the encoded size of a protocol buffer message. +// This is the main entry point. +func Size(pb Message) int { + if m, ok := pb.(newMarshaler); ok { + return m.XXX_Size() + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, _ := m.Marshal() + return len(b) + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return 0 + } + var info InternalMessageInfo + return info.Size(pb) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, returning the data. +// This is the main entry point. +func Marshal(pb Message) ([]byte, error) { + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + b := make([]byte, 0, siz) + return m.XXX_Marshal(b, false) + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + return m.Marshal() + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return nil, ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + b := make([]byte, 0, siz) + return info.Marshal(b, pb, false) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, writing the result to the +// Buffer. +// This is an alternative entry point. It is not necessary to use +// a Buffer for most applications. +func (p *Buffer) Marshal(pb Message) error { + var err error + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + p.grow(siz) // make sure buf has enough capacity + p.buf, err = m.XXX_Marshal(p.buf, p.deterministic) + return err + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, err := m.Marshal() + p.buf = append(p.buf, b...) + return err + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + p.grow(siz) // make sure buf has enough capacity + p.buf, err = info.Marshal(p.buf, pb, p.deterministic) + return err +} + +// grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After grow(n), at least n bytes can be written to the +// buffer without another allocation. +func (p *Buffer) grow(n int) { + need := len(p.buf) + n + if need <= cap(p.buf) { + return + } + newCap := len(p.buf) * 2 + if newCap < need { + newCap = need + } + p.buf = append(make([]byte, 0, newCap), p.buf...) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_merge.go b/vendor/github.com/golang/protobuf/proto/table_merge.go new file mode 100644 index 0000000..5525def --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_merge.go @@ -0,0 +1,654 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +// Merge merges the src message into dst. +// This assumes that dst and src of the same type and are non-nil. +func (a *InternalMessageInfo) Merge(dst, src Message) { + mi := atomicLoadMergeInfo(&a.merge) + if mi == nil { + mi = getMergeInfo(reflect.TypeOf(dst).Elem()) + atomicStoreMergeInfo(&a.merge, mi) + } + mi.merge(toPointer(&dst), toPointer(&src)) +} + +type mergeInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []mergeFieldInfo + unrecognized field // Offset of XXX_unrecognized +} + +type mergeFieldInfo struct { + field field // Offset of field, guaranteed to be valid + + // isPointer reports whether the value in the field is a pointer. + // This is true for the following situations: + // * Pointer to struct + // * Pointer to basic type (proto2 only) + // * Slice (first value in slice header is a pointer) + // * String (first value in string header is a pointer) + isPointer bool + + // basicWidth reports the width of the field assuming that it is directly + // embedded in the struct (as is the case for basic types in proto3). + // The possible values are: + // 0: invalid + // 1: bool + // 4: int32, uint32, float32 + // 8: int64, uint64, float64 + basicWidth int + + // Where dst and src are pointers to the types being merged. + merge func(dst, src pointer) +} + +var ( + mergeInfoMap = map[reflect.Type]*mergeInfo{} + mergeInfoLock sync.Mutex +) + +func getMergeInfo(t reflect.Type) *mergeInfo { + mergeInfoLock.Lock() + defer mergeInfoLock.Unlock() + mi := mergeInfoMap[t] + if mi == nil { + mi = &mergeInfo{typ: t} + mergeInfoMap[t] = mi + } + return mi +} + +// merge merges src into dst assuming they are both of type *mi.typ. +func (mi *mergeInfo) merge(dst, src pointer) { + if dst.isNil() { + panic("proto: nil destination") + } + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&mi.initialized) == 0 { + mi.computeMergeInfo() + } + + for _, fi := range mi.fields { + sfp := src.offset(fi.field) + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string + continue + } + if fi.basicWidth > 0 { + switch { + case fi.basicWidth == 1 && !*sfp.toBool(): + continue + case fi.basicWidth == 4 && *sfp.toUint32() == 0: + continue + case fi.basicWidth == 8 && *sfp.toUint64() == 0: + continue + } + } + } + + dfp := dst.offset(fi.field) + fi.merge(dfp, sfp) + } + + // TODO: Make this faster? + out := dst.asPointerTo(mi.typ).Elem() + in := src.asPointerTo(mi.typ).Elem() + if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + if mi.unrecognized.IsValid() { + if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { + *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) + } + } +} + +func (mi *mergeInfo) computeMergeInfo() { + mi.lock.Lock() + defer mi.lock.Unlock() + if mi.initialized != 0 { + return + } + t := mi.typ + n := t.NumField() + + props := GetProperties(t) + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + mfi := mergeFieldInfo{field: toField(&f)} + tf := f.Type + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + switch tf.Kind() { + case reflect.Ptr, reflect.Slice, reflect.String: + // As a special case, we assume slices and strings are pointers + // since we know that the first field in the SliceSlice or + // StringHeader is a data pointer. + mfi.isPointer = true + case reflect.Bool: + mfi.basicWidth = 1 + case reflect.Int32, reflect.Uint32, reflect.Float32: + mfi.basicWidth = 4 + case reflect.Int64, reflect.Uint64, reflect.Float64: + mfi.basicWidth = 8 + } + } + + // Unwrap tf to get at its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + tf.Name()) + } + + switch tf.Kind() { + case reflect.Int32: + switch { + case isSlice: // E.g., []int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Slice is not defined (see pointer_reflect.go). + /* + sfsp := src.toInt32Slice() + if *sfsp != nil { + dfsp := dst.toInt32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + */ + sfs := src.getInt32Slice() + if sfs != nil { + dfs := dst.getInt32Slice() + dfs = append(dfs, sfs...) + if dfs == nil { + dfs = []int32{} + } + dst.setInt32Slice(dfs) + } + } + case isPointer: // E.g., *int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). + /* + sfpp := src.toInt32Ptr() + if *sfpp != nil { + dfpp := dst.toInt32Ptr() + if *dfpp == nil { + *dfpp = Int32(**sfpp) + } else { + **dfpp = **sfpp + } + } + */ + sfp := src.getInt32Ptr() + if sfp != nil { + dfp := dst.getInt32Ptr() + if dfp == nil { + dst.setInt32Ptr(*sfp) + } else { + *dfp = *sfp + } + } + } + default: // E.g., int32 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt32(); v != 0 { + *dst.toInt32() = v + } + } + } + case reflect.Int64: + switch { + case isSlice: // E.g., []int64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toInt64Slice() + if *sfsp != nil { + dfsp := dst.toInt64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + } + case isPointer: // E.g., *int64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toInt64Ptr() + if *sfpp != nil { + dfpp := dst.toInt64Ptr() + if *dfpp == nil { + *dfpp = Int64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., int64 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt64(); v != 0 { + *dst.toInt64() = v + } + } + } + case reflect.Uint32: + switch { + case isSlice: // E.g., []uint32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint32Slice() + if *sfsp != nil { + dfsp := dst.toUint32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint32{} + } + } + } + case isPointer: // E.g., *uint32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint32Ptr() + if *sfpp != nil { + dfpp := dst.toUint32Ptr() + if *dfpp == nil { + *dfpp = Uint32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint32 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint32(); v != 0 { + *dst.toUint32() = v + } + } + } + case reflect.Uint64: + switch { + case isSlice: // E.g., []uint64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint64Slice() + if *sfsp != nil { + dfsp := dst.toUint64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint64{} + } + } + } + case isPointer: // E.g., *uint64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint64Ptr() + if *sfpp != nil { + dfpp := dst.toUint64Ptr() + if *dfpp == nil { + *dfpp = Uint64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint64 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint64(); v != 0 { + *dst.toUint64() = v + } + } + } + case reflect.Float32: + switch { + case isSlice: // E.g., []float32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat32Slice() + if *sfsp != nil { + dfsp := dst.toFloat32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float32{} + } + } + } + case isPointer: // E.g., *float32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat32Ptr() + if *sfpp != nil { + dfpp := dst.toFloat32Ptr() + if *dfpp == nil { + *dfpp = Float32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float32 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat32(); v != 0 { + *dst.toFloat32() = v + } + } + } + case reflect.Float64: + switch { + case isSlice: // E.g., []float64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat64Slice() + if *sfsp != nil { + dfsp := dst.toFloat64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float64{} + } + } + } + case isPointer: // E.g., *float64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat64Ptr() + if *sfpp != nil { + dfpp := dst.toFloat64Ptr() + if *dfpp == nil { + *dfpp = Float64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float64 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat64(); v != 0 { + *dst.toFloat64() = v + } + } + } + case reflect.Bool: + switch { + case isSlice: // E.g., []bool + mfi.merge = func(dst, src pointer) { + sfsp := src.toBoolSlice() + if *sfsp != nil { + dfsp := dst.toBoolSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []bool{} + } + } + } + case isPointer: // E.g., *bool + mfi.merge = func(dst, src pointer) { + sfpp := src.toBoolPtr() + if *sfpp != nil { + dfpp := dst.toBoolPtr() + if *dfpp == nil { + *dfpp = Bool(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., bool + mfi.merge = func(dst, src pointer) { + if v := *src.toBool(); v { + *dst.toBool() = v + } + } + } + case reflect.String: + switch { + case isSlice: // E.g., []string + mfi.merge = func(dst, src pointer) { + sfsp := src.toStringSlice() + if *sfsp != nil { + dfsp := dst.toStringSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []string{} + } + } + } + case isPointer: // E.g., *string + mfi.merge = func(dst, src pointer) { + sfpp := src.toStringPtr() + if *sfpp != nil { + dfpp := dst.toStringPtr() + if *dfpp == nil { + *dfpp = String(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., string + mfi.merge = func(dst, src pointer) { + if v := *src.toString(); v != "" { + *dst.toString() = v + } + } + } + case reflect.Slice: + isProto3 := props.Prop[i].proto3 + switch { + case isPointer: + panic("bad pointer in byte slice case in " + tf.Name()) + case tf.Elem().Kind() != reflect.Uint8: + panic("bad element kind in byte slice case in " + tf.Name()) + case isSlice: // E.g., [][]byte + mfi.merge = func(dst, src pointer) { + sbsp := src.toBytesSlice() + if *sbsp != nil { + dbsp := dst.toBytesSlice() + for _, sb := range *sbsp { + if sb == nil { + *dbsp = append(*dbsp, nil) + } else { + *dbsp = append(*dbsp, append([]byte{}, sb...)) + } + } + if *dbsp == nil { + *dbsp = [][]byte{} + } + } + } + default: // E.g., []byte + mfi.merge = func(dst, src pointer) { + sbp := src.toBytes() + if *sbp != nil { + dbp := dst.toBytes() + if !isProto3 || len(*sbp) > 0 { + *dbp = append([]byte{}, *sbp...) + } + } + } + } + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("message field %s without pointer", tf)) + case isSlice: // E.g., []*pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sps := src.getPointerSlice() + if sps != nil { + dps := dst.getPointerSlice() + for _, sp := range sps { + var dp pointer + if !sp.isNil() { + dp = valToPointer(reflect.New(tf)) + mi.merge(dp, sp) + } + dps = append(dps, dp) + } + if dps == nil { + dps = []pointer{} + } + dst.setPointerSlice(dps) + } + } + default: // E.g., *pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sp := src.getPointer() + if !sp.isNil() { + dp := dst.getPointer() + if dp.isNil() { + dp = valToPointer(reflect.New(tf)) + dst.setPointer(dp) + } + mi.merge(dp, sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic("bad pointer or slice in map case in " + tf.Name()) + default: // E.g., map[K]V + mfi.merge = func(dst, src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + dm := dst.asPointerTo(tf).Elem() + if dm.IsNil() { + dm.Set(reflect.MakeMap(tf)) + } + + switch tf.Elem().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(Clone(val.Interface().(Message))) + dm.SetMapIndex(key, val) + } + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + dm.SetMapIndex(key, val) + } + default: // Basic type (e.g., string) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + dm.SetMapIndex(key, val) + } + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic("bad pointer or slice in interface case in " + tf.Name()) + default: // E.g., interface{} + // TODO: Make this faster? + mfi.merge = func(dst, src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + du := dst.asPointerTo(tf).Elem() + typ := su.Elem().Type() + if du.IsNil() || du.Elem().Type() != typ { + du.Set(reflect.New(typ.Elem())) // Initialize interface if empty + } + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + dv := du.Elem().Elem().Field(0) + if dv.Kind() == reflect.Ptr && dv.IsNil() { + dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + Merge(dv.Interface().(Message), sv.Interface().(Message)) + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) + default: // Basic type (e.g., string) + dv.Set(sv) + } + } + } + } + default: + panic(fmt.Sprintf("merger not found for type:%s", tf)) + } + mi.fields = append(mi.fields, mfi) + } + + mi.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + mi.unrecognized = toField(&f) + } + + atomic.StoreInt32(&mi.initialized, 1) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go new file mode 100644 index 0000000..55f0340 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go @@ -0,0 +1,1967 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "errors" + "fmt" + "io" + "math" + "reflect" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// Unmarshal is the entry point from the generated .pb.go files. +// This function is not intended to be used by non-generated code. +// This function is not subject to any compatibility guarantee. +// msg contains a pointer to a protocol buffer struct. +// b is the data to be unmarshaled into the protocol buffer. +// a is a pointer to a place to store cached unmarshal information. +func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { + // Load the unmarshal information for this message type. + // The atomic load ensures memory consistency. + u := atomicLoadUnmarshalInfo(&a.unmarshal) + if u == nil { + // Slow path: find unmarshal info for msg, update a with it. + u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) + atomicStoreUnmarshalInfo(&a.unmarshal, u) + } + // Then do the unmarshaling. + err := u.unmarshal(toPointer(&msg), b) + return err +} + +type unmarshalInfo struct { + typ reflect.Type // type of the protobuf struct + + // 0 = only typ field is initialized + // 1 = completely initialized + initialized int32 + lock sync.Mutex // prevents double initialization + dense []unmarshalFieldInfo // fields indexed by tag # + sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # + reqFields []string // names of required fields + reqMask uint64 // 1< 0 { + // Read tag and wire type. + // Special case 1 and 2 byte varints. + var x uint64 + if b[0] < 128 { + x = uint64(b[0]) + b = b[1:] + } else if len(b) >= 2 && b[1] < 128 { + x = uint64(b[0]&0x7f) + uint64(b[1])<<7 + b = b[2:] + } else { + var n int + x, n = decodeVarint(b) + if n == 0 { + return io.ErrUnexpectedEOF + } + b = b[n:] + } + tag := x >> 3 + wire := int(x) & 7 + + // Dispatch on the tag to one of the unmarshal* functions below. + var f unmarshalFieldInfo + if tag < uint64(len(u.dense)) { + f = u.dense[tag] + } else { + f = u.sparse[tag] + } + if fn := f.unmarshal; fn != nil { + var err error + b, err = fn(b, m.offset(f.field), wire) + if err == nil { + reqMask |= f.reqMask + continue + } + if r, ok := err.(*RequiredNotSetError); ok { + // Remember this error, but keep parsing. We need to produce + // a full parse even if a required field is missing. + rnse = r + reqMask |= f.reqMask + continue + } + if err != errInternalBadWireType { + return err + } + // Fragments with bad wire type are treated as unknown fields. + } + + // Unknown tag. + if !u.unrecognized.IsValid() { + // Don't keep unrecognized data; just skip it. + var err error + b, err = skipField(b, wire) + if err != nil { + return err + } + continue + } + // Keep unrecognized data around. + // maybe in extensions, maybe in the unrecognized field. + z := m.offset(u.unrecognized).toBytes() + var emap map[int32]Extension + var e Extension + for _, r := range u.extensionRanges { + if uint64(r.Start) <= tag && tag <= uint64(r.End) { + if u.extensions.IsValid() { + mp := m.offset(u.extensions).toExtensions() + emap = mp.extensionsWrite() + e = emap[int32(tag)] + z = &e.enc + break + } + if u.oldExtensions.IsValid() { + p := m.offset(u.oldExtensions).toOldExtensions() + emap = *p + if emap == nil { + emap = map[int32]Extension{} + *p = emap + } + e = emap[int32(tag)] + z = &e.enc + break + } + panic("no extensions field available") + } + } + + // Use wire type to skip data. + var err error + b0 := b + b, err = skipField(b, wire) + if err != nil { + return err + } + *z = encodeVarint(*z, tag<<3|uint64(wire)) + *z = append(*z, b0[:len(b0)-len(b)]...) + + if emap != nil { + emap[int32(tag)] = e + } + } + if rnse != nil { + // A required field of a submessage/group is missing. Return that error. + return rnse + } + if reqMask != u.reqMask { + // A required field of this message is missing. + for _, n := range u.reqFields { + if reqMask&1 == 0 { + return &RequiredNotSetError{n} + } + reqMask >>= 1 + } + } + return nil +} + +// computeUnmarshalInfo fills in u with information for use +// in unmarshaling protocol buffers of type u.typ. +func (u *unmarshalInfo) computeUnmarshalInfo() { + u.lock.Lock() + defer u.lock.Unlock() + if u.initialized != 0 { + return + } + t := u.typ + n := t.NumField() + + // Set up the "not found" value for the unrecognized byte buffer. + // This is the default for proto3. + u.unrecognized = invalidField + u.extensions = invalidField + u.oldExtensions = invalidField + + // List of the generated type and offset for each oneof field. + type oneofField struct { + ityp reflect.Type // interface type of oneof field + field field // offset in containing message + } + var oneofFields []oneofField + + for i := 0; i < n; i++ { + f := t.Field(i) + if f.Name == "XXX_unrecognized" { + // The byte slice used to hold unrecognized input is special. + if f.Type != reflect.TypeOf(([]byte)(nil)) { + panic("bad type for XXX_unrecognized field: " + f.Type.Name()) + } + u.unrecognized = toField(&f) + continue + } + if f.Name == "XXX_InternalExtensions" { + // Ditto here. + if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { + panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) + } + u.extensions = toField(&f) + if f.Tag.Get("protobuf_messageset") == "1" { + u.isMessageSet = true + } + continue + } + if f.Name == "XXX_extensions" { + // An older form of the extensions field. + if f.Type != reflect.TypeOf((map[int32]Extension)(nil)) { + panic("bad type for XXX_extensions field: " + f.Type.Name()) + } + u.oldExtensions = toField(&f) + continue + } + if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { + continue + } + + oneof := f.Tag.Get("protobuf_oneof") + if oneof != "" { + oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) + // The rest of oneof processing happens below. + continue + } + + tags := f.Tag.Get("protobuf") + tagArray := strings.Split(tags, ",") + if len(tagArray) < 2 { + panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) + } + tag, err := strconv.Atoi(tagArray[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tagArray[1]) + } + + name := "" + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + } + + // Extract unmarshaling function from the field (its type and tags). + unmarshal := fieldUnmarshaler(&f) + + // Required field? + var reqMask uint64 + if tagArray[2] == "req" { + bit := len(u.reqFields) + u.reqFields = append(u.reqFields, name) + reqMask = uint64(1) << uint(bit) + // TODO: if we have more than 64 required fields, we end up + // not verifying that all required fields are present. + // Fix this, perhaps using a count of required fields? + } + + // Store the info in the correct slot in the message. + u.setTag(tag, toField(&f), unmarshal, reqMask) + } + + // Find any types associated with oneof fields. + // TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it? + fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs") + if fn.IsValid() { + res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{} + for i := res.Len() - 1; i >= 0; i-- { + v := res.Index(i) // interface{} + tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X + typ := tptr.Elem() // Msg_X + + f := typ.Field(0) // oneof implementers have one field + baseUnmarshal := fieldUnmarshaler(&f) + tagstr := strings.Split(f.Tag.Get("protobuf"), ",")[1] + tag, err := strconv.Atoi(tagstr) + if err != nil { + panic("protobuf tag field not an integer: " + tagstr) + } + + // Find the oneof field that this struct implements. + // Might take O(n^2) to process all of the oneofs, but who cares. + for _, of := range oneofFields { + if tptr.Implements(of.ityp) { + // We have found the corresponding interface for this struct. + // That lets us know where this struct should be stored + // when we encounter it during unmarshaling. + unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) + u.setTag(tag, of.field, unmarshal, 0) + } + } + } + } + + // Get extension ranges, if any. + fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") + if fn.IsValid() { + if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { + panic("a message with extensions, but no extensions field in " + t.Name()) + } + u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) + } + + // Explicitly disallow tag 0. This will ensure we flag an error + // when decoding a buffer of all zeros. Without this code, we + // would decode and skip an all-zero buffer of even length. + // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. + u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { + return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) + }, 0) + + // Set mask for required field check. + u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? + for len(u.dense) <= tag { + u.dense = append(u.dense, unmarshalFieldInfo{}) + } + u.dense[tag] = i + return + } + if u.sparse == nil { + u.sparse = map[uint64]unmarshalFieldInfo{} + } + u.sparse[uint64(tag)] = i +} + +// fieldUnmarshaler returns an unmarshaler for the given field. +func fieldUnmarshaler(f *reflect.StructField) unmarshaler { + if f.Type.Kind() == reflect.Map { + return makeUnmarshalMap(f) + } + return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) +} + +// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. +func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { + tagArray := strings.Split(tags, ",") + encoding := tagArray[0] + name := "unknown" + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + } + + // Figure out packaging (pointer, slice, or both) + slice := false + pointer := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + // We'll never have both pointer and slice for basic types. + if pointer && slice && t.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + t.Name()) + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return unmarshalBoolPtr + } + if slice { + return unmarshalBoolSlice + } + return unmarshalBoolValue + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixedS32Ptr + } + if slice { + return unmarshalFixedS32Slice + } + return unmarshalFixedS32Value + case "varint": + // this could be int32 or enum + if pointer { + return unmarshalInt32Ptr + } + if slice { + return unmarshalInt32Slice + } + return unmarshalInt32Value + case "zigzag32": + if pointer { + return unmarshalSint32Ptr + } + if slice { + return unmarshalSint32Slice + } + return unmarshalSint32Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixedS64Ptr + } + if slice { + return unmarshalFixedS64Slice + } + return unmarshalFixedS64Value + case "varint": + if pointer { + return unmarshalInt64Ptr + } + if slice { + return unmarshalInt64Slice + } + return unmarshalInt64Value + case "zigzag64": + if pointer { + return unmarshalSint64Ptr + } + if slice { + return unmarshalSint64Slice + } + return unmarshalSint64Value + } + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixed32Ptr + } + if slice { + return unmarshalFixed32Slice + } + return unmarshalFixed32Value + case "varint": + if pointer { + return unmarshalUint32Ptr + } + if slice { + return unmarshalUint32Slice + } + return unmarshalUint32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixed64Ptr + } + if slice { + return unmarshalFixed64Slice + } + return unmarshalFixed64Value + case "varint": + if pointer { + return unmarshalUint64Ptr + } + if slice { + return unmarshalUint64Slice + } + return unmarshalUint64Value + } + case reflect.Float32: + if pointer { + return unmarshalFloat32Ptr + } + if slice { + return unmarshalFloat32Slice + } + return unmarshalFloat32Value + case reflect.Float64: + if pointer { + return unmarshalFloat64Ptr + } + if slice { + return unmarshalFloat64Slice + } + return unmarshalFloat64Value + case reflect.Map: + panic("map type in typeUnmarshaler in " + t.Name()) + case reflect.Slice: + if pointer { + panic("bad pointer in slice case in " + t.Name()) + } + if slice { + return unmarshalBytesSlice + } + return unmarshalBytesValue + case reflect.String: + if pointer { + return unmarshalStringPtr + } + if slice { + return unmarshalStringSlice + } + return unmarshalStringValue + case reflect.Struct: + // message or group field + if !pointer { + panic(fmt.Sprintf("message/group field %s:%s without pointer", t, encoding)) + } + switch encoding { + case "bytes": + if slice { + return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) + case "group": + if slice { + return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) + } + } + panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) +} + +// Below are all the unmarshalers for individual fields of various types. + +func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64() = v + return b, nil +} + +func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64() = v + return b, nil +} + +func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64() = v + return b, nil +} + +func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64Ptr() = &v + return b, nil +} + +func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + *f.toInt32() = v + return b, nil +} + +func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + *f.toInt32() = v + return b, nil +} + +func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32() = v + return b, nil +} + +func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32Ptr() = &v + return b, nil +} + +func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64() = v + return b[8:], nil +} + +func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64() = v + return b[8:], nil +} + +func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32() = v + return b[4:], nil +} + +func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32Ptr() = &v + return b[4:], nil +} + +func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + *f.toInt32() = v + return b[4:], nil +} + +func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.setInt32Ptr(v) + return b[4:], nil +} + +func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + return b[4:], nil +} + +func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + // Note: any length varint is allowed, even though any sane + // encoder will use one byte. + // See https://github.com/golang/protobuf/issues/76 + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + // TODO: check if x>1? Tests seem to indicate no. + v := x != 0 + *f.toBool() = v + return b[n:], nil +} + +func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + *f.toBoolPtr() = &v + return b[n:], nil +} + +func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + b = b[n:] + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + return b[n:], nil +} + +func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64() = v + return b[8:], nil +} + +func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64Ptr() = &v + return b[8:], nil +} + +func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32() = v + return b[4:], nil +} + +func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32Ptr() = &v + return b[4:], nil +} + +func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + *f.toString() = v + return b[x:], nil +} + +func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + *f.toStringPtr() = &v + return b[x:], nil +} + +func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + if !utf8.ValidString(v) { + return nil, errInvalidUTF8 + } + s := f.toStringSlice() + *s = append(*s, v) + return b[x:], nil +} + +var emptyBuf [0]byte + +func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // The use of append here is a trick which avoids the zeroing + // that would be required if we used a make/copy pair. + // We append to emptyBuf instead of nil because we want + // a non-nil result even when the length is 0. + v := append(emptyBuf[:], b[:x]...) + *f.toBytes() = v + return b[x:], nil +} + +func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := append(emptyBuf[:], b[:x]...) + s := f.toBytesSlice() + *s = append(*s, v) + return b[x:], nil +} + +func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // First read the message field to see if something is there. + // The semantics of multiple submessages are weird. Instead of + // the last one winning (as it is for all other fields), multiple + // submessages are merged. + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[x:], err + } +} + +func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[x:], err + } +} + +func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[y:], err + } +} + +func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[y:], err + } +} + +func makeUnmarshalMap(f *reflect.StructField) unmarshaler { + t := f.Type + kt := t.Key() + vt := t.Elem() + unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) + unmarshalVal := typeUnmarshaler(vt, f.Tag.Get("protobuf_val")) + return func(b []byte, f pointer, w int) ([]byte, error) { + // The map entry is a submessage. Figure out how big it is. + if w != WireBytes { + return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + r := b[x:] // unused data to return + b = b[:x] // data for map entry + + // Note: we could use #keys * #values ~= 200 functions + // to do map decoding without reflection. Probably not worth it. + // Maps will be somewhat slow. Oh well. + + // Read key and value from data. + k := reflect.New(kt) + v := reflect.New(vt) + for len(b) > 0 { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + wire := int(x) & 7 + b = b[n:] + + var err error + switch x >> 3 { + case 1: + b, err = unmarshalKey(b, valToPointer(k), wire) + case 2: + b, err = unmarshalVal(b, valToPointer(v), wire) + default: + err = errInternalBadWireType // skip unknown tag + } + + if err == nil { + continue + } + if err != errInternalBadWireType { + return nil, err + } + + // Skip past unknown fields. + b, err = skipField(b, wire) + if err != nil { + return nil, err + } + } + + // Get map, allocate if needed. + m := f.asPointerTo(t).Elem() // an addressable map[K]T + if m.IsNil() { + m.Set(reflect.MakeMap(t)) + } + + // Insert into map. + m.SetMapIndex(k.Elem(), v.Elem()) + + return r, nil + } +} + +// makeUnmarshalOneof makes an unmarshaler for oneof fields. +// for: +// message Msg { +// oneof F { +// int64 X = 1; +// float64 Y = 2; +// } +// } +// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). +// ityp is the interface type of the oneof field (e.g. isMsg_F). +// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). +// Note that this function will be called once for each case in the oneof. +func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { + sf := typ.Field(0) + field0 := toField(&sf) + return func(b []byte, f pointer, w int) ([]byte, error) { + // Allocate holder for value. + v := reflect.New(typ) + + // Unmarshal data into holder. + // We unmarshal into the first field of the holder object. + var err error + b, err = unmarshal(b, valToPointer(v).offset(field0), w) + if err != nil { + return nil, err + } + + // Write pointer to holder into target field. + f.asPointerTo(ityp).Elem().Set(v) + + return b, nil + } +} + +// Error used by decode internally. +var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") + +// skipField skips past a field of type wire and returns the remaining bytes. +func skipField(b []byte, wire int) ([]byte, error) { + switch wire { + case WireVarint: + _, k := decodeVarint(b) + if k == 0 { + return b, io.ErrUnexpectedEOF + } + b = b[k:] + case WireFixed32: + if len(b) < 4 { + return b, io.ErrUnexpectedEOF + } + b = b[4:] + case WireFixed64: + if len(b) < 8 { + return b, io.ErrUnexpectedEOF + } + b = b[8:] + case WireBytes: + m, k := decodeVarint(b) + if k == 0 || uint64(len(b)-k) < m { + return b, io.ErrUnexpectedEOF + } + b = b[uint64(k)+m:] + case WireStartGroup: + _, i := findEndGroup(b) + if i == -1 { + return b, io.ErrUnexpectedEOF + } + b = b[i:] + default: + return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) + } + return b, nil +} + +// findEndGroup finds the index of the next EndGroup tag. +// Groups may be nested, so the "next" EndGroup tag is the first +// unpaired EndGroup. +// findEndGroup returns the indexes of the start and end of the EndGroup tag. +// Returns (-1,-1) if it can't find one. +func findEndGroup(b []byte) (int, int) { + depth := 1 + i := 0 + for { + x, n := decodeVarint(b[i:]) + if n == 0 { + return -1, -1 + } + j := i + i += n + switch x & 7 { + case WireVarint: + _, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + case WireFixed32: + if len(b)-4 < i { + return -1, -1 + } + i += 4 + case WireFixed64: + if len(b)-8 < i { + return -1, -1 + } + i += 8 + case WireBytes: + m, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + if uint64(len(b)-i) < m { + return -1, -1 + } + i += int(m) + case WireStartGroup: + depth++ + case WireEndGroup: + depth-- + if depth == 0 { + return j, i + } + default: + return -1, -1 + } + } +} + +// encodeVarint appends a varint-encoded integer to b and returns the result. +func encodeVarint(b []byte, x uint64) []byte { + for x >= 1<<7 { + b = append(b, byte(x&0x7f|0x80)) + x >>= 7 + } + return append(b, byte(x)) +} + +// decodeVarint reads a varint-encoded integer from b. +// Returns the decoded integer and the number of bytes read. +// If there is an error, it returns 0,0. +func decodeVarint(b []byte) (uint64, int) { + var x, y uint64 + if len(b) <= 0 { + goto bad + } + x = uint64(b[0]) + if x < 0x80 { + return x, 1 + } + x -= 0x80 + + if len(b) <= 1 { + goto bad + } + y = uint64(b[1]) + x += y << 7 + if y < 0x80 { + return x, 2 + } + x -= 0x80 << 7 + + if len(b) <= 2 { + goto bad + } + y = uint64(b[2]) + x += y << 14 + if y < 0x80 { + return x, 3 + } + x -= 0x80 << 14 + + if len(b) <= 3 { + goto bad + } + y = uint64(b[3]) + x += y << 21 + if y < 0x80 { + return x, 4 + } + x -= 0x80 << 21 + + if len(b) <= 4 { + goto bad + } + y = uint64(b[4]) + x += y << 28 + if y < 0x80 { + return x, 5 + } + x -= 0x80 << 28 + + if len(b) <= 5 { + goto bad + } + y = uint64(b[5]) + x += y << 35 + if y < 0x80 { + return x, 6 + } + x -= 0x80 << 35 + + if len(b) <= 6 { + goto bad + } + y = uint64(b[6]) + x += y << 42 + if y < 0x80 { + return x, 7 + } + x -= 0x80 << 42 + + if len(b) <= 7 { + goto bad + } + y = uint64(b[7]) + x += y << 49 + if y < 0x80 { + return x, 8 + } + x -= 0x80 << 49 + + if len(b) <= 8 { + goto bad + } + y = uint64(b[8]) + x += y << 56 + if y < 0x80 { + return x, 9 + } + x -= 0x80 << 56 + + if len(b) <= 9 { + goto bad + } + y = uint64(b[9]) + x += y << 63 + if y < 2 { + return x, 10 + } + +bad: + return 0, 0 +} diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go new file mode 100644 index 0000000..2205fda --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -0,0 +1,843 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if name == "XXX_NoUnkeyedLiteral" { + continue + } + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + + // Enums have a String method, so writeAny will work fine. + if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv.Addr() + if _, err := extendable(pv.Interface()); err == nil { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if v.CanAddr() { + // Calling v.Interface on a struct causes the reflect package to + // copy the entire struct. This is racy with the new Marshaler + // since we atomically update the XXX_sizecache. + // + // Thus, we retrieve a pointer to the struct if possible to avoid + // a race since v.Interface on the pointer doesn't copy the struct. + // + // If v is not addressable, then we are not worried about a race + // since it implies that the binary Marshaler cannot possibly be + // mutating this value. + v = v.Addr() + } + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if err := tm.writeStruct(w, v); err != nil { + return err + } + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, err := fmt.Fprintf(w, "/* %v */\n", err) + return err + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, err := w.Write(endBraceNewline); err != nil { + return err + } + continue + } + if _, err := fmt.Fprint(w, tag); err != nil { + return err + } + if wire != WireStartGroup { + if err := w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err := w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err = w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + ep, _ := extendable(pv.Interface()) + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + m, mu := ep.extensionsRead() + if m == nil { + return nil + } + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(ep, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go new file mode 100644 index 0000000..0685bae --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -0,0 +1,880 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + ss := string(r) + s[:2] + s = s[2:] + i, err := strconv.ParseUint(ss, 8, 8) + if err != nil { + return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) + } + return string([]byte{byte(i)}), s, nil + case 'x', 'X', 'u', 'U': + var n int + switch r { + case 'x', 'X': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) + } + ss := s[:n] + s = s[n:] + i, err := strconv.ParseUint(ss, 16, 64) + if err != nil { + return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) + } + if r == 'x' || r == 'X' { + return string([]byte{byte(i)}), s, nil + } + if i > utf8.MaxRune { + return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) + } + return string(i), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + if p.done && tok.value != "]" { + return "", p.errorf("unclosed type_url or extension name") + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "]" { + break + } + if tok.value != "," { + return p.errorf("Expected ']' or ',' found %q", tok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(uint64(x)) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + return um.UnmarshalText([]byte(s)) + } + pb.Reset() + v := reflect.ValueOf(pb) + return newTextParser(s).readStruct(v.Elem(), "") +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go new file mode 100644 index 0000000..b2af97f --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any.go @@ -0,0 +1,139 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements functions to marshal proto.Message to/from +// google.protobuf.Any message. + +import ( + "fmt" + "reflect" + "strings" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +const googleApis = "type.googleapis.com/" + +// AnyMessageName returns the name of the message contained in a google.protobuf.Any message. +// +// Note that regular type assertions should be done using the Is +// function. AnyMessageName is provided for less common use cases like filtering a +// sequence of Any messages based on a set of allowed message type names. +func AnyMessageName(any *any.Any) (string, error) { + if any == nil { + return "", fmt.Errorf("message is nil") + } + slash := strings.LastIndex(any.TypeUrl, "/") + if slash < 0 { + return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) + } + return any.TypeUrl[slash+1:], nil +} + +// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any. +func MarshalAny(pb proto.Message) (*any.Any, error) { + value, err := proto.Marshal(pb) + if err != nil { + return nil, err + } + return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil +} + +// DynamicAny is a value that can be passed to UnmarshalAny to automatically +// allocate a proto.Message for the type specified in a google.protobuf.Any +// message. The allocated message is stored in the embedded proto.Message. +// +// Example: +// +// var x ptypes.DynamicAny +// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } +// fmt.Printf("unmarshaled message: %v", x.Message) +type DynamicAny struct { + proto.Message +} + +// Empty returns a new proto.Message of the type specified in a +// google.protobuf.Any message. It returns an error if corresponding message +// type isn't linked in. +func Empty(any *any.Any) (proto.Message, error) { + aname, err := AnyMessageName(any) + if err != nil { + return nil, err + } + + t := proto.MessageType(aname) + if t == nil { + return nil, fmt.Errorf("any: message type %q isn't linked in", aname) + } + return reflect.New(t.Elem()).Interface().(proto.Message), nil +} + +// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any +// message and places the decoded result in pb. It returns an error if type of +// contents of Any message does not match type of pb message. +// +// pb can be a proto.Message, or a *DynamicAny. +func UnmarshalAny(any *any.Any, pb proto.Message) error { + if d, ok := pb.(*DynamicAny); ok { + if d.Message == nil { + var err error + d.Message, err = Empty(any) + if err != nil { + return err + } + } + return UnmarshalAny(any, d.Message) + } + + aname, err := AnyMessageName(any) + if err != nil { + return err + } + + mname := proto.MessageName(pb) + if aname != mname { + return fmt.Errorf("mismatched message type: got %q want %q", aname, mname) + } + return proto.Unmarshal(any.Value, pb) +} + +// Is returns true if any value contains a given message type. +func Is(any *any.Any, pb proto.Message) bool { + aname, err := AnyMessageName(any) + if err != nil { + return false + } + + return aname == proto.MessageName(pb) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go new file mode 100644 index 0000000..f67edc7 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go @@ -0,0 +1,191 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/any.proto + +package any // import "github.com/golang/protobuf/ptypes/any" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +type Any struct { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"` + // Must be a valid serialized protocol buffer of the above specified type. + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { + return fileDescriptor_any_744b9ca530f228db, []int{0} +} +func (*Any) XXX_WellKnownType() string { return "Any" } +func (m *Any) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Any.Unmarshal(m, b) +} +func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Any.Marshal(b, m, deterministic) +} +func (dst *Any) XXX_Merge(src proto.Message) { + xxx_messageInfo_Any.Merge(dst, src) +} +func (m *Any) XXX_Size() int { + return xxx_messageInfo_Any.Size(m) +} +func (m *Any) XXX_DiscardUnknown() { + xxx_messageInfo_Any.DiscardUnknown(m) +} + +var xxx_messageInfo_Any proto.InternalMessageInfo + +func (m *Any) GetTypeUrl() string { + if m != nil { + return m.TypeUrl + } + return "" +} + +func (m *Any) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*Any)(nil), "google.protobuf.Any") +} + +func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) } + +var fileDescriptor_any_744b9ca530f228db = []byte{ + // 185 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, + 0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a, + 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, + 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, + 0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce, + 0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52, + 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, + 0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c, + 0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, + 0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.proto b/vendor/github.com/golang/protobuf/ptypes/any/any.proto new file mode 100644 index 0000000..c748667 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.proto @@ -0,0 +1,149 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go new file mode 100644 index 0000000..c0d595d --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/doc.go @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +/* +Package ptypes contains code for interacting with well-known types. +*/ +package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go new file mode 100644 index 0000000..65cb0f8 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration.go @@ -0,0 +1,102 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" + + durpb "github.com/golang/protobuf/ptypes/duration" +) + +const ( + // Range of a durpb.Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the durpb.Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid durpb.Duration +// may still be too large to fit into a time.Duration (the range of durpb.Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *durpb.Duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %v: seconds and nanos have different signs", d) + } + return nil +} + +// Duration converts a durpb.Duration to a time.Duration. Duration +// returns an error if the durpb.Duration is invalid or is too large to be +// represented in a time.Duration. +func Duration(p *durpb.Duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a durpb.Duration. +func DurationProto(d time.Duration) *durpb.Duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &durpb.Duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go new file mode 100644 index 0000000..4d75473 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go @@ -0,0 +1,159 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/duration.proto + +package duration // import "github.com/golang/protobuf/ptypes/duration" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +type Duration struct { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Duration) Reset() { *m = Duration{} } +func (m *Duration) String() string { return proto.CompactTextString(m) } +func (*Duration) ProtoMessage() {} +func (*Duration) Descriptor() ([]byte, []int) { + return fileDescriptor_duration_e7d612259e3f0613, []int{0} +} +func (*Duration) XXX_WellKnownType() string { return "Duration" } +func (m *Duration) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Duration.Unmarshal(m, b) +} +func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Duration.Marshal(b, m, deterministic) +} +func (dst *Duration) XXX_Merge(src proto.Message) { + xxx_messageInfo_Duration.Merge(dst, src) +} +func (m *Duration) XXX_Size() int { + return xxx_messageInfo_Duration.Size(m) +} +func (m *Duration) XXX_DiscardUnknown() { + xxx_messageInfo_Duration.DiscardUnknown(m) +} + +var xxx_messageInfo_Duration proto.InternalMessageInfo + +func (m *Duration) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Duration) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") +} + +func init() { + proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613) +} + +var fileDescriptor_duration_e7d612259e3f0613 = []byte{ + // 190 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, + 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56, + 0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5, + 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e, + 0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c, + 0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56, + 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, + 0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4, + 0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78, + 0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63, + 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto new file mode 100644 index 0000000..975fce4 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto @@ -0,0 +1,117 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/duration"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go new file mode 100644 index 0000000..47f10db --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp.go @@ -0,0 +1,134 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" + + tspb "github.com/golang/protobuf/ptypes/timestamp" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *tspb.Timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// Timestamp converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func Timestamp(ts *tspb.Timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampNow returns a google.protobuf.Timestamp for the current time. +func TimestampNow() *tspb.Timestamp { + ts, err := TimestampProto(time.Now()) + if err != nil { + panic("ptypes: time.Now() out of Timestamp range") + } + return ts +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func TimestampProto(t time.Time) (*tspb.Timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := &tspb.Timestamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} + +// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid +// Timestamps, it returns an error message in parentheses. +func TimestampString(ts *tspb.Timestamp) string { + t, err := Timestamp(ts) + if err != nil { + return fmt.Sprintf("(%v)", err) + } + return t.Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go new file mode 100644 index 0000000..e9c2222 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go @@ -0,0 +1,175 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + +package timestamp // import "github.com/golang/protobuf/ptypes/timestamp" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--) +// to obtain a formatter capable of generating timestamps in this format. +// +// +type Timestamp struct { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Timestamp) Reset() { *m = Timestamp{} } +func (m *Timestamp) String() string { return proto.CompactTextString(m) } +func (*Timestamp) ProtoMessage() {} +func (*Timestamp) Descriptor() ([]byte, []int) { + return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0} +} +func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } +func (m *Timestamp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Timestamp.Unmarshal(m, b) +} +func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic) +} +func (dst *Timestamp) XXX_Merge(src proto.Message) { + xxx_messageInfo_Timestamp.Merge(dst, src) +} +func (m *Timestamp) XXX_Size() int { + return xxx_messageInfo_Timestamp.Size(m) +} +func (m *Timestamp) XXX_DiscardUnknown() { + xxx_messageInfo_Timestamp.DiscardUnknown(m) +} + +var xxx_messageInfo_Timestamp proto.InternalMessageInfo + +func (m *Timestamp) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Timestamp) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") +} + +func init() { + proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8) +} + +var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{ + // 191 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, + 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28, + 0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5, + 0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89, + 0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70, + 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51, + 0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89, + 0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71, + 0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a, + 0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto new file mode 100644 index 0000000..06750ab --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto @@ -0,0 +1,133 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--) +// to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/golang/snappy/.gitignore b/vendor/github.com/golang/snappy/.gitignore new file mode 100644 index 0000000..042091d --- /dev/null +++ b/vendor/github.com/golang/snappy/.gitignore @@ -0,0 +1,16 @@ +cmd/snappytool/snappytool +testdata/bench + +# These explicitly listed benchmark data files are for an obsolete version of +# snappy_test.go. +testdata/alice29.txt +testdata/asyoulik.txt +testdata/fireworks.jpeg +testdata/geo.protodata +testdata/html +testdata/html_x_4 +testdata/kppkn.gtb +testdata/lcet10.txt +testdata/paper-100k.pdf +testdata/plrabn12.txt +testdata/urls.10K diff --git a/vendor/github.com/golang/snappy/AUTHORS b/vendor/github.com/golang/snappy/AUTHORS new file mode 100644 index 0000000..bcfa195 --- /dev/null +++ b/vendor/github.com/golang/snappy/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of Snappy-Go authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Damian Gryski +Google Inc. +Jan Mercl <0xjnml@gmail.com> +Rodolfo Carvalho +Sebastien Binet diff --git a/vendor/github.com/golang/snappy/CONTRIBUTORS b/vendor/github.com/golang/snappy/CONTRIBUTORS new file mode 100644 index 0000000..931ae31 --- /dev/null +++ b/vendor/github.com/golang/snappy/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This is the official list of people who can contribute +# (and typically have contributed) code to the Snappy-Go repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name + +# Please keep the list sorted. + +Damian Gryski +Jan Mercl <0xjnml@gmail.com> +Kai Backman +Marc-Antoine Ruel +Nigel Tao +Rob Pike +Rodolfo Carvalho +Russ Cox +Sebastien Binet diff --git a/vendor/github.com/golang/snappy/LICENSE b/vendor/github.com/golang/snappy/LICENSE new file mode 100644 index 0000000..6050c10 --- /dev/null +++ b/vendor/github.com/golang/snappy/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The Snappy-Go Authors. 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/vendor/github.com/golang/snappy/README b/vendor/github.com/golang/snappy/README new file mode 100644 index 0000000..cea1287 --- /dev/null +++ b/vendor/github.com/golang/snappy/README @@ -0,0 +1,107 @@ +The Snappy compression format in the Go programming language. + +To download and install from source: +$ go get github.com/golang/snappy + +Unless otherwise noted, the Snappy-Go source files are distributed +under the BSD-style license found in the LICENSE file. + + + +Benchmarks. + +The golang/snappy benchmarks include compressing (Z) and decompressing (U) ten +or so files, the same set used by the C++ Snappy code (github.com/google/snappy +and note the "google", not "golang"). On an "Intel(R) Core(TM) i7-3770 CPU @ +3.40GHz", Go's GOARCH=amd64 numbers as of 2016-05-29: + +"go test -test.bench=." + +_UFlat0-8 2.19GB/s ± 0% html +_UFlat1-8 1.41GB/s ± 0% urls +_UFlat2-8 23.5GB/s ± 2% jpg +_UFlat3-8 1.91GB/s ± 0% jpg_200 +_UFlat4-8 14.0GB/s ± 1% pdf +_UFlat5-8 1.97GB/s ± 0% html4 +_UFlat6-8 814MB/s ± 0% txt1 +_UFlat7-8 785MB/s ± 0% txt2 +_UFlat8-8 857MB/s ± 0% txt3 +_UFlat9-8 719MB/s ± 1% txt4 +_UFlat10-8 2.84GB/s ± 0% pb +_UFlat11-8 1.05GB/s ± 0% gaviota + +_ZFlat0-8 1.04GB/s ± 0% html +_ZFlat1-8 534MB/s ± 0% urls +_ZFlat2-8 15.7GB/s ± 1% jpg +_ZFlat3-8 740MB/s ± 3% jpg_200 +_ZFlat4-8 9.20GB/s ± 1% pdf +_ZFlat5-8 991MB/s ± 0% html4 +_ZFlat6-8 379MB/s ± 0% txt1 +_ZFlat7-8 352MB/s ± 0% txt2 +_ZFlat8-8 396MB/s ± 1% txt3 +_ZFlat9-8 327MB/s ± 1% txt4 +_ZFlat10-8 1.33GB/s ± 1% pb +_ZFlat11-8 605MB/s ± 1% gaviota + + + +"go test -test.bench=. -tags=noasm" + +_UFlat0-8 621MB/s ± 2% html +_UFlat1-8 494MB/s ± 1% urls +_UFlat2-8 23.2GB/s ± 1% jpg +_UFlat3-8 1.12GB/s ± 1% jpg_200 +_UFlat4-8 4.35GB/s ± 1% pdf +_UFlat5-8 609MB/s ± 0% html4 +_UFlat6-8 296MB/s ± 0% txt1 +_UFlat7-8 288MB/s ± 0% txt2 +_UFlat8-8 309MB/s ± 1% txt3 +_UFlat9-8 280MB/s ± 1% txt4 +_UFlat10-8 753MB/s ± 0% pb +_UFlat11-8 400MB/s ± 0% gaviota + +_ZFlat0-8 409MB/s ± 1% html +_ZFlat1-8 250MB/s ± 1% urls +_ZFlat2-8 12.3GB/s ± 1% jpg +_ZFlat3-8 132MB/s ± 0% jpg_200 +_ZFlat4-8 2.92GB/s ± 0% pdf +_ZFlat5-8 405MB/s ± 1% html4 +_ZFlat6-8 179MB/s ± 1% txt1 +_ZFlat7-8 170MB/s ± 1% txt2 +_ZFlat8-8 189MB/s ± 1% txt3 +_ZFlat9-8 164MB/s ± 1% txt4 +_ZFlat10-8 479MB/s ± 1% pb +_ZFlat11-8 270MB/s ± 1% gaviota + + + +For comparison (Go's encoded output is byte-for-byte identical to C++'s), here +are the numbers from C++ Snappy's + +make CXXFLAGS="-O2 -DNDEBUG -g" clean snappy_unittest.log && cat snappy_unittest.log + +BM_UFlat/0 2.4GB/s html +BM_UFlat/1 1.4GB/s urls +BM_UFlat/2 21.8GB/s jpg +BM_UFlat/3 1.5GB/s jpg_200 +BM_UFlat/4 13.3GB/s pdf +BM_UFlat/5 2.1GB/s html4 +BM_UFlat/6 1.0GB/s txt1 +BM_UFlat/7 959.4MB/s txt2 +BM_UFlat/8 1.0GB/s txt3 +BM_UFlat/9 864.5MB/s txt4 +BM_UFlat/10 2.9GB/s pb +BM_UFlat/11 1.2GB/s gaviota + +BM_ZFlat/0 944.3MB/s html (22.31 %) +BM_ZFlat/1 501.6MB/s urls (47.78 %) +BM_ZFlat/2 14.3GB/s jpg (99.95 %) +BM_ZFlat/3 538.3MB/s jpg_200 (73.00 %) +BM_ZFlat/4 8.3GB/s pdf (83.30 %) +BM_ZFlat/5 903.5MB/s html4 (22.52 %) +BM_ZFlat/6 336.0MB/s txt1 (57.88 %) +BM_ZFlat/7 312.3MB/s txt2 (61.91 %) +BM_ZFlat/8 353.1MB/s txt3 (54.99 %) +BM_ZFlat/9 289.9MB/s txt4 (66.26 %) +BM_ZFlat/10 1.2GB/s pb (19.68 %) +BM_ZFlat/11 527.4MB/s gaviota (37.72 %) diff --git a/vendor/github.com/golang/snappy/decode.go b/vendor/github.com/golang/snappy/decode.go new file mode 100644 index 0000000..72efb03 --- /dev/null +++ b/vendor/github.com/golang/snappy/decode.go @@ -0,0 +1,237 @@ +// Copyright 2011 The Snappy-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 snappy + +import ( + "encoding/binary" + "errors" + "io" +) + +var ( + // ErrCorrupt reports that the input is invalid. + ErrCorrupt = errors.New("snappy: corrupt input") + // ErrTooLarge reports that the uncompressed length is too large. + ErrTooLarge = errors.New("snappy: decoded block is too large") + // ErrUnsupported reports that the input isn't supported. + ErrUnsupported = errors.New("snappy: unsupported input") + + errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length") +) + +// DecodedLen returns the length of the decoded block. +func DecodedLen(src []byte) (int, error) { + v, _, err := decodedLen(src) + return v, err +} + +// decodedLen returns the length of the decoded block and the number of bytes +// that the length header occupied. +func decodedLen(src []byte) (blockLen, headerLen int, err error) { + v, n := binary.Uvarint(src) + if n <= 0 || v > 0xffffffff { + return 0, 0, ErrCorrupt + } + + const wordSize = 32 << (^uint(0) >> 32 & 1) + if wordSize == 32 && v > 0x7fffffff { + return 0, 0, ErrTooLarge + } + return int(v), n, nil +} + +const ( + decodeErrCodeCorrupt = 1 + decodeErrCodeUnsupportedLiteralLength = 2 +) + +// Decode returns the decoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire decoded block. +// Otherwise, a newly allocated slice will be returned. +// +// The dst and src must not overlap. It is valid to pass a nil dst. +func Decode(dst, src []byte) ([]byte, error) { + dLen, s, err := decodedLen(src) + if err != nil { + return nil, err + } + if dLen <= len(dst) { + dst = dst[:dLen] + } else { + dst = make([]byte, dLen) + } + switch decode(dst, src[s:]) { + case 0: + return dst, nil + case decodeErrCodeUnsupportedLiteralLength: + return nil, errUnsupportedLiteralLength + } + return nil, ErrCorrupt +} + +// NewReader returns a new Reader that decompresses from r, using the framing +// format described at +// https://github.com/google/snappy/blob/master/framing_format.txt +func NewReader(r io.Reader) *Reader { + return &Reader{ + r: r, + decoded: make([]byte, maxBlockSize), + buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize), + } +} + +// Reader is an io.Reader that can read Snappy-compressed bytes. +type Reader struct { + r io.Reader + err error + decoded []byte + buf []byte + // decoded[i:j] contains decoded bytes that have not yet been passed on. + i, j int + readHeader bool +} + +// Reset discards any buffered data, resets all state, and switches the Snappy +// reader to read from r. This permits reusing a Reader rather than allocating +// a new one. +func (r *Reader) Reset(reader io.Reader) { + r.r = reader + r.err = nil + r.i = 0 + r.j = 0 + r.readHeader = false +} + +func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) { + if _, r.err = io.ReadFull(r.r, p); r.err != nil { + if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) { + r.err = ErrCorrupt + } + return false + } + return true +} + +// Read satisfies the io.Reader interface. +func (r *Reader) Read(p []byte) (int, error) { + if r.err != nil { + return 0, r.err + } + for { + if r.i < r.j { + n := copy(p, r.decoded[r.i:r.j]) + r.i += n + return n, nil + } + if !r.readFull(r.buf[:4], true) { + return 0, r.err + } + chunkType := r.buf[0] + if !r.readHeader { + if chunkType != chunkTypeStreamIdentifier { + r.err = ErrCorrupt + return 0, r.err + } + r.readHeader = true + } + chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16 + if chunkLen > len(r.buf) { + r.err = ErrUnsupported + return 0, r.err + } + + // The chunk types are specified at + // https://github.com/google/snappy/blob/master/framing_format.txt + switch chunkType { + case chunkTypeCompressedData: + // Section 4.2. Compressed data (chunk type 0x00). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return 0, r.err + } + buf := r.buf[:chunkLen] + if !r.readFull(buf, false) { + return 0, r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + buf = buf[checksumSize:] + + n, err := DecodedLen(buf) + if err != nil { + r.err = err + return 0, r.err + } + if n > len(r.decoded) { + r.err = ErrCorrupt + return 0, r.err + } + if _, err := Decode(r.decoded, buf); err != nil { + r.err = err + return 0, r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return 0, r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeUncompressedData: + // Section 4.3. Uncompressed data (chunk type 0x01). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return 0, r.err + } + buf := r.buf[:checksumSize] + if !r.readFull(buf, false) { + return 0, r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + // Read directly into r.decoded instead of via r.buf. + n := chunkLen - checksumSize + if n > len(r.decoded) { + r.err = ErrCorrupt + return 0, r.err + } + if !r.readFull(r.decoded[:n], false) { + return 0, r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return 0, r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeStreamIdentifier: + // Section 4.1. Stream identifier (chunk type 0xff). + if chunkLen != len(magicBody) { + r.err = ErrCorrupt + return 0, r.err + } + if !r.readFull(r.buf[:len(magicBody)], false) { + return 0, r.err + } + for i := 0; i < len(magicBody); i++ { + if r.buf[i] != magicBody[i] { + r.err = ErrCorrupt + return 0, r.err + } + } + continue + } + + if chunkType <= 0x7f { + // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f). + r.err = ErrUnsupported + return 0, r.err + } + // Section 4.4 Padding (chunk type 0xfe). + // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd). + if !r.readFull(r.buf[:chunkLen], false) { + return 0, r.err + } + } +} diff --git a/vendor/github.com/golang/snappy/decode_amd64.go b/vendor/github.com/golang/snappy/decode_amd64.go new file mode 100644 index 0000000..fcd192b --- /dev/null +++ b/vendor/github.com/golang/snappy/decode_amd64.go @@ -0,0 +1,14 @@ +// Copyright 2016 The Snappy-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 !appengine +// +build gc +// +build !noasm + +package snappy + +// decode has the same semantics as in decode_other.go. +// +//go:noescape +func decode(dst, src []byte) int diff --git a/vendor/github.com/golang/snappy/decode_amd64.s b/vendor/github.com/golang/snappy/decode_amd64.s new file mode 100644 index 0000000..e6179f6 --- /dev/null +++ b/vendor/github.com/golang/snappy/decode_amd64.s @@ -0,0 +1,490 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine +// +build gc +// +build !noasm + +#include "textflag.h" + +// The asm code generally follows the pure Go code in decode_other.go, except +// where marked with a "!!!". + +// func decode(dst, src []byte) int +// +// All local variables fit into registers. The non-zero stack size is only to +// spill registers and push args when issuing a CALL. The register allocation: +// - AX scratch +// - BX scratch +// - CX length or x +// - DX offset +// - SI &src[s] +// - DI &dst[d] +// + R8 dst_base +// + R9 dst_len +// + R10 dst_base + dst_len +// + R11 src_base +// + R12 src_len +// + R13 src_base + src_len +// - R14 used by doCopy +// - R15 used by doCopy +// +// The registers R8-R13 (marked with a "+") are set at the start of the +// function, and after a CALL returns, and are not otherwise modified. +// +// The d variable is implicitly DI - R8, and len(dst)-d is R10 - DI. +// The s variable is implicitly SI - R11, and len(src)-s is R13 - SI. +TEXT ·decode(SB), NOSPLIT, $48-56 + // Initialize SI, DI and R8-R13. + MOVQ dst_base+0(FP), R8 + MOVQ dst_len+8(FP), R9 + MOVQ R8, DI + MOVQ R8, R10 + ADDQ R9, R10 + MOVQ src_base+24(FP), R11 + MOVQ src_len+32(FP), R12 + MOVQ R11, SI + MOVQ R11, R13 + ADDQ R12, R13 + +loop: + // for s < len(src) + CMPQ SI, R13 + JEQ end + + // CX = uint32(src[s]) + // + // switch src[s] & 0x03 + MOVBLZX (SI), CX + MOVL CX, BX + ANDL $3, BX + CMPL BX, $1 + JAE tagCopy + + // ---------------------------------------- + // The code below handles literal tags. + + // case tagLiteral: + // x := uint32(src[s] >> 2) + // switch + SHRL $2, CX + CMPL CX, $60 + JAE tagLit60Plus + + // case x < 60: + // s++ + INCQ SI + +doLit: + // This is the end of the inner "switch", when we have a literal tag. + // + // We assume that CX == x and x fits in a uint32, where x is the variable + // used in the pure Go decode_other.go code. + + // length = int(x) + 1 + // + // Unlike the pure Go code, we don't need to check if length <= 0 because + // CX can hold 64 bits, so the increment cannot overflow. + INCQ CX + + // Prepare to check if copying length bytes will run past the end of dst or + // src. + // + // AX = len(dst) - d + // BX = len(src) - s + MOVQ R10, AX + SUBQ DI, AX + MOVQ R13, BX + SUBQ SI, BX + + // !!! Try a faster technique for short (16 or fewer bytes) copies. + // + // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 { + // goto callMemmove // Fall back on calling runtime·memmove. + // } + // + // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s + // against 21 instead of 16, because it cannot assume that all of its input + // is contiguous in memory and so it needs to leave enough source bytes to + // read the next tag without refilling buffers, but Go's Decode assumes + // contiguousness (the src argument is a []byte). + CMPQ CX, $16 + JGT callMemmove + CMPQ AX, $16 + JLT callMemmove + CMPQ BX, $16 + JLT callMemmove + + // !!! Implement the copy from src to dst as a 16-byte load and store. + // (Decode's documentation says that dst and src must not overlap.) + // + // This always copies 16 bytes, instead of only length bytes, but that's + // OK. If the input is a valid Snappy encoding then subsequent iterations + // will fix up the overrun. Otherwise, Decode returns a nil []byte (and a + // non-nil error), so the overrun will be ignored. + // + // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or + // 16-byte loads and stores. This technique probably wouldn't be as + // effective on architectures that are fussier about alignment. + MOVOU 0(SI), X0 + MOVOU X0, 0(DI) + + // d += length + // s += length + ADDQ CX, DI + ADDQ CX, SI + JMP loop + +callMemmove: + // if length > len(dst)-d || length > len(src)-s { etc } + CMPQ CX, AX + JGT errCorrupt + CMPQ CX, BX + JGT errCorrupt + + // copy(dst[d:], src[s:s+length]) + // + // This means calling runtime·memmove(&dst[d], &src[s], length), so we push + // DI, SI and CX as arguments. Coincidentally, we also need to spill those + // three registers to the stack, to save local variables across the CALL. + MOVQ DI, 0(SP) + MOVQ SI, 8(SP) + MOVQ CX, 16(SP) + MOVQ DI, 24(SP) + MOVQ SI, 32(SP) + MOVQ CX, 40(SP) + CALL runtime·memmove(SB) + + // Restore local variables: unspill registers from the stack and + // re-calculate R8-R13. + MOVQ 24(SP), DI + MOVQ 32(SP), SI + MOVQ 40(SP), CX + MOVQ dst_base+0(FP), R8 + MOVQ dst_len+8(FP), R9 + MOVQ R8, R10 + ADDQ R9, R10 + MOVQ src_base+24(FP), R11 + MOVQ src_len+32(FP), R12 + MOVQ R11, R13 + ADDQ R12, R13 + + // d += length + // s += length + ADDQ CX, DI + ADDQ CX, SI + JMP loop + +tagLit60Plus: + // !!! This fragment does the + // + // s += x - 58; if uint(s) > uint(len(src)) { etc } + // + // checks. In the asm version, we code it once instead of once per switch case. + ADDQ CX, SI + SUBQ $58, SI + MOVQ SI, BX + SUBQ R11, BX + CMPQ BX, R12 + JA errCorrupt + + // case x == 60: + CMPL CX, $61 + JEQ tagLit61 + JA tagLit62Plus + + // x = uint32(src[s-1]) + MOVBLZX -1(SI), CX + JMP doLit + +tagLit61: + // case x == 61: + // x = uint32(src[s-2]) | uint32(src[s-1])<<8 + MOVWLZX -2(SI), CX + JMP doLit + +tagLit62Plus: + CMPL CX, $62 + JA tagLit63 + + // case x == 62: + // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 + MOVWLZX -3(SI), CX + MOVBLZX -1(SI), BX + SHLL $16, BX + ORL BX, CX + JMP doLit + +tagLit63: + // case x == 63: + // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 + MOVL -4(SI), CX + JMP doLit + +// The code above handles literal tags. +// ---------------------------------------- +// The code below handles copy tags. + +tagCopy4: + // case tagCopy4: + // s += 5 + ADDQ $5, SI + + // if uint(s) > uint(len(src)) { etc } + MOVQ SI, BX + SUBQ R11, BX + CMPQ BX, R12 + JA errCorrupt + + // length = 1 + int(src[s-5])>>2 + SHRQ $2, CX + INCQ CX + + // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) + MOVLQZX -4(SI), DX + JMP doCopy + +tagCopy2: + // case tagCopy2: + // s += 3 + ADDQ $3, SI + + // if uint(s) > uint(len(src)) { etc } + MOVQ SI, BX + SUBQ R11, BX + CMPQ BX, R12 + JA errCorrupt + + // length = 1 + int(src[s-3])>>2 + SHRQ $2, CX + INCQ CX + + // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) + MOVWQZX -2(SI), DX + JMP doCopy + +tagCopy: + // We have a copy tag. We assume that: + // - BX == src[s] & 0x03 + // - CX == src[s] + CMPQ BX, $2 + JEQ tagCopy2 + JA tagCopy4 + + // case tagCopy1: + // s += 2 + ADDQ $2, SI + + // if uint(s) > uint(len(src)) { etc } + MOVQ SI, BX + SUBQ R11, BX + CMPQ BX, R12 + JA errCorrupt + + // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) + MOVQ CX, DX + ANDQ $0xe0, DX + SHLQ $3, DX + MOVBQZX -1(SI), BX + ORQ BX, DX + + // length = 4 + int(src[s-2])>>2&0x7 + SHRQ $2, CX + ANDQ $7, CX + ADDQ $4, CX + +doCopy: + // This is the end of the outer "switch", when we have a copy tag. + // + // We assume that: + // - CX == length && CX > 0 + // - DX == offset + + // if offset <= 0 { etc } + CMPQ DX, $0 + JLE errCorrupt + + // if d < offset { etc } + MOVQ DI, BX + SUBQ R8, BX + CMPQ BX, DX + JLT errCorrupt + + // if length > len(dst)-d { etc } + MOVQ R10, BX + SUBQ DI, BX + CMPQ CX, BX + JGT errCorrupt + + // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length + // + // Set: + // - R14 = len(dst)-d + // - R15 = &dst[d-offset] + MOVQ R10, R14 + SUBQ DI, R14 + MOVQ DI, R15 + SUBQ DX, R15 + + // !!! Try a faster technique for short (16 or fewer bytes) forward copies. + // + // First, try using two 8-byte load/stores, similar to the doLit technique + // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is + // still OK if offset >= 8. Note that this has to be two 8-byte load/stores + // and not one 16-byte load/store, and the first store has to be before the + // second load, due to the overlap if offset is in the range [8, 16). + // + // if length > 16 || offset < 8 || len(dst)-d < 16 { + // goto slowForwardCopy + // } + // copy 16 bytes + // d += length + CMPQ CX, $16 + JGT slowForwardCopy + CMPQ DX, $8 + JLT slowForwardCopy + CMPQ R14, $16 + JLT slowForwardCopy + MOVQ 0(R15), AX + MOVQ AX, 0(DI) + MOVQ 8(R15), BX + MOVQ BX, 8(DI) + ADDQ CX, DI + JMP loop + +slowForwardCopy: + // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we + // can still try 8-byte load stores, provided we can overrun up to 10 extra + // bytes. As above, the overrun will be fixed up by subsequent iterations + // of the outermost loop. + // + // The C++ snappy code calls this technique IncrementalCopyFastPath. Its + // commentary says: + // + // ---- + // + // The main part of this loop is a simple copy of eight bytes at a time + // until we've copied (at least) the requested amount of bytes. However, + // if d and d-offset are less than eight bytes apart (indicating a + // repeating pattern of length < 8), we first need to expand the pattern in + // order to get the correct results. For instance, if the buffer looks like + // this, with the eight-byte and patterns marked as + // intervals: + // + // abxxxxxxxxxxxx + // [------] d-offset + // [------] d + // + // a single eight-byte copy from to will repeat the pattern + // once, after which we can move two bytes without moving : + // + // ababxxxxxxxxxx + // [------] d-offset + // [------] d + // + // and repeat the exercise until the two no longer overlap. + // + // This allows us to do very well in the special case of one single byte + // repeated many times, without taking a big hit for more general cases. + // + // The worst case of extra writing past the end of the match occurs when + // offset == 1 and length == 1; the last copy will read from byte positions + // [0..7] and write to [4..11], whereas it was only supposed to write to + // position 1. Thus, ten excess bytes. + // + // ---- + // + // That "10 byte overrun" worst case is confirmed by Go's + // TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy + // and finishSlowForwardCopy algorithm. + // + // if length > len(dst)-d-10 { + // goto verySlowForwardCopy + // } + SUBQ $10, R14 + CMPQ CX, R14 + JGT verySlowForwardCopy + +makeOffsetAtLeast8: + // !!! As above, expand the pattern so that offset >= 8 and we can use + // 8-byte load/stores. + // + // for offset < 8 { + // copy 8 bytes from dst[d-offset:] to dst[d:] + // length -= offset + // d += offset + // offset += offset + // // The two previous lines together means that d-offset, and therefore + // // R15, is unchanged. + // } + CMPQ DX, $8 + JGE fixUpSlowForwardCopy + MOVQ (R15), BX + MOVQ BX, (DI) + SUBQ DX, CX + ADDQ DX, DI + ADDQ DX, DX + JMP makeOffsetAtLeast8 + +fixUpSlowForwardCopy: + // !!! Add length (which might be negative now) to d (implied by DI being + // &dst[d]) so that d ends up at the right place when we jump back to the + // top of the loop. Before we do that, though, we save DI to AX so that, if + // length is positive, copying the remaining length bytes will write to the + // right place. + MOVQ DI, AX + ADDQ CX, DI + +finishSlowForwardCopy: + // !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative + // length means that we overrun, but as above, that will be fixed up by + // subsequent iterations of the outermost loop. + CMPQ CX, $0 + JLE loop + MOVQ (R15), BX + MOVQ BX, (AX) + ADDQ $8, R15 + ADDQ $8, AX + SUBQ $8, CX + JMP finishSlowForwardCopy + +verySlowForwardCopy: + // verySlowForwardCopy is a simple implementation of forward copy. In C + // parlance, this is a do/while loop instead of a while loop, since we know + // that length > 0. In Go syntax: + // + // for { + // dst[d] = dst[d - offset] + // d++ + // length-- + // if length == 0 { + // break + // } + // } + MOVB (R15), BX + MOVB BX, (DI) + INCQ R15 + INCQ DI + DECQ CX + JNZ verySlowForwardCopy + JMP loop + +// The code above handles copy tags. +// ---------------------------------------- + +end: + // This is the end of the "for s < len(src)". + // + // if d != len(dst) { etc } + CMPQ DI, R10 + JNE errCorrupt + + // return 0 + MOVQ $0, ret+48(FP) + RET + +errCorrupt: + // return decodeErrCodeCorrupt + MOVQ $1, ret+48(FP) + RET diff --git a/vendor/github.com/golang/snappy/decode_other.go b/vendor/github.com/golang/snappy/decode_other.go new file mode 100644 index 0000000..8c9f204 --- /dev/null +++ b/vendor/github.com/golang/snappy/decode_other.go @@ -0,0 +1,101 @@ +// Copyright 2016 The Snappy-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 !amd64 appengine !gc noasm + +package snappy + +// decode writes the decoding of src to dst. It assumes that the varint-encoded +// length of the decompressed bytes has already been read, and that len(dst) +// equals that length. +// +// It returns 0 on success or a decodeErrCodeXxx error code on failure. +func decode(dst, src []byte) int { + var d, s, offset, length int + for s < len(src) { + switch src[s] & 0x03 { + case tagLiteral: + x := uint32(src[s] >> 2) + switch { + case x < 60: + s++ + case x == 60: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-1]) + case x == 61: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-2]) | uint32(src[s-1])<<8 + case x == 62: + s += 4 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 + case x == 63: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 + } + length = int(x) + 1 + if length <= 0 { + return decodeErrCodeUnsupportedLiteralLength + } + if length > len(dst)-d || length > len(src)-s { + return decodeErrCodeCorrupt + } + copy(dst[d:], src[s:s+length]) + d += length + s += length + continue + + case tagCopy1: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 4 + int(src[s-2])>>2&0x7 + offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) + + case tagCopy2: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 1 + int(src[s-3])>>2 + offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) + + case tagCopy4: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 1 + int(src[s-5])>>2 + offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) + } + + if offset <= 0 || d < offset || length > len(dst)-d { + return decodeErrCodeCorrupt + } + // Copy from an earlier sub-slice of dst to a later sub-slice. Unlike + // the built-in copy function, this byte-by-byte copy always runs + // forwards, even if the slices overlap. Conceptually, this is: + // + // d += forwardCopy(dst[d:d+length], dst[d-offset:]) + for end := d + length; d != end; d++ { + dst[d] = dst[d-offset] + } + } + if d != len(dst) { + return decodeErrCodeCorrupt + } + return 0 +} diff --git a/vendor/github.com/golang/snappy/encode.go b/vendor/github.com/golang/snappy/encode.go new file mode 100644 index 0000000..8d393e9 --- /dev/null +++ b/vendor/github.com/golang/snappy/encode.go @@ -0,0 +1,285 @@ +// Copyright 2011 The Snappy-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 snappy + +import ( + "encoding/binary" + "errors" + "io" +) + +// Encode returns the encoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire encoded block. +// Otherwise, a newly allocated slice will be returned. +// +// The dst and src must not overlap. It is valid to pass a nil dst. +func Encode(dst, src []byte) []byte { + if n := MaxEncodedLen(len(src)); n < 0 { + panic(ErrTooLarge) + } else if len(dst) < n { + dst = make([]byte, n) + } + + // The block starts with the varint-encoded length of the decompressed bytes. + d := binary.PutUvarint(dst, uint64(len(src))) + + for len(src) > 0 { + p := src + src = nil + if len(p) > maxBlockSize { + p, src = p[:maxBlockSize], p[maxBlockSize:] + } + if len(p) < minNonLiteralBlockSize { + d += emitLiteral(dst[d:], p) + } else { + d += encodeBlock(dst[d:], p) + } + } + return dst[:d] +} + +// inputMargin is the minimum number of extra input bytes to keep, inside +// encodeBlock's inner loop. On some architectures, this margin lets us +// implement a fast path for emitLiteral, where the copy of short (<= 16 byte) +// literals can be implemented as a single load to and store from a 16-byte +// register. That literal's actual length can be as short as 1 byte, so this +// can copy up to 15 bytes too much, but that's OK as subsequent iterations of +// the encoding loop will fix up the copy overrun, and this inputMargin ensures +// that we don't overrun the dst and src buffers. +const inputMargin = 16 - 1 + +// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that +// could be encoded with a copy tag. This is the minimum with respect to the +// algorithm used by encodeBlock, not a minimum enforced by the file format. +// +// The encoded output must start with at least a 1 byte literal, as there are +// no previous bytes to copy. A minimal (1 byte) copy after that, generated +// from an emitCopy call in encodeBlock's main loop, would require at least +// another inputMargin bytes, for the reason above: we want any emitLiteral +// calls inside encodeBlock's main loop to use the fast path if possible, which +// requires being able to overrun by inputMargin bytes. Thus, +// minNonLiteralBlockSize equals 1 + 1 + inputMargin. +// +// The C++ code doesn't use this exact threshold, but it could, as discussed at +// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion +// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an +// optimization. It should not affect the encoded form. This is tested by +// TestSameEncodingAsCppShortCopies. +const minNonLiteralBlockSize = 1 + 1 + inputMargin + +// MaxEncodedLen returns the maximum length of a snappy block, given its +// uncompressed length. +// +// It will return a negative value if srcLen is too large to encode. +func MaxEncodedLen(srcLen int) int { + n := uint64(srcLen) + if n > 0xffffffff { + return -1 + } + // Compressed data can be defined as: + // compressed := item* literal* + // item := literal* copy + // + // The trailing literal sequence has a space blowup of at most 62/60 + // since a literal of length 60 needs one tag byte + one extra byte + // for length information. + // + // Item blowup is trickier to measure. Suppose the "copy" op copies + // 4 bytes of data. Because of a special check in the encoding code, + // we produce a 4-byte copy only if the offset is < 65536. Therefore + // the copy op takes 3 bytes to encode, and this type of item leads + // to at most the 62/60 blowup for representing literals. + // + // Suppose the "copy" op copies 5 bytes of data. If the offset is big + // enough, it will take 5 bytes to encode the copy op. Therefore the + // worst case here is a one-byte literal followed by a five-byte copy. + // That is, 6 bytes of input turn into 7 bytes of "compressed" data. + // + // This last factor dominates the blowup, so the final estimate is: + n = 32 + n + n/6 + if n > 0xffffffff { + return -1 + } + return int(n) +} + +var errClosed = errors.New("snappy: Writer is closed") + +// NewWriter returns a new Writer that compresses to w. +// +// The Writer returned does not buffer writes. There is no need to Flush or +// Close such a Writer. +// +// Deprecated: the Writer returned is not suitable for many small writes, only +// for few large writes. Use NewBufferedWriter instead, which is efficient +// regardless of the frequency and shape of the writes, and remember to Close +// that Writer when done. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + obuf: make([]byte, obufLen), + } +} + +// NewBufferedWriter returns a new Writer that compresses to w, using the +// framing format described at +// https://github.com/google/snappy/blob/master/framing_format.txt +// +// The Writer returned buffers writes. Users must call Close to guarantee all +// data has been forwarded to the underlying io.Writer. They may also call +// Flush zero or more times before calling Close. +func NewBufferedWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + ibuf: make([]byte, 0, maxBlockSize), + obuf: make([]byte, obufLen), + } +} + +// Writer is an io.Writer that can write Snappy-compressed bytes. +type Writer struct { + w io.Writer + err error + + // ibuf is a buffer for the incoming (uncompressed) bytes. + // + // Its use is optional. For backwards compatibility, Writers created by the + // NewWriter function have ibuf == nil, do not buffer incoming bytes, and + // therefore do not need to be Flush'ed or Close'd. + ibuf []byte + + // obuf is a buffer for the outgoing (compressed) bytes. + obuf []byte + + // wroteStreamHeader is whether we have written the stream header. + wroteStreamHeader bool +} + +// Reset discards the writer's state and switches the Snappy writer to write to +// w. This permits reusing a Writer rather than allocating a new one. +func (w *Writer) Reset(writer io.Writer) { + w.w = writer + w.err = nil + if w.ibuf != nil { + w.ibuf = w.ibuf[:0] + } + w.wroteStreamHeader = false +} + +// Write satisfies the io.Writer interface. +func (w *Writer) Write(p []byte) (nRet int, errRet error) { + if w.ibuf == nil { + // Do not buffer incoming bytes. This does not perform or compress well + // if the caller of Writer.Write writes many small slices. This + // behavior is therefore deprecated, but still supported for backwards + // compatibility with code that doesn't explicitly Flush or Close. + return w.write(p) + } + + // The remainder of this method is based on bufio.Writer.Write from the + // standard library. + + for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil { + var n int + if len(w.ibuf) == 0 { + // Large write, empty buffer. + // Write directly from p to avoid copy. + n, _ = w.write(p) + } else { + n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) + w.ibuf = w.ibuf[:len(w.ibuf)+n] + w.Flush() + } + nRet += n + p = p[n:] + } + if w.err != nil { + return nRet, w.err + } + n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) + w.ibuf = w.ibuf[:len(w.ibuf)+n] + nRet += n + return nRet, nil +} + +func (w *Writer) write(p []byte) (nRet int, errRet error) { + if w.err != nil { + return 0, w.err + } + for len(p) > 0 { + obufStart := len(magicChunk) + if !w.wroteStreamHeader { + w.wroteStreamHeader = true + copy(w.obuf, magicChunk) + obufStart = 0 + } + + var uncompressed []byte + if len(p) > maxBlockSize { + uncompressed, p = p[:maxBlockSize], p[maxBlockSize:] + } else { + uncompressed, p = p, nil + } + checksum := crc(uncompressed) + + // Compress the buffer, discarding the result if the improvement + // isn't at least 12.5%. + compressed := Encode(w.obuf[obufHeaderLen:], uncompressed) + chunkType := uint8(chunkTypeCompressedData) + chunkLen := 4 + len(compressed) + obufEnd := obufHeaderLen + len(compressed) + if len(compressed) >= len(uncompressed)-len(uncompressed)/8 { + chunkType = chunkTypeUncompressedData + chunkLen = 4 + len(uncompressed) + obufEnd = obufHeaderLen + } + + // Fill in the per-chunk header that comes before the body. + w.obuf[len(magicChunk)+0] = chunkType + w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0) + w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8) + w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16) + w.obuf[len(magicChunk)+4] = uint8(checksum >> 0) + w.obuf[len(magicChunk)+5] = uint8(checksum >> 8) + w.obuf[len(magicChunk)+6] = uint8(checksum >> 16) + w.obuf[len(magicChunk)+7] = uint8(checksum >> 24) + + if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil { + w.err = err + return nRet, err + } + if chunkType == chunkTypeUncompressedData { + if _, err := w.w.Write(uncompressed); err != nil { + w.err = err + return nRet, err + } + } + nRet += len(uncompressed) + } + return nRet, nil +} + +// Flush flushes the Writer to its underlying io.Writer. +func (w *Writer) Flush() error { + if w.err != nil { + return w.err + } + if len(w.ibuf) == 0 { + return nil + } + w.write(w.ibuf) + w.ibuf = w.ibuf[:0] + return w.err +} + +// Close calls Flush and then closes the Writer. +func (w *Writer) Close() error { + w.Flush() + ret := w.err + if w.err == nil { + w.err = errClosed + } + return ret +} diff --git a/vendor/github.com/golang/snappy/encode_amd64.go b/vendor/github.com/golang/snappy/encode_amd64.go new file mode 100644 index 0000000..150d91b --- /dev/null +++ b/vendor/github.com/golang/snappy/encode_amd64.go @@ -0,0 +1,29 @@ +// Copyright 2016 The Snappy-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 !appengine +// +build gc +// +build !noasm + +package snappy + +// emitLiteral has the same semantics as in encode_other.go. +// +//go:noescape +func emitLiteral(dst, lit []byte) int + +// emitCopy has the same semantics as in encode_other.go. +// +//go:noescape +func emitCopy(dst []byte, offset, length int) int + +// extendMatch has the same semantics as in encode_other.go. +// +//go:noescape +func extendMatch(src []byte, i, j int) int + +// encodeBlock has the same semantics as in encode_other.go. +// +//go:noescape +func encodeBlock(dst, src []byte) (d int) diff --git a/vendor/github.com/golang/snappy/encode_amd64.s b/vendor/github.com/golang/snappy/encode_amd64.s new file mode 100644 index 0000000..adfd979 --- /dev/null +++ b/vendor/github.com/golang/snappy/encode_amd64.s @@ -0,0 +1,730 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine +// +build gc +// +build !noasm + +#include "textflag.h" + +// The XXX lines assemble on Go 1.4, 1.5 and 1.7, but not 1.6, due to a +// Go toolchain regression. See https://github.com/golang/go/issues/15426 and +// https://github.com/golang/snappy/issues/29 +// +// As a workaround, the package was built with a known good assembler, and +// those instructions were disassembled by "objdump -d" to yield the +// 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 +// style comments, in AT&T asm syntax. Note that rsp here is a physical +// register, not Go/asm's SP pseudo-register (see https://golang.org/doc/asm). +// The instructions were then encoded as "BYTE $0x.." sequences, which assemble +// fine on Go 1.6. + +// The asm code generally follows the pure Go code in encode_other.go, except +// where marked with a "!!!". + +// ---------------------------------------------------------------------------- + +// func emitLiteral(dst, lit []byte) int +// +// All local variables fit into registers. The register allocation: +// - AX len(lit) +// - BX n +// - DX return value +// - DI &dst[i] +// - R10 &lit[0] +// +// The 24 bytes of stack space is to call runtime·memmove. +// +// The unusual register allocation of local variables, such as R10 for the +// source pointer, matches the allocation used at the call site in encodeBlock, +// which makes it easier to manually inline this function. +TEXT ·emitLiteral(SB), NOSPLIT, $24-56 + MOVQ dst_base+0(FP), DI + MOVQ lit_base+24(FP), R10 + MOVQ lit_len+32(FP), AX + MOVQ AX, DX + MOVL AX, BX + SUBL $1, BX + + CMPL BX, $60 + JLT oneByte + CMPL BX, $256 + JLT twoBytes + +threeBytes: + MOVB $0xf4, 0(DI) + MOVW BX, 1(DI) + ADDQ $3, DI + ADDQ $3, DX + JMP memmove + +twoBytes: + MOVB $0xf0, 0(DI) + MOVB BX, 1(DI) + ADDQ $2, DI + ADDQ $2, DX + JMP memmove + +oneByte: + SHLB $2, BX + MOVB BX, 0(DI) + ADDQ $1, DI + ADDQ $1, DX + +memmove: + MOVQ DX, ret+48(FP) + + // copy(dst[i:], lit) + // + // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push + // DI, R10 and AX as arguments. + MOVQ DI, 0(SP) + MOVQ R10, 8(SP) + MOVQ AX, 16(SP) + CALL runtime·memmove(SB) + RET + +// ---------------------------------------------------------------------------- + +// func emitCopy(dst []byte, offset, length int) int +// +// All local variables fit into registers. The register allocation: +// - AX length +// - SI &dst[0] +// - DI &dst[i] +// - R11 offset +// +// The unusual register allocation of local variables, such as R11 for the +// offset, matches the allocation used at the call site in encodeBlock, which +// makes it easier to manually inline this function. +TEXT ·emitCopy(SB), NOSPLIT, $0-48 + MOVQ dst_base+0(FP), DI + MOVQ DI, SI + MOVQ offset+24(FP), R11 + MOVQ length+32(FP), AX + +loop0: + // for length >= 68 { etc } + CMPL AX, $68 + JLT step1 + + // Emit a length 64 copy, encoded as 3 bytes. + MOVB $0xfe, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + SUBL $64, AX + JMP loop0 + +step1: + // if length > 64 { etc } + CMPL AX, $64 + JLE step2 + + // Emit a length 60 copy, encoded as 3 bytes. + MOVB $0xee, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + SUBL $60, AX + +step2: + // if length >= 12 || offset >= 2048 { goto step3 } + CMPL AX, $12 + JGE step3 + CMPL R11, $2048 + JGE step3 + + // Emit the remaining copy, encoded as 2 bytes. + MOVB R11, 1(DI) + SHRL $8, R11 + SHLB $5, R11 + SUBB $4, AX + SHLB $2, AX + ORB AX, R11 + ORB $1, R11 + MOVB R11, 0(DI) + ADDQ $2, DI + + // Return the number of bytes written. + SUBQ SI, DI + MOVQ DI, ret+40(FP) + RET + +step3: + // Emit the remaining copy, encoded as 3 bytes. + SUBL $1, AX + SHLB $2, AX + ORB $2, AX + MOVB AX, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + + // Return the number of bytes written. + SUBQ SI, DI + MOVQ DI, ret+40(FP) + RET + +// ---------------------------------------------------------------------------- + +// func extendMatch(src []byte, i, j int) int +// +// All local variables fit into registers. The register allocation: +// - DX &src[0] +// - SI &src[j] +// - R13 &src[len(src) - 8] +// - R14 &src[len(src)] +// - R15 &src[i] +// +// The unusual register allocation of local variables, such as R15 for a source +// pointer, matches the allocation used at the call site in encodeBlock, which +// makes it easier to manually inline this function. +TEXT ·extendMatch(SB), NOSPLIT, $0-48 + MOVQ src_base+0(FP), DX + MOVQ src_len+8(FP), R14 + MOVQ i+24(FP), R15 + MOVQ j+32(FP), SI + ADDQ DX, R14 + ADDQ DX, R15 + ADDQ DX, SI + MOVQ R14, R13 + SUBQ $8, R13 + +cmp8: + // As long as we are 8 or more bytes before the end of src, we can load and + // compare 8 bytes at a time. If those 8 bytes are equal, repeat. + CMPQ SI, R13 + JA cmp1 + MOVQ (R15), AX + MOVQ (SI), BX + CMPQ AX, BX + JNE bsf + ADDQ $8, R15 + ADDQ $8, SI + JMP cmp8 + +bsf: + // If those 8 bytes were not equal, XOR the two 8 byte values, and return + // the index of the first byte that differs. The BSF instruction finds the + // least significant 1 bit, the amd64 architecture is little-endian, and + // the shift by 3 converts a bit index to a byte index. + XORQ AX, BX + BSFQ BX, BX + SHRQ $3, BX + ADDQ BX, SI + + // Convert from &src[ret] to ret. + SUBQ DX, SI + MOVQ SI, ret+40(FP) + RET + +cmp1: + // In src's tail, compare 1 byte at a time. + CMPQ SI, R14 + JAE extendMatchEnd + MOVB (R15), AX + MOVB (SI), BX + CMPB AX, BX + JNE extendMatchEnd + ADDQ $1, R15 + ADDQ $1, SI + JMP cmp1 + +extendMatchEnd: + // Convert from &src[ret] to ret. + SUBQ DX, SI + MOVQ SI, ret+40(FP) + RET + +// ---------------------------------------------------------------------------- + +// func encodeBlock(dst, src []byte) (d int) +// +// All local variables fit into registers, other than "var table". The register +// allocation: +// - AX . . +// - BX . . +// - CX 56 shift (note that amd64 shifts by non-immediates must use CX). +// - DX 64 &src[0], tableSize +// - SI 72 &src[s] +// - DI 80 &dst[d] +// - R9 88 sLimit +// - R10 . &src[nextEmit] +// - R11 96 prevHash, currHash, nextHash, offset +// - R12 104 &src[base], skip +// - R13 . &src[nextS], &src[len(src) - 8] +// - R14 . len(src), bytesBetweenHashLookups, &src[len(src)], x +// - R15 112 candidate +// +// The second column (56, 64, etc) is the stack offset to spill the registers +// when calling other functions. We could pack this slightly tighter, but it's +// simpler to have a dedicated spill map independent of the function called. +// +// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An +// extra 56 bytes, to call other functions, and an extra 64 bytes, to spill +// local variables (registers) during calls gives 32768 + 56 + 64 = 32888. +TEXT ·encodeBlock(SB), 0, $32888-56 + MOVQ dst_base+0(FP), DI + MOVQ src_base+24(FP), SI + MOVQ src_len+32(FP), R14 + + // shift, tableSize := uint32(32-8), 1<<8 + MOVQ $24, CX + MOVQ $256, DX + +calcShift: + // for ; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 { + // shift-- + // } + CMPQ DX, $16384 + JGE varTable + CMPQ DX, R14 + JGE varTable + SUBQ $1, CX + SHLQ $1, DX + JMP calcShift + +varTable: + // var table [maxTableSize]uint16 + // + // In the asm code, unlike the Go code, we can zero-initialize only the + // first tableSize elements. Each uint16 element is 2 bytes and each MOVOU + // writes 16 bytes, so we can do only tableSize/8 writes instead of the + // 2048 writes that would zero-initialize all of table's 32768 bytes. + SHRQ $3, DX + LEAQ table-32768(SP), BX + PXOR X0, X0 + +memclr: + MOVOU X0, 0(BX) + ADDQ $16, BX + SUBQ $1, DX + JNZ memclr + + // !!! DX = &src[0] + MOVQ SI, DX + + // sLimit := len(src) - inputMargin + MOVQ R14, R9 + SUBQ $15, R9 + + // !!! Pre-emptively spill CX, DX and R9 to the stack. Their values don't + // change for the rest of the function. + MOVQ CX, 56(SP) + MOVQ DX, 64(SP) + MOVQ R9, 88(SP) + + // nextEmit := 0 + MOVQ DX, R10 + + // s := 1 + ADDQ $1, SI + + // nextHash := hash(load32(src, s), shift) + MOVL 0(SI), R11 + IMULL $0x1e35a7bd, R11 + SHRL CX, R11 + +outer: + // for { etc } + + // skip := 32 + MOVQ $32, R12 + + // nextS := s + MOVQ SI, R13 + + // candidate := 0 + MOVQ $0, R15 + +inner0: + // for { etc } + + // s := nextS + MOVQ R13, SI + + // bytesBetweenHashLookups := skip >> 5 + MOVQ R12, R14 + SHRQ $5, R14 + + // nextS = s + bytesBetweenHashLookups + ADDQ R14, R13 + + // skip += bytesBetweenHashLookups + ADDQ R14, R12 + + // if nextS > sLimit { goto emitRemainder } + MOVQ R13, AX + SUBQ DX, AX + CMPQ AX, R9 + JA emitRemainder + + // candidate = int(table[nextHash]) + // XXX: MOVWQZX table-32768(SP)(R11*2), R15 + // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 + BYTE $0x4e + BYTE $0x0f + BYTE $0xb7 + BYTE $0x7c + BYTE $0x5c + BYTE $0x78 + + // table[nextHash] = uint16(s) + MOVQ SI, AX + SUBQ DX, AX + + // XXX: MOVW AX, table-32768(SP)(R11*2) + // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) + BYTE $0x66 + BYTE $0x42 + BYTE $0x89 + BYTE $0x44 + BYTE $0x5c + BYTE $0x78 + + // nextHash = hash(load32(src, nextS), shift) + MOVL 0(R13), R11 + IMULL $0x1e35a7bd, R11 + SHRL CX, R11 + + // if load32(src, s) != load32(src, candidate) { continue } break + MOVL 0(SI), AX + MOVL (DX)(R15*1), BX + CMPL AX, BX + JNE inner0 + +fourByteMatch: + // As per the encode_other.go code: + // + // A 4-byte match has been found. We'll later see etc. + + // !!! Jump to a fast path for short (<= 16 byte) literals. See the comment + // on inputMargin in encode.go. + MOVQ SI, AX + SUBQ R10, AX + CMPQ AX, $16 + JLE emitLiteralFastPath + + // ---------------------------------------- + // Begin inline of the emitLiteral call. + // + // d += emitLiteral(dst[d:], src[nextEmit:s]) + + MOVL AX, BX + SUBL $1, BX + + CMPL BX, $60 + JLT inlineEmitLiteralOneByte + CMPL BX, $256 + JLT inlineEmitLiteralTwoBytes + +inlineEmitLiteralThreeBytes: + MOVB $0xf4, 0(DI) + MOVW BX, 1(DI) + ADDQ $3, DI + JMP inlineEmitLiteralMemmove + +inlineEmitLiteralTwoBytes: + MOVB $0xf0, 0(DI) + MOVB BX, 1(DI) + ADDQ $2, DI + JMP inlineEmitLiteralMemmove + +inlineEmitLiteralOneByte: + SHLB $2, BX + MOVB BX, 0(DI) + ADDQ $1, DI + +inlineEmitLiteralMemmove: + // Spill local variables (registers) onto the stack; call; unspill. + // + // copy(dst[i:], lit) + // + // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push + // DI, R10 and AX as arguments. + MOVQ DI, 0(SP) + MOVQ R10, 8(SP) + MOVQ AX, 16(SP) + ADDQ AX, DI // Finish the "d +=" part of "d += emitLiteral(etc)". + MOVQ SI, 72(SP) + MOVQ DI, 80(SP) + MOVQ R15, 112(SP) + CALL runtime·memmove(SB) + MOVQ 56(SP), CX + MOVQ 64(SP), DX + MOVQ 72(SP), SI + MOVQ 80(SP), DI + MOVQ 88(SP), R9 + MOVQ 112(SP), R15 + JMP inner1 + +inlineEmitLiteralEnd: + // End inline of the emitLiteral call. + // ---------------------------------------- + +emitLiteralFastPath: + // !!! Emit the 1-byte encoding "uint8(len(lit)-1)<<2". + MOVB AX, BX + SUBB $1, BX + SHLB $2, BX + MOVB BX, (DI) + ADDQ $1, DI + + // !!! Implement the copy from lit to dst as a 16-byte load and store. + // (Encode's documentation says that dst and src must not overlap.) + // + // This always copies 16 bytes, instead of only len(lit) bytes, but that's + // OK. Subsequent iterations will fix up the overrun. + // + // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or + // 16-byte loads and stores. This technique probably wouldn't be as + // effective on architectures that are fussier about alignment. + MOVOU 0(R10), X0 + MOVOU X0, 0(DI) + ADDQ AX, DI + +inner1: + // for { etc } + + // base := s + MOVQ SI, R12 + + // !!! offset := base - candidate + MOVQ R12, R11 + SUBQ R15, R11 + SUBQ DX, R11 + + // ---------------------------------------- + // Begin inline of the extendMatch call. + // + // s = extendMatch(src, candidate+4, s+4) + + // !!! R14 = &src[len(src)] + MOVQ src_len+32(FP), R14 + ADDQ DX, R14 + + // !!! R13 = &src[len(src) - 8] + MOVQ R14, R13 + SUBQ $8, R13 + + // !!! R15 = &src[candidate + 4] + ADDQ $4, R15 + ADDQ DX, R15 + + // !!! s += 4 + ADDQ $4, SI + +inlineExtendMatchCmp8: + // As long as we are 8 or more bytes before the end of src, we can load and + // compare 8 bytes at a time. If those 8 bytes are equal, repeat. + CMPQ SI, R13 + JA inlineExtendMatchCmp1 + MOVQ (R15), AX + MOVQ (SI), BX + CMPQ AX, BX + JNE inlineExtendMatchBSF + ADDQ $8, R15 + ADDQ $8, SI + JMP inlineExtendMatchCmp8 + +inlineExtendMatchBSF: + // If those 8 bytes were not equal, XOR the two 8 byte values, and return + // the index of the first byte that differs. The BSF instruction finds the + // least significant 1 bit, the amd64 architecture is little-endian, and + // the shift by 3 converts a bit index to a byte index. + XORQ AX, BX + BSFQ BX, BX + SHRQ $3, BX + ADDQ BX, SI + JMP inlineExtendMatchEnd + +inlineExtendMatchCmp1: + // In src's tail, compare 1 byte at a time. + CMPQ SI, R14 + JAE inlineExtendMatchEnd + MOVB (R15), AX + MOVB (SI), BX + CMPB AX, BX + JNE inlineExtendMatchEnd + ADDQ $1, R15 + ADDQ $1, SI + JMP inlineExtendMatchCmp1 + +inlineExtendMatchEnd: + // End inline of the extendMatch call. + // ---------------------------------------- + + // ---------------------------------------- + // Begin inline of the emitCopy call. + // + // d += emitCopy(dst[d:], base-candidate, s-base) + + // !!! length := s - base + MOVQ SI, AX + SUBQ R12, AX + +inlineEmitCopyLoop0: + // for length >= 68 { etc } + CMPL AX, $68 + JLT inlineEmitCopyStep1 + + // Emit a length 64 copy, encoded as 3 bytes. + MOVB $0xfe, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + SUBL $64, AX + JMP inlineEmitCopyLoop0 + +inlineEmitCopyStep1: + // if length > 64 { etc } + CMPL AX, $64 + JLE inlineEmitCopyStep2 + + // Emit a length 60 copy, encoded as 3 bytes. + MOVB $0xee, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + SUBL $60, AX + +inlineEmitCopyStep2: + // if length >= 12 || offset >= 2048 { goto inlineEmitCopyStep3 } + CMPL AX, $12 + JGE inlineEmitCopyStep3 + CMPL R11, $2048 + JGE inlineEmitCopyStep3 + + // Emit the remaining copy, encoded as 2 bytes. + MOVB R11, 1(DI) + SHRL $8, R11 + SHLB $5, R11 + SUBB $4, AX + SHLB $2, AX + ORB AX, R11 + ORB $1, R11 + MOVB R11, 0(DI) + ADDQ $2, DI + JMP inlineEmitCopyEnd + +inlineEmitCopyStep3: + // Emit the remaining copy, encoded as 3 bytes. + SUBL $1, AX + SHLB $2, AX + ORB $2, AX + MOVB AX, 0(DI) + MOVW R11, 1(DI) + ADDQ $3, DI + +inlineEmitCopyEnd: + // End inline of the emitCopy call. + // ---------------------------------------- + + // nextEmit = s + MOVQ SI, R10 + + // if s >= sLimit { goto emitRemainder } + MOVQ SI, AX + SUBQ DX, AX + CMPQ AX, R9 + JAE emitRemainder + + // As per the encode_other.go code: + // + // We could immediately etc. + + // x := load64(src, s-1) + MOVQ -1(SI), R14 + + // prevHash := hash(uint32(x>>0), shift) + MOVL R14, R11 + IMULL $0x1e35a7bd, R11 + SHRL CX, R11 + + // table[prevHash] = uint16(s-1) + MOVQ SI, AX + SUBQ DX, AX + SUBQ $1, AX + + // XXX: MOVW AX, table-32768(SP)(R11*2) + // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) + BYTE $0x66 + BYTE $0x42 + BYTE $0x89 + BYTE $0x44 + BYTE $0x5c + BYTE $0x78 + + // currHash := hash(uint32(x>>8), shift) + SHRQ $8, R14 + MOVL R14, R11 + IMULL $0x1e35a7bd, R11 + SHRL CX, R11 + + // candidate = int(table[currHash]) + // XXX: MOVWQZX table-32768(SP)(R11*2), R15 + // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 + BYTE $0x4e + BYTE $0x0f + BYTE $0xb7 + BYTE $0x7c + BYTE $0x5c + BYTE $0x78 + + // table[currHash] = uint16(s) + ADDQ $1, AX + + // XXX: MOVW AX, table-32768(SP)(R11*2) + // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) + BYTE $0x66 + BYTE $0x42 + BYTE $0x89 + BYTE $0x44 + BYTE $0x5c + BYTE $0x78 + + // if uint32(x>>8) == load32(src, candidate) { continue } + MOVL (DX)(R15*1), BX + CMPL R14, BX + JEQ inner1 + + // nextHash = hash(uint32(x>>16), shift) + SHRQ $8, R14 + MOVL R14, R11 + IMULL $0x1e35a7bd, R11 + SHRL CX, R11 + + // s++ + ADDQ $1, SI + + // break out of the inner1 for loop, i.e. continue the outer loop. + JMP outer + +emitRemainder: + // if nextEmit < len(src) { etc } + MOVQ src_len+32(FP), AX + ADDQ DX, AX + CMPQ R10, AX + JEQ encodeBlockEnd + + // d += emitLiteral(dst[d:], src[nextEmit:]) + // + // Push args. + MOVQ DI, 0(SP) + MOVQ $0, 8(SP) // Unnecessary, as the callee ignores it, but conservative. + MOVQ $0, 16(SP) // Unnecessary, as the callee ignores it, but conservative. + MOVQ R10, 24(SP) + SUBQ R10, AX + MOVQ AX, 32(SP) + MOVQ AX, 40(SP) // Unnecessary, as the callee ignores it, but conservative. + + // Spill local variables (registers) onto the stack; call; unspill. + MOVQ DI, 80(SP) + CALL ·emitLiteral(SB) + MOVQ 80(SP), DI + + // Finish the "d +=" part of "d += emitLiteral(etc)". + ADDQ 48(SP), DI + +encodeBlockEnd: + MOVQ dst_base+0(FP), AX + SUBQ AX, DI + MOVQ DI, d+48(FP) + RET diff --git a/vendor/github.com/golang/snappy/encode_other.go b/vendor/github.com/golang/snappy/encode_other.go new file mode 100644 index 0000000..dbcae90 --- /dev/null +++ b/vendor/github.com/golang/snappy/encode_other.go @@ -0,0 +1,238 @@ +// Copyright 2016 The Snappy-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 !amd64 appengine !gc noasm + +package snappy + +func load32(b []byte, i int) uint32 { + b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load64(b []byte, i int) uint64 { + b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +// emitLiteral writes a literal chunk and returns the number of bytes written. +// +// It assumes that: +// dst is long enough to hold the encoded bytes +// 1 <= len(lit) && len(lit) <= 65536 +func emitLiteral(dst, lit []byte) int { + i, n := 0, uint(len(lit)-1) + switch { + case n < 60: + dst[0] = uint8(n)<<2 | tagLiteral + i = 1 + case n < 1<<8: + dst[0] = 60<<2 | tagLiteral + dst[1] = uint8(n) + i = 2 + default: + dst[0] = 61<<2 | tagLiteral + dst[1] = uint8(n) + dst[2] = uint8(n >> 8) + i = 3 + } + return i + copy(dst[i:], lit) +} + +// emitCopy writes a copy chunk and returns the number of bytes written. +// +// It assumes that: +// dst is long enough to hold the encoded bytes +// 1 <= offset && offset <= 65535 +// 4 <= length && length <= 65535 +func emitCopy(dst []byte, offset, length int) int { + i := 0 + // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The + // threshold for this loop is a little higher (at 68 = 64 + 4), and the + // length emitted down below is is a little lower (at 60 = 64 - 4), because + // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed + // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as + // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as + // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a + // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an + // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1. + for length >= 68 { + // Emit a length 64 copy, encoded as 3 bytes. + dst[i+0] = 63<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + i += 3 + length -= 64 + } + if length > 64 { + // Emit a length 60 copy, encoded as 3 bytes. + dst[i+0] = 59<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + i += 3 + length -= 60 + } + if length >= 12 || offset >= 2048 { + // Emit the remaining copy, encoded as 3 bytes. + dst[i+0] = uint8(length-1)<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + return i + 3 + } + // Emit the remaining copy, encoded as 2 bytes. + dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1 + dst[i+1] = uint8(offset) + return i + 2 +} + +// extendMatch returns the largest k such that k <= len(src) and that +// src[i:i+k-j] and src[j:k] have the same contents. +// +// It assumes that: +// 0 <= i && i < j && j <= len(src) +func extendMatch(src []byte, i, j int) int { + for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 { + } + return j +} + +func hash(u, shift uint32) uint32 { + return (u * 0x1e35a7bd) >> shift +} + +// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It +// assumes that the varint-encoded length of the decompressed bytes has already +// been written. +// +// It also assumes that: +// len(dst) >= MaxEncodedLen(len(src)) && +// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize +func encodeBlock(dst, src []byte) (d int) { + // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. + // The table element type is uint16, as s < sLimit and sLimit < len(src) + // and len(src) <= maxBlockSize and maxBlockSize == 65536. + const ( + maxTableSize = 1 << 14 + // tableMask is redundant, but helps the compiler eliminate bounds + // checks. + tableMask = maxTableSize - 1 + ) + shift := uint32(32 - 8) + for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 { + shift-- + } + // In Go, all array elements are zero-initialized, so there is no advantage + // to a smaller tableSize per se. However, it matches the C++ algorithm, + // and in the asm versions of this code, we can get away with zeroing only + // the first tableSize elements. + var table [maxTableSize]uint16 + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := len(src) - inputMargin + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := 0 + + // The encoded form must start with a literal, as there are no previous + // bytes to copy, so we start looking for hash matches at s == 1. + s := 1 + nextHash := hash(load32(src, s), shift) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := 32 + + nextS := s + candidate := 0 + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidate = int(table[nextHash&tableMask]) + table[nextHash&tableMask] = uint16(s) + nextHash = hash(load32(src, nextS), shift) + if load32(src, s) == load32(src, candidate) { + break + } + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + d += emitLiteral(dst[d:], src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + base := s + + // Extend the 4-byte match as long as possible. + // + // This is an inlined version of: + // s = extendMatch(src, candidate+4, s+4) + s += 4 + for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 { + } + + d += emitCopy(dst[d:], base-candidate, s-base) + nextEmit = s + if s >= sLimit { + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load64(src, s-1) + prevHash := hash(uint32(x>>0), shift) + table[prevHash&tableMask] = uint16(s - 1) + currHash := hash(uint32(x>>8), shift) + candidate = int(table[currHash&tableMask]) + table[currHash&tableMask] = uint16(s) + if uint32(x>>8) != load32(src, candidate) { + nextHash = hash(uint32(x>>16), shift) + s++ + break + } + } + } + +emitRemainder: + if nextEmit < len(src) { + d += emitLiteral(dst[d:], src[nextEmit:]) + } + return d +} diff --git a/vendor/github.com/golang/snappy/snappy.go b/vendor/github.com/golang/snappy/snappy.go new file mode 100644 index 0000000..ece692e --- /dev/null +++ b/vendor/github.com/golang/snappy/snappy.go @@ -0,0 +1,98 @@ +// Copyright 2011 The Snappy-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 snappy implements the Snappy compression format. It aims for very +// high speeds and reasonable compression. +// +// There are actually two Snappy formats: block and stream. They are related, +// but different: trying to decompress block-compressed data as a Snappy stream +// will fail, and vice versa. The block format is the Decode and Encode +// functions and the stream format is the Reader and Writer types. +// +// The block format, the more common case, is used when the complete size (the +// number of bytes) of the original data is known upfront, at the time +// compression starts. The stream format, also known as the framing format, is +// for when that isn't always true. +// +// The canonical, C++ implementation is at https://github.com/google/snappy and +// it only implements the block format. +package snappy // import "github.com/golang/snappy" + +import ( + "hash/crc32" +) + +/* +Each encoded block begins with the varint-encoded length of the decoded data, +followed by a sequence of chunks. Chunks begin and end on byte boundaries. The +first byte of each chunk is broken into its 2 least and 6 most significant bits +called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag. +Zero means a literal tag. All other values mean a copy tag. + +For literal tags: + - If m < 60, the next 1 + m bytes are literal bytes. + - Otherwise, let n be the little-endian unsigned integer denoted by the next + m - 59 bytes. The next 1 + n bytes after that are literal bytes. + +For copy tags, length bytes are copied from offset bytes ago, in the style of +Lempel-Ziv compression algorithms. In particular: + - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12). + The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10 + of the offset. The next byte is bits 0-7 of the offset. + - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65). + The length is 1 + m. The offset is the little-endian unsigned integer + denoted by the next 2 bytes. + - For l == 3, this tag is a legacy format that is no longer issued by most + encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in + [1, 65). The length is 1 + m. The offset is the little-endian unsigned + integer denoted by the next 4 bytes. +*/ +const ( + tagLiteral = 0x00 + tagCopy1 = 0x01 + tagCopy2 = 0x02 + tagCopy4 = 0x03 +) + +const ( + checksumSize = 4 + chunkHeaderSize = 4 + magicChunk = "\xff\x06\x00\x00" + magicBody + magicBody = "sNaPpY" + + // maxBlockSize is the maximum size of the input to encodeBlock. It is not + // part of the wire format per se, but some parts of the encoder assume + // that an offset fits into a uint16. + // + // Also, for the framing format (Writer type instead of Encode function), + // https://github.com/google/snappy/blob/master/framing_format.txt says + // that "the uncompressed data in a chunk must be no longer than 65536 + // bytes". + maxBlockSize = 65536 + + // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is + // hard coded to be a const instead of a variable, so that obufLen can also + // be a const. Their equivalence is confirmed by + // TestMaxEncodedLenOfMaxBlockSize. + maxEncodedLenOfMaxBlockSize = 76490 + + obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize + obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize +) + +const ( + chunkTypeCompressedData = 0x00 + chunkTypeUncompressedData = 0x01 + chunkTypePadding = 0xfe + chunkTypeStreamIdentifier = 0xff +) + +var crcTable = crc32.MakeTable(crc32.Castagnoli) + +// crc implements the checksum specified in section 3 of +// https://github.com/google/snappy/blob/master/framing_format.txt +func crc(b []byte) uint32 { + c := crc32.Update(0, crcTable, b) + return uint32(c>>15|c<<17) + 0xa282ead8 +} diff --git a/vendor/github.com/google/gofuzz/.travis.yml b/vendor/github.com/google/gofuzz/.travis.yml new file mode 100644 index 0000000..f8684d9 --- /dev/null +++ b/vendor/github.com/google/gofuzz/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - 1.4 + - 1.3 + - 1.2 + - tip + +install: + - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi + +script: + - go test -cover diff --git a/vendor/github.com/google/gofuzz/CONTRIBUTING.md b/vendor/github.com/google/gofuzz/CONTRIBUTING.md new file mode 100644 index 0000000..51cf5cd --- /dev/null +++ b/vendor/github.com/google/gofuzz/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# How to contribute # + +We'd love to accept your patches and contributions to this project. There are +a just a few small guidelines you need to follow. + + +## Contributor License Agreement ## + +Contributions to any Google project must be accompanied by a Contributor +License Agreement. This is not a copyright **assignment**, it simply gives +Google permission to use and redistribute your contributions as part of the +project. + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual + CLA][]. + + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA][]. + +You generally only need to submit a CLA once, so if you've already submitted +one (even if it was for a different project), you probably don't need to do it +again. + +[individual CLA]: https://developers.google.com/open-source/cla/individual +[corporate CLA]: https://developers.google.com/open-source/cla/corporate + + +## Submitting a patch ## + + 1. It's generally best to start by opening a new issue describing the bug or + feature you're intending to fix. Even if you think it's relatively minor, + it's helpful to know what people are working on. Mention in the initial + issue that you are planning to work on that bug or feature so that it can + be assigned to you. + + 1. Follow the normal process of [forking][] the project, and setup a new + branch to work in. It's important that each group of changes be done in + separate branches in order to ensure that a pull request only includes the + commits related to that bug or feature. + + 1. Go makes it very simple to ensure properly formatted code, so always run + `go fmt` on your code before committing it. You should also run + [golint][] over your code. As noted in the [golint readme][], it's not + strictly necessary that your code be completely "lint-free", but this will + help you find common style issues. + + 1. Any significant changes should almost always be accompanied by tests. The + project already has good test coverage, so look at some of the existing + tests if you're unsure how to go about it. [gocov][] and [gocov-html][] + are invaluable tools for seeing which parts of your code aren't being + exercised by your tests. + + 1. Do your best to have [well-formed commit messages][] for each change. + This provides consistency throughout the project, and ensures that commit + messages are able to be formatted properly by various git tools. + + 1. Finally, push the commits to your fork and submit a [pull request][]. + +[forking]: https://help.github.com/articles/fork-a-repo +[golint]: https://github.com/golang/lint +[golint readme]: https://github.com/golang/lint/blob/master/README +[gocov]: https://github.com/axw/gocov +[gocov-html]: https://github.com/matm/gocov-html +[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits +[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/vendor/github.com/google/gofuzz/LICENSE b/vendor/github.com/google/gofuzz/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/vendor/github.com/google/gofuzz/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/gofuzz/README.md b/vendor/github.com/google/gofuzz/README.md new file mode 100644 index 0000000..64869af --- /dev/null +++ b/vendor/github.com/google/gofuzz/README.md @@ -0,0 +1,71 @@ +gofuzz +====== + +gofuzz is a library for populating go objects with random values. + +[![GoDoc](https://godoc.org/github.com/google/gofuzz?status.png)](https://godoc.org/github.com/google/gofuzz) +[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz) + +This is useful for testing: + +* Do your project's objects really serialize/unserialize correctly in all cases? +* Is there an incorrectly formatted object that will cause your project to panic? + +Import with ```import "github.com/google/gofuzz"``` + +You can use it on single variables: +```go +f := fuzz.New() +var myInt int +f.Fuzz(&myInt) // myInt gets a random value. +``` + +You can use it on maps: +```go +f := fuzz.New().NilChance(0).NumElements(1, 1) +var myMap map[ComplexKeyType]string +f.Fuzz(&myMap) // myMap will have exactly one element. +``` + +Customize the chance of getting a nil pointer: +```go +f := fuzz.New().NilChance(.5) +var fancyStruct struct { + A, B, C, D *string +} +f.Fuzz(&fancyStruct) // About half the pointers should be set. +``` + +You can even customize the randomization completely if needed: +```go +type MyEnum string +const ( + A MyEnum = "A" + B MyEnum = "B" +) +type MyInfo struct { + Type MyEnum + AInfo *string + BInfo *string +} + +f := fuzz.New().NilChance(0).Funcs( + func(e *MyInfo, c fuzz.Continue) { + switch c.Intn(2) { + case 0: + e.Type = A + c.Fuzz(&e.AInfo) + case 1: + e.Type = B + c.Fuzz(&e.BInfo) + } + }, +) + +var myObject MyInfo +f.Fuzz(&myObject) // Type will correspond to whether A or B info is set. +``` + +See more examples in ```example_test.go```. + +Happy testing! diff --git a/vendor/github.com/google/gofuzz/doc.go b/vendor/github.com/google/gofuzz/doc.go new file mode 100644 index 0000000..9f9956d --- /dev/null +++ b/vendor/github.com/google/gofuzz/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package fuzz is a library for populating go objects with random values. +package fuzz diff --git a/vendor/github.com/google/gofuzz/fuzz.go b/vendor/github.com/google/gofuzz/fuzz.go new file mode 100644 index 0000000..1dfa80a --- /dev/null +++ b/vendor/github.com/google/gofuzz/fuzz.go @@ -0,0 +1,487 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fuzz + +import ( + "fmt" + "math/rand" + "reflect" + "time" +) + +// fuzzFuncMap is a map from a type to a fuzzFunc that handles that type. +type fuzzFuncMap map[reflect.Type]reflect.Value + +// Fuzzer knows how to fill any object with random fields. +type Fuzzer struct { + fuzzFuncs fuzzFuncMap + defaultFuzzFuncs fuzzFuncMap + r *rand.Rand + nilChance float64 + minElements int + maxElements int + maxDepth int +} + +// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs, +// RandSource, NilChance, or NumElements in any order. +func New() *Fuzzer { + return NewWithSeed(time.Now().UnixNano()) +} + +func NewWithSeed(seed int64) *Fuzzer { + f := &Fuzzer{ + defaultFuzzFuncs: fuzzFuncMap{ + reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime), + }, + + fuzzFuncs: fuzzFuncMap{}, + r: rand.New(rand.NewSource(seed)), + nilChance: .2, + minElements: 1, + maxElements: 10, + maxDepth: 100, + } + return f +} + +// Funcs adds each entry in fuzzFuncs as a custom fuzzing function. +// +// Each entry in fuzzFuncs must be a function taking two parameters. +// The first parameter must be a pointer or map. It is the variable that +// function will fill with random data. The second parameter must be a +// fuzz.Continue, which will provide a source of randomness and a way +// to automatically continue fuzzing smaller pieces of the first parameter. +// +// These functions are called sensibly, e.g., if you wanted custom string +// fuzzing, the function `func(s *string, c fuzz.Continue)` would get +// called and passed the address of strings. Maps and pointers will always +// be made/new'd for you, ignoring the NilChange option. For slices, it +// doesn't make much sense to pre-create them--Fuzzer doesn't know how +// long you want your slice--so take a pointer to a slice, and make it +// yourself. (If you don't want your map/pointer type pre-made, take a +// pointer to it, and make it yourself.) See the examples for a range of +// custom functions. +func (f *Fuzzer) Funcs(fuzzFuncs ...interface{}) *Fuzzer { + for i := range fuzzFuncs { + v := reflect.ValueOf(fuzzFuncs[i]) + if v.Kind() != reflect.Func { + panic("Need only funcs!") + } + t := v.Type() + if t.NumIn() != 2 || t.NumOut() != 0 { + panic("Need 2 in and 0 out params!") + } + argT := t.In(0) + switch argT.Kind() { + case reflect.Ptr, reflect.Map: + default: + panic("fuzzFunc must take pointer or map type") + } + if t.In(1) != reflect.TypeOf(Continue{}) { + panic("fuzzFunc's second parameter must be type fuzz.Continue") + } + f.fuzzFuncs[argT] = v + } + return f +} + +// RandSource causes f to get values from the given source of randomness. +// Use if you want deterministic fuzzing. +func (f *Fuzzer) RandSource(s rand.Source) *Fuzzer { + f.r = rand.New(s) + return f +} + +// NilChance sets the probability of creating a nil pointer, map, or slice to +// 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive. +func (f *Fuzzer) NilChance(p float64) *Fuzzer { + if p < 0 || p > 1 { + panic("p should be between 0 and 1, inclusive.") + } + f.nilChance = p + return f +} + +// NumElements sets the minimum and maximum number of elements that will be +// added to a non-nil map or slice. +func (f *Fuzzer) NumElements(atLeast, atMost int) *Fuzzer { + if atLeast > atMost { + panic("atLeast must be <= atMost") + } + if atLeast < 0 { + panic("atLeast must be >= 0") + } + f.minElements = atLeast + f.maxElements = atMost + return f +} + +func (f *Fuzzer) genElementCount() int { + if f.minElements == f.maxElements { + return f.minElements + } + return f.minElements + f.r.Intn(f.maxElements-f.minElements+1) +} + +func (f *Fuzzer) genShouldFill() bool { + return f.r.Float64() > f.nilChance +} + +// MaxDepth sets the maximum number of recursive fuzz calls that will be made +// before stopping. This includes struct members, pointers, and map and slice +// elements. +func (f *Fuzzer) MaxDepth(d int) *Fuzzer { + f.maxDepth = d + return f +} + +// Fuzz recursively fills all of obj's fields with something random. First +// this tries to find a custom fuzz function (see Funcs). If there is no +// custom function this tests whether the object implements fuzz.Interface and, +// if so, calls Fuzz on it to fuzz itself. If that fails, this will see if +// there is a default fuzz function provided by this package. If all of that +// fails, this will generate random values for all primitive fields and then +// recurse for all non-primitives. +// +// This is safe for cyclic or tree-like structs, up to a limit. Use the +// MaxDepth method to adjust how deep you need it to recurse. +// +// obj must be a pointer. Only exported (public) fields can be set (thanks, +// golang :/ ) Intended for tests, so will panic on bad input or unimplemented +// fields. +func (f *Fuzzer) Fuzz(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + f.fuzzWithContext(v, 0) +} + +// FuzzNoCustom is just like Fuzz, except that any custom fuzz function for +// obj's type will not be called and obj will not be tested for fuzz.Interface +// conformance. This applies only to obj and not other instances of obj's +// type. +// Not safe for cyclic or tree-like structs! +// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ ) +// Intended for tests, so will panic on bad input or unimplemented fields. +func (f *Fuzzer) FuzzNoCustom(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + f.fuzzWithContext(v, flagNoCustomFuzz) +} + +const ( + // Do not try to find a custom fuzz function. Does not apply recursively. + flagNoCustomFuzz uint64 = 1 << iota +) + +func (f *Fuzzer) fuzzWithContext(v reflect.Value, flags uint64) { + fc := &fuzzerContext{fuzzer: f} + fc.doFuzz(v, flags) +} + +// fuzzerContext carries context about a single fuzzing run, which lets Fuzzer +// be thread-safe. +type fuzzerContext struct { + fuzzer *Fuzzer + curDepth int +} + +func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) { + if fc.curDepth >= fc.fuzzer.maxDepth { + return + } + fc.curDepth++ + defer func() { fc.curDepth-- }() + + if !v.CanSet() { + return + } + + if flags&flagNoCustomFuzz == 0 { + // Check for both pointer and non-pointer custom functions. + if v.CanAddr() && fc.tryCustom(v.Addr()) { + return + } + if fc.tryCustom(v) { + return + } + } + + if fn, ok := fillFuncMap[v.Kind()]; ok { + fn(v, fc.fuzzer.r) + return + } + switch v.Kind() { + case reflect.Map: + if fc.fuzzer.genShouldFill() { + v.Set(reflect.MakeMap(v.Type())) + n := fc.fuzzer.genElementCount() + for i := 0; i < n; i++ { + key := reflect.New(v.Type().Key()).Elem() + fc.doFuzz(key, 0) + val := reflect.New(v.Type().Elem()).Elem() + fc.doFuzz(val, 0) + v.SetMapIndex(key, val) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Ptr: + if fc.fuzzer.genShouldFill() { + v.Set(reflect.New(v.Type().Elem())) + fc.doFuzz(v.Elem(), 0) + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Slice: + if fc.fuzzer.genShouldFill() { + n := fc.fuzzer.genElementCount() + v.Set(reflect.MakeSlice(v.Type(), n, n)) + for i := 0; i < n; i++ { + fc.doFuzz(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Array: + if fc.fuzzer.genShouldFill() { + n := v.Len() + for i := 0; i < n; i++ { + fc.doFuzz(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + fc.doFuzz(v.Field(i), 0) + } + case reflect.Chan: + fallthrough + case reflect.Func: + fallthrough + case reflect.Interface: + fallthrough + default: + panic(fmt.Sprintf("Can't handle %#v", v.Interface())) + } +} + +// tryCustom searches for custom handlers, and returns true iff it finds a match +// and successfully randomizes v. +func (fc *fuzzerContext) tryCustom(v reflect.Value) bool { + // First: see if we have a fuzz function for it. + doCustom, ok := fc.fuzzer.fuzzFuncs[v.Type()] + if !ok { + // Second: see if it can fuzz itself. + if v.CanInterface() { + intf := v.Interface() + if fuzzable, ok := intf.(Interface); ok { + fuzzable.Fuzz(Continue{fc: fc, Rand: fc.fuzzer.r}) + return true + } + } + // Finally: see if there is a default fuzz function. + doCustom, ok = fc.fuzzer.defaultFuzzFuncs[v.Type()] + if !ok { + return false + } + } + + switch v.Kind() { + case reflect.Ptr: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.New(v.Type().Elem())) + } + case reflect.Map: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.MakeMap(v.Type())) + } + default: + return false + } + + doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{ + fc: fc, + Rand: fc.fuzzer.r, + })}) + return true +} + +// Interface represents an object that knows how to fuzz itself. Any time we +// find a type that implements this interface we will delegate the act of +// fuzzing itself. +type Interface interface { + Fuzz(c Continue) +} + +// Continue can be passed to custom fuzzing functions to allow them to use +// the correct source of randomness and to continue fuzzing their members. +type Continue struct { + fc *fuzzerContext + + // For convenience, Continue implements rand.Rand via embedding. + // Use this for generating any randomness if you want your fuzzing + // to be repeatable for a given seed. + *rand.Rand +} + +// Fuzz continues fuzzing obj. obj must be a pointer. +func (c Continue) Fuzz(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + c.fc.doFuzz(v, 0) +} + +// FuzzNoCustom continues fuzzing obj, except that any custom fuzz function for +// obj's type will not be called and obj will not be tested for fuzz.Interface +// conformance. This applies only to obj and not other instances of obj's +// type. +func (c Continue) FuzzNoCustom(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + c.fc.doFuzz(v, flagNoCustomFuzz) +} + +// RandString makes a random string up to 20 characters long. The returned string +// may include a variety of (valid) UTF-8 encodings. +func (c Continue) RandString() string { + return randString(c.Rand) +} + +// RandUint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func (c Continue) RandUint64() uint64 { + return randUint64(c.Rand) +} + +// RandBool returns true or false randomly. +func (c Continue) RandBool() bool { + return randBool(c.Rand) +} + +func fuzzInt(v reflect.Value, r *rand.Rand) { + v.SetInt(int64(randUint64(r))) +} + +func fuzzUint(v reflect.Value, r *rand.Rand) { + v.SetUint(randUint64(r)) +} + +func fuzzTime(t *time.Time, c Continue) { + var sec, nsec int64 + // Allow for about 1000 years of random time values, which keeps things + // like JSON parsing reasonably happy. + sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60) + c.Fuzz(&nsec) + *t = time.Unix(sec, nsec) +} + +var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){ + reflect.Bool: func(v reflect.Value, r *rand.Rand) { + v.SetBool(randBool(r)) + }, + reflect.Int: fuzzInt, + reflect.Int8: fuzzInt, + reflect.Int16: fuzzInt, + reflect.Int32: fuzzInt, + reflect.Int64: fuzzInt, + reflect.Uint: fuzzUint, + reflect.Uint8: fuzzUint, + reflect.Uint16: fuzzUint, + reflect.Uint32: fuzzUint, + reflect.Uint64: fuzzUint, + reflect.Uintptr: fuzzUint, + reflect.Float32: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(float64(r.Float32())) + }, + reflect.Float64: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(r.Float64()) + }, + reflect.Complex64: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, + reflect.Complex128: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, + reflect.String: func(v reflect.Value, r *rand.Rand) { + v.SetString(randString(r)) + }, + reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, +} + +// randBool returns true or false randomly. +func randBool(r *rand.Rand) bool { + if r.Int()&1 == 1 { + return true + } + return false +} + +type charRange struct { + first, last rune +} + +// choose returns a random unicode character from the given range, using the +// given randomness source. +func (r *charRange) choose(rand *rand.Rand) rune { + count := int64(r.last - r.first) + return r.first + rune(rand.Int63n(count)) +} + +var unicodeRanges = []charRange{ + {' ', '~'}, // ASCII characters + {'\u00a0', '\u02af'}, // Multi-byte encoded characters + {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) +} + +// randString makes a random string up to 20 characters long. The returned string +// may include a variety of (valid) UTF-8 encodings. +func randString(r *rand.Rand) string { + n := r.Intn(20) + runes := make([]rune, n) + for i := range runes { + runes[i] = unicodeRanges[r.Intn(len(unicodeRanges))].choose(r) + } + return string(runes) +} + +// randUint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func randUint64(r *rand.Rand) uint64 { + return uint64(r.Uint32())<<32 | uint64(r.Uint32()) +} diff --git a/vendor/github.com/googleapis/gnostic/LICENSE b/vendor/github.com/googleapis/gnostic/LICENSE new file mode 100644 index 0000000..6b0b127 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go new file mode 100644 index 0000000..5351f36 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go @@ -0,0 +1,8728 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +package openapi_v2 + +import ( + "fmt" + "github.com/googleapis/gnostic/compiler" + "gopkg.in/yaml.v2" + "regexp" + "strings" +) + +// Version returns the package name (and OpenAPI version). +func Version() string { + return "openapi_v2" +} + +// NewAdditionalPropertiesItem creates an object of type AdditionalPropertiesItem if possible, returning an error if not. +func NewAdditionalPropertiesItem(in interface{}, context *compiler.Context) (*AdditionalPropertiesItem, error) { + errors := make([]error, 0) + x := &AdditionalPropertiesItem{} + matched := false + // Schema schema = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchema(m, compiler.NewContext("schema", context)) + if matchingError == nil { + x.Oneof = &AdditionalPropertiesItem_Schema{Schema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // bool boolean = 2; + boolValue, ok := in.(bool) + if ok { + x.Oneof = &AdditionalPropertiesItem_Boolean{Boolean: boolValue} + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewAny creates an object of type Any if possible, returning an error if not. +func NewAny(in interface{}, context *compiler.Context) (*Any, error) { + errors := make([]error, 0) + x := &Any{} + bytes, _ := yaml.Marshal(in) + x.Yaml = string(bytes) + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewApiKeySecurity creates an object of type ApiKeySecurity if possible, returning an error if not. +func NewApiKeySecurity(in interface{}, context *compiler.Context) (*ApiKeySecurity, error) { + errors := make([]error, 0) + x := &ApiKeySecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "in", "name", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [apiKey] + if ok && !compiler.StringArrayContainsValue([]string{"apiKey"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 2; + v2 := compiler.MapValueForKey(m, "name") + if v2 != nil { + x.Name, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 3; + v3 := compiler.MapValueForKey(m, "in") + if v3 != nil { + x.In, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [header query] + if ok && !compiler.StringArrayContainsValue([]string{"header", "query"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 4; + v4 := compiler.MapValueForKey(m, "description") + if v4 != nil { + x.Description, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 5; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewBasicAuthenticationSecurity creates an object of type BasicAuthenticationSecurity if possible, returning an error if not. +func NewBasicAuthenticationSecurity(in interface{}, context *compiler.Context) (*BasicAuthenticationSecurity, error) { + errors := make([]error, 0) + x := &BasicAuthenticationSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [basic] + if ok && !compiler.StringArrayContainsValue([]string{"basic"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewBodyParameter creates an object of type BodyParameter if possible, returning an error if not. +func NewBodyParameter(in interface{}, context *compiler.Context) (*BodyParameter, error) { + errors := make([]error, 0) + x := &BodyParameter{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "schema"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "in", "name", "required", "schema"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 2; + v2 := compiler.MapValueForKey(m, "name") + if v2 != nil { + x.Name, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 3; + v3 := compiler.MapValueForKey(m, "in") + if v3 != nil { + x.In, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [body] + if ok && !compiler.StringArrayContainsValue([]string{"body"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool required = 4; + v4 := compiler.MapValueForKey(m, "required") + if v4 != nil { + x.Required, ok = v4.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Schema schema = 5; + v5 := compiler.MapValueForKey(m, "schema") + if v5 != nil { + var err error + x.Schema, err = NewSchema(v5, compiler.NewContext("schema", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewContact creates an object of type Contact if possible, returning an error if not. +func NewContact(in interface{}, context *compiler.Context) (*Contact, error) { + errors := make([]error, 0) + x := &Contact{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"email", "name", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string email = 3; + v3 := compiler.MapValueForKey(m, "email") + if v3 != nil { + x.Email, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for email: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 4; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDefault creates an object of type Default if possible, returning an error if not. +func NewDefault(in interface{}, context *compiler.Context) (*Default, error) { + errors := make([]error, 0) + x := &Default{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDefinitions creates an object of type Definitions if possible, returning an error if not. +func NewDefinitions(in interface{}, context *compiler.Context) (*Definitions, error) { + errors := make([]error, 0) + x := &Definitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchema additional_properties = 1; + // MAP: Schema + x.AdditionalProperties = make([]*NamedSchema, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSchema{} + pair.Name = k + var err error + pair.Value, err = NewSchema(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDocument creates an object of type Document if possible, returning an error if not. +func NewDocument(in interface{}, context *compiler.Context) (*Document, error) { + errors := make([]error, 0) + x := &Document{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"info", "paths", "swagger"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"basePath", "consumes", "definitions", "externalDocs", "host", "info", "parameters", "paths", "produces", "responses", "schemes", "security", "securityDefinitions", "swagger", "tags"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string swagger = 1; + v1 := compiler.MapValueForKey(m, "swagger") + if v1 != nil { + x.Swagger, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for swagger: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [2.0] + if ok && !compiler.StringArrayContainsValue([]string{"2.0"}, x.Swagger) { + message := fmt.Sprintf("has unexpected value for swagger: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Info info = 2; + v2 := compiler.MapValueForKey(m, "info") + if v2 != nil { + var err error + x.Info, err = NewInfo(v2, compiler.NewContext("info", context)) + if err != nil { + errors = append(errors, err) + } + } + // string host = 3; + v3 := compiler.MapValueForKey(m, "host") + if v3 != nil { + x.Host, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for host: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string base_path = 4; + v4 := compiler.MapValueForKey(m, "basePath") + if v4 != nil { + x.BasePath, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for basePath: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string schemes = 5; + v5 := compiler.MapValueForKey(m, "schemes") + if v5 != nil { + v, ok := v5.([]interface{}) + if ok { + x.Schemes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for schemes: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [http https ws wss] + if ok && !compiler.StringArrayContainsValues([]string{"http", "https", "ws", "wss"}, x.Schemes) { + message := fmt.Sprintf("has unexpected value for schemes: %+v", v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string consumes = 6; + v6 := compiler.MapValueForKey(m, "consumes") + if v6 != nil { + v, ok := v6.([]interface{}) + if ok { + x.Consumes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for consumes: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string produces = 7; + v7 := compiler.MapValueForKey(m, "produces") + if v7 != nil { + v, ok := v7.([]interface{}) + if ok { + x.Produces = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for produces: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Paths paths = 8; + v8 := compiler.MapValueForKey(m, "paths") + if v8 != nil { + var err error + x.Paths, err = NewPaths(v8, compiler.NewContext("paths", context)) + if err != nil { + errors = append(errors, err) + } + } + // Definitions definitions = 9; + v9 := compiler.MapValueForKey(m, "definitions") + if v9 != nil { + var err error + x.Definitions, err = NewDefinitions(v9, compiler.NewContext("definitions", context)) + if err != nil { + errors = append(errors, err) + } + } + // ParameterDefinitions parameters = 10; + v10 := compiler.MapValueForKey(m, "parameters") + if v10 != nil { + var err error + x.Parameters, err = NewParameterDefinitions(v10, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + } + // ResponseDefinitions responses = 11; + v11 := compiler.MapValueForKey(m, "responses") + if v11 != nil { + var err error + x.Responses, err = NewResponseDefinitions(v11, compiler.NewContext("responses", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated SecurityRequirement security = 12; + v12 := compiler.MapValueForKey(m, "security") + if v12 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := v12.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // SecurityDefinitions security_definitions = 13; + v13 := compiler.MapValueForKey(m, "securityDefinitions") + if v13 != nil { + var err error + x.SecurityDefinitions, err = NewSecurityDefinitions(v13, compiler.NewContext("securityDefinitions", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Tag tags = 14; + v14 := compiler.MapValueForKey(m, "tags") + if v14 != nil { + // repeated Tag + x.Tags = make([]*Tag, 0) + a, ok := v14.([]interface{}) + if ok { + for _, item := range a { + y, err := NewTag(item, compiler.NewContext("tags", context)) + if err != nil { + errors = append(errors, err) + } + x.Tags = append(x.Tags, y) + } + } + } + // ExternalDocs external_docs = 15; + v15 := compiler.MapValueForKey(m, "externalDocs") + if v15 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v15, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 16; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExamples creates an object of type Examples if possible, returning an error if not. +func NewExamples(in interface{}, context *compiler.Context) (*Examples, error) { + errors := make([]error, 0) + x := &Examples{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExternalDocs creates an object of type ExternalDocs if possible, returning an error if not. +func NewExternalDocs(in interface{}, context *compiler.Context) (*ExternalDocs, error) { + errors := make([]error, 0) + x := &ExternalDocs{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"url"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewFileSchema creates an object of type FileSchema if possible, returning an error if not. +func NewFileSchema(in interface{}, context *compiler.Context) (*FileSchema, error) { + errors := make([]error, 0) + x := &FileSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"default", "description", "example", "externalDocs", "format", "readOnly", "required", "title", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string format = 1; + v1 := compiler.MapValueForKey(m, "format") + if v1 != nil { + x.Format, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string title = 2; + v2 := compiler.MapValueForKey(m, "title") + if v2 != nil { + x.Title, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 4; + v4 := compiler.MapValueForKey(m, "default") + if v4 != nil { + var err error + x.Default, err = NewAny(v4, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated string required = 5; + v5 := compiler.MapValueForKey(m, "required") + if v5 != nil { + v, ok := v5.([]interface{}) + if ok { + x.Required = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [file] + if ok && !compiler.StringArrayContainsValue([]string{"file"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool read_only = 7; + v7 := compiler.MapValueForKey(m, "readOnly") + if v7 != nil { + x.ReadOnly, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for readOnly: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 8; + v8 := compiler.MapValueForKey(m, "externalDocs") + if v8 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v8, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 9; + v9 := compiler.MapValueForKey(m, "example") + if v9 != nil { + var err error + x.Example, err = NewAny(v9, compiler.NewContext("example", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 10; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewFormDataParameterSubSchema creates an object of type FormDataParameterSubSchema if possible, returning an error if not. +func NewFormDataParameterSubSchema(in interface{}, context *compiler.Context) (*FormDataParameterSubSchema, error) { + errors := make([]error, 0) + x := &FormDataParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowEmptyValue", "collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [formData] + if ok && !compiler.StringArrayContainsValue([]string{"formData"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 5; + v5 := compiler.MapValueForKey(m, "allowEmptyValue") + if v5 != nil { + x.AllowEmptyValue, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array file] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array", "file"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 7; + v7 := compiler.MapValueForKey(m, "format") + if v7 != nil { + x.Format, ok = v7.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 8; + v8 := compiler.MapValueForKey(m, "items") + if v8 != nil { + var err error + x.Items, err = NewPrimitivesItems(v8, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 9; + v9 := compiler.MapValueForKey(m, "collectionFormat") + if v9 != nil { + x.CollectionFormat, ok = v9.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes multi] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes", "multi"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 10; + v10 := compiler.MapValueForKey(m, "default") + if v10 != nil { + var err error + x.Default, err = NewAny(v10, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 11; + v11 := compiler.MapValueForKey(m, "maximum") + if v11 != nil { + switch v11 := v11.(type) { + case float64: + x.Maximum = v11 + case float32: + x.Maximum = float64(v11) + case uint64: + x.Maximum = float64(v11) + case uint32: + x.Maximum = float64(v11) + case int64: + x.Maximum = float64(v11) + case int32: + x.Maximum = float64(v11) + case int: + x.Maximum = float64(v11) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 12; + v12 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v12 != nil { + x.ExclusiveMaximum, ok = v12.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 13; + v13 := compiler.MapValueForKey(m, "minimum") + if v13 != nil { + switch v13 := v13.(type) { + case float64: + x.Minimum = v13 + case float32: + x.Minimum = float64(v13) + case uint64: + x.Minimum = float64(v13) + case uint32: + x.Minimum = float64(v13) + case int64: + x.Minimum = float64(v13) + case int32: + x.Minimum = float64(v13) + case int: + x.Minimum = float64(v13) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 14; + v14 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v14 != nil { + x.ExclusiveMinimum, ok = v14.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 15; + v15 := compiler.MapValueForKey(m, "maxLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 16; + v16 := compiler.MapValueForKey(m, "minLength") + if v16 != nil { + t, ok := v16.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 17; + v17 := compiler.MapValueForKey(m, "pattern") + if v17 != nil { + x.Pattern, ok = v17.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 18; + v18 := compiler.MapValueForKey(m, "maxItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 19; + v19 := compiler.MapValueForKey(m, "minItems") + if v19 != nil { + t, ok := v19.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 20; + v20 := compiler.MapValueForKey(m, "uniqueItems") + if v20 != nil { + x.UniqueItems, ok = v20.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v20, v20) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 21; + v21 := compiler.MapValueForKey(m, "enum") + if v21 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v21.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 22; + v22 := compiler.MapValueForKey(m, "multipleOf") + if v22 != nil { + switch v22 := v22.(type) { + case float64: + x.MultipleOf = v22 + case float32: + x.MultipleOf = float64(v22) + case uint64: + x.MultipleOf = float64(v22) + case uint32: + x.MultipleOf = float64(v22) + case int64: + x.MultipleOf = float64(v22) + case int32: + x.MultipleOf = float64(v22) + case int: + x.MultipleOf = float64(v22) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v22, v22) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 23; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeader creates an object of type Header if possible, returning an error if not. +func NewHeader(in interface{}, context *compiler.Context) (*Header, error) { + errors := make([]error, 0) + x := &Header{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number integer boolean array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "integer", "boolean", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 3; + v3 := compiler.MapValueForKey(m, "items") + if v3 != nil { + var err error + x.Items, err = NewPrimitivesItems(v3, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 4; + v4 := compiler.MapValueForKey(m, "collectionFormat") + if v4 != nil { + x.CollectionFormat, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 6; + v6 := compiler.MapValueForKey(m, "maximum") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.Maximum = v6 + case float32: + x.Maximum = float64(v6) + case uint64: + x.Maximum = float64(v6) + case uint32: + x.Maximum = float64(v6) + case int64: + x.Maximum = float64(v6) + case int32: + x.Maximum = float64(v6) + case int: + x.Maximum = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 7; + v7 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v7 != nil { + x.ExclusiveMaximum, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 8; + v8 := compiler.MapValueForKey(m, "minimum") + if v8 != nil { + switch v8 := v8.(type) { + case float64: + x.Minimum = v8 + case float32: + x.Minimum = float64(v8) + case uint64: + x.Minimum = float64(v8) + case uint32: + x.Minimum = float64(v8) + case int64: + x.Minimum = float64(v8) + case int32: + x.Minimum = float64(v8) + case int: + x.Minimum = float64(v8) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 9; + v9 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v9 != nil { + x.ExclusiveMinimum, ok = v9.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 10; + v10 := compiler.MapValueForKey(m, "maxLength") + if v10 != nil { + t, ok := v10.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 11; + v11 := compiler.MapValueForKey(m, "minLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 12; + v12 := compiler.MapValueForKey(m, "pattern") + if v12 != nil { + x.Pattern, ok = v12.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 13; + v13 := compiler.MapValueForKey(m, "maxItems") + if v13 != nil { + t, ok := v13.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 14; + v14 := compiler.MapValueForKey(m, "minItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 15; + v15 := compiler.MapValueForKey(m, "uniqueItems") + if v15 != nil { + x.UniqueItems, ok = v15.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 16; + v16 := compiler.MapValueForKey(m, "enum") + if v16 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v16.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 17; + v17 := compiler.MapValueForKey(m, "multipleOf") + if v17 != nil { + switch v17 := v17.(type) { + case float64: + x.MultipleOf = v17 + case float32: + x.MultipleOf = float64(v17) + case uint64: + x.MultipleOf = float64(v17) + case uint32: + x.MultipleOf = float64(v17) + case int64: + x.MultipleOf = float64(v17) + case int32: + x.MultipleOf = float64(v17) + case int: + x.MultipleOf = float64(v17) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 18; + v18 := compiler.MapValueForKey(m, "description") + if v18 != nil { + x.Description, ok = v18.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 19; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeaderParameterSubSchema creates an object of type HeaderParameterSubSchema if possible, returning an error if not. +func NewHeaderParameterSubSchema(in interface{}, context *compiler.Context) (*HeaderParameterSubSchema, error) { + errors := make([]error, 0) + x := &HeaderParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [header] + if ok && !compiler.StringArrayContainsValue([]string{"header"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 5; + v5 := compiler.MapValueForKey(m, "type") + if v5 != nil { + x.Type, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 6; + v6 := compiler.MapValueForKey(m, "format") + if v6 != nil { + x.Format, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 7; + v7 := compiler.MapValueForKey(m, "items") + if v7 != nil { + var err error + x.Items, err = NewPrimitivesItems(v7, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 8; + v8 := compiler.MapValueForKey(m, "collectionFormat") + if v8 != nil { + x.CollectionFormat, ok = v8.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 9; + v9 := compiler.MapValueForKey(m, "default") + if v9 != nil { + var err error + x.Default, err = NewAny(v9, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 10; + v10 := compiler.MapValueForKey(m, "maximum") + if v10 != nil { + switch v10 := v10.(type) { + case float64: + x.Maximum = v10 + case float32: + x.Maximum = float64(v10) + case uint64: + x.Maximum = float64(v10) + case uint32: + x.Maximum = float64(v10) + case int64: + x.Maximum = float64(v10) + case int32: + x.Maximum = float64(v10) + case int: + x.Maximum = float64(v10) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 11; + v11 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v11 != nil { + x.ExclusiveMaximum, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 12; + v12 := compiler.MapValueForKey(m, "minimum") + if v12 != nil { + switch v12 := v12.(type) { + case float64: + x.Minimum = v12 + case float32: + x.Minimum = float64(v12) + case uint64: + x.Minimum = float64(v12) + case uint32: + x.Minimum = float64(v12) + case int64: + x.Minimum = float64(v12) + case int32: + x.Minimum = float64(v12) + case int: + x.Minimum = float64(v12) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 13; + v13 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v13 != nil { + x.ExclusiveMinimum, ok = v13.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 14; + v14 := compiler.MapValueForKey(m, "maxLength") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 15; + v15 := compiler.MapValueForKey(m, "minLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 16; + v16 := compiler.MapValueForKey(m, "pattern") + if v16 != nil { + x.Pattern, ok = v16.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 17; + v17 := compiler.MapValueForKey(m, "maxItems") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 18; + v18 := compiler.MapValueForKey(m, "minItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 19; + v19 := compiler.MapValueForKey(m, "uniqueItems") + if v19 != nil { + x.UniqueItems, ok = v19.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 21; + v21 := compiler.MapValueForKey(m, "multipleOf") + if v21 != nil { + switch v21 := v21.(type) { + case float64: + x.MultipleOf = v21 + case float32: + x.MultipleOf = float64(v21) + case uint64: + x.MultipleOf = float64(v21) + case uint32: + x.MultipleOf = float64(v21) + case int64: + x.MultipleOf = float64(v21) + case int32: + x.MultipleOf = float64(v21) + case int: + x.MultipleOf = float64(v21) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v21, v21) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 22; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeaders creates an object of type Headers if possible, returning an error if not. +func NewHeaders(in interface{}, context *compiler.Context) (*Headers, error) { + errors := make([]error, 0) + x := &Headers{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedHeader additional_properties = 1; + // MAP: Header + x.AdditionalProperties = make([]*NamedHeader, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedHeader{} + pair.Name = k + var err error + pair.Value, err = NewHeader(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewInfo creates an object of type Info if possible, returning an error if not. +func NewInfo(in interface{}, context *compiler.Context) (*Info, error) { + errors := make([]error, 0) + x := &Info{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"title", "version"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"contact", "description", "license", "termsOfService", "title", "version"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string title = 1; + v1 := compiler.MapValueForKey(m, "title") + if v1 != nil { + x.Title, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string version = 2; + v2 := compiler.MapValueForKey(m, "version") + if v2 != nil { + x.Version, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for version: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string terms_of_service = 4; + v4 := compiler.MapValueForKey(m, "termsOfService") + if v4 != nil { + x.TermsOfService, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for termsOfService: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Contact contact = 5; + v5 := compiler.MapValueForKey(m, "contact") + if v5 != nil { + var err error + x.Contact, err = NewContact(v5, compiler.NewContext("contact", context)) + if err != nil { + errors = append(errors, err) + } + } + // License license = 6; + v6 := compiler.MapValueForKey(m, "license") + if v6 != nil { + var err error + x.License, err = NewLicense(v6, compiler.NewContext("license", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 7; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewItemsItem creates an object of type ItemsItem if possible, returning an error if not. +func NewItemsItem(in interface{}, context *compiler.Context) (*ItemsItem, error) { + errors := make([]error, 0) + x := &ItemsItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value for item array: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + x.Schema = make([]*Schema, 0) + y, err := NewSchema(m, compiler.NewContext("", context)) + if err != nil { + return nil, err + } + x.Schema = append(x.Schema, y) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewJsonReference creates an object of type JsonReference if possible, returning an error if not. +func NewJsonReference(in interface{}, context *compiler.Context) (*JsonReference, error) { + errors := make([]error, 0) + x := &JsonReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"$ref"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"$ref", "description"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLicense creates an object of type License if possible, returning an error if not. +func NewLicense(in interface{}, context *compiler.Context) (*License, error) { + errors := make([]error, 0) + x := &License{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"name", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedAny creates an object of type NamedAny if possible, returning an error if not. +func NewNamedAny(in interface{}, context *compiler.Context) (*NamedAny, error) { + errors := make([]error, 0) + x := &NamedAny{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewAny(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedHeader creates an object of type NamedHeader if possible, returning an error if not. +func NewNamedHeader(in interface{}, context *compiler.Context) (*NamedHeader, error) { + errors := make([]error, 0) + x := &NamedHeader{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Header value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewHeader(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedParameter creates an object of type NamedParameter if possible, returning an error if not. +func NewNamedParameter(in interface{}, context *compiler.Context) (*NamedParameter, error) { + errors := make([]error, 0) + x := &NamedParameter{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Parameter value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewParameter(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedPathItem creates an object of type NamedPathItem if possible, returning an error if not. +func NewNamedPathItem(in interface{}, context *compiler.Context) (*NamedPathItem, error) { + errors := make([]error, 0) + x := &NamedPathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PathItem value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewPathItem(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedResponse creates an object of type NamedResponse if possible, returning an error if not. +func NewNamedResponse(in interface{}, context *compiler.Context) (*NamedResponse, error) { + errors := make([]error, 0) + x := &NamedResponse{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Response value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewResponse(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedResponseValue creates an object of type NamedResponseValue if possible, returning an error if not. +func NewNamedResponseValue(in interface{}, context *compiler.Context) (*NamedResponseValue, error) { + errors := make([]error, 0) + x := &NamedResponseValue{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ResponseValue value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewResponseValue(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSchema creates an object of type NamedSchema if possible, returning an error if not. +func NewNamedSchema(in interface{}, context *compiler.Context) (*NamedSchema, error) { + errors := make([]error, 0) + x := &NamedSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Schema value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSchema(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSecurityDefinitionsItem creates an object of type NamedSecurityDefinitionsItem if possible, returning an error if not. +func NewNamedSecurityDefinitionsItem(in interface{}, context *compiler.Context) (*NamedSecurityDefinitionsItem, error) { + errors := make([]error, 0) + x := &NamedSecurityDefinitionsItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SecurityDefinitionsItem value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSecurityDefinitionsItem(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedString creates an object of type NamedString if possible, returning an error if not. +func NewNamedString(in interface{}, context *compiler.Context) (*NamedString, error) { + errors := make([]error, 0) + x := &NamedString{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + x.Value, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for value: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedStringArray creates an object of type NamedStringArray if possible, returning an error if not. +func NewNamedStringArray(in interface{}, context *compiler.Context) (*NamedStringArray, error) { + errors := make([]error, 0) + x := &NamedStringArray{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // StringArray value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewStringArray(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNonBodyParameter creates an object of type NonBodyParameter if possible, returning an error if not. +func NewNonBodyParameter(in interface{}, context *compiler.Context) (*NonBodyParameter, error) { + errors := make([]error, 0) + x := &NonBodyParameter{} + matched := false + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // HeaderParameterSubSchema header_parameter_sub_schema = 1; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewHeaderParameterSubSchema(m, compiler.NewContext("headerParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_HeaderParameterSubSchema{HeaderParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // FormDataParameterSubSchema form_data_parameter_sub_schema = 2; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewFormDataParameterSubSchema(m, compiler.NewContext("formDataParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_FormDataParameterSubSchema{FormDataParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // QueryParameterSubSchema query_parameter_sub_schema = 3; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewQueryParameterSubSchema(m, compiler.NewContext("queryParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_QueryParameterSubSchema{QueryParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // PathParameterSubSchema path_parameter_sub_schema = 4; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewPathParameterSubSchema(m, compiler.NewContext("pathParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_PathParameterSubSchema{PathParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2AccessCodeSecurity creates an object of type Oauth2AccessCodeSecurity if possible, returning an error if not. +func NewOauth2AccessCodeSecurity(in interface{}, context *compiler.Context) (*Oauth2AccessCodeSecurity, error) { + errors := make([]error, 0) + x := &Oauth2AccessCodeSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"authorizationUrl", "flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"authorizationUrl", "description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [accessCode] + if ok && !compiler.StringArrayContainsValue([]string{"accessCode"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string authorization_url = 4; + v4 := compiler.MapValueForKey(m, "authorizationUrl") + if v4 != nil { + x.AuthorizationUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for authorizationUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string token_url = 5; + v5 := compiler.MapValueForKey(m, "tokenUrl") + if v5 != nil { + x.TokenUrl, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 6; + v6 := compiler.MapValueForKey(m, "description") + if v6 != nil { + x.Description, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 7; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2ApplicationSecurity creates an object of type Oauth2ApplicationSecurity if possible, returning an error if not. +func NewOauth2ApplicationSecurity(in interface{}, context *compiler.Context) (*Oauth2ApplicationSecurity, error) { + errors := make([]error, 0) + x := &Oauth2ApplicationSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [application] + if ok && !compiler.StringArrayContainsValue([]string{"application"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string token_url = 4; + v4 := compiler.MapValueForKey(m, "tokenUrl") + if v4 != nil { + x.TokenUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2ImplicitSecurity creates an object of type Oauth2ImplicitSecurity if possible, returning an error if not. +func NewOauth2ImplicitSecurity(in interface{}, context *compiler.Context) (*Oauth2ImplicitSecurity, error) { + errors := make([]error, 0) + x := &Oauth2ImplicitSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"authorizationUrl", "flow", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"authorizationUrl", "description", "flow", "scopes", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [implicit] + if ok && !compiler.StringArrayContainsValue([]string{"implicit"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string authorization_url = 4; + v4 := compiler.MapValueForKey(m, "authorizationUrl") + if v4 != nil { + x.AuthorizationUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for authorizationUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2PasswordSecurity creates an object of type Oauth2PasswordSecurity if possible, returning an error if not. +func NewOauth2PasswordSecurity(in interface{}, context *compiler.Context) (*Oauth2PasswordSecurity, error) { + errors := make([]error, 0) + x := &Oauth2PasswordSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [password] + if ok && !compiler.StringArrayContainsValue([]string{"password"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string token_url = 4; + v4 := compiler.MapValueForKey(m, "tokenUrl") + if v4 != nil { + x.TokenUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2Scopes creates an object of type Oauth2Scopes if possible, returning an error if not. +func NewOauth2Scopes(in interface{}, context *compiler.Context) (*Oauth2Scopes, error) { + errors := make([]error, 0) + x := &Oauth2Scopes{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedString additional_properties = 1; + // MAP: string + x.AdditionalProperties = make([]*NamedString, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedString{} + pair.Name = k + pair.Value = v.(string) + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOperation creates an object of type Operation if possible, returning an error if not. +func NewOperation(in interface{}, context *compiler.Context) (*Operation, error) { + errors := make([]error, 0) + x := &Operation{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"responses"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"consumes", "deprecated", "description", "externalDocs", "operationId", "parameters", "produces", "responses", "schemes", "security", "summary", "tags"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated string tags = 1; + v1 := compiler.MapValueForKey(m, "tags") + if v1 != nil { + v, ok := v1.([]interface{}) + if ok { + x.Tags = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for tags: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 2; + v2 := compiler.MapValueForKey(m, "summary") + if v2 != nil { + x.Summary, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 4; + v4 := compiler.MapValueForKey(m, "externalDocs") + if v4 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v4, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // string operation_id = 5; + v5 := compiler.MapValueForKey(m, "operationId") + if v5 != nil { + x.OperationId, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for operationId: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string produces = 6; + v6 := compiler.MapValueForKey(m, "produces") + if v6 != nil { + v, ok := v6.([]interface{}) + if ok { + x.Produces = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for produces: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string consumes = 7; + v7 := compiler.MapValueForKey(m, "consumes") + if v7 != nil { + v, ok := v7.([]interface{}) + if ok { + x.Consumes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for consumes: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated ParametersItem parameters = 8; + v8 := compiler.MapValueForKey(m, "parameters") + if v8 != nil { + // repeated ParametersItem + x.Parameters = make([]*ParametersItem, 0) + a, ok := v8.([]interface{}) + if ok { + for _, item := range a { + y, err := NewParametersItem(item, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // Responses responses = 9; + v9 := compiler.MapValueForKey(m, "responses") + if v9 != nil { + var err error + x.Responses, err = NewResponses(v9, compiler.NewContext("responses", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated string schemes = 10; + v10 := compiler.MapValueForKey(m, "schemes") + if v10 != nil { + v, ok := v10.([]interface{}) + if ok { + x.Schemes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for schemes: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [http https ws wss] + if ok && !compiler.StringArrayContainsValues([]string{"http", "https", "ws", "wss"}, x.Schemes) { + message := fmt.Sprintf("has unexpected value for schemes: %+v", v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool deprecated = 11; + v11 := compiler.MapValueForKey(m, "deprecated") + if v11 != nil { + x.Deprecated, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated SecurityRequirement security = 12; + v12 := compiler.MapValueForKey(m, "security") + if v12 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := v12.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // repeated NamedAny vendor_extension = 13; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameter creates an object of type Parameter if possible, returning an error if not. +func NewParameter(in interface{}, context *compiler.Context) (*Parameter, error) { + errors := make([]error, 0) + x := &Parameter{} + matched := false + // BodyParameter body_parameter = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewBodyParameter(m, compiler.NewContext("bodyParameter", context)) + if matchingError == nil { + x.Oneof = &Parameter_BodyParameter{BodyParameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // NonBodyParameter non_body_parameter = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewNonBodyParameter(m, compiler.NewContext("nonBodyParameter", context)) + if matchingError == nil { + x.Oneof = &Parameter_NonBodyParameter{NonBodyParameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameterDefinitions creates an object of type ParameterDefinitions if possible, returning an error if not. +func NewParameterDefinitions(in interface{}, context *compiler.Context) (*ParameterDefinitions, error) { + errors := make([]error, 0) + x := &ParameterDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedParameter additional_properties = 1; + // MAP: Parameter + x.AdditionalProperties = make([]*NamedParameter, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedParameter{} + pair.Name = k + var err error + pair.Value, err = NewParameter(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParametersItem creates an object of type ParametersItem if possible, returning an error if not. +func NewParametersItem(in interface{}, context *compiler.Context) (*ParametersItem, error) { + errors := make([]error, 0) + x := &ParametersItem{} + matched := false + // Parameter parameter = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewParameter(m, compiler.NewContext("parameter", context)) + if matchingError == nil { + x.Oneof = &ParametersItem_Parameter{Parameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // JsonReference json_reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewJsonReference(m, compiler.NewContext("jsonReference", context)) + if matchingError == nil { + x.Oneof = &ParametersItem_JsonReference{JsonReference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPathItem creates an object of type PathItem if possible, returning an error if not. +func NewPathItem(in interface{}, context *compiler.Context) (*PathItem, error) { + errors := make([]error, 0) + x := &PathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"$ref", "delete", "get", "head", "options", "parameters", "patch", "post", "put"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Operation get = 2; + v2 := compiler.MapValueForKey(m, "get") + if v2 != nil { + var err error + x.Get, err = NewOperation(v2, compiler.NewContext("get", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation put = 3; + v3 := compiler.MapValueForKey(m, "put") + if v3 != nil { + var err error + x.Put, err = NewOperation(v3, compiler.NewContext("put", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation post = 4; + v4 := compiler.MapValueForKey(m, "post") + if v4 != nil { + var err error + x.Post, err = NewOperation(v4, compiler.NewContext("post", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation delete = 5; + v5 := compiler.MapValueForKey(m, "delete") + if v5 != nil { + var err error + x.Delete, err = NewOperation(v5, compiler.NewContext("delete", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation options = 6; + v6 := compiler.MapValueForKey(m, "options") + if v6 != nil { + var err error + x.Options, err = NewOperation(v6, compiler.NewContext("options", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation head = 7; + v7 := compiler.MapValueForKey(m, "head") + if v7 != nil { + var err error + x.Head, err = NewOperation(v7, compiler.NewContext("head", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation patch = 8; + v8 := compiler.MapValueForKey(m, "patch") + if v8 != nil { + var err error + x.Patch, err = NewOperation(v8, compiler.NewContext("patch", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated ParametersItem parameters = 9; + v9 := compiler.MapValueForKey(m, "parameters") + if v9 != nil { + // repeated ParametersItem + x.Parameters = make([]*ParametersItem, 0) + a, ok := v9.([]interface{}) + if ok { + for _, item := range a { + y, err := NewParametersItem(item, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // repeated NamedAny vendor_extension = 10; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPathParameterSubSchema creates an object of type PathParameterSubSchema if possible, returning an error if not. +func NewPathParameterSubSchema(in interface{}, context *compiler.Context) (*PathParameterSubSchema, error) { + errors := make([]error, 0) + x := &PathParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"required"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [path] + if ok && !compiler.StringArrayContainsValue([]string{"path"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 5; + v5 := compiler.MapValueForKey(m, "type") + if v5 != nil { + x.Type, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 6; + v6 := compiler.MapValueForKey(m, "format") + if v6 != nil { + x.Format, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 7; + v7 := compiler.MapValueForKey(m, "items") + if v7 != nil { + var err error + x.Items, err = NewPrimitivesItems(v7, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 8; + v8 := compiler.MapValueForKey(m, "collectionFormat") + if v8 != nil { + x.CollectionFormat, ok = v8.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 9; + v9 := compiler.MapValueForKey(m, "default") + if v9 != nil { + var err error + x.Default, err = NewAny(v9, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 10; + v10 := compiler.MapValueForKey(m, "maximum") + if v10 != nil { + switch v10 := v10.(type) { + case float64: + x.Maximum = v10 + case float32: + x.Maximum = float64(v10) + case uint64: + x.Maximum = float64(v10) + case uint32: + x.Maximum = float64(v10) + case int64: + x.Maximum = float64(v10) + case int32: + x.Maximum = float64(v10) + case int: + x.Maximum = float64(v10) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 11; + v11 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v11 != nil { + x.ExclusiveMaximum, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 12; + v12 := compiler.MapValueForKey(m, "minimum") + if v12 != nil { + switch v12 := v12.(type) { + case float64: + x.Minimum = v12 + case float32: + x.Minimum = float64(v12) + case uint64: + x.Minimum = float64(v12) + case uint32: + x.Minimum = float64(v12) + case int64: + x.Minimum = float64(v12) + case int32: + x.Minimum = float64(v12) + case int: + x.Minimum = float64(v12) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 13; + v13 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v13 != nil { + x.ExclusiveMinimum, ok = v13.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 14; + v14 := compiler.MapValueForKey(m, "maxLength") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 15; + v15 := compiler.MapValueForKey(m, "minLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 16; + v16 := compiler.MapValueForKey(m, "pattern") + if v16 != nil { + x.Pattern, ok = v16.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 17; + v17 := compiler.MapValueForKey(m, "maxItems") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 18; + v18 := compiler.MapValueForKey(m, "minItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 19; + v19 := compiler.MapValueForKey(m, "uniqueItems") + if v19 != nil { + x.UniqueItems, ok = v19.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 21; + v21 := compiler.MapValueForKey(m, "multipleOf") + if v21 != nil { + switch v21 := v21.(type) { + case float64: + x.MultipleOf = v21 + case float32: + x.MultipleOf = float64(v21) + case uint64: + x.MultipleOf = float64(v21) + case uint32: + x.MultipleOf = float64(v21) + case int64: + x.MultipleOf = float64(v21) + case int32: + x.MultipleOf = float64(v21) + case int: + x.MultipleOf = float64(v21) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v21, v21) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 22; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPaths creates an object of type Paths if possible, returning an error if not. +func NewPaths(in interface{}, context *compiler.Context) (*Paths, error) { + errors := make([]error, 0) + x := &Paths{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern0, pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedAny vendor_extension = 1; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + // repeated NamedPathItem path = 2; + // MAP: PathItem ^/ + x.Path = make([]*NamedPathItem, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "/") { + pair := &NamedPathItem{} + pair.Name = k + var err error + pair.Value, err = NewPathItem(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.Path = append(x.Path, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPrimitivesItems creates an object of type PrimitivesItems if possible, returning an error if not. +func NewPrimitivesItems(in interface{}, context *compiler.Context) (*PrimitivesItems, error) { + errors := make([]error, 0) + x := &PrimitivesItems{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"collectionFormat", "default", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number integer boolean array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "integer", "boolean", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 3; + v3 := compiler.MapValueForKey(m, "items") + if v3 != nil { + var err error + x.Items, err = NewPrimitivesItems(v3, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 4; + v4 := compiler.MapValueForKey(m, "collectionFormat") + if v4 != nil { + x.CollectionFormat, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 6; + v6 := compiler.MapValueForKey(m, "maximum") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.Maximum = v6 + case float32: + x.Maximum = float64(v6) + case uint64: + x.Maximum = float64(v6) + case uint32: + x.Maximum = float64(v6) + case int64: + x.Maximum = float64(v6) + case int32: + x.Maximum = float64(v6) + case int: + x.Maximum = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 7; + v7 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v7 != nil { + x.ExclusiveMaximum, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 8; + v8 := compiler.MapValueForKey(m, "minimum") + if v8 != nil { + switch v8 := v8.(type) { + case float64: + x.Minimum = v8 + case float32: + x.Minimum = float64(v8) + case uint64: + x.Minimum = float64(v8) + case uint32: + x.Minimum = float64(v8) + case int64: + x.Minimum = float64(v8) + case int32: + x.Minimum = float64(v8) + case int: + x.Minimum = float64(v8) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 9; + v9 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v9 != nil { + x.ExclusiveMinimum, ok = v9.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 10; + v10 := compiler.MapValueForKey(m, "maxLength") + if v10 != nil { + t, ok := v10.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 11; + v11 := compiler.MapValueForKey(m, "minLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 12; + v12 := compiler.MapValueForKey(m, "pattern") + if v12 != nil { + x.Pattern, ok = v12.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 13; + v13 := compiler.MapValueForKey(m, "maxItems") + if v13 != nil { + t, ok := v13.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 14; + v14 := compiler.MapValueForKey(m, "minItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 15; + v15 := compiler.MapValueForKey(m, "uniqueItems") + if v15 != nil { + x.UniqueItems, ok = v15.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 16; + v16 := compiler.MapValueForKey(m, "enum") + if v16 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v16.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 17; + v17 := compiler.MapValueForKey(m, "multipleOf") + if v17 != nil { + switch v17 := v17.(type) { + case float64: + x.MultipleOf = v17 + case float32: + x.MultipleOf = float64(v17) + case uint64: + x.MultipleOf = float64(v17) + case uint32: + x.MultipleOf = float64(v17) + case int64: + x.MultipleOf = float64(v17) + case int32: + x.MultipleOf = float64(v17) + case int: + x.MultipleOf = float64(v17) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 18; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewProperties creates an object of type Properties if possible, returning an error if not. +func NewProperties(in interface{}, context *compiler.Context) (*Properties, error) { + errors := make([]error, 0) + x := &Properties{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchema additional_properties = 1; + // MAP: Schema + x.AdditionalProperties = make([]*NamedSchema, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSchema{} + pair.Name = k + var err error + pair.Value, err = NewSchema(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewQueryParameterSubSchema creates an object of type QueryParameterSubSchema if possible, returning an error if not. +func NewQueryParameterSubSchema(in interface{}, context *compiler.Context) (*QueryParameterSubSchema, error) { + errors := make([]error, 0) + x := &QueryParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowEmptyValue", "collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [query] + if ok && !compiler.StringArrayContainsValue([]string{"query"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 5; + v5 := compiler.MapValueForKey(m, "allowEmptyValue") + if v5 != nil { + x.AllowEmptyValue, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 7; + v7 := compiler.MapValueForKey(m, "format") + if v7 != nil { + x.Format, ok = v7.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 8; + v8 := compiler.MapValueForKey(m, "items") + if v8 != nil { + var err error + x.Items, err = NewPrimitivesItems(v8, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 9; + v9 := compiler.MapValueForKey(m, "collectionFormat") + if v9 != nil { + x.CollectionFormat, ok = v9.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes multi] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes", "multi"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 10; + v10 := compiler.MapValueForKey(m, "default") + if v10 != nil { + var err error + x.Default, err = NewAny(v10, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 11; + v11 := compiler.MapValueForKey(m, "maximum") + if v11 != nil { + switch v11 := v11.(type) { + case float64: + x.Maximum = v11 + case float32: + x.Maximum = float64(v11) + case uint64: + x.Maximum = float64(v11) + case uint32: + x.Maximum = float64(v11) + case int64: + x.Maximum = float64(v11) + case int32: + x.Maximum = float64(v11) + case int: + x.Maximum = float64(v11) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 12; + v12 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v12 != nil { + x.ExclusiveMaximum, ok = v12.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 13; + v13 := compiler.MapValueForKey(m, "minimum") + if v13 != nil { + switch v13 := v13.(type) { + case float64: + x.Minimum = v13 + case float32: + x.Minimum = float64(v13) + case uint64: + x.Minimum = float64(v13) + case uint32: + x.Minimum = float64(v13) + case int64: + x.Minimum = float64(v13) + case int32: + x.Minimum = float64(v13) + case int: + x.Minimum = float64(v13) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 14; + v14 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v14 != nil { + x.ExclusiveMinimum, ok = v14.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 15; + v15 := compiler.MapValueForKey(m, "maxLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 16; + v16 := compiler.MapValueForKey(m, "minLength") + if v16 != nil { + t, ok := v16.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 17; + v17 := compiler.MapValueForKey(m, "pattern") + if v17 != nil { + x.Pattern, ok = v17.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 18; + v18 := compiler.MapValueForKey(m, "maxItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 19; + v19 := compiler.MapValueForKey(m, "minItems") + if v19 != nil { + t, ok := v19.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 20; + v20 := compiler.MapValueForKey(m, "uniqueItems") + if v20 != nil { + x.UniqueItems, ok = v20.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v20, v20) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 21; + v21 := compiler.MapValueForKey(m, "enum") + if v21 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v21.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 22; + v22 := compiler.MapValueForKey(m, "multipleOf") + if v22 != nil { + switch v22 := v22.(type) { + case float64: + x.MultipleOf = v22 + case float32: + x.MultipleOf = float64(v22) + case uint64: + x.MultipleOf = float64(v22) + case uint32: + x.MultipleOf = float64(v22) + case int64: + x.MultipleOf = float64(v22) + case int32: + x.MultipleOf = float64(v22) + case int: + x.MultipleOf = float64(v22) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v22, v22) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 23; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponse creates an object of type Response if possible, returning an error if not. +func NewResponse(in interface{}, context *compiler.Context) (*Response, error) { + errors := make([]error, 0) + x := &Response{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"description"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "examples", "headers", "schema"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SchemaItem schema = 2; + v2 := compiler.MapValueForKey(m, "schema") + if v2 != nil { + var err error + x.Schema, err = NewSchemaItem(v2, compiler.NewContext("schema", context)) + if err != nil { + errors = append(errors, err) + } + } + // Headers headers = 3; + v3 := compiler.MapValueForKey(m, "headers") + if v3 != nil { + var err error + x.Headers, err = NewHeaders(v3, compiler.NewContext("headers", context)) + if err != nil { + errors = append(errors, err) + } + } + // Examples examples = 4; + v4 := compiler.MapValueForKey(m, "examples") + if v4 != nil { + var err error + x.Examples, err = NewExamples(v4, compiler.NewContext("examples", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 5; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponseDefinitions creates an object of type ResponseDefinitions if possible, returning an error if not. +func NewResponseDefinitions(in interface{}, context *compiler.Context) (*ResponseDefinitions, error) { + errors := make([]error, 0) + x := &ResponseDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedResponse additional_properties = 1; + // MAP: Response + x.AdditionalProperties = make([]*NamedResponse, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedResponse{} + pair.Name = k + var err error + pair.Value, err = NewResponse(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponseValue creates an object of type ResponseValue if possible, returning an error if not. +func NewResponseValue(in interface{}, context *compiler.Context) (*ResponseValue, error) { + errors := make([]error, 0) + x := &ResponseValue{} + matched := false + // Response response = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewResponse(m, compiler.NewContext("response", context)) + if matchingError == nil { + x.Oneof = &ResponseValue_Response{Response: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // JsonReference json_reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewJsonReference(m, compiler.NewContext("jsonReference", context)) + if matchingError == nil { + x.Oneof = &ResponseValue_JsonReference{JsonReference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponses creates an object of type Responses if possible, returning an error if not. +func NewResponses(in interface{}, context *compiler.Context) (*Responses, error) { + errors := make([]error, 0) + x := &Responses{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern2, pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedResponseValue response_code = 1; + // MAP: ResponseValue ^([0-9]{3})$|^(default)$ + x.ResponseCode = make([]*NamedResponseValue, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if pattern2.MatchString(k) { + pair := &NamedResponseValue{} + pair.Name = k + var err error + pair.Value, err = NewResponseValue(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.ResponseCode = append(x.ResponseCode, pair) + } + } + } + // repeated NamedAny vendor_extension = 2; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchema creates an object of type Schema if possible, returning an error if not. +func NewSchema(in interface{}, context *compiler.Context) (*Schema, error) { + errors := make([]error, 0) + x := &Schema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"$ref", "additionalProperties", "allOf", "default", "description", "discriminator", "enum", "example", "exclusiveMaximum", "exclusiveMinimum", "externalDocs", "format", "items", "maxItems", "maxLength", "maxProperties", "maximum", "minItems", "minLength", "minProperties", "minimum", "multipleOf", "pattern", "properties", "readOnly", "required", "title", "type", "uniqueItems", "xml"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string title = 3; + v3 := compiler.MapValueForKey(m, "title") + if v3 != nil { + x.Title, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 4; + v4 := compiler.MapValueForKey(m, "description") + if v4 != nil { + x.Description, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float multiple_of = 6; + v6 := compiler.MapValueForKey(m, "multipleOf") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.MultipleOf = v6 + case float32: + x.MultipleOf = float64(v6) + case uint64: + x.MultipleOf = float64(v6) + case uint32: + x.MultipleOf = float64(v6) + case int64: + x.MultipleOf = float64(v6) + case int32: + x.MultipleOf = float64(v6) + case int: + x.MultipleOf = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float maximum = 7; + v7 := compiler.MapValueForKey(m, "maximum") + if v7 != nil { + switch v7 := v7.(type) { + case float64: + x.Maximum = v7 + case float32: + x.Maximum = float64(v7) + case uint64: + x.Maximum = float64(v7) + case uint32: + x.Maximum = float64(v7) + case int64: + x.Maximum = float64(v7) + case int32: + x.Maximum = float64(v7) + case int: + x.Maximum = float64(v7) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 8; + v8 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v8 != nil { + x.ExclusiveMaximum, ok = v8.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 9; + v9 := compiler.MapValueForKey(m, "minimum") + if v9 != nil { + switch v9 := v9.(type) { + case float64: + x.Minimum = v9 + case float32: + x.Minimum = float64(v9) + case uint64: + x.Minimum = float64(v9) + case uint32: + x.Minimum = float64(v9) + case int64: + x.Minimum = float64(v9) + case int32: + x.Minimum = float64(v9) + case int: + x.Minimum = float64(v9) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 10; + v10 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v10 != nil { + x.ExclusiveMinimum, ok = v10.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 11; + v11 := compiler.MapValueForKey(m, "maxLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 12; + v12 := compiler.MapValueForKey(m, "minLength") + if v12 != nil { + t, ok := v12.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 13; + v13 := compiler.MapValueForKey(m, "pattern") + if v13 != nil { + x.Pattern, ok = v13.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 14; + v14 := compiler.MapValueForKey(m, "maxItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 15; + v15 := compiler.MapValueForKey(m, "minItems") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 16; + v16 := compiler.MapValueForKey(m, "uniqueItems") + if v16 != nil { + x.UniqueItems, ok = v16.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_properties = 17; + v17 := compiler.MapValueForKey(m, "maxProperties") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxProperties: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_properties = 18; + v18 := compiler.MapValueForKey(m, "minProperties") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minProperties: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string required = 19; + v19 := compiler.MapValueForKey(m, "required") + if v19 != nil { + v, ok := v19.([]interface{}) + if ok { + x.Required = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // AdditionalPropertiesItem additional_properties = 21; + v21 := compiler.MapValueForKey(m, "additionalProperties") + if v21 != nil { + var err error + x.AdditionalProperties, err = NewAdditionalPropertiesItem(v21, compiler.NewContext("additionalProperties", context)) + if err != nil { + errors = append(errors, err) + } + } + // TypeItem type = 22; + v22 := compiler.MapValueForKey(m, "type") + if v22 != nil { + var err error + x.Type, err = NewTypeItem(v22, compiler.NewContext("type", context)) + if err != nil { + errors = append(errors, err) + } + } + // ItemsItem items = 23; + v23 := compiler.MapValueForKey(m, "items") + if v23 != nil { + var err error + x.Items, err = NewItemsItem(v23, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Schema all_of = 24; + v24 := compiler.MapValueForKey(m, "allOf") + if v24 != nil { + // repeated Schema + x.AllOf = make([]*Schema, 0) + a, ok := v24.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSchema(item, compiler.NewContext("allOf", context)) + if err != nil { + errors = append(errors, err) + } + x.AllOf = append(x.AllOf, y) + } + } + } + // Properties properties = 25; + v25 := compiler.MapValueForKey(m, "properties") + if v25 != nil { + var err error + x.Properties, err = NewProperties(v25, compiler.NewContext("properties", context)) + if err != nil { + errors = append(errors, err) + } + } + // string discriminator = 26; + v26 := compiler.MapValueForKey(m, "discriminator") + if v26 != nil { + x.Discriminator, ok = v26.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for discriminator: %+v (%T)", v26, v26) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool read_only = 27; + v27 := compiler.MapValueForKey(m, "readOnly") + if v27 != nil { + x.ReadOnly, ok = v27.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for readOnly: %+v (%T)", v27, v27) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Xml xml = 28; + v28 := compiler.MapValueForKey(m, "xml") + if v28 != nil { + var err error + x.Xml, err = NewXml(v28, compiler.NewContext("xml", context)) + if err != nil { + errors = append(errors, err) + } + } + // ExternalDocs external_docs = 29; + v29 := compiler.MapValueForKey(m, "externalDocs") + if v29 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v29, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 30; + v30 := compiler.MapValueForKey(m, "example") + if v30 != nil { + var err error + x.Example, err = NewAny(v30, compiler.NewContext("example", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 31; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchemaItem creates an object of type SchemaItem if possible, returning an error if not. +func NewSchemaItem(in interface{}, context *compiler.Context) (*SchemaItem, error) { + errors := make([]error, 0) + x := &SchemaItem{} + matched := false + // Schema schema = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchema(m, compiler.NewContext("schema", context)) + if matchingError == nil { + x.Oneof = &SchemaItem_Schema{Schema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // FileSchema file_schema = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewFileSchema(m, compiler.NewContext("fileSchema", context)) + if matchingError == nil { + x.Oneof = &SchemaItem_FileSchema{FileSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityDefinitions creates an object of type SecurityDefinitions if possible, returning an error if not. +func NewSecurityDefinitions(in interface{}, context *compiler.Context) (*SecurityDefinitions, error) { + errors := make([]error, 0) + x := &SecurityDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSecurityDefinitionsItem additional_properties = 1; + // MAP: SecurityDefinitionsItem + x.AdditionalProperties = make([]*NamedSecurityDefinitionsItem, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSecurityDefinitionsItem{} + pair.Name = k + var err error + pair.Value, err = NewSecurityDefinitionsItem(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityDefinitionsItem creates an object of type SecurityDefinitionsItem if possible, returning an error if not. +func NewSecurityDefinitionsItem(in interface{}, context *compiler.Context) (*SecurityDefinitionsItem, error) { + errors := make([]error, 0) + x := &SecurityDefinitionsItem{} + matched := false + // BasicAuthenticationSecurity basic_authentication_security = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewBasicAuthenticationSecurity(m, compiler.NewContext("basicAuthenticationSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_BasicAuthenticationSecurity{BasicAuthenticationSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // ApiKeySecurity api_key_security = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewApiKeySecurity(m, compiler.NewContext("apiKeySecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_ApiKeySecurity{ApiKeySecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2ImplicitSecurity oauth2_implicit_security = 3; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2ImplicitSecurity(m, compiler.NewContext("oauth2ImplicitSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2ImplicitSecurity{Oauth2ImplicitSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2PasswordSecurity oauth2_password_security = 4; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2PasswordSecurity(m, compiler.NewContext("oauth2PasswordSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2PasswordSecurity{Oauth2PasswordSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2ApplicationSecurity oauth2_application_security = 5; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2ApplicationSecurity(m, compiler.NewContext("oauth2ApplicationSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2ApplicationSecurity{Oauth2ApplicationSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2AccessCodeSecurity oauth2_access_code_security = 6; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2AccessCodeSecurity(m, compiler.NewContext("oauth2AccessCodeSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2AccessCodeSecurity{Oauth2AccessCodeSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityRequirement creates an object of type SecurityRequirement if possible, returning an error if not. +func NewSecurityRequirement(in interface{}, context *compiler.Context) (*SecurityRequirement, error) { + errors := make([]error, 0) + x := &SecurityRequirement{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedStringArray additional_properties = 1; + // MAP: StringArray + x.AdditionalProperties = make([]*NamedStringArray, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedStringArray{} + pair.Name = k + var err error + pair.Value, err = NewStringArray(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewStringArray creates an object of type StringArray if possible, returning an error if not. +func NewStringArray(in interface{}, context *compiler.Context) (*StringArray, error) { + errors := make([]error, 0) + x := &StringArray{} + a, ok := in.([]interface{}) + if !ok { + message := fmt.Sprintf("has unexpected value for StringArray: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + x.Value = make([]string, 0) + for _, s := range a { + x.Value = append(x.Value, s.(string)) + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewTag creates an object of type Tag if possible, returning an error if not. +func NewTag(in interface{}, context *compiler.Context) (*Tag, error) { + errors := make([]error, 0) + x := &Tag{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "externalDocs", "name"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 3; + v3 := compiler.MapValueForKey(m, "externalDocs") + if v3 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v3, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 4; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewTypeItem creates an object of type TypeItem if possible, returning an error if not. +func NewTypeItem(in interface{}, context *compiler.Context) (*TypeItem, error) { + errors := make([]error, 0) + x := &TypeItem{} + switch in := in.(type) { + case string: + x.Value = make([]string, 0) + x.Value = append(x.Value, in) + case []interface{}: + x.Value = make([]string, 0) + for _, v := range in { + value, ok := v.(string) + if ok { + x.Value = append(x.Value, value) + } else { + message := fmt.Sprintf("has unexpected value for string array element: %+v (%T)", value, value) + errors = append(errors, compiler.NewError(context, message)) + } + } + default: + message := fmt.Sprintf("has unexpected value for string array: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewVendorExtension creates an object of type VendorExtension if possible, returning an error if not. +func NewVendorExtension(in interface{}, context *compiler.Context) (*VendorExtension, error) { + errors := make([]error, 0) + x := &VendorExtension{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewXml creates an object of type Xml if possible, returning an error if not. +func NewXml(in interface{}, context *compiler.Context) (*Xml, error) { + errors := make([]error, 0) + x := &Xml{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"attribute", "name", "namespace", "prefix", "wrapped"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string namespace = 2; + v2 := compiler.MapValueForKey(m, "namespace") + if v2 != nil { + x.Namespace, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for namespace: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string prefix = 3; + v3 := compiler.MapValueForKey(m, "prefix") + if v3 != nil { + x.Prefix, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for prefix: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool attribute = 4; + v4 := compiler.MapValueForKey(m, "attribute") + if v4 != nil { + x.Attribute, ok = v4.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for attribute: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool wrapped = 5; + v5 := compiler.MapValueForKey(m, "wrapped") + if v5 != nil { + x.Wrapped, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for wrapped: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside AdditionalPropertiesItem objects. +func (m *AdditionalPropertiesItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*AdditionalPropertiesItem_Schema) + if ok { + _, err := p.Schema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Any objects. +func (m *Any) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ApiKeySecurity objects. +func (m *ApiKeySecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside BasicAuthenticationSecurity objects. +func (m *BasicAuthenticationSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside BodyParameter objects. +func (m *BodyParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Schema != nil { + _, err := m.Schema.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Contact objects. +func (m *Contact) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Default objects. +func (m *Default) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Definitions objects. +func (m *Definitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Document objects. +func (m *Document) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Info != nil { + _, err := m.Info.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Paths != nil { + _, err := m.Paths.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Definitions != nil { + _, err := m.Definitions.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Parameters != nil { + _, err := m.Parameters.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Responses != nil { + _, err := m.Responses.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Security { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.SecurityDefinitions != nil { + _, err := m.SecurityDefinitions.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Tags { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Examples objects. +func (m *Examples) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ExternalDocs objects. +func (m *ExternalDocs) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside FileSchema objects. +func (m *FileSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Example != nil { + _, err := m.Example.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside FormDataParameterSubSchema objects. +func (m *FormDataParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Header objects. +func (m *Header) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside HeaderParameterSubSchema objects. +func (m *HeaderParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Headers objects. +func (m *Headers) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Info objects. +func (m *Info) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Contact != nil { + _, err := m.Contact.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.License != nil { + _, err := m.License.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ItemsItem objects. +func (m *ItemsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.Schema { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside JsonReference objects. +func (m *JsonReference) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewJsonReference(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside License objects. +func (m *License) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedAny objects. +func (m *NamedAny) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedHeader objects. +func (m *NamedHeader) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedParameter objects. +func (m *NamedParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedPathItem objects. +func (m *NamedPathItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedResponse objects. +func (m *NamedResponse) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedResponseValue objects. +func (m *NamedResponseValue) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedSchema objects. +func (m *NamedSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedSecurityDefinitionsItem objects. +func (m *NamedSecurityDefinitionsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedString objects. +func (m *NamedString) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedStringArray objects. +func (m *NamedStringArray) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NonBodyParameter objects. +func (m *NonBodyParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*NonBodyParameter_HeaderParameterSubSchema) + if ok { + _, err := p.HeaderParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_FormDataParameterSubSchema) + if ok { + _, err := p.FormDataParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_QueryParameterSubSchema) + if ok { + _, err := p.QueryParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_PathParameterSubSchema) + if ok { + _, err := p.PathParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2AccessCodeSecurity objects. +func (m *Oauth2AccessCodeSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2ApplicationSecurity objects. +func (m *Oauth2ApplicationSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2ImplicitSecurity objects. +func (m *Oauth2ImplicitSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2PasswordSecurity objects. +func (m *Oauth2PasswordSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2Scopes objects. +func (m *Oauth2Scopes) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Operation objects. +func (m *Operation) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Parameters { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.Responses != nil { + _, err := m.Responses.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Security { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Parameter objects. +func (m *Parameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*Parameter_BodyParameter) + if ok { + _, err := p.BodyParameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*Parameter_NonBodyParameter) + if ok { + _, err := p.NonBodyParameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ParameterDefinitions objects. +func (m *ParameterDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ParametersItem objects. +func (m *ParametersItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*ParametersItem_Parameter) + if ok { + _, err := p.Parameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*ParametersItem_JsonReference) + if ok { + info, err := p.JsonReference.ResolveReferences(root) + if err != nil { + return nil, err + } else if info != nil { + n, err := NewParametersItem(info, nil) + if err != nil { + return nil, err + } else if n != nil { + *m = *n + return nil, nil + } + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PathItem objects. +func (m *PathItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewPathItem(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + if m.Get != nil { + _, err := m.Get.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Put != nil { + _, err := m.Put.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Post != nil { + _, err := m.Post.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Delete != nil { + _, err := m.Delete.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Options != nil { + _, err := m.Options.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Head != nil { + _, err := m.Head.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Patch != nil { + _, err := m.Patch.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Parameters { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PathParameterSubSchema objects. +func (m *PathParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Paths objects. +func (m *Paths) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.Path { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PrimitivesItems objects. +func (m *PrimitivesItems) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Properties objects. +func (m *Properties) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside QueryParameterSubSchema objects. +func (m *QueryParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Response objects. +func (m *Response) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Schema != nil { + _, err := m.Schema.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Headers != nil { + _, err := m.Headers.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Examples != nil { + _, err := m.Examples.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ResponseDefinitions objects. +func (m *ResponseDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ResponseValue objects. +func (m *ResponseValue) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*ResponseValue_Response) + if ok { + _, err := p.Response.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*ResponseValue_JsonReference) + if ok { + info, err := p.JsonReference.ResolveReferences(root) + if err != nil { + return nil, err + } else if info != nil { + n, err := NewResponseValue(info, nil) + if err != nil { + return nil, err + } else if n != nil { + *m = *n + return nil, nil + } + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Responses objects. +func (m *Responses) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.ResponseCode { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Schema objects. +func (m *Schema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewSchema(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.AdditionalProperties != nil { + _, err := m.AdditionalProperties.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Type != nil { + _, err := m.Type.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.AllOf { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.Properties != nil { + _, err := m.Properties.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Xml != nil { + _, err := m.Xml.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Example != nil { + _, err := m.Example.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SchemaItem objects. +func (m *SchemaItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*SchemaItem_Schema) + if ok { + _, err := p.Schema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SchemaItem_FileSchema) + if ok { + _, err := p.FileSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityDefinitions objects. +func (m *SecurityDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityDefinitionsItem objects. +func (m *SecurityDefinitionsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_BasicAuthenticationSecurity) + if ok { + _, err := p.BasicAuthenticationSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_ApiKeySecurity) + if ok { + _, err := p.ApiKeySecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2ImplicitSecurity) + if ok { + _, err := p.Oauth2ImplicitSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2PasswordSecurity) + if ok { + _, err := p.Oauth2PasswordSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2ApplicationSecurity) + if ok { + _, err := p.Oauth2ApplicationSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2AccessCodeSecurity) + if ok { + _, err := p.Oauth2AccessCodeSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityRequirement objects. +func (m *SecurityRequirement) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside StringArray objects. +func (m *StringArray) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Tag objects. +func (m *Tag) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside TypeItem objects. +func (m *TypeItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside VendorExtension objects. +func (m *VendorExtension) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Xml objects. +func (m *Xml) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ToRawInfo returns a description of AdditionalPropertiesItem suitable for JSON or YAML export. +func (m *AdditionalPropertiesItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // AdditionalPropertiesItem + // {Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:boolean Type:bool StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if v1, ok := m.GetOneof().(*AdditionalPropertiesItem_Boolean); ok { + return v1.Boolean + } + return nil +} + +// ToRawInfo returns a description of Any suitable for JSON or YAML export. +func (m *Any) ToRawInfo() interface{} { + var err error + var info1 []yaml.MapSlice + err = yaml.Unmarshal([]byte(m.Yaml), &info1) + if err == nil { + return info1 + } + var info2 yaml.MapSlice + err = yaml.Unmarshal([]byte(m.Yaml), &info2) + if err == nil { + return info2 + } + var info3 interface{} + err = yaml.Unmarshal([]byte(m.Yaml), &info3) + if err == nil { + return info3 + } + return nil +} + +// ToRawInfo returns a description of ApiKeySecurity suitable for JSON or YAML export. +func (m *ApiKeySecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of BasicAuthenticationSecurity suitable for JSON or YAML export. +func (m *BasicAuthenticationSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of BodyParameter suitable for JSON or YAML export. +func (m *BodyParameter) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Required != false { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.Schema != nil { + info = append(info, yaml.MapItem{Key: "schema", Value: m.Schema.ToRawInfo()}) + } + // &{Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Contact suitable for JSON or YAML export. +func (m *Contact) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{Key: "url", Value: m.Url}) + } + if m.Email != "" { + info = append(info, yaml.MapItem{Key: "email", Value: m.Email}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Default suitable for JSON or YAML export. +func (m *Default) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:false Description:} + return info +} + +// ToRawInfo returns a description of Definitions suitable for JSON or YAML export. +func (m *Definitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSchema StringEnumValues:[] MapType:Schema Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Document suitable for JSON or YAML export. +func (m *Document) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Swagger != "" { + info = append(info, yaml.MapItem{Key: "swagger", Value: m.Swagger}) + } + if m.Info != nil { + info = append(info, yaml.MapItem{Key: "info", Value: m.Info.ToRawInfo()}) + } + // &{Name:info Type:Info StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Host != "" { + info = append(info, yaml.MapItem{Key: "host", Value: m.Host}) + } + if m.BasePath != "" { + info = append(info, yaml.MapItem{Key: "basePath", Value: m.BasePath}) + } + if len(m.Schemes) != 0 { + info = append(info, yaml.MapItem{Key: "schemes", Value: m.Schemes}) + } + if len(m.Consumes) != 0 { + info = append(info, yaml.MapItem{Key: "consumes", Value: m.Consumes}) + } + if len(m.Produces) != 0 { + info = append(info, yaml.MapItem{Key: "produces", Value: m.Produces}) + } + if m.Paths != nil { + info = append(info, yaml.MapItem{Key: "paths", Value: m.Paths.ToRawInfo()}) + } + // &{Name:paths Type:Paths StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Definitions != nil { + info = append(info, yaml.MapItem{Key: "definitions", Value: m.Definitions.ToRawInfo()}) + } + // &{Name:definitions Type:Definitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Parameters != nil { + info = append(info, yaml.MapItem{Key: "parameters", Value: m.Parameters.ToRawInfo()}) + } + // &{Name:parameters Type:ParameterDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Responses != nil { + info = append(info, yaml.MapItem{Key: "responses", Value: m.Responses.ToRawInfo()}) + } + // &{Name:responses Type:ResponseDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Security) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Security { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "security", Value: items}) + } + // &{Name:security Type:SecurityRequirement StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.SecurityDefinitions != nil { + info = append(info, yaml.MapItem{Key: "securityDefinitions", Value: m.SecurityDefinitions.ToRawInfo()}) + } + // &{Name:securityDefinitions Type:SecurityDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Tags) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Tags { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "tags", Value: items}) + } + // &{Name:tags Type:Tag StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{Key: "externalDocs", Value: m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Examples suitable for JSON or YAML export. +func (m *Examples) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ExternalDocs suitable for JSON or YAML export. +func (m *ExternalDocs) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{Key: "url", Value: m.Url}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of FileSchema suitable for JSON or YAML export. +func (m *FileSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Title != "" { + info = append(info, yaml.MapItem{Key: "title", Value: m.Title}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Required) != 0 { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.ReadOnly != false { + info = append(info, yaml.MapItem{Key: "readOnly", Value: m.ReadOnly}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{Key: "externalDocs", Value: m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Example != nil { + info = append(info, yaml.MapItem{Key: "example", Value: m.Example.ToRawInfo()}) + } + // &{Name:example Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of FormDataParameterSubSchema suitable for JSON or YAML export. +func (m *FormDataParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.AllowEmptyValue != false { + info = append(info, yaml.MapItem{Key: "allowEmptyValue", Value: m.AllowEmptyValue}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Header suitable for JSON or YAML export. +func (m *Header) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of HeaderParameterSubSchema suitable for JSON or YAML export. +func (m *HeaderParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Headers suitable for JSON or YAML export. +func (m *Headers) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedHeader StringEnumValues:[] MapType:Header Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Info suitable for JSON or YAML export. +func (m *Info) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Title != "" { + info = append(info, yaml.MapItem{Key: "title", Value: m.Title}) + } + if m.Version != "" { + info = append(info, yaml.MapItem{Key: "version", Value: m.Version}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.TermsOfService != "" { + info = append(info, yaml.MapItem{Key: "termsOfService", Value: m.TermsOfService}) + } + if m.Contact != nil { + info = append(info, yaml.MapItem{Key: "contact", Value: m.Contact.ToRawInfo()}) + } + // &{Name:contact Type:Contact StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.License != nil { + info = append(info, yaml.MapItem{Key: "license", Value: m.License.ToRawInfo()}) + } + // &{Name:license Type:License StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ItemsItem suitable for JSON or YAML export. +func (m *ItemsItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Schema) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Schema { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "schema", Value: items}) + } + // &{Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + return info +} + +// ToRawInfo returns a description of JsonReference suitable for JSON or YAML export. +func (m *JsonReference) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + return info +} + +// ToRawInfo returns a description of License suitable for JSON or YAML export. +func (m *License) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{Key: "url", Value: m.Url}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of NamedAny suitable for JSON or YAML export. +func (m *NamedAny) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedHeader suitable for JSON or YAML export. +func (m *NamedHeader) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:Header StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedParameter suitable for JSON or YAML export. +func (m *NamedParameter) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:Parameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedPathItem suitable for JSON or YAML export. +func (m *NamedPathItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:PathItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedResponse suitable for JSON or YAML export. +func (m *NamedResponse) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:Response StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedResponseValue suitable for JSON or YAML export. +func (m *NamedResponseValue) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:ResponseValue StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedSchema suitable for JSON or YAML export. +func (m *NamedSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedSecurityDefinitionsItem suitable for JSON or YAML export. +func (m *NamedSecurityDefinitionsItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:SecurityDefinitionsItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedString suitable for JSON or YAML export. +func (m *NamedString) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Value != "" { + info = append(info, yaml.MapItem{Key: "value", Value: m.Value}) + } + return info +} + +// ToRawInfo returns a description of NamedStringArray suitable for JSON or YAML export. +func (m *NamedStringArray) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + // &{Name:value Type:StringArray StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NonBodyParameter suitable for JSON or YAML export. +func (m *NonBodyParameter) ToRawInfo() interface{} { + // ONE OF WRAPPER + // NonBodyParameter + // {Name:headerParameterSubSchema Type:HeaderParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetHeaderParameterSubSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:formDataParameterSubSchema Type:FormDataParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetFormDataParameterSubSchema() + if v1 != nil { + return v1.ToRawInfo() + } + // {Name:queryParameterSubSchema Type:QueryParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v2 := m.GetQueryParameterSubSchema() + if v2 != nil { + return v2.ToRawInfo() + } + // {Name:pathParameterSubSchema Type:PathParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v3 := m.GetPathParameterSubSchema() + if v3 != nil { + return v3.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of Oauth2AccessCodeSecurity suitable for JSON or YAML export. +func (m *Oauth2AccessCodeSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.AuthorizationUrl != "" { + info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl}) + } + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2ApplicationSecurity suitable for JSON or YAML export. +func (m *Oauth2ApplicationSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2ImplicitSecurity suitable for JSON or YAML export. +func (m *Oauth2ImplicitSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.AuthorizationUrl != "" { + info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2PasswordSecurity suitable for JSON or YAML export. +func (m *Oauth2PasswordSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2Scopes suitable for JSON or YAML export. +func (m *Oauth2Scopes) ToRawInfo() interface{} { + info := yaml.MapSlice{} + // &{Name:additionalProperties Type:NamedString StringEnumValues:[] MapType:string Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Operation suitable for JSON or YAML export. +func (m *Operation) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Tags) != 0 { + info = append(info, yaml.MapItem{Key: "tags", Value: m.Tags}) + } + if m.Summary != "" { + info = append(info, yaml.MapItem{Key: "summary", Value: m.Summary}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{Key: "externalDocs", Value: m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.OperationId != "" { + info = append(info, yaml.MapItem{Key: "operationId", Value: m.OperationId}) + } + if len(m.Produces) != 0 { + info = append(info, yaml.MapItem{Key: "produces", Value: m.Produces}) + } + if len(m.Consumes) != 0 { + info = append(info, yaml.MapItem{Key: "consumes", Value: m.Consumes}) + } + if len(m.Parameters) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Parameters { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "parameters", Value: items}) + } + // &{Name:parameters Type:ParametersItem StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:The parameters needed to send a valid API call.} + if m.Responses != nil { + info = append(info, yaml.MapItem{Key: "responses", Value: m.Responses.ToRawInfo()}) + } + // &{Name:responses Type:Responses StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Schemes) != 0 { + info = append(info, yaml.MapItem{Key: "schemes", Value: m.Schemes}) + } + if m.Deprecated != false { + info = append(info, yaml.MapItem{Key: "deprecated", Value: m.Deprecated}) + } + if len(m.Security) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Security { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "security", Value: items}) + } + // &{Name:security Type:SecurityRequirement StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Parameter suitable for JSON or YAML export. +func (m *Parameter) ToRawInfo() interface{} { + // ONE OF WRAPPER + // Parameter + // {Name:bodyParameter Type:BodyParameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetBodyParameter() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:nonBodyParameter Type:NonBodyParameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetNonBodyParameter() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of ParameterDefinitions suitable for JSON or YAML export. +func (m *ParameterDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedParameter StringEnumValues:[] MapType:Parameter Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ParametersItem suitable for JSON or YAML export. +func (m *ParametersItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // ParametersItem + // {Name:parameter Type:Parameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetParameter() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:jsonReference Type:JsonReference StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetJsonReference() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of PathItem suitable for JSON or YAML export. +func (m *PathItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef}) + } + if m.Get != nil { + info = append(info, yaml.MapItem{Key: "get", Value: m.Get.ToRawInfo()}) + } + // &{Name:get Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Put != nil { + info = append(info, yaml.MapItem{Key: "put", Value: m.Put.ToRawInfo()}) + } + // &{Name:put Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Post != nil { + info = append(info, yaml.MapItem{Key: "post", Value: m.Post.ToRawInfo()}) + } + // &{Name:post Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Delete != nil { + info = append(info, yaml.MapItem{Key: "delete", Value: m.Delete.ToRawInfo()}) + } + // &{Name:delete Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Options != nil { + info = append(info, yaml.MapItem{Key: "options", Value: m.Options.ToRawInfo()}) + } + // &{Name:options Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Head != nil { + info = append(info, yaml.MapItem{Key: "head", Value: m.Head.ToRawInfo()}) + } + // &{Name:head Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Patch != nil { + info = append(info, yaml.MapItem{Key: "patch", Value: m.Patch.ToRawInfo()}) + } + // &{Name:patch Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Parameters) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Parameters { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "parameters", Value: items}) + } + // &{Name:parameters Type:ParametersItem StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:The parameters needed to send a valid API call.} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of PathParameterSubSchema suitable for JSON or YAML export. +func (m *PathParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Paths suitable for JSON or YAML export. +func (m *Paths) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + if m.Path != nil { + for _, item := range m.Path { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:Path Type:NamedPathItem StringEnumValues:[] MapType:PathItem Repeated:true Pattern:^/ Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of PrimitivesItems suitable for JSON or YAML export. +func (m *PrimitivesItems) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Properties suitable for JSON or YAML export. +func (m *Properties) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSchema StringEnumValues:[] MapType:Schema Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of QueryParameterSubSchema suitable for JSON or YAML export. +func (m *QueryParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{Key: "in", Value: m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.AllowEmptyValue != false { + info = append(info, yaml.MapItem{Key: "allowEmptyValue", Value: m.AllowEmptyValue}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{Key: "items", Value: m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{Key: "collectionFormat", Value: m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Response suitable for JSON or YAML export. +func (m *Response) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Schema != nil { + info = append(info, yaml.MapItem{Key: "schema", Value: m.Schema.ToRawInfo()}) + } + // &{Name:schema Type:SchemaItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Headers != nil { + info = append(info, yaml.MapItem{Key: "headers", Value: m.Headers.ToRawInfo()}) + } + // &{Name:headers Type:Headers StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Examples != nil { + info = append(info, yaml.MapItem{Key: "examples", Value: m.Examples.ToRawInfo()}) + } + // &{Name:examples Type:Examples StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ResponseDefinitions suitable for JSON or YAML export. +func (m *ResponseDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedResponse StringEnumValues:[] MapType:Response Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ResponseValue suitable for JSON or YAML export. +func (m *ResponseValue) ToRawInfo() interface{} { + // ONE OF WRAPPER + // ResponseValue + // {Name:response Type:Response StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetResponse() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:jsonReference Type:JsonReference StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetJsonReference() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of Responses suitable for JSON or YAML export. +func (m *Responses) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.ResponseCode != nil { + for _, item := range m.ResponseCode { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:ResponseCode Type:NamedResponseValue StringEnumValues:[] MapType:ResponseValue Repeated:true Pattern:^([0-9]{3})$|^(default)$ Implicit:true Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Schema suitable for JSON or YAML export. +func (m *Schema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{Key: "format", Value: m.Format}) + } + if m.Title != "" { + info = append(info, yaml.MapItem{Key: "title", Value: m.Title}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{Key: "default", Value: m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{Key: "multipleOf", Value: m.MultipleOf}) + } + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{Key: "maximum", Value: m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMaximum", Value: m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{Key: "minimum", Value: m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{Key: "exclusiveMinimum", Value: m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{Key: "maxLength", Value: m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{Key: "minLength", Value: m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{Key: "pattern", Value: m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{Key: "maxItems", Value: m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{Key: "minItems", Value: m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{Key: "uniqueItems", Value: m.UniqueItems}) + } + if m.MaxProperties != 0 { + info = append(info, yaml.MapItem{Key: "maxProperties", Value: m.MaxProperties}) + } + if m.MinProperties != 0 { + info = append(info, yaml.MapItem{Key: "minProperties", Value: m.MinProperties}) + } + if len(m.Required) != 0 { + info = append(info, yaml.MapItem{Key: "required", Value: m.Required}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "enum", Value: items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.AdditionalProperties != nil { + info = append(info, yaml.MapItem{Key: "additionalProperties", Value: m.AdditionalProperties.ToRawInfo()}) + } + // &{Name:additionalProperties Type:AdditionalPropertiesItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Type != nil { + if len(m.Type.Value) == 1 { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type.Value[0]}) + } else { + info = append(info, yaml.MapItem{Key: "type", Value: m.Type.Value}) + } + } + // &{Name:type Type:TypeItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Items != nil { + items := make([]interface{}, 0) + for _, item := range m.Items.Schema { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "items", Value: items[0]}) + } + // &{Name:items Type:ItemsItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.AllOf) != 0 { + items := make([]interface{}, 0) + for _, item := range m.AllOf { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{Key: "allOf", Value: items}) + } + // &{Name:allOf Type:Schema StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.Properties != nil { + info = append(info, yaml.MapItem{Key: "properties", Value: m.Properties.ToRawInfo()}) + } + // &{Name:properties Type:Properties StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Discriminator != "" { + info = append(info, yaml.MapItem{Key: "discriminator", Value: m.Discriminator}) + } + if m.ReadOnly != false { + info = append(info, yaml.MapItem{Key: "readOnly", Value: m.ReadOnly}) + } + if m.Xml != nil { + info = append(info, yaml.MapItem{Key: "xml", Value: m.Xml.ToRawInfo()}) + } + // &{Name:xml Type:Xml StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{Key: "externalDocs", Value: m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Example != nil { + info = append(info, yaml.MapItem{Key: "example", Value: m.Example.ToRawInfo()}) + } + // &{Name:example Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of SchemaItem suitable for JSON or YAML export. +func (m *SchemaItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // SchemaItem + // {Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:fileSchema Type:FileSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetFileSchema() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of SecurityDefinitions suitable for JSON or YAML export. +func (m *SecurityDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSecurityDefinitionsItem StringEnumValues:[] MapType:SecurityDefinitionsItem Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of SecurityDefinitionsItem suitable for JSON or YAML export. +func (m *SecurityDefinitionsItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // SecurityDefinitionsItem + // {Name:basicAuthenticationSecurity Type:BasicAuthenticationSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetBasicAuthenticationSecurity() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:apiKeySecurity Type:ApiKeySecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetApiKeySecurity() + if v1 != nil { + return v1.ToRawInfo() + } + // {Name:oauth2ImplicitSecurity Type:Oauth2ImplicitSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v2 := m.GetOauth2ImplicitSecurity() + if v2 != nil { + return v2.ToRawInfo() + } + // {Name:oauth2PasswordSecurity Type:Oauth2PasswordSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v3 := m.GetOauth2PasswordSecurity() + if v3 != nil { + return v3.ToRawInfo() + } + // {Name:oauth2ApplicationSecurity Type:Oauth2ApplicationSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v4 := m.GetOauth2ApplicationSecurity() + if v4 != nil { + return v4.ToRawInfo() + } + // {Name:oauth2AccessCodeSecurity Type:Oauth2AccessCodeSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v5 := m.GetOauth2AccessCodeSecurity() + if v5 != nil { + return v5.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of SecurityRequirement suitable for JSON or YAML export. +func (m *SecurityRequirement) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedStringArray StringEnumValues:[] MapType:StringArray Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of StringArray suitable for JSON or YAML export. +func (m *StringArray) ToRawInfo() interface{} { + return m.Value +} + +// ToRawInfo returns a description of Tag suitable for JSON or YAML export. +func (m *Tag) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{Key: "description", Value: m.Description}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{Key: "externalDocs", Value: m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of TypeItem suitable for JSON or YAML export. +func (m *TypeItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Value) != 0 { + info = append(info, yaml.MapItem{Key: "value", Value: m.Value}) + } + return info +} + +// ToRawInfo returns a description of VendorExtension suitable for JSON or YAML export. +func (m *VendorExtension) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Xml suitable for JSON or YAML export. +func (m *Xml) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{Key: "name", Value: m.Name}) + } + if m.Namespace != "" { + info = append(info, yaml.MapItem{Key: "namespace", Value: m.Namespace}) + } + if m.Prefix != "" { + info = append(info, yaml.MapItem{Key: "prefix", Value: m.Prefix}) + } + if m.Attribute != false { + info = append(info, yaml.MapItem{Key: "attribute", Value: m.Attribute}) + } + if m.Wrapped != false { + info = append(info, yaml.MapItem{Key: "wrapped", Value: m.Wrapped}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +var ( + pattern0 = regexp.MustCompile("^x-") + pattern1 = regexp.MustCompile("^/") + pattern2 = regexp.MustCompile("^([0-9]{3})$|^(default)$") +) diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go new file mode 100644 index 0000000..a030fa6 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go @@ -0,0 +1,4455 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: OpenAPIv2/OpenAPIv2.proto + +/* +Package openapi_v2 is a generated protocol buffer package. + +It is generated from these files: + OpenAPIv2/OpenAPIv2.proto + +It has these top-level messages: + AdditionalPropertiesItem + Any + ApiKeySecurity + BasicAuthenticationSecurity + BodyParameter + Contact + Default + Definitions + Document + Examples + ExternalDocs + FileSchema + FormDataParameterSubSchema + Header + HeaderParameterSubSchema + Headers + Info + ItemsItem + JsonReference + License + NamedAny + NamedHeader + NamedParameter + NamedPathItem + NamedResponse + NamedResponseValue + NamedSchema + NamedSecurityDefinitionsItem + NamedString + NamedStringArray + NonBodyParameter + Oauth2AccessCodeSecurity + Oauth2ApplicationSecurity + Oauth2ImplicitSecurity + Oauth2PasswordSecurity + Oauth2Scopes + Operation + Parameter + ParameterDefinitions + ParametersItem + PathItem + PathParameterSubSchema + Paths + PrimitivesItems + Properties + QueryParameterSubSchema + Response + ResponseDefinitions + ResponseValue + Responses + Schema + SchemaItem + SecurityDefinitions + SecurityDefinitionsItem + SecurityRequirement + StringArray + Tag + TypeItem + VendorExtension + Xml +*/ +package openapi_v2 + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type AdditionalPropertiesItem struct { + // Types that are valid to be assigned to Oneof: + // *AdditionalPropertiesItem_Schema + // *AdditionalPropertiesItem_Boolean + Oneof isAdditionalPropertiesItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *AdditionalPropertiesItem) Reset() { *m = AdditionalPropertiesItem{} } +func (m *AdditionalPropertiesItem) String() string { return proto.CompactTextString(m) } +func (*AdditionalPropertiesItem) ProtoMessage() {} +func (*AdditionalPropertiesItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type isAdditionalPropertiesItem_Oneof interface { + isAdditionalPropertiesItem_Oneof() +} + +type AdditionalPropertiesItem_Schema struct { + Schema *Schema `protobuf:"bytes,1,opt,name=schema,oneof"` +} +type AdditionalPropertiesItem_Boolean struct { + Boolean bool `protobuf:"varint,2,opt,name=boolean,oneof"` +} + +func (*AdditionalPropertiesItem_Schema) isAdditionalPropertiesItem_Oneof() {} +func (*AdditionalPropertiesItem_Boolean) isAdditionalPropertiesItem_Oneof() {} + +func (m *AdditionalPropertiesItem) GetOneof() isAdditionalPropertiesItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *AdditionalPropertiesItem) GetSchema() *Schema { + if x, ok := m.GetOneof().(*AdditionalPropertiesItem_Schema); ok { + return x.Schema + } + return nil +} + +func (m *AdditionalPropertiesItem) GetBoolean() bool { + if x, ok := m.GetOneof().(*AdditionalPropertiesItem_Boolean); ok { + return x.Boolean + } + return false +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*AdditionalPropertiesItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _AdditionalPropertiesItem_OneofMarshaler, _AdditionalPropertiesItem_OneofUnmarshaler, _AdditionalPropertiesItem_OneofSizer, []interface{}{ + (*AdditionalPropertiesItem_Schema)(nil), + (*AdditionalPropertiesItem_Boolean)(nil), + } +} + +func _AdditionalPropertiesItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*AdditionalPropertiesItem) + // oneof + switch x := m.Oneof.(type) { + case *AdditionalPropertiesItem_Schema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Schema); err != nil { + return err + } + case *AdditionalPropertiesItem_Boolean: + t := uint64(0) + if x.Boolean { + t = 1 + } + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(t) + case nil: + default: + return fmt.Errorf("AdditionalPropertiesItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _AdditionalPropertiesItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*AdditionalPropertiesItem) + switch tag { + case 1: // oneof.schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Schema) + err := b.DecodeMessage(msg) + m.Oneof = &AdditionalPropertiesItem_Schema{msg} + return true, err + case 2: // oneof.boolean + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Oneof = &AdditionalPropertiesItem_Boolean{x != 0} + return true, err + default: + return false, nil + } +} + +func _AdditionalPropertiesItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*AdditionalPropertiesItem) + // oneof + switch x := m.Oneof.(type) { + case *AdditionalPropertiesItem_Schema: + s := proto.Size(x.Schema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *AdditionalPropertiesItem_Boolean: + n += proto.SizeVarint(2<<3 | proto.WireVarint) + n += 1 + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Any struct { + Value *google_protobuf.Any `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Yaml string `protobuf:"bytes,2,opt,name=yaml" json:"yaml,omitempty"` +} + +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Any) GetValue() *google_protobuf.Any { + if m != nil { + return m.Value + } + return nil +} + +func (m *Any) GetYaml() string { + if m != nil { + return m.Yaml + } + return "" +} + +type ApiKeySecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + In string `protobuf:"bytes,3,opt,name=in" json:"in,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,5,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *ApiKeySecurity) Reset() { *m = ApiKeySecurity{} } +func (m *ApiKeySecurity) String() string { return proto.CompactTextString(m) } +func (*ApiKeySecurity) ProtoMessage() {} +func (*ApiKeySecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ApiKeySecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *ApiKeySecurity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ApiKeySecurity) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *ApiKeySecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ApiKeySecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type BasicAuthenticationSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *BasicAuthenticationSecurity) Reset() { *m = BasicAuthenticationSecurity{} } +func (m *BasicAuthenticationSecurity) String() string { return proto.CompactTextString(m) } +func (*BasicAuthenticationSecurity) ProtoMessage() {} +func (*BasicAuthenticationSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *BasicAuthenticationSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *BasicAuthenticationSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *BasicAuthenticationSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type BodyParameter struct { + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,3,opt,name=in" json:"in,omitempty"` + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,4,opt,name=required" json:"required,omitempty"` + Schema *Schema `protobuf:"bytes,5,opt,name=schema" json:"schema,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *BodyParameter) Reset() { *m = BodyParameter{} } +func (m *BodyParameter) String() string { return proto.CompactTextString(m) } +func (*BodyParameter) ProtoMessage() {} +func (*BodyParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *BodyParameter) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *BodyParameter) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *BodyParameter) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *BodyParameter) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *BodyParameter) GetSchema() *Schema { + if m != nil { + return m.Schema + } + return nil +} + +func (m *BodyParameter) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Contact information for the owners of the API. +type Contact struct { + // The identifying name of the contact person/organization. + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // The URL pointing to the contact information. + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + // The email address of the contact person/organization. + Email string `protobuf:"bytes,3,opt,name=email" json:"email,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,4,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Contact) Reset() { *m = Contact{} } +func (m *Contact) String() string { return proto.CompactTextString(m) } +func (*Contact) ProtoMessage() {} +func (*Contact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *Contact) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Contact) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *Contact) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *Contact) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Default struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Default) Reset() { *m = Default{} } +func (m *Default) String() string { return proto.CompactTextString(m) } +func (*Default) ProtoMessage() {} +func (*Default) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *Default) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// One or more JSON objects describing the schemas being consumed and produced by the API. +type Definitions struct { + AdditionalProperties []*NamedSchema `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Definitions) Reset() { *m = Definitions{} } +func (m *Definitions) String() string { return proto.CompactTextString(m) } +func (*Definitions) ProtoMessage() {} +func (*Definitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *Definitions) GetAdditionalProperties() []*NamedSchema { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Document struct { + // The Swagger version of this document. + Swagger string `protobuf:"bytes,1,opt,name=swagger" json:"swagger,omitempty"` + Info *Info `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"` + // The host (name or ip) of the API. Example: 'swagger.io' + Host string `protobuf:"bytes,3,opt,name=host" json:"host,omitempty"` + // The base path to the API. Example: '/api'. + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath" json:"base_path,omitempty"` + // The transfer protocol of the API. + Schemes []string `protobuf:"bytes,5,rep,name=schemes" json:"schemes,omitempty"` + // A list of MIME types accepted by the API. + Consumes []string `protobuf:"bytes,6,rep,name=consumes" json:"consumes,omitempty"` + // A list of MIME types the API can produce. + Produces []string `protobuf:"bytes,7,rep,name=produces" json:"produces,omitempty"` + Paths *Paths `protobuf:"bytes,8,opt,name=paths" json:"paths,omitempty"` + Definitions *Definitions `protobuf:"bytes,9,opt,name=definitions" json:"definitions,omitempty"` + Parameters *ParameterDefinitions `protobuf:"bytes,10,opt,name=parameters" json:"parameters,omitempty"` + Responses *ResponseDefinitions `protobuf:"bytes,11,opt,name=responses" json:"responses,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security" json:"security,omitempty"` + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,13,opt,name=security_definitions,json=securityDefinitions" json:"security_definitions,omitempty"` + Tags []*Tag `protobuf:"bytes,14,rep,name=tags" json:"tags,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,15,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,16,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Document) Reset() { *m = Document{} } +func (m *Document) String() string { return proto.CompactTextString(m) } +func (*Document) ProtoMessage() {} +func (*Document) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *Document) GetSwagger() string { + if m != nil { + return m.Swagger + } + return "" +} + +func (m *Document) GetInfo() *Info { + if m != nil { + return m.Info + } + return nil +} + +func (m *Document) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *Document) GetBasePath() string { + if m != nil { + return m.BasePath + } + return "" +} + +func (m *Document) GetSchemes() []string { + if m != nil { + return m.Schemes + } + return nil +} + +func (m *Document) GetConsumes() []string { + if m != nil { + return m.Consumes + } + return nil +} + +func (m *Document) GetProduces() []string { + if m != nil { + return m.Produces + } + return nil +} + +func (m *Document) GetPaths() *Paths { + if m != nil { + return m.Paths + } + return nil +} + +func (m *Document) GetDefinitions() *Definitions { + if m != nil { + return m.Definitions + } + return nil +} + +func (m *Document) GetParameters() *ParameterDefinitions { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *Document) GetResponses() *ResponseDefinitions { + if m != nil { + return m.Responses + } + return nil +} + +func (m *Document) GetSecurity() []*SecurityRequirement { + if m != nil { + return m.Security + } + return nil +} + +func (m *Document) GetSecurityDefinitions() *SecurityDefinitions { + if m != nil { + return m.SecurityDefinitions + } + return nil +} + +func (m *Document) GetTags() []*Tag { + if m != nil { + return m.Tags + } + return nil +} + +func (m *Document) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Document) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Examples struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Examples) Reset() { *m = Examples{} } +func (m *Examples) String() string { return proto.CompactTextString(m) } +func (*Examples) ProtoMessage() {} +func (*Examples) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *Examples) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// information about external documentation +type ExternalDocs struct { + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *ExternalDocs) Reset() { *m = ExternalDocs{} } +func (m *ExternalDocs) String() string { return proto.CompactTextString(m) } +func (*ExternalDocs) ProtoMessage() {} +func (*ExternalDocs) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *ExternalDocs) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ExternalDocs) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *ExternalDocs) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// A deterministic version of a JSON Schema object. +type FileSchema struct { + Format string `protobuf:"bytes,1,opt,name=format" json:"format,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + Default *Any `protobuf:"bytes,4,opt,name=default" json:"default,omitempty"` + Required []string `protobuf:"bytes,5,rep,name=required" json:"required,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + ReadOnly bool `protobuf:"varint,7,opt,name=read_only,json=readOnly" json:"read_only,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,8,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + Example *Any `protobuf:"bytes,9,opt,name=example" json:"example,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,10,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *FileSchema) Reset() { *m = FileSchema{} } +func (m *FileSchema) String() string { return proto.CompactTextString(m) } +func (*FileSchema) ProtoMessage() {} +func (*FileSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *FileSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *FileSchema) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *FileSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *FileSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *FileSchema) GetRequired() []string { + if m != nil { + return m.Required + } + return nil +} + +func (m *FileSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *FileSchema) GetReadOnly() bool { + if m != nil { + return m.ReadOnly + } + return false +} + +func (m *FileSchema) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *FileSchema) GetExample() *Any { + if m != nil { + return m.Example + } + return nil +} + +func (m *FileSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type FormDataParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + // allows sending a parameter by name only or with an empty value. + AllowEmptyValue bool `protobuf:"varint,5,opt,name=allow_empty_value,json=allowEmptyValue" json:"allow_empty_value,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,7,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,8,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,9,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,10,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,15,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,16,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,18,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,19,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,20,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,21,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,22,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,23,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *FormDataParameterSubSchema) Reset() { *m = FormDataParameterSubSchema{} } +func (m *FormDataParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*FormDataParameterSubSchema) ProtoMessage() {} +func (*FormDataParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +func (m *FormDataParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *FormDataParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *FormDataParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *FormDataParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *FormDataParameterSubSchema) GetAllowEmptyValue() bool { + if m != nil { + return m.AllowEmptyValue + } + return false +} + +func (m *FormDataParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *FormDataParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *FormDataParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *FormDataParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *FormDataParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *FormDataParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *FormDataParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *FormDataParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *FormDataParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *FormDataParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *FormDataParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Header struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,3,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,4,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,6,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,7,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,8,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,9,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,10,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,11,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,12,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,13,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,14,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,15,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,16,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,17,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + Description string `protobuf:"bytes,18,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,19,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +func (m *Header) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Header) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *Header) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *Header) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *Header) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *Header) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *Header) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *Header) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *Header) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *Header) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *Header) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *Header) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *Header) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *Header) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *Header) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *Header) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *Header) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *Header) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Header) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type HeaderParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,6,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,7,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,8,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,9,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,10,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,11,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,12,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,13,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,14,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,15,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,16,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,17,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,18,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,19,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,21,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,22,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *HeaderParameterSubSchema) Reset() { *m = HeaderParameterSubSchema{} } +func (m *HeaderParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*HeaderParameterSubSchema) ProtoMessage() {} +func (*HeaderParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +func (m *HeaderParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *HeaderParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *HeaderParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *HeaderParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *HeaderParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *HeaderParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *HeaderParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *HeaderParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *HeaderParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *HeaderParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *HeaderParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *HeaderParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *HeaderParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *HeaderParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *HeaderParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Headers struct { + AdditionalProperties []*NamedHeader `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Headers) Reset() { *m = Headers{} } +func (m *Headers) String() string { return proto.CompactTextString(m) } +func (*Headers) ProtoMessage() {} +func (*Headers) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +func (m *Headers) GetAdditionalProperties() []*NamedHeader { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// General information about the API. +type Info struct { + // A unique and precise title of the API. + Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` + // A semantic version number of the API. + Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` + // A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The terms of service for the API. + TermsOfService string `protobuf:"bytes,4,opt,name=terms_of_service,json=termsOfService" json:"terms_of_service,omitempty"` + Contact *Contact `protobuf:"bytes,5,opt,name=contact" json:"contact,omitempty"` + License *License `protobuf:"bytes,6,opt,name=license" json:"license,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,7,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Info) Reset() { *m = Info{} } +func (m *Info) String() string { return proto.CompactTextString(m) } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } + +func (m *Info) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *Info) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Info) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Info) GetTermsOfService() string { + if m != nil { + return m.TermsOfService + } + return "" +} + +func (m *Info) GetContact() *Contact { + if m != nil { + return m.Contact + } + return nil +} + +func (m *Info) GetLicense() *License { + if m != nil { + return m.License + } + return nil +} + +func (m *Info) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type ItemsItem struct { + Schema []*Schema `protobuf:"bytes,1,rep,name=schema" json:"schema,omitempty"` +} + +func (m *ItemsItem) Reset() { *m = ItemsItem{} } +func (m *ItemsItem) String() string { return proto.CompactTextString(m) } +func (*ItemsItem) ProtoMessage() {} +func (*ItemsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *ItemsItem) GetSchema() []*Schema { + if m != nil { + return m.Schema + } + return nil +} + +type JsonReference struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` +} + +func (m *JsonReference) Reset() { *m = JsonReference{} } +func (m *JsonReference) String() string { return proto.CompactTextString(m) } +func (*JsonReference) ProtoMessage() {} +func (*JsonReference) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } + +func (m *JsonReference) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *JsonReference) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +type License struct { + // The name of the license type. It's encouraged to use an OSI compatible license. + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // The URL pointing to the license. + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *License) Reset() { *m = License{} } +func (m *License) String() string { return proto.CompactTextString(m) } +func (*License) ProtoMessage() {} +func (*License) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } + +func (m *License) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *License) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *License) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +type NamedAny struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Any `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedAny) Reset() { *m = NamedAny{} } +func (m *NamedAny) String() string { return proto.CompactTextString(m) } +func (*NamedAny) ProtoMessage() {} +func (*NamedAny) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } + +func (m *NamedAny) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedAny) GetValue() *Any { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs. +type NamedHeader struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Header `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedHeader) Reset() { *m = NamedHeader{} } +func (m *NamedHeader) String() string { return proto.CompactTextString(m) } +func (*NamedHeader) ProtoMessage() {} +func (*NamedHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } + +func (m *NamedHeader) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedHeader) GetValue() *Header { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs. +type NamedParameter struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Parameter `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedParameter) Reset() { *m = NamedParameter{} } +func (m *NamedParameter) String() string { return proto.CompactTextString(m) } +func (*NamedParameter) ProtoMessage() {} +func (*NamedParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } + +func (m *NamedParameter) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedParameter) GetValue() *Parameter { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +type NamedPathItem struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *PathItem `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedPathItem) Reset() { *m = NamedPathItem{} } +func (m *NamedPathItem) String() string { return proto.CompactTextString(m) } +func (*NamedPathItem) ProtoMessage() {} +func (*NamedPathItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } + +func (m *NamedPathItem) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedPathItem) GetValue() *PathItem { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs. +type NamedResponse struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Response `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedResponse) Reset() { *m = NamedResponse{} } +func (m *NamedResponse) String() string { return proto.CompactTextString(m) } +func (*NamedResponse) ProtoMessage() {} +func (*NamedResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } + +func (m *NamedResponse) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedResponse) GetValue() *Response { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs. +type NamedResponseValue struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *ResponseValue `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedResponseValue) Reset() { *m = NamedResponseValue{} } +func (m *NamedResponseValue) String() string { return proto.CompactTextString(m) } +func (*NamedResponseValue) ProtoMessage() {} +func (*NamedResponseValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } + +func (m *NamedResponseValue) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedResponseValue) GetValue() *ResponseValue { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs. +type NamedSchema struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Schema `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedSchema) Reset() { *m = NamedSchema{} } +func (m *NamedSchema) String() string { return proto.CompactTextString(m) } +func (*NamedSchema) ProtoMessage() {} +func (*NamedSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } + +func (m *NamedSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedSchema) GetValue() *Schema { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs. +type NamedSecurityDefinitionsItem struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *SecurityDefinitionsItem `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedSecurityDefinitionsItem) Reset() { *m = NamedSecurityDefinitionsItem{} } +func (m *NamedSecurityDefinitionsItem) String() string { return proto.CompactTextString(m) } +func (*NamedSecurityDefinitionsItem) ProtoMessage() {} +func (*NamedSecurityDefinitionsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } + +func (m *NamedSecurityDefinitionsItem) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedSecurityDefinitionsItem) GetValue() *SecurityDefinitionsItem { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +type NamedString struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedString) Reset() { *m = NamedString{} } +func (m *NamedString) String() string { return proto.CompactTextString(m) } +func (*NamedString) ProtoMessage() {} +func (*NamedString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } + +func (m *NamedString) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedString) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +type NamedStringArray struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *StringArray `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedStringArray) Reset() { *m = NamedStringArray{} } +func (m *NamedStringArray) String() string { return proto.CompactTextString(m) } +func (*NamedStringArray) ProtoMessage() {} +func (*NamedStringArray) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } + +func (m *NamedStringArray) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedStringArray) GetValue() *StringArray { + if m != nil { + return m.Value + } + return nil +} + +type NonBodyParameter struct { + // Types that are valid to be assigned to Oneof: + // *NonBodyParameter_HeaderParameterSubSchema + // *NonBodyParameter_FormDataParameterSubSchema + // *NonBodyParameter_QueryParameterSubSchema + // *NonBodyParameter_PathParameterSubSchema + Oneof isNonBodyParameter_Oneof `protobuf_oneof:"oneof"` +} + +func (m *NonBodyParameter) Reset() { *m = NonBodyParameter{} } +func (m *NonBodyParameter) String() string { return proto.CompactTextString(m) } +func (*NonBodyParameter) ProtoMessage() {} +func (*NonBodyParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } + +type isNonBodyParameter_Oneof interface { + isNonBodyParameter_Oneof() +} + +type NonBodyParameter_HeaderParameterSubSchema struct { + HeaderParameterSubSchema *HeaderParameterSubSchema `protobuf:"bytes,1,opt,name=header_parameter_sub_schema,json=headerParameterSubSchema,oneof"` +} +type NonBodyParameter_FormDataParameterSubSchema struct { + FormDataParameterSubSchema *FormDataParameterSubSchema `protobuf:"bytes,2,opt,name=form_data_parameter_sub_schema,json=formDataParameterSubSchema,oneof"` +} +type NonBodyParameter_QueryParameterSubSchema struct { + QueryParameterSubSchema *QueryParameterSubSchema `protobuf:"bytes,3,opt,name=query_parameter_sub_schema,json=queryParameterSubSchema,oneof"` +} +type NonBodyParameter_PathParameterSubSchema struct { + PathParameterSubSchema *PathParameterSubSchema `protobuf:"bytes,4,opt,name=path_parameter_sub_schema,json=pathParameterSubSchema,oneof"` +} + +func (*NonBodyParameter_HeaderParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_FormDataParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_QueryParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_PathParameterSubSchema) isNonBodyParameter_Oneof() {} + +func (m *NonBodyParameter) GetOneof() isNonBodyParameter_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *NonBodyParameter) GetHeaderParameterSubSchema() *HeaderParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_HeaderParameterSubSchema); ok { + return x.HeaderParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetFormDataParameterSubSchema() *FormDataParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_FormDataParameterSubSchema); ok { + return x.FormDataParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetQueryParameterSubSchema() *QueryParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_QueryParameterSubSchema); ok { + return x.QueryParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetPathParameterSubSchema() *PathParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_PathParameterSubSchema); ok { + return x.PathParameterSubSchema + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*NonBodyParameter) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _NonBodyParameter_OneofMarshaler, _NonBodyParameter_OneofUnmarshaler, _NonBodyParameter_OneofSizer, []interface{}{ + (*NonBodyParameter_HeaderParameterSubSchema)(nil), + (*NonBodyParameter_FormDataParameterSubSchema)(nil), + (*NonBodyParameter_QueryParameterSubSchema)(nil), + (*NonBodyParameter_PathParameterSubSchema)(nil), + } +} + +func _NonBodyParameter_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*NonBodyParameter) + // oneof + switch x := m.Oneof.(type) { + case *NonBodyParameter_HeaderParameterSubSchema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.HeaderParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_FormDataParameterSubSchema: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.FormDataParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_QueryParameterSubSchema: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.QueryParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_PathParameterSubSchema: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.PathParameterSubSchema); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("NonBodyParameter.Oneof has unexpected type %T", x) + } + return nil +} + +func _NonBodyParameter_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*NonBodyParameter) + switch tag { + case 1: // oneof.header_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(HeaderParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_HeaderParameterSubSchema{msg} + return true, err + case 2: // oneof.form_data_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(FormDataParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_FormDataParameterSubSchema{msg} + return true, err + case 3: // oneof.query_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(QueryParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_QueryParameterSubSchema{msg} + return true, err + case 4: // oneof.path_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(PathParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_PathParameterSubSchema{msg} + return true, err + default: + return false, nil + } +} + +func _NonBodyParameter_OneofSizer(msg proto.Message) (n int) { + m := msg.(*NonBodyParameter) + // oneof + switch x := m.Oneof.(type) { + case *NonBodyParameter_HeaderParameterSubSchema: + s := proto.Size(x.HeaderParameterSubSchema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_FormDataParameterSubSchema: + s := proto.Size(x.FormDataParameterSubSchema) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_QueryParameterSubSchema: + s := proto.Size(x.QueryParameterSubSchema) + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_PathParameterSubSchema: + s := proto.Size(x.PathParameterSubSchema) + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Oauth2AccessCodeSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + AuthorizationUrl string `protobuf:"bytes,4,opt,name=authorization_url,json=authorizationUrl" json:"authorization_url,omitempty"` + TokenUrl string `protobuf:"bytes,5,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,7,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2AccessCodeSecurity) Reset() { *m = Oauth2AccessCodeSecurity{} } +func (m *Oauth2AccessCodeSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2AccessCodeSecurity) ProtoMessage() {} +func (*Oauth2AccessCodeSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } + +func (m *Oauth2AccessCodeSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2AccessCodeSecurity) GetAuthorizationUrl() string { + if m != nil { + return m.AuthorizationUrl + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2ApplicationSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + TokenUrl string `protobuf:"bytes,4,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2ApplicationSecurity) Reset() { *m = Oauth2ApplicationSecurity{} } +func (m *Oauth2ApplicationSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2ApplicationSecurity) ProtoMessage() {} +func (*Oauth2ApplicationSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } + +func (m *Oauth2ApplicationSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2ApplicationSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2ImplicitSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + AuthorizationUrl string `protobuf:"bytes,4,opt,name=authorization_url,json=authorizationUrl" json:"authorization_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2ImplicitSecurity) Reset() { *m = Oauth2ImplicitSecurity{} } +func (m *Oauth2ImplicitSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2ImplicitSecurity) ProtoMessage() {} +func (*Oauth2ImplicitSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } + +func (m *Oauth2ImplicitSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2ImplicitSecurity) GetAuthorizationUrl() string { + if m != nil { + return m.AuthorizationUrl + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2PasswordSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + TokenUrl string `protobuf:"bytes,4,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2PasswordSecurity) Reset() { *m = Oauth2PasswordSecurity{} } +func (m *Oauth2PasswordSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2PasswordSecurity) ProtoMessage() {} +func (*Oauth2PasswordSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } + +func (m *Oauth2PasswordSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2PasswordSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2Scopes struct { + AdditionalProperties []*NamedString `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Oauth2Scopes) Reset() { *m = Oauth2Scopes{} } +func (m *Oauth2Scopes) String() string { return proto.CompactTextString(m) } +func (*Oauth2Scopes) ProtoMessage() {} +func (*Oauth2Scopes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } + +func (m *Oauth2Scopes) GetAdditionalProperties() []*NamedString { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Operation struct { + Tags []string `protobuf:"bytes,1,rep,name=tags" json:"tags,omitempty"` + // A brief summary of the operation. + Summary string `protobuf:"bytes,2,opt,name=summary" json:"summary,omitempty"` + // A longer description of the operation, GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + // A unique identifier of the operation. + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId" json:"operation_id,omitempty"` + // A list of MIME types the API can produce. + Produces []string `protobuf:"bytes,6,rep,name=produces" json:"produces,omitempty"` + // A list of MIME types the API can consume. + Consumes []string `protobuf:"bytes,7,rep,name=consumes" json:"consumes,omitempty"` + // The parameters needed to send a valid API call. + Parameters []*ParametersItem `protobuf:"bytes,8,rep,name=parameters" json:"parameters,omitempty"` + Responses *Responses `protobuf:"bytes,9,opt,name=responses" json:"responses,omitempty"` + // The transfer protocol of the API. + Schemes []string `protobuf:"bytes,10,rep,name=schemes" json:"schemes,omitempty"` + Deprecated bool `protobuf:"varint,11,opt,name=deprecated" json:"deprecated,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security" json:"security,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,13,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Operation) Reset() { *m = Operation{} } +func (m *Operation) String() string { return proto.CompactTextString(m) } +func (*Operation) ProtoMessage() {} +func (*Operation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } + +func (m *Operation) GetTags() []string { + if m != nil { + return m.Tags + } + return nil +} + +func (m *Operation) GetSummary() string { + if m != nil { + return m.Summary + } + return "" +} + +func (m *Operation) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Operation) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Operation) GetOperationId() string { + if m != nil { + return m.OperationId + } + return "" +} + +func (m *Operation) GetProduces() []string { + if m != nil { + return m.Produces + } + return nil +} + +func (m *Operation) GetConsumes() []string { + if m != nil { + return m.Consumes + } + return nil +} + +func (m *Operation) GetParameters() []*ParametersItem { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *Operation) GetResponses() *Responses { + if m != nil { + return m.Responses + } + return nil +} + +func (m *Operation) GetSchemes() []string { + if m != nil { + return m.Schemes + } + return nil +} + +func (m *Operation) GetDeprecated() bool { + if m != nil { + return m.Deprecated + } + return false +} + +func (m *Operation) GetSecurity() []*SecurityRequirement { + if m != nil { + return m.Security + } + return nil +} + +func (m *Operation) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Parameter struct { + // Types that are valid to be assigned to Oneof: + // *Parameter_BodyParameter + // *Parameter_NonBodyParameter + Oneof isParameter_Oneof `protobuf_oneof:"oneof"` +} + +func (m *Parameter) Reset() { *m = Parameter{} } +func (m *Parameter) String() string { return proto.CompactTextString(m) } +func (*Parameter) ProtoMessage() {} +func (*Parameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } + +type isParameter_Oneof interface { + isParameter_Oneof() +} + +type Parameter_BodyParameter struct { + BodyParameter *BodyParameter `protobuf:"bytes,1,opt,name=body_parameter,json=bodyParameter,oneof"` +} +type Parameter_NonBodyParameter struct { + NonBodyParameter *NonBodyParameter `protobuf:"bytes,2,opt,name=non_body_parameter,json=nonBodyParameter,oneof"` +} + +func (*Parameter_BodyParameter) isParameter_Oneof() {} +func (*Parameter_NonBodyParameter) isParameter_Oneof() {} + +func (m *Parameter) GetOneof() isParameter_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *Parameter) GetBodyParameter() *BodyParameter { + if x, ok := m.GetOneof().(*Parameter_BodyParameter); ok { + return x.BodyParameter + } + return nil +} + +func (m *Parameter) GetNonBodyParameter() *NonBodyParameter { + if x, ok := m.GetOneof().(*Parameter_NonBodyParameter); ok { + return x.NonBodyParameter + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Parameter) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Parameter_OneofMarshaler, _Parameter_OneofUnmarshaler, _Parameter_OneofSizer, []interface{}{ + (*Parameter_BodyParameter)(nil), + (*Parameter_NonBodyParameter)(nil), + } +} + +func _Parameter_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Parameter) + // oneof + switch x := m.Oneof.(type) { + case *Parameter_BodyParameter: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.BodyParameter); err != nil { + return err + } + case *Parameter_NonBodyParameter: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.NonBodyParameter); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Parameter.Oneof has unexpected type %T", x) + } + return nil +} + +func _Parameter_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Parameter) + switch tag { + case 1: // oneof.body_parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(BodyParameter) + err := b.DecodeMessage(msg) + m.Oneof = &Parameter_BodyParameter{msg} + return true, err + case 2: // oneof.non_body_parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(NonBodyParameter) + err := b.DecodeMessage(msg) + m.Oneof = &Parameter_NonBodyParameter{msg} + return true, err + default: + return false, nil + } +} + +func _Parameter_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Parameter) + // oneof + switch x := m.Oneof.(type) { + case *Parameter_BodyParameter: + s := proto.Size(x.BodyParameter) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Parameter_NonBodyParameter: + s := proto.Size(x.NonBodyParameter) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// One or more JSON representations for parameters +type ParameterDefinitions struct { + AdditionalProperties []*NamedParameter `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *ParameterDefinitions) Reset() { *m = ParameterDefinitions{} } +func (m *ParameterDefinitions) String() string { return proto.CompactTextString(m) } +func (*ParameterDefinitions) ProtoMessage() {} +func (*ParameterDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } + +func (m *ParameterDefinitions) GetAdditionalProperties() []*NamedParameter { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type ParametersItem struct { + // Types that are valid to be assigned to Oneof: + // *ParametersItem_Parameter + // *ParametersItem_JsonReference + Oneof isParametersItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *ParametersItem) Reset() { *m = ParametersItem{} } +func (m *ParametersItem) String() string { return proto.CompactTextString(m) } +func (*ParametersItem) ProtoMessage() {} +func (*ParametersItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } + +type isParametersItem_Oneof interface { + isParametersItem_Oneof() +} + +type ParametersItem_Parameter struct { + Parameter *Parameter `protobuf:"bytes,1,opt,name=parameter,oneof"` +} +type ParametersItem_JsonReference struct { + JsonReference *JsonReference `protobuf:"bytes,2,opt,name=json_reference,json=jsonReference,oneof"` +} + +func (*ParametersItem_Parameter) isParametersItem_Oneof() {} +func (*ParametersItem_JsonReference) isParametersItem_Oneof() {} + +func (m *ParametersItem) GetOneof() isParametersItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *ParametersItem) GetParameter() *Parameter { + if x, ok := m.GetOneof().(*ParametersItem_Parameter); ok { + return x.Parameter + } + return nil +} + +func (m *ParametersItem) GetJsonReference() *JsonReference { + if x, ok := m.GetOneof().(*ParametersItem_JsonReference); ok { + return x.JsonReference + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ParametersItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ParametersItem_OneofMarshaler, _ParametersItem_OneofUnmarshaler, _ParametersItem_OneofSizer, []interface{}{ + (*ParametersItem_Parameter)(nil), + (*ParametersItem_JsonReference)(nil), + } +} + +func _ParametersItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ParametersItem) + // oneof + switch x := m.Oneof.(type) { + case *ParametersItem_Parameter: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Parameter); err != nil { + return err + } + case *ParametersItem_JsonReference: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.JsonReference); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("ParametersItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _ParametersItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ParametersItem) + switch tag { + case 1: // oneof.parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Parameter) + err := b.DecodeMessage(msg) + m.Oneof = &ParametersItem_Parameter{msg} + return true, err + case 2: // oneof.json_reference + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(JsonReference) + err := b.DecodeMessage(msg) + m.Oneof = &ParametersItem_JsonReference{msg} + return true, err + default: + return false, nil + } +} + +func _ParametersItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ParametersItem) + // oneof + switch x := m.Oneof.(type) { + case *ParametersItem_Parameter: + s := proto.Size(x.Parameter) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *ParametersItem_JsonReference: + s := proto.Size(x.JsonReference) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type PathItem struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Get *Operation `protobuf:"bytes,2,opt,name=get" json:"get,omitempty"` + Put *Operation `protobuf:"bytes,3,opt,name=put" json:"put,omitempty"` + Post *Operation `protobuf:"bytes,4,opt,name=post" json:"post,omitempty"` + Delete *Operation `protobuf:"bytes,5,opt,name=delete" json:"delete,omitempty"` + Options *Operation `protobuf:"bytes,6,opt,name=options" json:"options,omitempty"` + Head *Operation `protobuf:"bytes,7,opt,name=head" json:"head,omitempty"` + Patch *Operation `protobuf:"bytes,8,opt,name=patch" json:"patch,omitempty"` + // The parameters needed to send a valid API call. + Parameters []*ParametersItem `protobuf:"bytes,9,rep,name=parameters" json:"parameters,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,10,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PathItem) Reset() { *m = PathItem{} } +func (m *PathItem) String() string { return proto.CompactTextString(m) } +func (*PathItem) ProtoMessage() {} +func (*PathItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } + +func (m *PathItem) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *PathItem) GetGet() *Operation { + if m != nil { + return m.Get + } + return nil +} + +func (m *PathItem) GetPut() *Operation { + if m != nil { + return m.Put + } + return nil +} + +func (m *PathItem) GetPost() *Operation { + if m != nil { + return m.Post + } + return nil +} + +func (m *PathItem) GetDelete() *Operation { + if m != nil { + return m.Delete + } + return nil +} + +func (m *PathItem) GetOptions() *Operation { + if m != nil { + return m.Options + } + return nil +} + +func (m *PathItem) GetHead() *Operation { + if m != nil { + return m.Head + } + return nil +} + +func (m *PathItem) GetPatch() *Operation { + if m != nil { + return m.Patch + } + return nil +} + +func (m *PathItem) GetParameters() []*ParametersItem { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *PathItem) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type PathParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,6,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,7,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,8,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,9,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,10,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,11,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,12,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,13,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,14,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,15,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,16,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,17,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,18,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,19,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,21,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,22,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PathParameterSubSchema) Reset() { *m = PathParameterSubSchema{} } +func (m *PathParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*PathParameterSubSchema) ProtoMessage() {} +func (*PathParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } + +func (m *PathParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *PathParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *PathParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *PathParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PathParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *PathParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *PathParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *PathParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *PathParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *PathParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *PathParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *PathParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *PathParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *PathParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *PathParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *PathParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *PathParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *PathParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *PathParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *PathParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *PathParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *PathParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Relative paths to the individual endpoints. They must be relative to the 'basePath'. +type Paths struct { + VendorExtension []*NamedAny `protobuf:"bytes,1,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` + Path []*NamedPathItem `protobuf:"bytes,2,rep,name=path" json:"path,omitempty"` +} + +func (m *Paths) Reset() { *m = Paths{} } +func (m *Paths) String() string { return proto.CompactTextString(m) } +func (*Paths) ProtoMessage() {} +func (*Paths) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} } + +func (m *Paths) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +func (m *Paths) GetPath() []*NamedPathItem { + if m != nil { + return m.Path + } + return nil +} + +type PrimitivesItems struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,3,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,4,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,6,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,7,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,8,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,9,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,10,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,11,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,12,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,13,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,14,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,15,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,16,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,17,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,18,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PrimitivesItems) Reset() { *m = PrimitivesItems{} } +func (m *PrimitivesItems) String() string { return proto.CompactTextString(m) } +func (*PrimitivesItems) ProtoMessage() {} +func (*PrimitivesItems) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} } + +func (m *PrimitivesItems) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *PrimitivesItems) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *PrimitivesItems) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *PrimitivesItems) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *PrimitivesItems) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *PrimitivesItems) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *PrimitivesItems) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *PrimitivesItems) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *PrimitivesItems) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *PrimitivesItems) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *PrimitivesItems) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *PrimitivesItems) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *PrimitivesItems) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *PrimitivesItems) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *PrimitivesItems) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *PrimitivesItems) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *PrimitivesItems) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *PrimitivesItems) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Properties struct { + AdditionalProperties []*NamedSchema `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Properties) Reset() { *m = Properties{} } +func (m *Properties) String() string { return proto.CompactTextString(m) } +func (*Properties) ProtoMessage() {} +func (*Properties) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } + +func (m *Properties) GetAdditionalProperties() []*NamedSchema { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type QueryParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + // allows sending a parameter by name only or with an empty value. + AllowEmptyValue bool `protobuf:"varint,5,opt,name=allow_empty_value,json=allowEmptyValue" json:"allow_empty_value,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,7,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,8,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,9,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,10,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,15,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,16,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,18,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,19,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,20,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,21,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,22,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,23,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *QueryParameterSubSchema) Reset() { *m = QueryParameterSubSchema{} } +func (m *QueryParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*QueryParameterSubSchema) ProtoMessage() {} +func (*QueryParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} } + +func (m *QueryParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *QueryParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *QueryParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *QueryParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *QueryParameterSubSchema) GetAllowEmptyValue() bool { + if m != nil { + return m.AllowEmptyValue + } + return false +} + +func (m *QueryParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *QueryParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *QueryParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *QueryParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *QueryParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *QueryParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *QueryParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *QueryParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *QueryParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *QueryParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *QueryParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *QueryParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *QueryParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *QueryParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *QueryParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *QueryParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *QueryParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *QueryParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Response struct { + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + Schema *SchemaItem `protobuf:"bytes,2,opt,name=schema" json:"schema,omitempty"` + Headers *Headers `protobuf:"bytes,3,opt,name=headers" json:"headers,omitempty"` + Examples *Examples `protobuf:"bytes,4,opt,name=examples" json:"examples,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,5,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} } + +func (m *Response) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Response) GetSchema() *SchemaItem { + if m != nil { + return m.Schema + } + return nil +} + +func (m *Response) GetHeaders() *Headers { + if m != nil { + return m.Headers + } + return nil +} + +func (m *Response) GetExamples() *Examples { + if m != nil { + return m.Examples + } + return nil +} + +func (m *Response) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// One or more JSON representations for parameters +type ResponseDefinitions struct { + AdditionalProperties []*NamedResponse `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *ResponseDefinitions) Reset() { *m = ResponseDefinitions{} } +func (m *ResponseDefinitions) String() string { return proto.CompactTextString(m) } +func (*ResponseDefinitions) ProtoMessage() {} +func (*ResponseDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{47} } + +func (m *ResponseDefinitions) GetAdditionalProperties() []*NamedResponse { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type ResponseValue struct { + // Types that are valid to be assigned to Oneof: + // *ResponseValue_Response + // *ResponseValue_JsonReference + Oneof isResponseValue_Oneof `protobuf_oneof:"oneof"` +} + +func (m *ResponseValue) Reset() { *m = ResponseValue{} } +func (m *ResponseValue) String() string { return proto.CompactTextString(m) } +func (*ResponseValue) ProtoMessage() {} +func (*ResponseValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{48} } + +type isResponseValue_Oneof interface { + isResponseValue_Oneof() +} + +type ResponseValue_Response struct { + Response *Response `protobuf:"bytes,1,opt,name=response,oneof"` +} +type ResponseValue_JsonReference struct { + JsonReference *JsonReference `protobuf:"bytes,2,opt,name=json_reference,json=jsonReference,oneof"` +} + +func (*ResponseValue_Response) isResponseValue_Oneof() {} +func (*ResponseValue_JsonReference) isResponseValue_Oneof() {} + +func (m *ResponseValue) GetOneof() isResponseValue_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *ResponseValue) GetResponse() *Response { + if x, ok := m.GetOneof().(*ResponseValue_Response); ok { + return x.Response + } + return nil +} + +func (m *ResponseValue) GetJsonReference() *JsonReference { + if x, ok := m.GetOneof().(*ResponseValue_JsonReference); ok { + return x.JsonReference + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ResponseValue) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ResponseValue_OneofMarshaler, _ResponseValue_OneofUnmarshaler, _ResponseValue_OneofSizer, []interface{}{ + (*ResponseValue_Response)(nil), + (*ResponseValue_JsonReference)(nil), + } +} + +func _ResponseValue_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ResponseValue) + // oneof + switch x := m.Oneof.(type) { + case *ResponseValue_Response: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Response); err != nil { + return err + } + case *ResponseValue_JsonReference: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.JsonReference); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("ResponseValue.Oneof has unexpected type %T", x) + } + return nil +} + +func _ResponseValue_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ResponseValue) + switch tag { + case 1: // oneof.response + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Response) + err := b.DecodeMessage(msg) + m.Oneof = &ResponseValue_Response{msg} + return true, err + case 2: // oneof.json_reference + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(JsonReference) + err := b.DecodeMessage(msg) + m.Oneof = &ResponseValue_JsonReference{msg} + return true, err + default: + return false, nil + } +} + +func _ResponseValue_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ResponseValue) + // oneof + switch x := m.Oneof.(type) { + case *ResponseValue_Response: + s := proto.Size(x.Response) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *ResponseValue_JsonReference: + s := proto.Size(x.JsonReference) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// Response objects names can either be any valid HTTP status code or 'default'. +type Responses struct { + ResponseCode []*NamedResponseValue `protobuf:"bytes,1,rep,name=response_code,json=responseCode" json:"response_code,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,2,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Responses) Reset() { *m = Responses{} } +func (m *Responses) String() string { return proto.CompactTextString(m) } +func (*Responses) ProtoMessage() {} +func (*Responses) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{49} } + +func (m *Responses) GetResponseCode() []*NamedResponseValue { + if m != nil { + return m.ResponseCode + } + return nil +} + +func (m *Responses) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// A deterministic version of a JSON Schema object. +type Schema struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + MultipleOf float64 `protobuf:"fixed64,6,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + Maximum float64 `protobuf:"fixed64,7,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,8,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,9,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,10,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,11,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,12,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,13,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,14,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,15,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,16,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + MaxProperties int64 `protobuf:"varint,17,opt,name=max_properties,json=maxProperties" json:"max_properties,omitempty"` + MinProperties int64 `protobuf:"varint,18,opt,name=min_properties,json=minProperties" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,19,rep,name=required" json:"required,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + AdditionalProperties *AdditionalPropertiesItem `protobuf:"bytes,21,opt,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` + Type *TypeItem `protobuf:"bytes,22,opt,name=type" json:"type,omitempty"` + Items *ItemsItem `protobuf:"bytes,23,opt,name=items" json:"items,omitempty"` + AllOf []*Schema `protobuf:"bytes,24,rep,name=all_of,json=allOf" json:"all_of,omitempty"` + Properties *Properties `protobuf:"bytes,25,opt,name=properties" json:"properties,omitempty"` + Discriminator string `protobuf:"bytes,26,opt,name=discriminator" json:"discriminator,omitempty"` + ReadOnly bool `protobuf:"varint,27,opt,name=read_only,json=readOnly" json:"read_only,omitempty"` + Xml *Xml `protobuf:"bytes,28,opt,name=xml" json:"xml,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,29,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + Example *Any `protobuf:"bytes,30,opt,name=example" json:"example,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,31,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Schema) Reset() { *m = Schema{} } +func (m *Schema) String() string { return proto.CompactTextString(m) } +func (*Schema) ProtoMessage() {} +func (*Schema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{50} } + +func (m *Schema) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *Schema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *Schema) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *Schema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Schema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *Schema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *Schema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *Schema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *Schema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *Schema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *Schema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *Schema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *Schema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *Schema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *Schema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *Schema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *Schema) GetMaxProperties() int64 { + if m != nil { + return m.MaxProperties + } + return 0 +} + +func (m *Schema) GetMinProperties() int64 { + if m != nil { + return m.MinProperties + } + return 0 +} + +func (m *Schema) GetRequired() []string { + if m != nil { + return m.Required + } + return nil +} + +func (m *Schema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *Schema) GetAdditionalProperties() *AdditionalPropertiesItem { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +func (m *Schema) GetType() *TypeItem { + if m != nil { + return m.Type + } + return nil +} + +func (m *Schema) GetItems() *ItemsItem { + if m != nil { + return m.Items + } + return nil +} + +func (m *Schema) GetAllOf() []*Schema { + if m != nil { + return m.AllOf + } + return nil +} + +func (m *Schema) GetProperties() *Properties { + if m != nil { + return m.Properties + } + return nil +} + +func (m *Schema) GetDiscriminator() string { + if m != nil { + return m.Discriminator + } + return "" +} + +func (m *Schema) GetReadOnly() bool { + if m != nil { + return m.ReadOnly + } + return false +} + +func (m *Schema) GetXml() *Xml { + if m != nil { + return m.Xml + } + return nil +} + +func (m *Schema) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Schema) GetExample() *Any { + if m != nil { + return m.Example + } + return nil +} + +func (m *Schema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type SchemaItem struct { + // Types that are valid to be assigned to Oneof: + // *SchemaItem_Schema + // *SchemaItem_FileSchema + Oneof isSchemaItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *SchemaItem) Reset() { *m = SchemaItem{} } +func (m *SchemaItem) String() string { return proto.CompactTextString(m) } +func (*SchemaItem) ProtoMessage() {} +func (*SchemaItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{51} } + +type isSchemaItem_Oneof interface { + isSchemaItem_Oneof() +} + +type SchemaItem_Schema struct { + Schema *Schema `protobuf:"bytes,1,opt,name=schema,oneof"` +} +type SchemaItem_FileSchema struct { + FileSchema *FileSchema `protobuf:"bytes,2,opt,name=file_schema,json=fileSchema,oneof"` +} + +func (*SchemaItem_Schema) isSchemaItem_Oneof() {} +func (*SchemaItem_FileSchema) isSchemaItem_Oneof() {} + +func (m *SchemaItem) GetOneof() isSchemaItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *SchemaItem) GetSchema() *Schema { + if x, ok := m.GetOneof().(*SchemaItem_Schema); ok { + return x.Schema + } + return nil +} + +func (m *SchemaItem) GetFileSchema() *FileSchema { + if x, ok := m.GetOneof().(*SchemaItem_FileSchema); ok { + return x.FileSchema + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SchemaItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SchemaItem_OneofMarshaler, _SchemaItem_OneofUnmarshaler, _SchemaItem_OneofSizer, []interface{}{ + (*SchemaItem_Schema)(nil), + (*SchemaItem_FileSchema)(nil), + } +} + +func _SchemaItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SchemaItem) + // oneof + switch x := m.Oneof.(type) { + case *SchemaItem_Schema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Schema); err != nil { + return err + } + case *SchemaItem_FileSchema: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.FileSchema); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SchemaItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _SchemaItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SchemaItem) + switch tag { + case 1: // oneof.schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Schema) + err := b.DecodeMessage(msg) + m.Oneof = &SchemaItem_Schema{msg} + return true, err + case 2: // oneof.file_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(FileSchema) + err := b.DecodeMessage(msg) + m.Oneof = &SchemaItem_FileSchema{msg} + return true, err + default: + return false, nil + } +} + +func _SchemaItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SchemaItem) + // oneof + switch x := m.Oneof.(type) { + case *SchemaItem_Schema: + s := proto.Size(x.Schema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SchemaItem_FileSchema: + s := proto.Size(x.FileSchema) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type SecurityDefinitions struct { + AdditionalProperties []*NamedSecurityDefinitionsItem `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *SecurityDefinitions) Reset() { *m = SecurityDefinitions{} } +func (m *SecurityDefinitions) String() string { return proto.CompactTextString(m) } +func (*SecurityDefinitions) ProtoMessage() {} +func (*SecurityDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{52} } + +func (m *SecurityDefinitions) GetAdditionalProperties() []*NamedSecurityDefinitionsItem { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type SecurityDefinitionsItem struct { + // Types that are valid to be assigned to Oneof: + // *SecurityDefinitionsItem_BasicAuthenticationSecurity + // *SecurityDefinitionsItem_ApiKeySecurity + // *SecurityDefinitionsItem_Oauth2ImplicitSecurity + // *SecurityDefinitionsItem_Oauth2PasswordSecurity + // *SecurityDefinitionsItem_Oauth2ApplicationSecurity + // *SecurityDefinitionsItem_Oauth2AccessCodeSecurity + Oneof isSecurityDefinitionsItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *SecurityDefinitionsItem) Reset() { *m = SecurityDefinitionsItem{} } +func (m *SecurityDefinitionsItem) String() string { return proto.CompactTextString(m) } +func (*SecurityDefinitionsItem) ProtoMessage() {} +func (*SecurityDefinitionsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{53} } + +type isSecurityDefinitionsItem_Oneof interface { + isSecurityDefinitionsItem_Oneof() +} + +type SecurityDefinitionsItem_BasicAuthenticationSecurity struct { + BasicAuthenticationSecurity *BasicAuthenticationSecurity `protobuf:"bytes,1,opt,name=basic_authentication_security,json=basicAuthenticationSecurity,oneof"` +} +type SecurityDefinitionsItem_ApiKeySecurity struct { + ApiKeySecurity *ApiKeySecurity `protobuf:"bytes,2,opt,name=api_key_security,json=apiKeySecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2ImplicitSecurity struct { + Oauth2ImplicitSecurity *Oauth2ImplicitSecurity `protobuf:"bytes,3,opt,name=oauth2_implicit_security,json=oauth2ImplicitSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2PasswordSecurity struct { + Oauth2PasswordSecurity *Oauth2PasswordSecurity `protobuf:"bytes,4,opt,name=oauth2_password_security,json=oauth2PasswordSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2ApplicationSecurity struct { + Oauth2ApplicationSecurity *Oauth2ApplicationSecurity `protobuf:"bytes,5,opt,name=oauth2_application_security,json=oauth2ApplicationSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2AccessCodeSecurity struct { + Oauth2AccessCodeSecurity *Oauth2AccessCodeSecurity `protobuf:"bytes,6,opt,name=oauth2_access_code_security,json=oauth2AccessCodeSecurity,oneof"` +} + +func (*SecurityDefinitionsItem_BasicAuthenticationSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_ApiKeySecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2ImplicitSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2PasswordSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2ApplicationSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2AccessCodeSecurity) isSecurityDefinitionsItem_Oneof() {} + +func (m *SecurityDefinitionsItem) GetOneof() isSecurityDefinitionsItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *SecurityDefinitionsItem) GetBasicAuthenticationSecurity() *BasicAuthenticationSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_BasicAuthenticationSecurity); ok { + return x.BasicAuthenticationSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetApiKeySecurity() *ApiKeySecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_ApiKeySecurity); ok { + return x.ApiKeySecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2ImplicitSecurity() *Oauth2ImplicitSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2ImplicitSecurity); ok { + return x.Oauth2ImplicitSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2PasswordSecurity() *Oauth2PasswordSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2PasswordSecurity); ok { + return x.Oauth2PasswordSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2ApplicationSecurity() *Oauth2ApplicationSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2ApplicationSecurity); ok { + return x.Oauth2ApplicationSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2AccessCodeSecurity() *Oauth2AccessCodeSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2AccessCodeSecurity); ok { + return x.Oauth2AccessCodeSecurity + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SecurityDefinitionsItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SecurityDefinitionsItem_OneofMarshaler, _SecurityDefinitionsItem_OneofUnmarshaler, _SecurityDefinitionsItem_OneofSizer, []interface{}{ + (*SecurityDefinitionsItem_BasicAuthenticationSecurity)(nil), + (*SecurityDefinitionsItem_ApiKeySecurity)(nil), + (*SecurityDefinitionsItem_Oauth2ImplicitSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2PasswordSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2ApplicationSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2AccessCodeSecurity)(nil), + } +} + +func _SecurityDefinitionsItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SecurityDefinitionsItem) + // oneof + switch x := m.Oneof.(type) { + case *SecurityDefinitionsItem_BasicAuthenticationSecurity: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.BasicAuthenticationSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_ApiKeySecurity: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.ApiKeySecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2ImplicitSecurity: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2ImplicitSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2PasswordSecurity: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2PasswordSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2ApplicationSecurity: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2ApplicationSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2AccessCodeSecurity: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2AccessCodeSecurity); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SecurityDefinitionsItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _SecurityDefinitionsItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SecurityDefinitionsItem) + switch tag { + case 1: // oneof.basic_authentication_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(BasicAuthenticationSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_BasicAuthenticationSecurity{msg} + return true, err + case 2: // oneof.api_key_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(ApiKeySecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_ApiKeySecurity{msg} + return true, err + case 3: // oneof.oauth2_implicit_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2ImplicitSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2ImplicitSecurity{msg} + return true, err + case 4: // oneof.oauth2_password_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2PasswordSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2PasswordSecurity{msg} + return true, err + case 5: // oneof.oauth2_application_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2ApplicationSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2ApplicationSecurity{msg} + return true, err + case 6: // oneof.oauth2_access_code_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2AccessCodeSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2AccessCodeSecurity{msg} + return true, err + default: + return false, nil + } +} + +func _SecurityDefinitionsItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SecurityDefinitionsItem) + // oneof + switch x := m.Oneof.(type) { + case *SecurityDefinitionsItem_BasicAuthenticationSecurity: + s := proto.Size(x.BasicAuthenticationSecurity) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_ApiKeySecurity: + s := proto.Size(x.ApiKeySecurity) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2ImplicitSecurity: + s := proto.Size(x.Oauth2ImplicitSecurity) + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2PasswordSecurity: + s := proto.Size(x.Oauth2PasswordSecurity) + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2ApplicationSecurity: + s := proto.Size(x.Oauth2ApplicationSecurity) + n += proto.SizeVarint(5<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2AccessCodeSecurity: + s := proto.Size(x.Oauth2AccessCodeSecurity) + n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type SecurityRequirement struct { + AdditionalProperties []*NamedStringArray `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *SecurityRequirement) Reset() { *m = SecurityRequirement{} } +func (m *SecurityRequirement) String() string { return proto.CompactTextString(m) } +func (*SecurityRequirement) ProtoMessage() {} +func (*SecurityRequirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{54} } + +func (m *SecurityRequirement) GetAdditionalProperties() []*NamedStringArray { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type StringArray struct { + Value []string `protobuf:"bytes,1,rep,name=value" json:"value,omitempty"` +} + +func (m *StringArray) Reset() { *m = StringArray{} } +func (m *StringArray) String() string { return proto.CompactTextString(m) } +func (*StringArray) ProtoMessage() {} +func (*StringArray) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{55} } + +func (m *StringArray) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +type Tag struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,4,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Tag) Reset() { *m = Tag{} } +func (m *Tag) String() string { return proto.CompactTextString(m) } +func (*Tag) ProtoMessage() {} +func (*Tag) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{56} } + +func (m *Tag) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Tag) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Tag) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Tag) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type TypeItem struct { + Value []string `protobuf:"bytes,1,rep,name=value" json:"value,omitempty"` +} + +func (m *TypeItem) Reset() { *m = TypeItem{} } +func (m *TypeItem) String() string { return proto.CompactTextString(m) } +func (*TypeItem) ProtoMessage() {} +func (*TypeItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{57} } + +func (m *TypeItem) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +// Any property starting with x- is valid. +type VendorExtension struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *VendorExtension) Reset() { *m = VendorExtension{} } +func (m *VendorExtension) String() string { return proto.CompactTextString(m) } +func (*VendorExtension) ProtoMessage() {} +func (*VendorExtension) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{58} } + +func (m *VendorExtension) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Xml struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` + Prefix string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` + Attribute bool `protobuf:"varint,4,opt,name=attribute" json:"attribute,omitempty"` + Wrapped bool `protobuf:"varint,5,opt,name=wrapped" json:"wrapped,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Xml) Reset() { *m = Xml{} } +func (m *Xml) String() string { return proto.CompactTextString(m) } +func (*Xml) ProtoMessage() {} +func (*Xml) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{59} } + +func (m *Xml) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Xml) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *Xml) GetPrefix() string { + if m != nil { + return m.Prefix + } + return "" +} + +func (m *Xml) GetAttribute() bool { + if m != nil { + return m.Attribute + } + return false +} + +func (m *Xml) GetWrapped() bool { + if m != nil { + return m.Wrapped + } + return false +} + +func (m *Xml) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +func init() { + proto.RegisterType((*AdditionalPropertiesItem)(nil), "openapi.v2.AdditionalPropertiesItem") + proto.RegisterType((*Any)(nil), "openapi.v2.Any") + proto.RegisterType((*ApiKeySecurity)(nil), "openapi.v2.ApiKeySecurity") + proto.RegisterType((*BasicAuthenticationSecurity)(nil), "openapi.v2.BasicAuthenticationSecurity") + proto.RegisterType((*BodyParameter)(nil), "openapi.v2.BodyParameter") + proto.RegisterType((*Contact)(nil), "openapi.v2.Contact") + proto.RegisterType((*Default)(nil), "openapi.v2.Default") + proto.RegisterType((*Definitions)(nil), "openapi.v2.Definitions") + proto.RegisterType((*Document)(nil), "openapi.v2.Document") + proto.RegisterType((*Examples)(nil), "openapi.v2.Examples") + proto.RegisterType((*ExternalDocs)(nil), "openapi.v2.ExternalDocs") + proto.RegisterType((*FileSchema)(nil), "openapi.v2.FileSchema") + proto.RegisterType((*FormDataParameterSubSchema)(nil), "openapi.v2.FormDataParameterSubSchema") + proto.RegisterType((*Header)(nil), "openapi.v2.Header") + proto.RegisterType((*HeaderParameterSubSchema)(nil), "openapi.v2.HeaderParameterSubSchema") + proto.RegisterType((*Headers)(nil), "openapi.v2.Headers") + proto.RegisterType((*Info)(nil), "openapi.v2.Info") + proto.RegisterType((*ItemsItem)(nil), "openapi.v2.ItemsItem") + proto.RegisterType((*JsonReference)(nil), "openapi.v2.JsonReference") + proto.RegisterType((*License)(nil), "openapi.v2.License") + proto.RegisterType((*NamedAny)(nil), "openapi.v2.NamedAny") + proto.RegisterType((*NamedHeader)(nil), "openapi.v2.NamedHeader") + proto.RegisterType((*NamedParameter)(nil), "openapi.v2.NamedParameter") + proto.RegisterType((*NamedPathItem)(nil), "openapi.v2.NamedPathItem") + proto.RegisterType((*NamedResponse)(nil), "openapi.v2.NamedResponse") + proto.RegisterType((*NamedResponseValue)(nil), "openapi.v2.NamedResponseValue") + proto.RegisterType((*NamedSchema)(nil), "openapi.v2.NamedSchema") + proto.RegisterType((*NamedSecurityDefinitionsItem)(nil), "openapi.v2.NamedSecurityDefinitionsItem") + proto.RegisterType((*NamedString)(nil), "openapi.v2.NamedString") + proto.RegisterType((*NamedStringArray)(nil), "openapi.v2.NamedStringArray") + proto.RegisterType((*NonBodyParameter)(nil), "openapi.v2.NonBodyParameter") + proto.RegisterType((*Oauth2AccessCodeSecurity)(nil), "openapi.v2.Oauth2AccessCodeSecurity") + proto.RegisterType((*Oauth2ApplicationSecurity)(nil), "openapi.v2.Oauth2ApplicationSecurity") + proto.RegisterType((*Oauth2ImplicitSecurity)(nil), "openapi.v2.Oauth2ImplicitSecurity") + proto.RegisterType((*Oauth2PasswordSecurity)(nil), "openapi.v2.Oauth2PasswordSecurity") + proto.RegisterType((*Oauth2Scopes)(nil), "openapi.v2.Oauth2Scopes") + proto.RegisterType((*Operation)(nil), "openapi.v2.Operation") + proto.RegisterType((*Parameter)(nil), "openapi.v2.Parameter") + proto.RegisterType((*ParameterDefinitions)(nil), "openapi.v2.ParameterDefinitions") + proto.RegisterType((*ParametersItem)(nil), "openapi.v2.ParametersItem") + proto.RegisterType((*PathItem)(nil), "openapi.v2.PathItem") + proto.RegisterType((*PathParameterSubSchema)(nil), "openapi.v2.PathParameterSubSchema") + proto.RegisterType((*Paths)(nil), "openapi.v2.Paths") + proto.RegisterType((*PrimitivesItems)(nil), "openapi.v2.PrimitivesItems") + proto.RegisterType((*Properties)(nil), "openapi.v2.Properties") + proto.RegisterType((*QueryParameterSubSchema)(nil), "openapi.v2.QueryParameterSubSchema") + proto.RegisterType((*Response)(nil), "openapi.v2.Response") + proto.RegisterType((*ResponseDefinitions)(nil), "openapi.v2.ResponseDefinitions") + proto.RegisterType((*ResponseValue)(nil), "openapi.v2.ResponseValue") + proto.RegisterType((*Responses)(nil), "openapi.v2.Responses") + proto.RegisterType((*Schema)(nil), "openapi.v2.Schema") + proto.RegisterType((*SchemaItem)(nil), "openapi.v2.SchemaItem") + proto.RegisterType((*SecurityDefinitions)(nil), "openapi.v2.SecurityDefinitions") + proto.RegisterType((*SecurityDefinitionsItem)(nil), "openapi.v2.SecurityDefinitionsItem") + proto.RegisterType((*SecurityRequirement)(nil), "openapi.v2.SecurityRequirement") + proto.RegisterType((*StringArray)(nil), "openapi.v2.StringArray") + proto.RegisterType((*Tag)(nil), "openapi.v2.Tag") + proto.RegisterType((*TypeItem)(nil), "openapi.v2.TypeItem") + proto.RegisterType((*VendorExtension)(nil), "openapi.v2.VendorExtension") + proto.RegisterType((*Xml)(nil), "openapi.v2.Xml") +} + +func init() { proto.RegisterFile("OpenAPIv2/OpenAPIv2.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 3129 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3b, 0x4b, 0x73, 0x1c, 0x57, + 0xd5, 0xf3, 0x7e, 0x1c, 0x69, 0x46, 0xa3, 0x96, 0x2c, 0xb7, 0x24, 0xc7, 0x71, 0xe4, 0x3c, 0x6c, + 0xe7, 0xb3, 0x9c, 0x4f, 0x29, 0x48, 0x05, 0x2a, 0x05, 0xf2, 0xab, 0xc6, 0xc4, 0x44, 0x4a, 0xcb, + 0x0e, 0x09, 0x04, 0xba, 0xae, 0x66, 0xee, 0x48, 0x9d, 0x74, 0xf7, 0x6d, 0x77, 0xf7, 0xc8, 0x1a, + 0x16, 0x2c, 0xa0, 0x8a, 0x35, 0x50, 0x59, 0x53, 0x15, 0x16, 0x14, 0x55, 0x59, 0xb0, 0x62, 0xc5, + 0x1f, 0x60, 0xc7, 0x3f, 0x60, 0x0d, 0x5b, 0xaa, 0x58, 0x51, 0x3c, 0xea, 0xbe, 0xfa, 0x31, 0x7d, + 0x7b, 0x1e, 0x96, 0x0b, 0x28, 0xd0, 0x6a, 0xe6, 0xde, 0x73, 0xee, 0xb9, 0xa7, 0x4f, 0x9f, 0xd7, + 0x3d, 0xe7, 0x36, 0xac, 0xef, 0x79, 0xd8, 0xdd, 0xdd, 0x7f, 0x70, 0xb2, 0x73, 0x2b, 0xfa, 0xb7, + 0xed, 0xf9, 0x24, 0x24, 0x1a, 0x10, 0x0f, 0xbb, 0xc8, 0xb3, 0xb6, 0x4f, 0x76, 0x36, 0xd6, 0x8f, + 0x08, 0x39, 0xb2, 0xf1, 0x2d, 0x06, 0x39, 0x1c, 0x0e, 0x6e, 0x21, 0x77, 0xc4, 0xd1, 0xb6, 0x1c, + 0xd0, 0x77, 0xfb, 0x7d, 0x2b, 0xb4, 0x88, 0x8b, 0xec, 0x7d, 0x9f, 0x78, 0xd8, 0x0f, 0x2d, 0x1c, + 0x3c, 0x08, 0xb1, 0xa3, 0xfd, 0x1f, 0xd4, 0x82, 0xde, 0x31, 0x76, 0x90, 0x5e, 0xbc, 0x52, 0xbc, + 0xb6, 0xb0, 0xa3, 0x6d, 0xc7, 0x34, 0xb7, 0x0f, 0x18, 0xa4, 0x5b, 0x30, 0x04, 0x8e, 0xb6, 0x01, + 0xf5, 0x43, 0x42, 0x6c, 0x8c, 0x5c, 0xbd, 0x74, 0xa5, 0x78, 0xad, 0xd1, 0x2d, 0x18, 0x72, 0xe2, + 0x76, 0x1d, 0xaa, 0xc4, 0xc5, 0x64, 0xb0, 0x75, 0x0f, 0xca, 0xbb, 0xee, 0x48, 0xbb, 0x01, 0xd5, + 0x13, 0x64, 0x0f, 0xb1, 0x20, 0xbc, 0xba, 0xcd, 0x19, 0xdc, 0x96, 0x0c, 0x6e, 0xef, 0xba, 0x23, + 0x83, 0xa3, 0x68, 0x1a, 0x54, 0x46, 0xc8, 0xb1, 0x19, 0xd1, 0xa6, 0xc1, 0xfe, 0x6f, 0x7d, 0x51, + 0x84, 0xf6, 0xae, 0x67, 0xbd, 0x8b, 0x47, 0x07, 0xb8, 0x37, 0xf4, 0xad, 0x70, 0x44, 0xd1, 0xc2, + 0x91, 0xc7, 0x29, 0x36, 0x0d, 0xf6, 0x9f, 0xce, 0xb9, 0xc8, 0xc1, 0x72, 0x29, 0xfd, 0xaf, 0xb5, + 0xa1, 0x64, 0xb9, 0x7a, 0x99, 0xcd, 0x94, 0x2c, 0x57, 0xbb, 0x02, 0x0b, 0x7d, 0x1c, 0xf4, 0x7c, + 0xcb, 0xa3, 0x32, 0xd0, 0x2b, 0x0c, 0x90, 0x9c, 0xd2, 0xbe, 0x06, 0x9d, 0x13, 0xec, 0xf6, 0x89, + 0x6f, 0xe2, 0xd3, 0x10, 0xbb, 0x01, 0x45, 0xab, 0x5e, 0x29, 0x33, 0xbe, 0x13, 0x02, 0x79, 0x0f, + 0x39, 0xb8, 0x4f, 0xf9, 0x5e, 0xe2, 0xd8, 0xf7, 0x24, 0xf2, 0xd6, 0x67, 0x45, 0xd8, 0xbc, 0x8d, + 0x02, 0xab, 0xb7, 0x3b, 0x0c, 0x8f, 0xb1, 0x1b, 0x5a, 0x3d, 0x44, 0x09, 0x4f, 0x64, 0x7d, 0x8c, + 0xad, 0xd2, 0x6c, 0x6c, 0x95, 0xe7, 0x61, 0xeb, 0x0f, 0x45, 0x68, 0xdd, 0x26, 0xfd, 0xd1, 0x3e, + 0xf2, 0x91, 0x83, 0x43, 0xec, 0x8f, 0x6f, 0x5a, 0xcc, 0x6e, 0x3a, 0x8b, 0x44, 0x37, 0xa0, 0xe1, + 0xe3, 0x27, 0x43, 0xcb, 0xc7, 0x7d, 0x26, 0xce, 0x86, 0x11, 0x8d, 0xb5, 0x1b, 0x91, 0x4a, 0x55, + 0xf3, 0x54, 0x2a, 0x52, 0x28, 0xd5, 0x03, 0xd6, 0xe6, 0x79, 0xc0, 0x1f, 0x17, 0xa1, 0x7e, 0x87, + 0xb8, 0x21, 0xea, 0x85, 0x11, 0xe3, 0xc5, 0x04, 0xe3, 0x1d, 0x28, 0x0f, 0x7d, 0xa9, 0x58, 0xf4, + 0xaf, 0xb6, 0x0a, 0x55, 0xec, 0x20, 0xcb, 0x16, 0x4f, 0xc3, 0x07, 0x4a, 0x46, 0x2a, 0xf3, 0x30, + 0xf2, 0x08, 0xea, 0x77, 0xf1, 0x00, 0x0d, 0xed, 0x50, 0x7b, 0x00, 0x17, 0x50, 0x64, 0x6f, 0xa6, + 0x17, 0x19, 0x9c, 0x5e, 0x9c, 0x40, 0x70, 0x15, 0x29, 0x4c, 0x74, 0xeb, 0x3b, 0xb0, 0x70, 0x17, + 0x0f, 0x2c, 0x97, 0x41, 0x02, 0xed, 0xe1, 0x64, 0xca, 0x17, 0x33, 0x94, 0x85, 0xb8, 0xd5, 0xc4, + 0xff, 0x58, 0x85, 0xc6, 0x5d, 0xd2, 0x1b, 0x3a, 0xd8, 0x0d, 0x35, 0x1d, 0xea, 0xc1, 0x53, 0x74, + 0x74, 0x84, 0x7d, 0x21, 0x3f, 0x39, 0xd4, 0x5e, 0x86, 0x8a, 0xe5, 0x0e, 0x08, 0x93, 0xe1, 0xc2, + 0x4e, 0x27, 0xb9, 0xc7, 0x03, 0x77, 0x40, 0x0c, 0x06, 0xa5, 0xc2, 0x3f, 0x26, 0x41, 0x28, 0xa4, + 0xca, 0xfe, 0x6b, 0x9b, 0xd0, 0x3c, 0x44, 0x01, 0x36, 0x3d, 0x14, 0x1e, 0x0b, 0xab, 0x6b, 0xd0, + 0x89, 0x7d, 0x14, 0x1e, 0xb3, 0x0d, 0x29, 0x77, 0x38, 0x60, 0x96, 0x46, 0x37, 0xe4, 0x43, 0xaa, + 0x5c, 0x3d, 0xe2, 0x06, 0x43, 0x0a, 0xaa, 0x31, 0x50, 0x34, 0xa6, 0x30, 0xcf, 0x27, 0xfd, 0x61, + 0x0f, 0x07, 0x7a, 0x9d, 0xc3, 0xe4, 0x58, 0x7b, 0x0d, 0xaa, 0x74, 0xa7, 0x40, 0x6f, 0x30, 0x4e, + 0x97, 0x93, 0x9c, 0xd2, 0x2d, 0x03, 0x83, 0xc3, 0xb5, 0xb7, 0xa9, 0x0d, 0x44, 0x52, 0xd5, 0x9b, + 0x0c, 0x3d, 0x25, 0xbc, 0x84, 0xd0, 0x8d, 0x24, 0xae, 0xf6, 0x75, 0x00, 0x4f, 0xda, 0x52, 0xa0, + 0x03, 0x5b, 0x79, 0x25, 0xbd, 0x91, 0x80, 0x26, 0x49, 0x24, 0xd6, 0x68, 0xef, 0x40, 0xd3, 0xc7, + 0x81, 0x47, 0xdc, 0x00, 0x07, 0xfa, 0x02, 0x23, 0xf0, 0x62, 0x92, 0x80, 0x21, 0x80, 0xc9, 0xf5, + 0xf1, 0x0a, 0xed, 0xab, 0xd0, 0x08, 0x84, 0x53, 0xd1, 0x17, 0xd9, 0x5b, 0x4f, 0xad, 0x96, 0x0e, + 0xc7, 0xe0, 0xd6, 0x48, 0x5f, 0xad, 0x11, 0x2d, 0xd0, 0x0c, 0x58, 0x95, 0xff, 0xcd, 0xa4, 0x04, + 0x5a, 0x59, 0x36, 0x24, 0xa1, 0x24, 0x1b, 0x2b, 0x41, 0x76, 0x52, 0xbb, 0x0a, 0x95, 0x10, 0x1d, + 0x05, 0x7a, 0x9b, 0x31, 0xb3, 0x94, 0xa4, 0xf1, 0x08, 0x1d, 0x19, 0x0c, 0xa8, 0xbd, 0x03, 0x2d, + 0x6a, 0x57, 0x3e, 0x55, 0xdb, 0x3e, 0xe9, 0x05, 0xfa, 0x12, 0xdb, 0x51, 0x4f, 0x62, 0xdf, 0x13, + 0x08, 0x77, 0x49, 0x2f, 0x30, 0x16, 0x71, 0x62, 0xa4, 0xb4, 0xce, 0xce, 0x3c, 0xd6, 0xf9, 0x18, + 0x1a, 0xf7, 0x4e, 0x91, 0xe3, 0xd9, 0x38, 0x78, 0x9e, 0xe6, 0xf9, 0xa3, 0x22, 0x2c, 0x26, 0xd9, + 0x9e, 0xc1, 0xbb, 0x66, 0x1d, 0xd2, 0x99, 0x9d, 0xfc, 0x3f, 0x4a, 0x00, 0xf7, 0x2d, 0x1b, 0x73, + 0x63, 0xd7, 0xd6, 0xa0, 0x36, 0x20, 0xbe, 0x83, 0x42, 0xb1, 0xbd, 0x18, 0x51, 0xc7, 0x17, 0x5a, + 0xa1, 0x2d, 0x1d, 0x3b, 0x1f, 0x8c, 0x73, 0x5c, 0xce, 0x72, 0x7c, 0x1d, 0xea, 0x7d, 0xee, 0xd9, + 0x98, 0x0d, 0x8f, 0xbd, 0x63, 0xca, 0x91, 0x84, 0xa7, 0xc2, 0x02, 0x37, 0xea, 0x38, 0x2c, 0xc8, + 0x08, 0x58, 0x4b, 0x44, 0xc0, 0x4d, 0x6a, 0x0b, 0xa8, 0x6f, 0x12, 0xd7, 0x1e, 0xe9, 0x75, 0x19, + 0x47, 0x50, 0x7f, 0xcf, 0xb5, 0x47, 0x59, 0x9d, 0x69, 0xcc, 0xa5, 0x33, 0xd7, 0xa1, 0x8e, 0xf9, + 0x2b, 0x17, 0x06, 0x9e, 0x65, 0x5b, 0xc0, 0x95, 0x6f, 0x00, 0xe6, 0x79, 0x03, 0x5f, 0xd4, 0x60, + 0xe3, 0x3e, 0xf1, 0x9d, 0xbb, 0x28, 0x44, 0x91, 0x03, 0x38, 0x18, 0x1e, 0x1e, 0xc8, 0xb4, 0x29, + 0x16, 0x4b, 0x71, 0x2c, 0x5a, 0xf2, 0xc8, 0x5a, 0xca, 0xcb, 0x55, 0xca, 0xf9, 0xf1, 0xb9, 0x92, + 0x08, 0x73, 0x37, 0x60, 0x19, 0xd9, 0x36, 0x79, 0x6a, 0x62, 0xc7, 0x0b, 0x47, 0x26, 0x4f, 0xbc, + 0xaa, 0x6c, 0xab, 0x25, 0x06, 0xb8, 0x47, 0xe7, 0x3f, 0x90, 0xc9, 0x56, 0xe6, 0x45, 0xc4, 0x3a, + 0x53, 0x4f, 0xe9, 0xcc, 0xff, 0x43, 0xd5, 0x0a, 0xb1, 0x23, 0x65, 0xbf, 0x99, 0xf2, 0x74, 0xbe, + 0xe5, 0x58, 0xa1, 0x75, 0xc2, 0x33, 0xc9, 0xc0, 0xe0, 0x98, 0xda, 0xeb, 0xb0, 0xdc, 0x23, 0xb6, + 0x8d, 0x7b, 0x94, 0x59, 0x53, 0x50, 0x6d, 0x32, 0xaa, 0x9d, 0x18, 0x70, 0x9f, 0xd3, 0x4f, 0xe8, + 0x16, 0x4c, 0xd1, 0x2d, 0x1d, 0xea, 0x0e, 0x3a, 0xb5, 0x9c, 0xa1, 0xc3, 0xbc, 0x66, 0xd1, 0x90, + 0x43, 0xba, 0x23, 0x3e, 0xed, 0xd9, 0xc3, 0xc0, 0x3a, 0xc1, 0xa6, 0xc4, 0x59, 0x64, 0x0f, 0xdf, + 0x89, 0x00, 0xdf, 0x14, 0xc8, 0x94, 0x8c, 0xe5, 0x32, 0x94, 0x96, 0x20, 0xc3, 0x87, 0x63, 0x64, + 0x04, 0x4e, 0x7b, 0x9c, 0x8c, 0x40, 0x7e, 0x01, 0xc0, 0x41, 0xa7, 0xa6, 0x8d, 0xdd, 0xa3, 0xf0, + 0x98, 0x79, 0xb3, 0xb2, 0xd1, 0x74, 0xd0, 0xe9, 0x43, 0x36, 0xc1, 0xc0, 0x96, 0x2b, 0xc1, 0x1d, + 0x01, 0xb6, 0x5c, 0x01, 0xd6, 0xa1, 0xee, 0xa1, 0x90, 0x2a, 0xab, 0xbe, 0xcc, 0x83, 0xad, 0x18, + 0x52, 0x8b, 0xa0, 0x74, 0xb9, 0xd0, 0x35, 0xb6, 0xae, 0xe1, 0xa0, 0x53, 0x26, 0x61, 0x06, 0xb4, + 0x5c, 0x01, 0x5c, 0x11, 0x40, 0xcb, 0xe5, 0xc0, 0x97, 0x60, 0x71, 0xe8, 0x5a, 0x4f, 0x86, 0x58, + 0xc0, 0x57, 0x19, 0xe7, 0x0b, 0x7c, 0x8e, 0xa3, 0x5c, 0x85, 0x0a, 0x76, 0x87, 0x8e, 0x7e, 0x21, + 0xeb, 0xaa, 0xa9, 0xa8, 0x19, 0x50, 0x7b, 0x11, 0x16, 0x9c, 0xa1, 0x1d, 0x5a, 0x9e, 0x8d, 0x4d, + 0x32, 0xd0, 0xd7, 0x98, 0x90, 0x40, 0x4e, 0xed, 0x0d, 0x94, 0xd6, 0x72, 0x71, 0x2e, 0x6b, 0xa9, + 0x42, 0xad, 0x8b, 0x51, 0x1f, 0xfb, 0xca, 0xb4, 0x38, 0xd6, 0xc5, 0x92, 0x5a, 0x17, 0xcb, 0x67, + 0xd3, 0xc5, 0xca, 0x74, 0x5d, 0xac, 0xce, 0xae, 0x8b, 0xb5, 0x19, 0x74, 0xb1, 0x3e, 0x5d, 0x17, + 0x1b, 0x33, 0xe8, 0x62, 0x73, 0x26, 0x5d, 0x84, 0xc9, 0xba, 0xb8, 0x30, 0x41, 0x17, 0x17, 0x27, + 0xe8, 0x62, 0x6b, 0x92, 0x2e, 0xb6, 0xa7, 0xe8, 0xe2, 0x52, 0xbe, 0x2e, 0x76, 0xe6, 0xd0, 0xc5, + 0xe5, 0x8c, 0x2e, 0x8e, 0x79, 0x4b, 0x6d, 0xb6, 0x23, 0xd4, 0xca, 0x3c, 0xda, 0xfa, 0xb7, 0x2a, + 0xe8, 0x5c, 0x5b, 0xff, 0x2d, 0x9e, 0x5d, 0x5a, 0x48, 0x55, 0x69, 0x21, 0x35, 0xb5, 0x85, 0xd4, + 0xcf, 0x66, 0x21, 0x8d, 0xe9, 0x16, 0xd2, 0x9c, 0xdd, 0x42, 0x60, 0x06, 0x0b, 0x59, 0x98, 0x6e, + 0x21, 0x8b, 0x33, 0x58, 0x48, 0x6b, 0x26, 0x0b, 0x69, 0x4f, 0xb6, 0x90, 0xa5, 0x09, 0x16, 0xd2, + 0x99, 0x60, 0x21, 0xcb, 0x93, 0x2c, 0x44, 0x9b, 0x62, 0x21, 0x2b, 0xf9, 0x16, 0xb2, 0x3a, 0x87, + 0x85, 0x5c, 0x98, 0xc9, 0x5b, 0xaf, 0xcd, 0xa3, 0xff, 0xdf, 0x82, 0x3a, 0x57, 0xff, 0x67, 0x38, + 0x7e, 0xf2, 0x85, 0x39, 0xc9, 0xf3, 0xe7, 0x25, 0xa8, 0xd0, 0x03, 0x64, 0x9c, 0x98, 0x16, 0x93, + 0x89, 0xa9, 0x0e, 0xf5, 0x13, 0xec, 0x07, 0x71, 0x65, 0x44, 0x0e, 0x67, 0x30, 0xa4, 0x6b, 0xd0, + 0x09, 0xb1, 0xef, 0x04, 0x26, 0x19, 0x98, 0x01, 0xf6, 0x4f, 0xac, 0x9e, 0x34, 0xaa, 0x36, 0x9b, + 0xdf, 0x1b, 0x1c, 0xf0, 0x59, 0xed, 0x26, 0xd4, 0x7b, 0xbc, 0x7c, 0x20, 0x9c, 0xfe, 0x4a, 0xf2, + 0x21, 0x44, 0x65, 0xc1, 0x90, 0x38, 0x14, 0xdd, 0xb6, 0x7a, 0xd8, 0x0d, 0x78, 0xfa, 0x34, 0x86, + 0xfe, 0x90, 0x83, 0x0c, 0x89, 0xa3, 0x14, 0x7e, 0x7d, 0x1e, 0xe1, 0xbf, 0x05, 0x4d, 0xa6, 0x0c, + 0xac, 0x56, 0x77, 0x23, 0x51, 0xab, 0x2b, 0x4f, 0x2e, 0xac, 0x6c, 0xdd, 0x85, 0xd6, 0x37, 0x02, + 0xe2, 0x1a, 0x78, 0x80, 0x7d, 0xec, 0xf6, 0xb0, 0xb6, 0x0c, 0x15, 0xd3, 0xc7, 0x03, 0x21, 0xe3, + 0xb2, 0x81, 0x07, 0xd3, 0xeb, 0x4f, 0x5b, 0x1e, 0xd4, 0xc5, 0x33, 0xcd, 0x58, 0x5c, 0x39, 0xf3, + 0x59, 0xe6, 0x1e, 0x34, 0x24, 0x50, 0xb9, 0xe5, 0x2b, 0xb2, 0xaa, 0x58, 0x52, 0x3b, 0x20, 0x0e, + 0xdd, 0x7a, 0x17, 0x16, 0x12, 0x0a, 0xa8, 0xa4, 0x74, 0x2d, 0x4d, 0x29, 0x25, 0x4c, 0xa1, 0xb7, + 0x82, 0xd8, 0xfb, 0xd0, 0x66, 0xc4, 0xe2, 0x22, 0x9a, 0x8a, 0xde, 0xeb, 0x69, 0x7a, 0x17, 0x94, + 0x45, 0x01, 0x49, 0x72, 0x0f, 0x5a, 0x82, 0x64, 0x78, 0xcc, 0xde, 0xad, 0x8a, 0xe2, 0x8d, 0x34, + 0xc5, 0xd5, 0xf1, 0x7a, 0x06, 0x5d, 0x38, 0x4e, 0x50, 0x56, 0x0f, 0xe6, 0x26, 0x28, 0x17, 0x4a, + 0x82, 0x1f, 0x81, 0x96, 0x22, 0x18, 0x9d, 0x1d, 0x32, 0x54, 0x6f, 0xa5, 0xa9, 0xae, 0xab, 0xa8, + 0xb2, 0xd5, 0xe3, 0x2f, 0x47, 0xc4, 0xd0, 0x79, 0x5f, 0x8e, 0xd0, 0x74, 0x41, 0xcc, 0x81, 0x4b, + 0x9c, 0x58, 0xb6, 0x34, 0x91, 0x2b, 0xd8, 0xb7, 0xd3, 0xd4, 0xaf, 0x4e, 0xa9, 0x7b, 0x24, 0xe5, + 0xfc, 0x96, 0xe4, 0x3d, 0xf4, 0x2d, 0xf7, 0x48, 0x49, 0x7d, 0x35, 0x49, 0xbd, 0x29, 0x17, 0x3e, + 0x86, 0x4e, 0x62, 0xe1, 0xae, 0xef, 0x23, 0xb5, 0x82, 0xdf, 0x4c, 0xf3, 0x96, 0xf2, 0xa9, 0x89, + 0xb5, 0x92, 0xec, 0x6f, 0xca, 0xd0, 0x79, 0x8f, 0xb8, 0xe9, 0x1a, 0x2f, 0x86, 0xcd, 0x63, 0xa6, + 0xc1, 0x66, 0x54, 0x77, 0x32, 0x83, 0xe1, 0xa1, 0x99, 0xaa, 0xf4, 0xbf, 0x9c, 0x55, 0xf8, 0x6c, + 0x82, 0xd3, 0x2d, 0x18, 0xfa, 0x71, 0x5e, 0xf2, 0x63, 0xc3, 0x65, 0x9a, 0x30, 0x98, 0x7d, 0x14, + 0x22, 0xf5, 0x4e, 0xfc, 0x19, 0x5e, 0x4d, 0xee, 0x94, 0x7f, 0x4c, 0xee, 0x16, 0x8c, 0x8d, 0x41, + 0xfe, 0x21, 0xfa, 0x10, 0x36, 0x9e, 0x0c, 0xb1, 0x3f, 0x52, 0xef, 0x54, 0xce, 0xbe, 0xc9, 0xf7, + 0x29, 0xb6, 0x72, 0x9b, 0x8b, 0x4f, 0xd4, 0x20, 0xcd, 0x84, 0x75, 0x0f, 0x85, 0xc7, 0xea, 0x2d, + 0x78, 0xf1, 0x63, 0x6b, 0xdc, 0x0a, 0x95, 0x3b, 0xac, 0x79, 0x4a, 0x48, 0xdc, 0x24, 0xf9, 0xbc, + 0x04, 0xfa, 0x1e, 0x1a, 0x86, 0xc7, 0x3b, 0xbb, 0xbd, 0x1e, 0x0e, 0x82, 0x3b, 0xa4, 0x8f, 0xa7, + 0xf5, 0x39, 0x06, 0x36, 0x79, 0x2a, 0xab, 0xf2, 0xf4, 0xbf, 0xf6, 0x06, 0x0d, 0x08, 0xc4, 0xc3, + 0xf2, 0x48, 0x94, 0x2a, 0x8d, 0x70, 0xea, 0x07, 0x0c, 0x6e, 0x08, 0x3c, 0x9a, 0x35, 0xd1, 0x69, + 0xe2, 0x5b, 0xdf, 0x67, 0xfd, 0x09, 0x93, 0xfa, 0x6f, 0x71, 0x20, 0x4a, 0x01, 0x1e, 0xfb, 0x36, + 0x4d, 0x60, 0x42, 0xf2, 0x29, 0xe6, 0x48, 0x3c, 0xff, 0x6c, 0xb0, 0x09, 0x0a, 0x1c, 0x0b, 0x1e, + 0xb5, 0xd9, 0x32, 0xef, 0xb9, 0x82, 0xdf, 0x5f, 0x8a, 0xb0, 0x2e, 0x64, 0xe4, 0x79, 0xf6, 0x2c, + 0x1d, 0x95, 0xe7, 0x23, 0xa4, 0xd4, 0x73, 0x57, 0x26, 0x3f, 0x77, 0x75, 0xb6, 0xe7, 0x9e, 0xab, + 0xa7, 0xf1, 0xc3, 0x12, 0xac, 0x71, 0xc6, 0x1e, 0x38, 0xf4, 0xb9, 0xad, 0xf0, 0x3f, 0x4d, 0x33, + 0xfe, 0x05, 0x42, 0xf8, 0x73, 0x51, 0x0a, 0x61, 0x1f, 0x05, 0xc1, 0x53, 0xe2, 0xf7, 0xff, 0x07, + 0xde, 0xfc, 0xc7, 0xb0, 0x98, 0xe4, 0xeb, 0x19, 0xfa, 0x3d, 0x2c, 0x42, 0xe4, 0x24, 0xdc, 0x3f, + 0xaf, 0x40, 0x73, 0xcf, 0xc3, 0x3e, 0x92, 0x87, 0x4d, 0x56, 0xb7, 0x2f, 0xb2, 0x3a, 0x2d, 0x2f, + 0xd3, 0xeb, 0x50, 0x0f, 0x86, 0x8e, 0x83, 0xfc, 0x91, 0xcc, 0xb9, 0xc5, 0x70, 0x86, 0x9c, 0x3b, + 0x53, 0xae, 0xad, 0xcc, 0x55, 0xae, 0x7d, 0x09, 0x16, 0x89, 0xe4, 0xcd, 0xb4, 0xfa, 0x52, 0xbc, + 0xd1, 0xdc, 0x83, 0x7e, 0xaa, 0xf7, 0x53, 0x1b, 0xeb, 0xfd, 0x24, 0x7b, 0x46, 0xf5, 0xb1, 0x9e, + 0xd1, 0x57, 0x52, 0x3d, 0x9b, 0x06, 0x13, 0xdd, 0x86, 0x32, 0x3d, 0xe3, 0xa1, 0x3e, 0xd9, 0xad, + 0x79, 0x33, 0xd9, 0xad, 0x69, 0x66, 0x33, 0x3b, 0x99, 0xe0, 0xa4, 0x7a, 0x34, 0x89, 0xd6, 0x16, + 0xa4, 0x5b, 0x5b, 0x97, 0x01, 0xfa, 0xd8, 0xf3, 0x71, 0x0f, 0x85, 0xb8, 0x2f, 0x4e, 0xbd, 0x89, + 0x99, 0xb3, 0x75, 0x77, 0x54, 0xea, 0xd7, 0x9a, 0x47, 0xfd, 0x7e, 0x59, 0x84, 0x66, 0x9c, 0x45, + 0xdc, 0x86, 0xf6, 0x21, 0xe9, 0x27, 0xe2, 0xad, 0x48, 0x1c, 0x52, 0x09, 0x5e, 0x2a, 0xf1, 0xe8, + 0x16, 0x8c, 0xd6, 0x61, 0x2a, 0x13, 0x79, 0x08, 0x9a, 0x4b, 0x5c, 0x73, 0x8c, 0x0e, 0x4f, 0x0b, + 0x2e, 0xa5, 0x98, 0x1a, 0xcb, 0x61, 0xba, 0x05, 0xa3, 0xe3, 0x8e, 0xcd, 0xc5, 0xd1, 0xf3, 0x08, + 0x56, 0x55, 0x7d, 0x36, 0x6d, 0x6f, 0xb2, 0xbd, 0x6c, 0x64, 0xc4, 0x10, 0x27, 0xe6, 0x6a, 0x93, + 0xf9, 0xac, 0x08, 0xed, 0xb4, 0x76, 0x68, 0x5f, 0x82, 0xe6, 0xb8, 0x44, 0xd4, 0xb9, 0x7e, 0xb7, + 0x60, 0xc4, 0x98, 0x54, 0x9a, 0x9f, 0x04, 0xc4, 0xa5, 0x67, 0x30, 0x7e, 0x22, 0x53, 0xa5, 0xcb, + 0xa9, 0x23, 0x1b, 0x95, 0xe6, 0x27, 0xc9, 0x89, 0xf8, 0xf9, 0x7f, 0x5f, 0x86, 0x46, 0x74, 0x74, + 0x50, 0x9c, 0xec, 0x5e, 0x83, 0xf2, 0x11, 0x0e, 0x55, 0x27, 0x91, 0xc8, 0xfe, 0x0d, 0x8a, 0x41, + 0x11, 0xbd, 0x61, 0x28, 0xfc, 0x63, 0x1e, 0xa2, 0x37, 0x0c, 0xb5, 0xeb, 0x50, 0xf1, 0x48, 0x20, + 0x3b, 0x40, 0x39, 0x98, 0x0c, 0x45, 0xbb, 0x09, 0xb5, 0x3e, 0xb6, 0x71, 0x88, 0xc5, 0x89, 0x3a, + 0x07, 0x59, 0x20, 0x69, 0xb7, 0xa0, 0x4e, 0x3c, 0xde, 0x86, 0xac, 0x4d, 0xc2, 0x97, 0x58, 0x94, + 0x15, 0x9a, 0x92, 0x8a, 0x22, 0x57, 0x1e, 0x2b, 0x14, 0x85, 0x9e, 0xc9, 0x3c, 0x14, 0xf6, 0x8e, + 0x45, 0xfb, 0x22, 0x07, 0x97, 0xe3, 0x8c, 0xb9, 0x89, 0xe6, 0x5c, 0x6e, 0xe2, 0xcc, 0x1d, 0xa4, + 0xbf, 0x56, 0x61, 0x4d, 0x9d, 0x4d, 0x9e, 0xd7, 0x18, 0xcf, 0x6b, 0x8c, 0xff, 0xed, 0x35, 0xc6, + 0xa7, 0x50, 0x65, 0x17, 0x34, 0x94, 0x94, 0x8a, 0x73, 0x50, 0xd2, 0x6e, 0x42, 0x85, 0xdd, 0x36, + 0x29, 0xb1, 0x45, 0xeb, 0x0a, 0x87, 0x2f, 0xea, 0x26, 0x0c, 0x6d, 0xeb, 0x67, 0x55, 0x58, 0x1a, + 0xd3, 0xda, 0xf3, 0x9e, 0xd4, 0x79, 0x4f, 0xea, 0x4c, 0x3d, 0x29, 0x95, 0x0e, 0x6b, 0xf3, 0x58, + 0xc3, 0xb7, 0x01, 0xe2, 0x14, 0xe4, 0x39, 0xdf, 0xf9, 0xfa, 0x55, 0x0d, 0x2e, 0xe6, 0x14, 0x46, + 0xce, 0xaf, 0x29, 0x9c, 0x5f, 0x53, 0x38, 0xbf, 0xa6, 0x10, 0x9b, 0xe1, 0xdf, 0x8b, 0xd0, 0x88, + 0xca, 0xe9, 0xd3, 0x2f, 0x76, 0x6d, 0x47, 0xdd, 0x19, 0x9e, 0x76, 0xaf, 0x65, 0x6b, 0xd6, 0x2c, + 0xf0, 0xc8, 0xab, 0xaf, 0x37, 0xa1, 0xce, 0x2b, 0xab, 0x32, 0x78, 0xac, 0x64, 0x0b, 0xb2, 0x81, + 0x21, 0x71, 0xb4, 0x37, 0xa0, 0x21, 0xae, 0x2b, 0xc9, 0x93, 0xf5, 0x6a, 0xfa, 0x64, 0xcd, 0x61, + 0x46, 0x84, 0x75, 0xf6, 0x3b, 0xcd, 0x18, 0x56, 0x14, 0x97, 0x11, 0xb5, 0xf7, 0x26, 0x3b, 0xa4, + 0x6c, 0xcc, 0x8d, 0x5a, 0x0b, 0x6a, 0x97, 0xf4, 0x93, 0x22, 0xb4, 0xd2, 0x5d, 0x86, 0x1d, 0xea, + 0x88, 0xf8, 0x44, 0x74, 0x7b, 0x5c, 0x71, 0xe6, 0xee, 0x16, 0x8c, 0x08, 0xef, 0xf9, 0x9e, 0xaf, + 0x7e, 0x5a, 0x84, 0x66, 0x74, 0xb2, 0xd7, 0xee, 0x40, 0x4b, 0x6e, 0x63, 0xf6, 0x48, 0x1f, 0x8b, + 0x07, 0xbd, 0x9c, 0xfb, 0xa0, 0xbc, 0xdb, 0xb1, 0x28, 0x17, 0xdd, 0x21, 0x7d, 0x75, 0x2b, 0xb0, + 0x34, 0xcf, 0xdb, 0xf8, 0x75, 0x13, 0x6a, 0xc2, 0x51, 0x2b, 0x4e, 0x7c, 0x79, 0x09, 0x4a, 0xd4, + 0x5b, 0x2d, 0x4f, 0xb8, 0xf4, 0x57, 0x99, 0x78, 0xe9, 0x6f, 0x5a, 0xe2, 0x31, 0x66, 0x89, 0xb5, + 0x8c, 0x25, 0x26, 0x5c, 0x62, 0x7d, 0x06, 0x97, 0xd8, 0x98, 0xee, 0x12, 0x9b, 0x33, 0xb8, 0x44, + 0x98, 0xc9, 0x25, 0x2e, 0x4c, 0x76, 0x89, 0x8b, 0x13, 0x5c, 0x62, 0x6b, 0x82, 0x4b, 0x6c, 0x4f, + 0x72, 0x89, 0x4b, 0x53, 0x5c, 0x62, 0x27, 0xeb, 0x12, 0x5f, 0x81, 0x36, 0x25, 0x9e, 0x30, 0x36, + 0x7e, 0x12, 0x68, 0x39, 0xe8, 0x34, 0x91, 0x2b, 0x50, 0x34, 0xcb, 0x4d, 0xa2, 0x69, 0x02, 0xcd, + 0x72, 0x13, 0x68, 0xc9, 0x40, 0xbf, 0x32, 0x76, 0x4d, 0x73, 0xa6, 0x13, 0xc1, 0x47, 0x79, 0x2e, + 0xe0, 0x42, 0xb6, 0xb5, 0x94, 0xf7, 0xe9, 0x89, 0xda, 0x1b, 0x68, 0xd7, 0x44, 0xd8, 0x5f, 0xcb, + 0xda, 0xfd, 0xa3, 0x91, 0x87, 0x79, 0xee, 0xce, 0x92, 0x81, 0xd7, 0x65, 0xd0, 0xbf, 0x98, 0x3d, + 0xdc, 0x47, 0x4d, 0x73, 0x19, 0xee, 0xaf, 0x43, 0x0d, 0xd9, 0x36, 0xd5, 0x4f, 0x3d, 0xb7, 0x77, + 0x5e, 0x45, 0xb6, 0xbd, 0x37, 0xd0, 0xbe, 0x0c, 0x90, 0x78, 0xa2, 0xf5, 0xac, 0x33, 0x8f, 0xb9, + 0x35, 0x12, 0x98, 0xda, 0xcb, 0xd0, 0xea, 0x5b, 0xd4, 0x82, 0x1c, 0xcb, 0x45, 0x21, 0xf1, 0xf5, + 0x0d, 0xa6, 0x20, 0xe9, 0xc9, 0xf4, 0x95, 0xd7, 0xcd, 0xb1, 0x2b, 0xaf, 0x2f, 0x41, 0xf9, 0xd4, + 0xb1, 0xf5, 0x4b, 0x59, 0x8b, 0xfb, 0xd0, 0xb1, 0x0d, 0x0a, 0xcb, 0x96, 0x59, 0x5f, 0x78, 0xd6, + 0x5b, 0xb1, 0x97, 0x9f, 0xe1, 0x56, 0xec, 0x8b, 0xf3, 0x78, 0xac, 0x1f, 0x00, 0xc4, 0x71, 0x6f, + 0xce, 0x2f, 0x8d, 0xde, 0x86, 0x85, 0x81, 0x65, 0x63, 0x33, 0x3f, 0xa4, 0xc6, 0x37, 0x9e, 0xbb, + 0x05, 0x03, 0x06, 0xd1, 0x28, 0xf6, 0xe2, 0x21, 0xac, 0x28, 0xba, 0xb9, 0xda, 0x77, 0x27, 0xc7, + 0xaf, 0x6b, 0xd9, 0x84, 0x3a, 0xa7, 0x25, 0xac, 0x0e, 0x67, 0x7f, 0xaa, 0xc0, 0xc5, 0xbc, 0x66, + 0xb4, 0x03, 0x2f, 0x1c, 0xa2, 0xc0, 0xea, 0x99, 0x28, 0xf5, 0x95, 0x90, 0x19, 0xd5, 0x7c, 0xb9, + 0x68, 0x5e, 0x4b, 0x55, 0x58, 0xf3, 0xbf, 0x2a, 0xea, 0x16, 0x8c, 0xcd, 0xc3, 0x09, 0x1f, 0x1d, + 0xdd, 0x87, 0x0e, 0xf2, 0x2c, 0xf3, 0x53, 0x3c, 0x8a, 0x77, 0xe0, 0x92, 0x4c, 0xd5, 0xb5, 0xd2, + 0x5f, 0x59, 0x75, 0x0b, 0x46, 0x1b, 0xa5, 0xbf, 0xbb, 0xfa, 0x1e, 0xe8, 0x84, 0xb5, 0x25, 0x4c, + 0x4b, 0x34, 0xa4, 0x62, 0x7a, 0xe5, 0x6c, 0x57, 0x54, 0xdd, 0xbb, 0xea, 0x16, 0x8c, 0x35, 0xa2, + 0xee, 0x6a, 0xc5, 0xf4, 0x3d, 0xd1, 0xeb, 0x89, 0xe9, 0x57, 0xf2, 0xe8, 0x8f, 0xb7, 0x85, 0x62, + 0xfa, 0x99, 0x86, 0xd1, 0x11, 0x6c, 0x0a, 0xfa, 0x28, 0x6e, 0x24, 0xc6, 0x5b, 0xf0, 0x00, 0xf7, + 0x4a, 0x76, 0x0b, 0x45, 0xdb, 0xb1, 0x5b, 0x30, 0xd6, 0x49, 0x6e, 0x4f, 0x12, 0xc7, 0x1b, 0xb1, + 0xae, 0x2e, 0x4b, 0x17, 0xe2, 0x8d, 0x6a, 0x59, 0xef, 0x98, 0xd7, 0x03, 0xee, 0x16, 0x0c, 0x21, + 0x93, 0x2c, 0x2c, 0xd6, 0xf0, 0xe3, 0x58, 0xc3, 0x13, 0x2d, 0x01, 0xed, 0xfd, 0xc9, 0x1a, 0x7e, + 0x29, 0xa7, 0x6d, 0xc4, 0x2f, 0x16, 0xa8, 0xb5, 0xfa, 0x2a, 0x2c, 0x24, 0x6f, 0x2e, 0xac, 0xc6, + 0x1f, 0xf7, 0x95, 0xe3, 0x3b, 0x0e, 0xbf, 0x2d, 0x42, 0xf9, 0x11, 0x52, 0xdf, 0x8a, 0x98, 0xfe, + 0xb1, 0x5b, 0xc6, 0xb3, 0x95, 0xcf, 0xfc, 0x8d, 0xc8, 0x5c, 0x5f, 0x70, 0x5d, 0x81, 0x86, 0x8c, + 0x30, 0x39, 0xcf, 0xf7, 0x31, 0x2c, 0x7d, 0x30, 0x56, 0x6f, 0x7a, 0x8e, 0x1f, 0x93, 0xfc, 0xae, + 0x08, 0xe5, 0x0f, 0x1d, 0x5b, 0x29, 0xbd, 0x4b, 0xd0, 0xa4, 0xbf, 0x81, 0x87, 0x7a, 0xf2, 0x5e, + 0x49, 0x3c, 0x41, 0x93, 0x3f, 0xcf, 0xc7, 0x03, 0xeb, 0x54, 0x64, 0x79, 0x62, 0x44, 0x57, 0xa1, + 0x30, 0xf4, 0xad, 0xc3, 0x61, 0x88, 0xc5, 0x67, 0x7a, 0xf1, 0x04, 0x4d, 0x65, 0x9e, 0xfa, 0xc8, + 0xf3, 0x70, 0x5f, 0x1c, 0xc1, 0xe5, 0xf0, 0xcc, 0x7d, 0xcc, 0xdb, 0xaf, 0x42, 0x9b, 0xf8, 0x47, + 0x12, 0xd7, 0x3c, 0xd9, 0xb9, 0xbd, 0x28, 0xbe, 0x5d, 0xdd, 0xf7, 0x49, 0x48, 0xf6, 0x8b, 0xbf, + 0x28, 0x95, 0xf7, 0x76, 0x0f, 0x0e, 0x6b, 0xec, 0x63, 0xd0, 0x37, 0xff, 0x19, 0x00, 0x00, 0xff, + 0xff, 0xd4, 0x0a, 0xef, 0xca, 0xe4, 0x3a, 0x00, 0x00, +} diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto new file mode 100644 index 0000000..557c880 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto @@ -0,0 +1,663 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +syntax = "proto3"; + +package openapi.v2; + +import "google/protobuf/any.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v2"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +message AdditionalPropertiesItem { + oneof oneof { + Schema schema = 1; + bool boolean = 2; + } +} + +message Any { + google.protobuf.Any value = 1; + string yaml = 2; +} + +message ApiKeySecurity { + string type = 1; + string name = 2; + string in = 3; + string description = 4; + repeated NamedAny vendor_extension = 5; +} + +message BasicAuthenticationSecurity { + string type = 1; + string description = 2; + repeated NamedAny vendor_extension = 3; +} + +message BodyParameter { + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 1; + // The name of the parameter. + string name = 2; + // Determines the location of the parameter. + string in = 3; + // Determines whether or not this parameter is required or optional. + bool required = 4; + Schema schema = 5; + repeated NamedAny vendor_extension = 6; +} + +// Contact information for the owners of the API. +message Contact { + // The identifying name of the contact person/organization. + string name = 1; + // The URL pointing to the contact information. + string url = 2; + // The email address of the contact person/organization. + string email = 3; + repeated NamedAny vendor_extension = 4; +} + +message Default { + repeated NamedAny additional_properties = 1; +} + +// One or more JSON objects describing the schemas being consumed and produced by the API. +message Definitions { + repeated NamedSchema additional_properties = 1; +} + +message Document { + // The Swagger version of this document. + string swagger = 1; + Info info = 2; + // The host (name or ip) of the API. Example: 'swagger.io' + string host = 3; + // The base path to the API. Example: '/api'. + string base_path = 4; + // The transfer protocol of the API. + repeated string schemes = 5; + // A list of MIME types accepted by the API. + repeated string consumes = 6; + // A list of MIME types the API can produce. + repeated string produces = 7; + Paths paths = 8; + Definitions definitions = 9; + ParameterDefinitions parameters = 10; + ResponseDefinitions responses = 11; + repeated SecurityRequirement security = 12; + SecurityDefinitions security_definitions = 13; + repeated Tag tags = 14; + ExternalDocs external_docs = 15; + repeated NamedAny vendor_extension = 16; +} + +message Examples { + repeated NamedAny additional_properties = 1; +} + +// information about external documentation +message ExternalDocs { + string description = 1; + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// A deterministic version of a JSON Schema object. +message FileSchema { + string format = 1; + string title = 2; + string description = 3; + Any default = 4; + repeated string required = 5; + string type = 6; + bool read_only = 7; + ExternalDocs external_docs = 8; + Any example = 9; + repeated NamedAny vendor_extension = 10; +} + +message FormDataParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Header { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + string description = 18; + repeated NamedAny vendor_extension = 19; +} + +message HeaderParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +message Headers { + repeated NamedHeader additional_properties = 1; +} + +// General information about the API. +message Info { + // A unique and precise title of the API. + string title = 1; + // A semantic version number of the API. + string version = 2; + // A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed. + string description = 3; + // The terms of service for the API. + string terms_of_service = 4; + Contact contact = 5; + License license = 6; + repeated NamedAny vendor_extension = 7; +} + +message ItemsItem { + repeated Schema schema = 1; +} + +message JsonReference { + string _ref = 1; + string description = 2; +} + +message License { + // The name of the license type. It's encouraged to use an OSI compatible license. + string name = 1; + // The URL pointing to the license. + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +message NamedAny { + // Map key + string name = 1; + // Mapped value + Any value = 2; +} + +// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs. +message NamedHeader { + // Map key + string name = 1; + // Mapped value + Header value = 2; +} + +// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs. +message NamedParameter { + // Map key + string name = 1; + // Mapped value + Parameter value = 2; +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +message NamedPathItem { + // Map key + string name = 1; + // Mapped value + PathItem value = 2; +} + +// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs. +message NamedResponse { + // Map key + string name = 1; + // Mapped value + Response value = 2; +} + +// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs. +message NamedResponseValue { + // Map key + string name = 1; + // Mapped value + ResponseValue value = 2; +} + +// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs. +message NamedSchema { + // Map key + string name = 1; + // Mapped value + Schema value = 2; +} + +// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs. +message NamedSecurityDefinitionsItem { + // Map key + string name = 1; + // Mapped value + SecurityDefinitionsItem value = 2; +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +message NamedString { + // Map key + string name = 1; + // Mapped value + string value = 2; +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +message NamedStringArray { + // Map key + string name = 1; + // Mapped value + StringArray value = 2; +} + +message NonBodyParameter { + oneof oneof { + HeaderParameterSubSchema header_parameter_sub_schema = 1; + FormDataParameterSubSchema form_data_parameter_sub_schema = 2; + QueryParameterSubSchema query_parameter_sub_schema = 3; + PathParameterSubSchema path_parameter_sub_schema = 4; + } +} + +message Oauth2AccessCodeSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string token_url = 5; + string description = 6; + repeated NamedAny vendor_extension = 7; +} + +message Oauth2ApplicationSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2ImplicitSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2PasswordSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2Scopes { + repeated NamedString additional_properties = 1; +} + +message Operation { + repeated string tags = 1; + // A brief summary of the operation. + string summary = 2; + // A longer description of the operation, GitHub Flavored Markdown is allowed. + string description = 3; + ExternalDocs external_docs = 4; + // A unique identifier of the operation. + string operation_id = 5; + // A list of MIME types the API can produce. + repeated string produces = 6; + // A list of MIME types the API can consume. + repeated string consumes = 7; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 8; + Responses responses = 9; + // The transfer protocol of the API. + repeated string schemes = 10; + bool deprecated = 11; + repeated SecurityRequirement security = 12; + repeated NamedAny vendor_extension = 13; +} + +message Parameter { + oneof oneof { + BodyParameter body_parameter = 1; + NonBodyParameter non_body_parameter = 2; + } +} + +// One or more JSON representations for parameters +message ParameterDefinitions { + repeated NamedParameter additional_properties = 1; +} + +message ParametersItem { + oneof oneof { + Parameter parameter = 1; + JsonReference json_reference = 2; + } +} + +message PathItem { + string _ref = 1; + Operation get = 2; + Operation put = 3; + Operation post = 4; + Operation delete = 5; + Operation options = 6; + Operation head = 7; + Operation patch = 8; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 9; + repeated NamedAny vendor_extension = 10; +} + +message PathParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +// Relative paths to the individual endpoints. They must be relative to the 'basePath'. +message Paths { + repeated NamedAny vendor_extension = 1; + repeated NamedPathItem path = 2; +} + +message PrimitivesItems { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + repeated NamedAny vendor_extension = 18; +} + +message Properties { + repeated NamedSchema additional_properties = 1; +} + +message QueryParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Response { + string description = 1; + SchemaItem schema = 2; + Headers headers = 3; + Examples examples = 4; + repeated NamedAny vendor_extension = 5; +} + +// One or more JSON representations for parameters +message ResponseDefinitions { + repeated NamedResponse additional_properties = 1; +} + +message ResponseValue { + oneof oneof { + Response response = 1; + JsonReference json_reference = 2; + } +} + +// Response objects names can either be any valid HTTP status code or 'default'. +message Responses { + repeated NamedResponseValue response_code = 1; + repeated NamedAny vendor_extension = 2; +} + +// A deterministic version of a JSON Schema object. +message Schema { + string _ref = 1; + string format = 2; + string title = 3; + string description = 4; + Any default = 5; + double multiple_of = 6; + double maximum = 7; + bool exclusive_maximum = 8; + double minimum = 9; + bool exclusive_minimum = 10; + int64 max_length = 11; + int64 min_length = 12; + string pattern = 13; + int64 max_items = 14; + int64 min_items = 15; + bool unique_items = 16; + int64 max_properties = 17; + int64 min_properties = 18; + repeated string required = 19; + repeated Any enum = 20; + AdditionalPropertiesItem additional_properties = 21; + TypeItem type = 22; + ItemsItem items = 23; + repeated Schema all_of = 24; + Properties properties = 25; + string discriminator = 26; + bool read_only = 27; + Xml xml = 28; + ExternalDocs external_docs = 29; + Any example = 30; + repeated NamedAny vendor_extension = 31; +} + +message SchemaItem { + oneof oneof { + Schema schema = 1; + FileSchema file_schema = 2; + } +} + +message SecurityDefinitions { + repeated NamedSecurityDefinitionsItem additional_properties = 1; +} + +message SecurityDefinitionsItem { + oneof oneof { + BasicAuthenticationSecurity basic_authentication_security = 1; + ApiKeySecurity api_key_security = 2; + Oauth2ImplicitSecurity oauth2_implicit_security = 3; + Oauth2PasswordSecurity oauth2_password_security = 4; + Oauth2ApplicationSecurity oauth2_application_security = 5; + Oauth2AccessCodeSecurity oauth2_access_code_security = 6; + } +} + +message SecurityRequirement { + repeated NamedStringArray additional_properties = 1; +} + +message StringArray { + repeated string value = 1; +} + +message Tag { + string name = 1; + string description = 2; + ExternalDocs external_docs = 3; + repeated NamedAny vendor_extension = 4; +} + +message TypeItem { + repeated string value = 1; +} + +// Any property starting with x- is valid. +message VendorExtension { + repeated NamedAny additional_properties = 1; +} + +message Xml { + string name = 1; + string namespace = 2; + string prefix = 3; + bool attribute = 4; + bool wrapped = 5; + repeated NamedAny vendor_extension = 6; +} + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md new file mode 100644 index 0000000..836fb32 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md @@ -0,0 +1,16 @@ +# OpenAPI v2 Protocol Buffer Models + +This directory contains a Protocol Buffer-language model +and related code for supporting OpenAPI v2. + +Gnostic applications and plugins can use OpenAPIv2.proto +to generate Protocol Buffer support code for their preferred languages. + +OpenAPIv2.go is used by Gnostic to read JSON and YAML OpenAPI +descriptions into the Protocol Buffer-based datastructures +generated from OpenAPIv2.proto. + +OpenAPIv2.proto and OpenAPIv2.go are generated by the Gnostic +compiler generator, and OpenAPIv2.pb.go is generated by +protoc, the Protocol Buffer compiler, and protoc-gen-go, the +Protocol Buffer Go code generation plugin. diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json new file mode 100644 index 0000000..2815a26 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json @@ -0,0 +1,1610 @@ +{ + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for parameters" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/README.md b/vendor/github.com/googleapis/gnostic/compiler/README.md new file mode 100644 index 0000000..848b16c --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/README.md @@ -0,0 +1,3 @@ +# Compiler support code + +This directory contains compiler support code used by Gnostic and Gnostic extensions. \ No newline at end of file diff --git a/vendor/github.com/googleapis/gnostic/compiler/context.go b/vendor/github.com/googleapis/gnostic/compiler/context.go new file mode 100644 index 0000000..a64c1b7 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/context.go @@ -0,0 +1,43 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +// Context contains state of the compiler as it traverses a document. +type Context struct { + Parent *Context + Name string + ExtensionHandlers *[]ExtensionHandler +} + +// NewContextWithExtensions returns a new object representing the compiler state +func NewContextWithExtensions(name string, parent *Context, extensionHandlers *[]ExtensionHandler) *Context { + return &Context{Name: name, Parent: parent, ExtensionHandlers: extensionHandlers} +} + +// NewContext returns a new object representing the compiler state +func NewContext(name string, parent *Context) *Context { + if parent != nil { + return &Context{Name: name, Parent: parent, ExtensionHandlers: parent.ExtensionHandlers} + } + return &Context{Name: name, Parent: parent, ExtensionHandlers: nil} +} + +// Description returns a text description of the compiler state +func (context *Context) Description() string { + if context.Parent != nil { + return context.Parent.Description() + "." + context.Name + } + return context.Name +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/error.go b/vendor/github.com/googleapis/gnostic/compiler/error.go new file mode 100644 index 0000000..d8672c1 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/error.go @@ -0,0 +1,61 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +// Error represents compiler errors and their location in the document. +type Error struct { + Context *Context + Message string +} + +// NewError creates an Error. +func NewError(context *Context, message string) *Error { + return &Error{Context: context, Message: message} +} + +// Error returns the string value of an Error. +func (err *Error) Error() string { + if err.Context == nil { + return "ERROR " + err.Message + } + return "ERROR " + err.Context.Description() + " " + err.Message +} + +// ErrorGroup is a container for groups of Error values. +type ErrorGroup struct { + Errors []error +} + +// NewErrorGroupOrNil returns a new ErrorGroup for a slice of errors or nil if the slice is empty. +func NewErrorGroupOrNil(errors []error) error { + if len(errors) == 0 { + return nil + } else if len(errors) == 1 { + return errors[0] + } else { + return &ErrorGroup{Errors: errors} + } +} + +func (group *ErrorGroup) Error() string { + result := "" + for i, err := range group.Errors { + if i > 0 { + result += "\n" + } + result += err.Error() + } + return result +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go b/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go new file mode 100644 index 0000000..1f85b65 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go @@ -0,0 +1,101 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "bytes" + "fmt" + "os/exec" + + "strings" + + "errors" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" + ext_plugin "github.com/googleapis/gnostic/extensions" + yaml "gopkg.in/yaml.v2" +) + +// ExtensionHandler describes a binary that is called by the compiler to handle specification extensions. +type ExtensionHandler struct { + Name string +} + +// HandleExtension calls a binary extension handler. +func HandleExtension(context *Context, in interface{}, extensionName string) (bool, *any.Any, error) { + handled := false + var errFromPlugin error + var outFromPlugin *any.Any + + if context != nil && context.ExtensionHandlers != nil && len(*(context.ExtensionHandlers)) != 0 { + for _, customAnyProtoGenerator := range *(context.ExtensionHandlers) { + outFromPlugin, errFromPlugin = customAnyProtoGenerator.handle(in, extensionName) + if outFromPlugin == nil { + continue + } else { + handled = true + break + } + } + } + return handled, outFromPlugin, errFromPlugin +} + +func (extensionHandlers *ExtensionHandler) handle(in interface{}, extensionName string) (*any.Any, error) { + if extensionHandlers.Name != "" { + binary, _ := yaml.Marshal(in) + + request := &ext_plugin.ExtensionHandlerRequest{} + + version := &ext_plugin.Version{} + version.Major = 0 + version.Minor = 1 + version.Patch = 0 + request.CompilerVersion = version + + request.Wrapper = &ext_plugin.Wrapper{} + + request.Wrapper.Version = "v2" + request.Wrapper.Yaml = string(binary) + request.Wrapper.ExtensionName = extensionName + + requestBytes, _ := proto.Marshal(request) + cmd := exec.Command(extensionHandlers.Name) + cmd.Stdin = bytes.NewReader(requestBytes) + output, err := cmd.Output() + + if err != nil { + fmt.Printf("Error: %+v\n", err) + return nil, err + } + response := &ext_plugin.ExtensionHandlerResponse{} + err = proto.Unmarshal(output, response) + if err != nil { + fmt.Printf("Error: %+v\n", err) + fmt.Printf("%s\n", string(output)) + return nil, err + } + if !response.Handled { + return nil, nil + } + if len(response.Error) != 0 { + message := fmt.Sprintf("Errors when parsing: %+v for field %s by vendor extension handler %s. Details %+v", in, extensionName, extensionHandlers.Name, strings.Join(response.Error, ",")) + return nil, errors.New(message) + } + return response.Value, nil + } + return nil, nil +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/helpers.go b/vendor/github.com/googleapis/gnostic/compiler/helpers.go new file mode 100644 index 0000000..76df635 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/helpers.go @@ -0,0 +1,197 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "fmt" + "gopkg.in/yaml.v2" + "regexp" + "sort" + "strconv" +) + +// compiler helper functions, usually called from generated code + +// UnpackMap gets a yaml.MapSlice if possible. +func UnpackMap(in interface{}) (yaml.MapSlice, bool) { + m, ok := in.(yaml.MapSlice) + if ok { + return m, true + } + // do we have an empty array? + a, ok := in.([]interface{}) + if ok && len(a) == 0 { + // if so, return an empty map + return yaml.MapSlice{}, true + } + return nil, false +} + +// SortedKeysForMap returns the sorted keys of a yaml.MapSlice. +func SortedKeysForMap(m yaml.MapSlice) []string { + keys := make([]string, 0) + for _, item := range m { + keys = append(keys, item.Key.(string)) + } + sort.Strings(keys) + return keys +} + +// MapHasKey returns true if a yaml.MapSlice contains a specified key. +func MapHasKey(m yaml.MapSlice, key string) bool { + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok && key == itemKey { + return true + } + } + return false +} + +// MapValueForKey gets the value of a map value for a specified key. +func MapValueForKey(m yaml.MapSlice, key string) interface{} { + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok && key == itemKey { + return item.Value + } + } + return nil +} + +// ConvertInterfaceArrayToStringArray converts an array of interfaces to an array of strings, if possible. +func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string { + stringArray := make([]string, 0) + for _, item := range interfaceArray { + v, ok := item.(string) + if ok { + stringArray = append(stringArray, v) + } + } + return stringArray +} + +// MissingKeysInMap identifies which keys from a list of required keys are not in a map. +func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string { + missingKeys := make([]string, 0) + for _, k := range requiredKeys { + if !MapHasKey(m, k) { + missingKeys = append(missingKeys, k) + } + } + return missingKeys +} + +// InvalidKeysInMap returns keys in a map that don't match a list of allowed keys and patterns. +func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string { + invalidKeys := make([]string, 0) + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok { + key := itemKey + found := false + // does the key match an allowed key? + for _, allowedKey := range allowedKeys { + if key == allowedKey { + found = true + break + } + } + if !found { + // does the key match an allowed pattern? + for _, allowedPattern := range allowedPatterns { + if allowedPattern.MatchString(key) { + found = true + break + } + } + if !found { + invalidKeys = append(invalidKeys, key) + } + } + } + } + return invalidKeys +} + +// DescribeMap describes a map (for debugging purposes). +func DescribeMap(in interface{}, indent string) string { + description := "" + m, ok := in.(map[string]interface{}) + if ok { + keys := make([]string, 0) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := m[k] + description += fmt.Sprintf("%s%s:\n", indent, k) + description += DescribeMap(v, indent+" ") + } + return description + } + a, ok := in.([]interface{}) + if ok { + for i, v := range a { + description += fmt.Sprintf("%s%d:\n", indent, i) + description += DescribeMap(v, indent+" ") + } + return description + } + description += fmt.Sprintf("%s%+v\n", indent, in) + return description +} + +// PluralProperties returns the string "properties" pluralized. +func PluralProperties(count int) string { + if count == 1 { + return "property" + } + return "properties" +} + +// StringArrayContainsValue returns true if a string array contains a specified value. +func StringArrayContainsValue(array []string, value string) bool { + for _, item := range array { + if item == value { + return true + } + } + return false +} + +// StringArrayContainsValues returns true if a string array contains all of a list of specified values. +func StringArrayContainsValues(array []string, values []string) bool { + for _, value := range values { + if !StringArrayContainsValue(array, value) { + return false + } + } + return true +} + +// StringValue returns the string value of an item. +func StringValue(item interface{}) (value string, ok bool) { + value, ok = item.(string) + if ok { + return value, ok + } + intValue, ok := item.(int) + if ok { + return strconv.Itoa(intValue), true + } + return "", false +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/main.go b/vendor/github.com/googleapis/gnostic/compiler/main.go new file mode 100644 index 0000000..9713a21 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/main.go @@ -0,0 +1,16 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package compiler provides support functions to generated compiler code. +package compiler diff --git a/vendor/github.com/googleapis/gnostic/compiler/reader.go b/vendor/github.com/googleapis/gnostic/compiler/reader.go new file mode 100644 index 0000000..c954a2d --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/reader.go @@ -0,0 +1,175 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "errors" + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "net/http" + "net/url" + "path/filepath" + "strings" +) + +var fileCache map[string][]byte +var infoCache map[string]interface{} +var count int64 + +var verboseReader = false + +func initializeFileCache() { + if fileCache == nil { + fileCache = make(map[string][]byte, 0) + } +} + +func initializeInfoCache() { + if infoCache == nil { + infoCache = make(map[string]interface{}, 0) + } +} + +// FetchFile gets a specified file from the local filesystem or a remote location. +func FetchFile(fileurl string) ([]byte, error) { + initializeFileCache() + bytes, ok := fileCache[fileurl] + if ok { + if verboseReader { + log.Printf("Cache hit %s", fileurl) + } + return bytes, nil + } + if verboseReader { + log.Printf("Fetching %s", fileurl) + } + response, err := http.Get(fileurl) + if err != nil { + return nil, err + } + if response.StatusCode != 200 { + return nil, errors.New(fmt.Sprintf("Error downloading %s: %s", fileurl, response.Status)) + } + defer response.Body.Close() + bytes, err = ioutil.ReadAll(response.Body) + if err == nil { + fileCache[fileurl] = bytes + } + return bytes, err +} + +// ReadBytesForFile reads the bytes of a file. +func ReadBytesForFile(filename string) ([]byte, error) { + // is the filename a url? + fileurl, _ := url.Parse(filename) + if fileurl.Scheme != "" { + // yes, fetch it + bytes, err := FetchFile(filename) + if err != nil { + return nil, err + } + return bytes, nil + } + // no, it's a local filename + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return bytes, nil +} + +// ReadInfoFromBytes unmarshals a file as a yaml.MapSlice. +func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) { + initializeInfoCache() + cachedInfo, ok := infoCache[filename] + if ok { + if verboseReader { + log.Printf("Cache hit info for file %s", filename) + } + return cachedInfo, nil + } + if verboseReader { + log.Printf("Reading info for file %s", filename) + } + var info yaml.MapSlice + err := yaml.Unmarshal(bytes, &info) + if err != nil { + return nil, err + } + if len(filename) > 0 { + infoCache[filename] = info + } + return info, nil +} + +// ReadInfoForRef reads a file and return the fragment needed to resolve a $ref. +func ReadInfoForRef(basefile string, ref string) (interface{}, error) { + initializeInfoCache() + { + info, ok := infoCache[ref] + if ok { + if verboseReader { + log.Printf("Cache hit for ref %s#%s", basefile, ref) + } + return info, nil + } + } + if verboseReader { + log.Printf("Reading info for ref %s#%s", basefile, ref) + } + count = count + 1 + basedir, _ := filepath.Split(basefile) + parts := strings.Split(ref, "#") + var filename string + if parts[0] != "" { + filename = basedir + parts[0] + } else { + filename = basefile + } + bytes, err := ReadBytesForFile(filename) + if err != nil { + return nil, err + } + info, err := ReadInfoFromBytes(filename, bytes) + if err != nil { + log.Printf("File error: %v\n", err) + } else { + if len(parts) > 1 { + path := strings.Split(parts[1], "/") + for i, key := range path { + if i > 0 { + m, ok := info.(yaml.MapSlice) + if ok { + found := false + for _, section := range m { + if section.Key == key { + info = section.Value + found = true + } + } + if !found { + infoCache[ref] = nil + return nil, NewError(nil, fmt.Sprintf("could not resolve %s", ref)) + } + } + } + } + } + } + infoCache[ref] = info + return info, nil +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh new file mode 100755 index 0000000..68d02a0 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh @@ -0,0 +1,5 @@ +go get github.com/golang/protobuf/protoc-gen-go + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto + diff --git a/vendor/github.com/googleapis/gnostic/extensions/README.md b/vendor/github.com/googleapis/gnostic/extensions/README.md new file mode 100644 index 0000000..ff1c2eb --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/README.md @@ -0,0 +1,5 @@ +# Extensions + +This directory contains support code for building Gnostic extensions and associated examples. + +Extensions are used to compile vendor or specification extensions into protocol buffer structures. diff --git a/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go b/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go new file mode 100644 index 0000000..749ff78 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go @@ -0,0 +1,218 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: extension.proto + +/* +Package openapiextension_v1 is a generated protocol buffer package. + +It is generated from these files: + extension.proto + +It has these top-level messages: + Version + ExtensionHandlerRequest + ExtensionHandlerResponse + Wrapper +*/ +package openapiextension_v1 + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// The version number of OpenAPI compiler. +type Version struct { + Major int32 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"` + Minor int32 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"` + Patch int32 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"` + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + Suffix string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` +} + +func (m *Version) Reset() { *m = Version{} } +func (m *Version) String() string { return proto.CompactTextString(m) } +func (*Version) ProtoMessage() {} +func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Version) GetMajor() int32 { + if m != nil { + return m.Major + } + return 0 +} + +func (m *Version) GetMinor() int32 { + if m != nil { + return m.Minor + } + return 0 +} + +func (m *Version) GetPatch() int32 { + if m != nil { + return m.Patch + } + return 0 +} + +func (m *Version) GetSuffix() string { + if m != nil { + return m.Suffix + } + return "" +} + +// An encoded Request is written to the ExtensionHandler's stdin. +type ExtensionHandlerRequest struct { + // The OpenAPI descriptions that were explicitly listed on the command line. + // The specifications will appear in the order they are specified to gnostic. + Wrapper *Wrapper `protobuf:"bytes,1,opt,name=wrapper" json:"wrapper,omitempty"` + // The version number of openapi compiler. + CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"` +} + +func (m *ExtensionHandlerRequest) Reset() { *m = ExtensionHandlerRequest{} } +func (m *ExtensionHandlerRequest) String() string { return proto.CompactTextString(m) } +func (*ExtensionHandlerRequest) ProtoMessage() {} +func (*ExtensionHandlerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *ExtensionHandlerRequest) GetWrapper() *Wrapper { + if m != nil { + return m.Wrapper + } + return nil +} + +func (m *ExtensionHandlerRequest) GetCompilerVersion() *Version { + if m != nil { + return m.CompilerVersion + } + return nil +} + +// The extensions writes an encoded ExtensionHandlerResponse to stdout. +type ExtensionHandlerResponse struct { + // true if the extension is handled by the extension handler; false otherwise + Handled bool `protobuf:"varint,1,opt,name=handled" json:"handled,omitempty"` + // Error message. If non-empty, the extension handling failed. + // The extension handler process should exit with status code zero + // even if it reports an error in this way. + // + // This should be used to indicate errors which prevent the extension from + // operating as intended. Errors which indicate a problem in gnostic + // itself -- such as the input Document being unparseable -- should be + // reported by writing a message to stderr and exiting with a non-zero + // status code. + Error []string `protobuf:"bytes,2,rep,name=error" json:"error,omitempty"` + // text output + Value *google_protobuf.Any `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"` +} + +func (m *ExtensionHandlerResponse) Reset() { *m = ExtensionHandlerResponse{} } +func (m *ExtensionHandlerResponse) String() string { return proto.CompactTextString(m) } +func (*ExtensionHandlerResponse) ProtoMessage() {} +func (*ExtensionHandlerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ExtensionHandlerResponse) GetHandled() bool { + if m != nil { + return m.Handled + } + return false +} + +func (m *ExtensionHandlerResponse) GetError() []string { + if m != nil { + return m.Error + } + return nil +} + +func (m *ExtensionHandlerResponse) GetValue() *google_protobuf.Any { + if m != nil { + return m.Value + } + return nil +} + +type Wrapper struct { + // version of the OpenAPI specification in which this extension was written. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + // Name of the extension + ExtensionName string `protobuf:"bytes,2,opt,name=extension_name,json=extensionName" json:"extension_name,omitempty"` + // Must be a valid yaml for the proto + Yaml string `protobuf:"bytes,3,opt,name=yaml" json:"yaml,omitempty"` +} + +func (m *Wrapper) Reset() { *m = Wrapper{} } +func (m *Wrapper) String() string { return proto.CompactTextString(m) } +func (*Wrapper) ProtoMessage() {} +func (*Wrapper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Wrapper) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Wrapper) GetExtensionName() string { + if m != nil { + return m.ExtensionName + } + return "" +} + +func (m *Wrapper) GetYaml() string { + if m != nil { + return m.Yaml + } + return "" +} + +func init() { + proto.RegisterType((*Version)(nil), "openapiextension.v1.Version") + proto.RegisterType((*ExtensionHandlerRequest)(nil), "openapiextension.v1.ExtensionHandlerRequest") + proto.RegisterType((*ExtensionHandlerResponse)(nil), "openapiextension.v1.ExtensionHandlerResponse") + proto.RegisterType((*Wrapper)(nil), "openapiextension.v1.Wrapper") +} + +func init() { proto.RegisterFile("extension.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 357 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x4d, 0x4b, 0xc3, 0x40, + 0x18, 0x84, 0x49, 0xbf, 0x62, 0x56, 0x6c, 0x65, 0x2d, 0x1a, 0xc5, 0x43, 0x09, 0x08, 0x45, 0x64, + 0x4b, 0x15, 0xbc, 0xb7, 0x50, 0xd4, 0x8b, 0x2d, 0x7b, 0xa8, 0x37, 0xcb, 0x36, 0x7d, 0x9b, 0x46, + 0x92, 0xdd, 0x75, 0xf3, 0x61, 0xfb, 0x57, 0x3c, 0xfa, 0x4b, 0x25, 0xbb, 0x49, 0x3d, 0xa8, 0xb7, + 0xcc, 0xc3, 0x24, 0xef, 0xcc, 0x04, 0x75, 0x60, 0x9b, 0x02, 0x4f, 0x42, 0xc1, 0x89, 0x54, 0x22, + 0x15, 0xf8, 0x44, 0x48, 0xe0, 0x4c, 0x86, 0x3f, 0x3c, 0x1f, 0x5e, 0x9c, 0x07, 0x42, 0x04, 0x11, + 0x0c, 0xb4, 0x65, 0x99, 0xad, 0x07, 0x8c, 0xef, 0x8c, 0xdf, 0xf3, 0x91, 0x3d, 0x07, 0x55, 0x18, + 0x71, 0x17, 0x35, 0x63, 0xf6, 0x26, 0x94, 0x6b, 0xf5, 0xac, 0x7e, 0x93, 0x1a, 0xa1, 0x69, 0xc8, + 0x85, 0x72, 0x6b, 0x25, 0x2d, 0x44, 0x41, 0x25, 0x4b, 0xfd, 0x8d, 0x5b, 0x37, 0x54, 0x0b, 0x7c, + 0x8a, 0x5a, 0x49, 0xb6, 0x5e, 0x87, 0x5b, 0xb7, 0xd1, 0xb3, 0xfa, 0x0e, 0x2d, 0x95, 0xf7, 0x69, + 0xa1, 0xb3, 0x49, 0x15, 0xe8, 0x91, 0xf1, 0x55, 0x04, 0x8a, 0xc2, 0x7b, 0x06, 0x49, 0x8a, 0xef, + 0x91, 0xfd, 0xa1, 0x98, 0x94, 0x60, 0xee, 0x1e, 0xde, 0x5e, 0x92, 0x3f, 0x2a, 0x90, 0x17, 0xe3, + 0xa1, 0x95, 0x19, 0x3f, 0xa0, 0x63, 0x5f, 0xc4, 0x32, 0x8c, 0x40, 0x2d, 0x72, 0xd3, 0x40, 0x87, + 0xf9, 0xef, 0x03, 0x65, 0x4b, 0xda, 0xa9, 0xde, 0x2a, 0x81, 0x97, 0x23, 0xf7, 0x77, 0xb6, 0x44, + 0x0a, 0x9e, 0x00, 0x76, 0x91, 0xbd, 0xd1, 0x68, 0xa5, 0xc3, 0x1d, 0xd0, 0x4a, 0x16, 0x03, 0x80, + 0x52, 0x7a, 0x96, 0x7a, 0xdf, 0xa1, 0x46, 0xe0, 0x6b, 0xd4, 0xcc, 0x59, 0x94, 0x41, 0x99, 0xa4, + 0x4b, 0xcc, 0xf0, 0xa4, 0x1a, 0x9e, 0x8c, 0xf8, 0x8e, 0x1a, 0x8b, 0xf7, 0x8a, 0xec, 0xb2, 0x54, + 0x71, 0xa6, 0xaa, 0x60, 0xe9, 0xe1, 0x2a, 0x89, 0xaf, 0x50, 0x7b, 0xdf, 0x62, 0xc1, 0x59, 0x0c, + 0xfa, 0x37, 0x38, 0xf4, 0x68, 0x4f, 0x9f, 0x59, 0x0c, 0x18, 0xa3, 0xc6, 0x8e, 0xc5, 0x91, 0x3e, + 0xeb, 0x50, 0xfd, 0x3c, 0xbe, 0x41, 0x6d, 0xa1, 0x02, 0x12, 0x70, 0x91, 0xa4, 0xa1, 0x4f, 0xf2, + 0xe1, 0x18, 0x4f, 0x25, 0xf0, 0xd1, 0xec, 0x69, 0x5f, 0x77, 0x3e, 0x9c, 0x59, 0x5f, 0xb5, 0xfa, + 0x74, 0x34, 0x59, 0xb6, 0x74, 0xc4, 0xbb, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x5c, 0x6b, + 0x80, 0x51, 0x02, 0x00, 0x00, +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/extension.proto b/vendor/github.com/googleapis/gnostic/extensions/extension.proto new file mode 100644 index 0000000..04856f9 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extension.proto @@ -0,0 +1,93 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +package openapiextension.v1; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIExtensionV1"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.gnostic.v1"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +// +option objc_class_prefix = "OAE"; // "OpenAPI Extension" + +// The version number of OpenAPI compiler. +message Version { + int32 major = 1; + int32 minor = 2; + int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + string suffix = 4; +} + +// An encoded Request is written to the ExtensionHandler's stdin. +message ExtensionHandlerRequest { + + // The OpenAPI descriptions that were explicitly listed on the command line. + // The specifications will appear in the order they are specified to gnostic. + Wrapper wrapper = 1; + + // The version number of openapi compiler. + Version compiler_version = 3; +} + +// The extensions writes an encoded ExtensionHandlerResponse to stdout. +message ExtensionHandlerResponse { + + // true if the extension is handled by the extension handler; false otherwise + bool handled = 1; + + // Error message. If non-empty, the extension handling failed. + // The extension handler process should exit with status code zero + // even if it reports an error in this way. + // + // This should be used to indicate errors which prevent the extension from + // operating as intended. Errors which indicate a problem in gnostic + // itself -- such as the input Document being unparseable -- should be + // reported by writing a message to stderr and exiting with a non-zero + // status code. + repeated string error = 2; + + // text output + google.protobuf.Any value = 3; +} + +message Wrapper { + // version of the OpenAPI specification in which this extension was written. + string version = 1; + + // Name of the extension + string extension_name = 2; + + // Must be a valid yaml for the proto + string yaml = 3; +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/extensions.go b/vendor/github.com/googleapis/gnostic/extensions/extensions.go new file mode 100644 index 0000000..94a8e62 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extensions.go @@ -0,0 +1,82 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openapiextension_v1 + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" +) + +type documentHandler func(version string, extensionName string, document string) +type extensionHandler func(name string, yamlInput string) (bool, proto.Message, error) + +func forInputYamlFromOpenapic(handler documentHandler) { + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + fmt.Println("File error:", err.Error()) + os.Exit(1) + } + if len(data) == 0 { + fmt.Println("No input data.") + os.Exit(1) + } + request := &ExtensionHandlerRequest{} + err = proto.Unmarshal(data, request) + if err != nil { + fmt.Println("Input error:", err.Error()) + os.Exit(1) + } + handler(request.Wrapper.Version, request.Wrapper.ExtensionName, request.Wrapper.Yaml) +} + +// ProcessExtension calles the handler for a specified extension. +func ProcessExtension(handleExtension extensionHandler) { + response := &ExtensionHandlerResponse{} + forInputYamlFromOpenapic( + func(version string, extensionName string, yamlInput string) { + var newObject proto.Message + var err error + + handled, newObject, err := handleExtension(extensionName, yamlInput) + if !handled { + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + + // If we reach here, then the extension is handled + response.Handled = true + if err != nil { + response.Error = append(response.Error, err.Error()) + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + response.Value, err = ptypes.MarshalAny(newObject) + if err != nil { + response.Error = append(response.Error, err.Error()) + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + }) + + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) +} diff --git a/vendor/github.com/hailocab/go-hostpool/.gitignore b/vendor/github.com/hailocab/go-hostpool/.gitignore new file mode 100644 index 0000000..0026861 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/hailocab/go-hostpool/.travis.yml b/vendor/github.com/hailocab/go-hostpool/.travis.yml new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/hailocab/go-hostpool/LICENSE b/vendor/github.com/hailocab/go-hostpool/LICENSE new file mode 100644 index 0000000..f24db89 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Bitly + +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/vendor/github.com/hailocab/go-hostpool/README.md b/vendor/github.com/hailocab/go-hostpool/README.md new file mode 100644 index 0000000..7f44372 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/README.md @@ -0,0 +1,17 @@ +go-hostpool +=========== + +A Go package to intelligently and flexibly pool among multiple hosts from your Go application. +Host selection can operate in round robin or epsilon greedy mode, and unresponsive hosts are +avoided. +Usage example: + +```go +hp := hostpool.NewEpsilonGreedy([]string{"a", "b"}, 0, &hostpool.LinearEpsilonValueCalculator{}) +hostResponse := hp.Get() +hostname := hostResponse.Host() +err := _ // (make a request with hostname) +hostResponse.Mark(err) +``` + +View more detailed documentation on [godoc.org](http://godoc.org/github.com/bitly/go-hostpool) diff --git a/vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go b/vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go new file mode 100644 index 0000000..8627aa5 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go @@ -0,0 +1,220 @@ +package hostpool + +import ( + "log" + "math/rand" + "time" +) + +type epsilonHostPoolResponse struct { + standardHostPoolResponse + started time.Time + ended time.Time +} + +func (r *epsilonHostPoolResponse) Mark(err error) { + r.Do(func() { + r.ended = time.Now() + doMark(err, r) + }) +} + +type epsilonGreedyHostPool struct { + standardHostPool // TODO - would be nifty if we could embed HostPool and Locker interfaces + epsilon float32 // this is our exploration factor + decayDuration time.Duration + EpsilonValueCalculator // embed the epsilonValueCalculator + timer + quit chan bool +} + +// Construct an Epsilon Greedy HostPool +// +// Epsilon Greedy is an algorithm that allows HostPool not only to track failure state, +// but also to learn about "better" options in terms of speed, and to pick from available hosts +// based on how well they perform. This gives a weighted request rate to better +// performing hosts, while still distributing requests to all hosts (proportionate to their performance). +// The interface is the same as the standard HostPool, but be sure to mark the HostResponse immediately +// after executing the request to the host, as that will stop the implicitly running request timer. +// +// A good overview of Epsilon Greedy is here http://stevehanov.ca/blog/index.php?id=132 +// +// To compute the weighting scores, we perform a weighted average of recent response times, over the course of +// `decayDuration`. decayDuration may be set to 0 to use the default value of 5 minutes +// We then use the supplied EpsilonValueCalculator to calculate a score from that weighted average response time. +func NewEpsilonGreedy(hosts []string, decayDuration time.Duration, calc EpsilonValueCalculator) HostPool { + + if decayDuration <= 0 { + decayDuration = defaultDecayDuration + } + stdHP := New(hosts).(*standardHostPool) + p := &epsilonGreedyHostPool{ + standardHostPool: *stdHP, + epsilon: float32(initialEpsilon), + decayDuration: decayDuration, + EpsilonValueCalculator: calc, + timer: &realTimer{}, + quit: make(chan bool), + } + + // allocate structures + for _, h := range p.hostList { + h.epsilonCounts = make([]int64, epsilonBuckets) + h.epsilonValues = make([]int64, epsilonBuckets) + } + go p.epsilonGreedyDecay() + return p +} + +func (p *epsilonGreedyHostPool) Close() { + // No need to do p.quit <- true as close(p.quit) does the trick. + close(p.quit) +} + +func (p *epsilonGreedyHostPool) SetEpsilon(newEpsilon float32) { + p.Lock() + defer p.Unlock() + p.epsilon = newEpsilon +} + +func (p *epsilonGreedyHostPool) SetHosts(hosts []string) { + p.Lock() + defer p.Unlock() + p.standardHostPool.setHosts(hosts) + for _, h := range p.hostList { + h.epsilonCounts = make([]int64, epsilonBuckets) + h.epsilonValues = make([]int64, epsilonBuckets) + } +} + +func (p *epsilonGreedyHostPool) epsilonGreedyDecay() { + durationPerBucket := p.decayDuration / epsilonBuckets + ticker := time.NewTicker(durationPerBucket) + for { + select { + case <-p.quit: + ticker.Stop() + return + case <-ticker.C: + p.performEpsilonGreedyDecay() + } + } +} +func (p *epsilonGreedyHostPool) performEpsilonGreedyDecay() { + p.Lock() + for _, h := range p.hostList { + h.epsilonIndex += 1 + h.epsilonIndex = h.epsilonIndex % epsilonBuckets + h.epsilonCounts[h.epsilonIndex] = 0 + h.epsilonValues[h.epsilonIndex] = 0 + } + p.Unlock() +} + +func (p *epsilonGreedyHostPool) Get() HostPoolResponse { + p.Lock() + defer p.Unlock() + host := p.getEpsilonGreedy() + if host == "" { + return nil + } + + started := time.Now() + return &epsilonHostPoolResponse{ + standardHostPoolResponse: standardHostPoolResponse{host: host, pool: p}, + started: started, + } +} + +func (p *epsilonGreedyHostPool) getEpsilonGreedy() string { + var hostToUse *hostEntry + + // this is our exploration phase + if rand.Float32() < p.epsilon { + p.epsilon = p.epsilon * epsilonDecay + if p.epsilon < minEpsilon { + p.epsilon = minEpsilon + } + return p.getRoundRobin() + } + + // calculate values for each host in the 0..1 range (but not ormalized) + var possibleHosts []*hostEntry + now := time.Now() + var sumValues float64 + for _, h := range p.hostList { + if h.canTryHost(now) { + v := h.getWeightedAverageResponseTime() + if v > 0 { + ev := p.CalcValueFromAvgResponseTime(v) + h.epsilonValue = ev + sumValues += ev + possibleHosts = append(possibleHosts, h) + } + } + } + + if len(possibleHosts) != 0 { + // now normalize to the 0..1 range to get a percentage + for _, h := range possibleHosts { + h.epsilonPercentage = h.epsilonValue / sumValues + } + + // do a weighted random choice among hosts + ceiling := 0.0 + pickPercentage := rand.Float64() + for _, h := range possibleHosts { + ceiling += h.epsilonPercentage + if pickPercentage <= ceiling { + hostToUse = h + break + } + } + } + + if hostToUse == nil { + if len(possibleHosts) != 0 { + log.Println("Failed to randomly choose a host, Dan loses") + } + + return p.getRoundRobin() + } + + if hostToUse.dead { + hostToUse.willRetryHost(p.maxRetryInterval) + } + return hostToUse.host +} + +func (p *epsilonGreedyHostPool) markSuccess(hostR HostPoolResponse) { + // first do the base markSuccess - a little redundant with host lookup but cleaner than repeating logic + p.standardHostPool.markSuccess(hostR) + eHostR, ok := hostR.(*epsilonHostPoolResponse) + if !ok { + log.Printf("Incorrect type in eps markSuccess!") // TODO reflection to print out offending type + return + } + host := eHostR.host + duration := p.between(eHostR.started, eHostR.ended) + + p.Lock() + defer p.Unlock() + h, ok := p.hosts[host] + if !ok { + log.Fatalf("host %s not in HostPool %v", host, p.Hosts()) + } + h.epsilonCounts[h.epsilonIndex]++ + h.epsilonValues[h.epsilonIndex] += int64(duration.Seconds() * 1000) +} + +// --- timer: this just exists for testing + +type timer interface { + between(time.Time, time.Time) time.Duration +} + +type realTimer struct{} + +func (rt *realTimer) between(start time.Time, end time.Time) time.Duration { + return end.Sub(start) +} diff --git a/vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go b/vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go new file mode 100644 index 0000000..9bc3102 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go @@ -0,0 +1,40 @@ +package hostpool + +// --- Value Calculators ----------------- + +import ( + "math" +) + +// --- Definitions ----------------------- + +// Structs implementing this interface are used to convert the average response time for a host +// into a score that can be used to weight hosts in the epsilon greedy hostpool. Lower response +// times should yield higher scores (we want to select the faster hosts more often) The default +// LinearEpsilonValueCalculator just uses the reciprocal of the response time. In practice, any +// decreasing function from the positive reals to the positive reals should work. +type EpsilonValueCalculator interface { + CalcValueFromAvgResponseTime(float64) float64 +} + +type LinearEpsilonValueCalculator struct{} +type LogEpsilonValueCalculator struct{ LinearEpsilonValueCalculator } +type PolynomialEpsilonValueCalculator struct { + LinearEpsilonValueCalculator + Exp float64 // the exponent to which we will raise the value to reweight +} + +// -------- Methods ----------------------- + +func (c *LinearEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 { + return 1.0 / v +} + +func (c *LogEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 { + // we need to add 1 to v so that this will be defined on all positive floats + return c.LinearEpsilonValueCalculator.CalcValueFromAvgResponseTime(math.Log(v + 1.0)) +} + +func (c *PolynomialEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 { + return c.LinearEpsilonValueCalculator.CalcValueFromAvgResponseTime(math.Pow(v, c.Exp)) +} diff --git a/vendor/github.com/hailocab/go-hostpool/host_entry.go b/vendor/github.com/hailocab/go-hostpool/host_entry.go new file mode 100644 index 0000000..dcec9a0 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/host_entry.go @@ -0,0 +1,62 @@ +package hostpool + +import ( + "time" +) + +// --- hostEntry - this is due to get upgraded + +type hostEntry struct { + host string + nextRetry time.Time + retryCount int16 + retryDelay time.Duration + dead bool + epsilonCounts []int64 + epsilonValues []int64 + epsilonIndex int + epsilonValue float64 + epsilonPercentage float64 +} + +func (h *hostEntry) canTryHost(now time.Time) bool { + if !h.dead { + return true + } + if h.nextRetry.Before(now) { + return true + } + return false +} + +func (h *hostEntry) willRetryHost(maxRetryInterval time.Duration) { + h.retryCount += 1 + newDelay := h.retryDelay * 2 + if newDelay < maxRetryInterval { + h.retryDelay = newDelay + } else { + h.retryDelay = maxRetryInterval + } + h.nextRetry = time.Now().Add(h.retryDelay) +} + +func (h *hostEntry) getWeightedAverageResponseTime() float64 { + var value float64 + var lastValue float64 + + // start at 1 so we start with the oldest entry + for i := 1; i <= epsilonBuckets; i += 1 { + pos := (h.epsilonIndex + i) % epsilonBuckets + bucketCount := h.epsilonCounts[pos] + // Changing the line below to what I think it should be to get the weights right + weight := float64(i) / float64(epsilonBuckets) + if bucketCount > 0 { + currentValue := float64(h.epsilonValues[pos]) / float64(bucketCount) + value += currentValue * weight + lastValue = currentValue + } else { + value += lastValue * weight + } + } + return value +} diff --git a/vendor/github.com/hailocab/go-hostpool/hostpool.go b/vendor/github.com/hailocab/go-hostpool/hostpool.go new file mode 100644 index 0000000..702ca92 --- /dev/null +++ b/vendor/github.com/hailocab/go-hostpool/hostpool.go @@ -0,0 +1,243 @@ +// A Go package to intelligently and flexibly pool among multiple hosts from your Go application. +// Host selection can operate in round robin or epsilon greedy mode, and unresponsive hosts are +// avoided. A good overview of Epsilon Greedy is here http://stevehanov.ca/blog/index.php?id=132 +package hostpool + +import ( + "log" + "sync" + "time" +) + +// Returns current version +func Version() string { + return "0.1" +} + +// --- Response interfaces and structs ---- + +// This interface represents the response from HostPool. You can retrieve the +// hostname by calling Host(), and after making a request to the host you should +// call Mark with any error encountered, which will inform the HostPool issuing +// the HostPoolResponse of what happened to the request and allow it to update. +type HostPoolResponse interface { + Host() string + Mark(error) + hostPool() HostPool +} + +type standardHostPoolResponse struct { + host string + sync.Once + pool HostPool +} + +// --- HostPool structs and interfaces ---- + +// This is the main HostPool interface. Structs implementing this interface +// allow you to Get a HostPoolResponse (which includes a hostname to use), +// get the list of all Hosts, and use ResetAll to reset state. +type HostPool interface { + Get() HostPoolResponse + // keep the marks separate so we can override independently + markSuccess(HostPoolResponse) + markFailed(HostPoolResponse) + + ResetAll() + // ReturnUnhealthy when called with true will prevent an unhealthy node from + // being returned and will instead return a nil HostPoolResponse. If using + // this feature then you should check the result of Get for nil + ReturnUnhealthy(v bool) + Hosts() []string + SetHosts([]string) + + // Close the hostpool and release all resources. + Close() +} + +type standardHostPool struct { + sync.RWMutex + hosts map[string]*hostEntry + hostList []*hostEntry + returnUnhealthy bool + initialRetryDelay time.Duration + maxRetryInterval time.Duration + nextHostIndex int +} + +// ------ constants ------------------- + +const epsilonBuckets = 120 +const epsilonDecay = 0.90 // decay the exploration rate +const minEpsilon = 0.01 // explore one percent of the time +const initialEpsilon = 0.3 +const defaultDecayDuration = time.Duration(5) * time.Minute + +// Construct a basic HostPool using the hostnames provided +func New(hosts []string) HostPool { + p := &standardHostPool{ + returnUnhealthy: true, + hosts: make(map[string]*hostEntry, len(hosts)), + hostList: make([]*hostEntry, len(hosts)), + initialRetryDelay: time.Duration(30) * time.Second, + maxRetryInterval: time.Duration(900) * time.Second, + } + + for i, h := range hosts { + e := &hostEntry{ + host: h, + retryDelay: p.initialRetryDelay, + } + p.hosts[h] = e + p.hostList[i] = e + } + + return p +} + +func (r *standardHostPoolResponse) Host() string { + return r.host +} + +func (r *standardHostPoolResponse) hostPool() HostPool { + return r.pool +} + +func (r *standardHostPoolResponse) Mark(err error) { + r.Do(func() { + doMark(err, r) + }) +} + +func doMark(err error, r HostPoolResponse) { + if err == nil { + r.hostPool().markSuccess(r) + } else { + r.hostPool().markFailed(r) + } +} + +// return an entry from the HostPool +func (p *standardHostPool) Get() HostPoolResponse { + p.Lock() + defer p.Unlock() + host := p.getRoundRobin() + if host == "" { + return nil + } + + return &standardHostPoolResponse{host: host, pool: p} +} + +func (p *standardHostPool) getRoundRobin() string { + now := time.Now() + hostCount := len(p.hostList) + for i := range p.hostList { + // iterate via sequenece from where we last iterated + currentIndex := (i + p.nextHostIndex) % hostCount + + h := p.hostList[currentIndex] + if !h.dead { + p.nextHostIndex = currentIndex + 1 + return h.host + } + if h.nextRetry.Before(now) { + h.willRetryHost(p.maxRetryInterval) + p.nextHostIndex = currentIndex + 1 + return h.host + } + } + + // all hosts are down and returnUnhealhy is false then return no host + if !p.returnUnhealthy { + return "" + } + + // all hosts are down. re-add them + p.doResetAll() + p.nextHostIndex = 0 + return p.hostList[0].host +} + +func (p *standardHostPool) ResetAll() { + p.Lock() + defer p.Unlock() + p.doResetAll() +} + +func (p *standardHostPool) SetHosts(hosts []string) { + p.Lock() + defer p.Unlock() + p.setHosts(hosts) +} + +func (p *standardHostPool) ReturnUnhealthy(v bool) { + p.Lock() + defer p.Unlock() + p.returnUnhealthy = v +} + +func (p *standardHostPool) setHosts(hosts []string) { + p.hosts = make(map[string]*hostEntry, len(hosts)) + p.hostList = make([]*hostEntry, len(hosts)) + + for i, h := range hosts { + e := &hostEntry{ + host: h, + retryDelay: p.initialRetryDelay, + } + p.hosts[h] = e + p.hostList[i] = e + } +} + +// this actually performs the logic to reset, +// and should only be called when the lock has +// already been acquired +func (p *standardHostPool) doResetAll() { + for _, h := range p.hosts { + h.dead = false + } +} + +func (p *standardHostPool) Close() { + for _, h := range p.hosts { + h.dead = true + } +} + +func (p *standardHostPool) markSuccess(hostR HostPoolResponse) { + host := hostR.Host() + p.Lock() + defer p.Unlock() + + h, ok := p.hosts[host] + if !ok { + log.Fatalf("host %s not in HostPool %v", host, p.Hosts()) + } + h.dead = false +} + +func (p *standardHostPool) markFailed(hostR HostPoolResponse) { + host := hostR.Host() + p.Lock() + defer p.Unlock() + h, ok := p.hosts[host] + if !ok { + log.Fatalf("host %s not in HostPool %v", host, p.Hosts()) + } + if !h.dead { + h.dead = true + h.retryCount = 0 + h.retryDelay = p.initialRetryDelay + h.nextRetry = time.Now().Add(h.retryDelay) + } + +} +func (p *standardHostPool) Hosts() []string { + hosts := make([]string, 0, len(p.hosts)) + for host := range p.hosts { + hosts = append(hosts, host) + } + return hosts +} diff --git a/vendor/github.com/hashicorp/errwrap/LICENSE b/vendor/github.com/hashicorp/errwrap/LICENSE new file mode 100644 index 0000000..c33dcc7 --- /dev/null +++ b/vendor/github.com/hashicorp/errwrap/LICENSE @@ -0,0 +1,354 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/errwrap/README.md b/vendor/github.com/hashicorp/errwrap/README.md new file mode 100644 index 0000000..1c95f59 --- /dev/null +++ b/vendor/github.com/hashicorp/errwrap/README.md @@ -0,0 +1,89 @@ +# errwrap + +`errwrap` is a package for Go that formalizes the pattern of wrapping errors +and checking if an error contains another error. + +There is a common pattern in Go of taking a returned `error` value and +then wrapping it (such as with `fmt.Errorf`) before returning it. The problem +with this pattern is that you completely lose the original `error` structure. + +Arguably the _correct_ approach is that you should make a custom structure +implementing the `error` interface, and have the original error as a field +on that structure, such [as this example](http://golang.org/pkg/os/#PathError). +This is a good approach, but you have to know the entire chain of possible +rewrapping that happens, when you might just care about one. + +`errwrap` formalizes this pattern (it doesn't matter what approach you use +above) by giving a single interface for wrapping errors, checking if a specific +error is wrapped, and extracting that error. + +## Installation and Docs + +Install using `go get github.com/hashicorp/errwrap`. + +Full documentation is available at +http://godoc.org/github.com/hashicorp/errwrap + +## Usage + +#### Basic Usage + +Below is a very basic example of its usage: + +```go +// A function that always returns an error, but wraps it, like a real +// function might. +func tryOpen() error { + _, err := os.Open("/i/dont/exist") + if err != nil { + return errwrap.Wrapf("Doesn't exist: {{err}}", err) + } + + return nil +} + +func main() { + err := tryOpen() + + // We can use the Contains helpers to check if an error contains + // another error. It is safe to do this with a nil error, or with + // an error that doesn't even use the errwrap package. + if errwrap.Contains(err, ErrNotExist) { + // Do something + } + if errwrap.ContainsType(err, new(os.PathError)) { + // Do something + } + + // Or we can use the associated `Get` functions to just extract + // a specific error. This would return nil if that specific error doesn't + // exist. + perr := errwrap.GetType(err, new(os.PathError)) +} +``` + +#### Custom Types + +If you're already making custom types that properly wrap errors, then +you can get all the functionality of `errwraps.Contains` and such by +implementing the `Wrapper` interface with just one function. Example: + +```go +type AppError { + Code ErrorCode + Err error +} + +func (e *AppError) WrappedErrors() []error { + return []error{e.Err} +} +``` + +Now this works: + +```go +err := &AppError{Err: fmt.Errorf("an error")} +if errwrap.ContainsType(err, fmt.Errorf("")) { + // This will work! +} +``` diff --git a/vendor/github.com/hashicorp/errwrap/errwrap.go b/vendor/github.com/hashicorp/errwrap/errwrap.go new file mode 100644 index 0000000..a733bef --- /dev/null +++ b/vendor/github.com/hashicorp/errwrap/errwrap.go @@ -0,0 +1,169 @@ +// Package errwrap implements methods to formalize error wrapping in Go. +// +// All of the top-level functions that take an `error` are built to be able +// to take any error, not just wrapped errors. This allows you to use errwrap +// without having to type-check and type-cast everywhere. +package errwrap + +import ( + "errors" + "reflect" + "strings" +) + +// WalkFunc is the callback called for Walk. +type WalkFunc func(error) + +// Wrapper is an interface that can be implemented by custom types to +// have all the Contains, Get, etc. functions in errwrap work. +// +// When Walk reaches a Wrapper, it will call the callback for every +// wrapped error in addition to the wrapper itself. Since all the top-level +// functions in errwrap use Walk, this means that all those functions work +// with your custom type. +type Wrapper interface { + WrappedErrors() []error +} + +// Wrap defines that outer wraps inner, returning an error type that +// can be cleanly used with the other methods in this package, such as +// Contains, GetAll, etc. +// +// This function won't modify the error message at all (the outer message +// will be used). +func Wrap(outer, inner error) error { + return &wrappedError{ + Outer: outer, + Inner: inner, + } +} + +// Wrapf wraps an error with a formatting message. This is similar to using +// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap +// errors, you should replace it with this. +// +// format is the format of the error message. The string '{{err}}' will +// be replaced with the original error message. +func Wrapf(format string, err error) error { + outerMsg := "" + if err != nil { + outerMsg = err.Error() + } + + outer := errors.New(strings.Replace( + format, "{{err}}", outerMsg, -1)) + + return Wrap(outer, err) +} + +// Contains checks if the given error contains an error with the +// message msg. If err is not a wrapped error, this will always return +// false unless the error itself happens to match this msg. +func Contains(err error, msg string) bool { + return len(GetAll(err, msg)) > 0 +} + +// ContainsType checks if the given error contains an error with +// the same concrete type as v. If err is not a wrapped error, this will +// check the err itself. +func ContainsType(err error, v interface{}) bool { + return len(GetAllType(err, v)) > 0 +} + +// Get is the same as GetAll but returns the deepest matching error. +func Get(err error, msg string) error { + es := GetAll(err, msg) + if len(es) > 0 { + return es[len(es)-1] + } + + return nil +} + +// GetType is the same as GetAllType but returns the deepest matching error. +func GetType(err error, v interface{}) error { + es := GetAllType(err, v) + if len(es) > 0 { + return es[len(es)-1] + } + + return nil +} + +// GetAll gets all the errors that might be wrapped in err with the +// given message. The order of the errors is such that the outermost +// matching error (the most recent wrap) is index zero, and so on. +func GetAll(err error, msg string) []error { + var result []error + + Walk(err, func(err error) { + if err.Error() == msg { + result = append(result, err) + } + }) + + return result +} + +// GetAllType gets all the errors that are the same type as v. +// +// The order of the return value is the same as described in GetAll. +func GetAllType(err error, v interface{}) []error { + var result []error + + var search string + if v != nil { + search = reflect.TypeOf(v).String() + } + Walk(err, func(err error) { + var needle string + if err != nil { + needle = reflect.TypeOf(err).String() + } + + if needle == search { + result = append(result, err) + } + }) + + return result +} + +// Walk walks all the wrapped errors in err and calls the callback. If +// err isn't a wrapped error, this will be called once for err. If err +// is a wrapped error, the callback will be called for both the wrapper +// that implements error as well as the wrapped error itself. +func Walk(err error, cb WalkFunc) { + if err == nil { + return + } + + switch e := err.(type) { + case *wrappedError: + cb(e.Outer) + Walk(e.Inner, cb) + case Wrapper: + cb(err) + + for _, err := range e.WrappedErrors() { + Walk(err, cb) + } + default: + cb(err) + } +} + +// wrappedError is an implementation of error that has both the +// outer and inner errors. +type wrappedError struct { + Outer error + Inner error +} + +func (w *wrappedError) Error() string { + return w.Outer.Error() +} + +func (w *wrappedError) WrappedErrors() []error { + return []error{w.Outer, w.Inner} +} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-cleanhttp/README.md b/vendor/github.com/hashicorp/go-cleanhttp/README.md new file mode 100644 index 0000000..036e531 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/README.md @@ -0,0 +1,30 @@ +# cleanhttp + +Functions for accessing "clean" Go http.Client values + +------------- + +The Go standard library contains a default `http.Client` called +`http.DefaultClient`. It is a common idiom in Go code to start with +`http.DefaultClient` and tweak it as necessary, and in fact, this is +encouraged; from the `http` package documentation: + +> The Client's Transport typically has internal state (cached TCP connections), +so Clients should be reused instead of created as needed. Clients are safe for +concurrent use by multiple goroutines. + +Unfortunately, this is a shared value, and it is not uncommon for libraries to +assume that they are free to modify it at will. With enough dependencies, it +can be very easy to encounter strange problems and race conditions due to +manipulation of this shared value across libraries and goroutines (clients are +safe for concurrent use, but writing values to the client struct itself is not +protected). + +Making things worse is the fact that a bare `http.Client` will use a default +`http.Transport` called `http.DefaultTransport`, which is another global value +that behaves the same way. So it is not simply enough to replace +`http.DefaultClient` with `&http.Client{}`. + +This repository provides some simple functions to get a "clean" `http.Client` +-- one that uses the same default values as the Go standard library, but +returns a client that does not share any state with other clients. diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go new file mode 100644 index 0000000..8d306bf --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go @@ -0,0 +1,57 @@ +package cleanhttp + +import ( + "net" + "net/http" + "runtime" + "time" +) + +// DefaultTransport returns a new http.Transport with similar default values to +// http.DefaultTransport, but with idle connections and keepalives disabled. +func DefaultTransport() *http.Transport { + transport := DefaultPooledTransport() + transport.DisableKeepAlives = true + transport.MaxIdleConnsPerHost = -1 + return transport +} + +// DefaultPooledTransport returns a new http.Transport with similar default +// values to http.DefaultTransport. Do not use this for transient transports as +// it can leak file descriptors over time. Only use this for transports that +// will be re-used for the same host(s). +func DefaultPooledTransport() *http.Transport { + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, + } + return transport +} + +// DefaultClient returns a new http.Client with similar default values to +// http.Client, but with a non-shared Transport, idle connections disabled, and +// keepalives disabled. +func DefaultClient() *http.Client { + return &http.Client{ + Transport: DefaultTransport(), + } +} + +// DefaultPooledClient returns a new http.Client with similar default values to +// http.Client, but with a shared Transport. Do not use this function for +// transient clients as it can leak file descriptors over time. Only use this +// for clients that will be re-used for the same host(s). +func DefaultPooledClient() *http.Client { + return &http.Client{ + Transport: DefaultPooledTransport(), + } +} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/doc.go b/vendor/github.com/hashicorp/go-cleanhttp/doc.go new file mode 100644 index 0000000..0584109 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/doc.go @@ -0,0 +1,20 @@ +// Package cleanhttp offers convenience utilities for acquiring "clean" +// http.Transport and http.Client structs. +// +// Values set on http.DefaultClient and http.DefaultTransport affect all +// callers. This can have detrimental effects, esepcially in TLS contexts, +// where client or root certificates set to talk to multiple endpoints can end +// up displacing each other, leading to hard-to-debug issues. This package +// provides non-shared http.Client and http.Transport structs to ensure that +// the configuration will not be overwritten by other parts of the application +// or dependencies. +// +// The DefaultClient and DefaultTransport functions disable idle connections +// and keepalives. Without ensuring that idle connections are closed before +// garbage collection, short-term clients/transports can leak file descriptors, +// eventually leading to "too many open files" errors. If you will be +// connecting to the same hosts repeatedly from the same client, you can use +// DefaultPooledClient to receive a client that has connection pooling +// semantics similar to http.DefaultClient. +// +package cleanhttp diff --git a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go new file mode 100644 index 0000000..7eda377 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go @@ -0,0 +1,43 @@ +package cleanhttp + +import ( + "net/http" + "strings" + "unicode" +) + +// HandlerInput provides input options to cleanhttp's handlers +type HandlerInput struct { + ErrStatus int +} + +// PrintablePathCheckHandler is a middleware that ensures the request path +// contains only printable runes. +func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler { + // Nil-check on input to make it optional + if input == nil { + input = &HandlerInput{ + ErrStatus: http.StatusBadRequest, + } + } + + // Default to http.StatusBadRequest on error + if input.ErrStatus == 0 { + input.ErrStatus = http.StatusBadRequest + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check URL path for non-printable characters + idx := strings.IndexFunc(r.URL.Path, func(c rune) bool { + return !unicode.IsPrint(c) + }) + + if idx != -1 { + w.WriteHeader(input.ErrStatus) + return + } + + next.ServeHTTP(w, r) + return + }) +} diff --git a/vendor/github.com/hashicorp/go-hclog/.gitignore b/vendor/github.com/hashicorp/go-hclog/.gitignore new file mode 100644 index 0000000..42cc410 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/.gitignore @@ -0,0 +1 @@ +.idea* \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-hclog/LICENSE b/vendor/github.com/hashicorp/go-hclog/LICENSE new file mode 100644 index 0000000..abaf1e4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 HashiCorp + +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/vendor/github.com/hashicorp/go-hclog/README.md b/vendor/github.com/hashicorp/go-hclog/README.md new file mode 100644 index 0000000..1153e28 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/README.md @@ -0,0 +1,133 @@ +# go-hclog + +[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] + +[godocs]: https://godoc.org/github.com/hashicorp/go-hclog + +`go-hclog` is a package for Go that provides a simple key/value logging +interface for use in development and production environments. + +It provides logging levels that provide decreased output based upon the +desired amount of output, unlike the standard library `log` package. + +It provides `Printf` style logging of values via `hclog.Fmt()`. + +It provides a human readable output mode for use in development as well as +JSON output mode for production. + +## Stability Note + +While this library is fully open source and HashiCorp will be maintaining it +(since we are and will be making extensive use of it), the API and output +format is subject to minor changes as we fully bake and vet it in our projects. +This notice will be removed once it's fully integrated into our major projects +and no further changes are anticipated. + +## Installation and Docs + +Install using `go get github.com/hashicorp/go-hclog`. + +Full documentation is available at +http://godoc.org/github.com/hashicorp/go-hclog + +## Usage + +### Use the global logger + +```go +hclog.Default().Info("hello world") +``` + +```text +2017-07-05T16:15:55.167-0700 [INFO ] hello world +``` + +(Note timestamps are removed in future examples for brevity.) + +### Create a new logger + +```go +appLogger := hclog.New(&hclog.LoggerOptions{ + Name: "my-app", + Level: hclog.LevelFromString("DEBUG"), +}) +``` + +### Emit an Info level message with 2 key/value pairs + +```go +input := "5.5" +_, err := strconv.ParseInt(input, 10, 32) +if err != nil { + appLogger.Info("Invalid input for ParseInt", "input", input, "error", err) +} +``` + +```text +... [INFO ] my-app: Invalid input for ParseInt: input=5.5 error="strconv.ParseInt: parsing "5.5": invalid syntax" +``` + +### Create a new Logger for a major subsystem + +```go +subsystemLogger := appLogger.Named("transport") +subsystemLogger.Info("we are transporting something") +``` + +```text +... [INFO ] my-app.transport: we are transporting something +``` + +Notice that logs emitted by `subsystemLogger` contain `my-app.transport`, +reflecting both the application and subsystem names. + +### Create a new Logger with fixed key/value pairs + +Using `With()` will include a specific key-value pair in all messages emitted +by that logger. + +```go +requestID := "5fb446b6-6eba-821d-df1b-cd7501b6a363" +requestLogger := subsystemLogger.With("request", requestID) +requestLogger.Info("we are transporting a request") +``` + +```text +... [INFO ] my-app.transport: we are transporting a request: request=5fb446b6-6eba-821d-df1b-cd7501b6a363 +``` + +This allows sub Loggers to be context specific without having to thread that +into all the callers. + +### Using `hclog.Fmt()` + +```go +var int totalBandwidth = 200 +appLogger.Info("total bandwidth exceeded", "bandwidth", hclog.Fmt("%d GB/s", totalBandwidth)) +``` + +```text +... [INFO ] my-app: total bandwidth exceeded: bandwidth="200 GB/s" +``` + +### Use this with code that uses the standard library logger + +If you want to use the standard library's `log.Logger` interface you can wrap +`hclog.Logger` by calling the `StandardLogger()` method. This allows you to use +it with the familiar `Println()`, `Printf()`, etc. For example: + +```go +stdLogger := appLogger.StandardLogger(&hclog.StandardLoggerOptions{ + InferLevels: true, +}) +// Printf() is provided by stdlib log.Logger interface, not hclog.Logger +stdLogger.Printf("[DEBUG] %+v", stdLogger) +``` + +```text +... [DEBUG] my-app: &{mu:{state:0 sema:0} prefix: flag:0 out:0xc42000a0a0 buf:[]} +``` + +Notice that if `appLogger` is initialized with the `INFO` log level _and_ you +specify `InferLevels: true`, you will not see any output here. You must change +`appLogger` to `DEBUG` to see output. See the docs for more information. diff --git a/vendor/github.com/hashicorp/go-hclog/global.go b/vendor/github.com/hashicorp/go-hclog/global.go new file mode 100644 index 0000000..55ce439 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/global.go @@ -0,0 +1,34 @@ +package hclog + +import ( + "sync" +) + +var ( + protect sync.Once + def Logger + + // The options used to create the Default logger. These are + // read only when the Default logger is created, so set them + // as soon as the process starts. + DefaultOptions = &LoggerOptions{ + Level: DefaultLevel, + Output: DefaultOutput, + } +) + +// Return a logger that is held globally. This can be a good starting +// place, and then you can use .With() and .Name() to create sub-loggers +// to be used in more specific contexts. +func Default() Logger { + protect.Do(func() { + def = New(DefaultOptions) + }) + + return def +} + +// A short alias for Default() +func L() Logger { + return Default() +} diff --git a/vendor/github.com/hashicorp/go-hclog/int.go b/vendor/github.com/hashicorp/go-hclog/int.go new file mode 100644 index 0000000..0166c3d --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/int.go @@ -0,0 +1,420 @@ +package hclog + +import ( + "bufio" + "encoding" + "encoding/json" + "fmt" + "log" + "os" + "runtime" + "strconv" + "strings" + "sync" + "time" +) + +var ( + _levelToBracket = map[Level]string{ + Debug: "[DEBUG]", + Trace: "[TRACE]", + Info: "[INFO ]", + Warn: "[WARN ]", + Error: "[ERROR]", + } +) + +// Given the options (nil for defaults), create a new Logger +func New(opts *LoggerOptions) Logger { + if opts == nil { + opts = &LoggerOptions{} + } + + output := opts.Output + if output == nil { + output = os.Stderr + } + + level := opts.Level + if level == NoLevel { + level = DefaultLevel + } + + mtx := opts.Mutex + if mtx == nil { + mtx = new(sync.Mutex) + } + + ret := &intLogger{ + m: mtx, + json: opts.JSONFormat, + caller: opts.IncludeLocation, + name: opts.Name, + timeFormat: TimeFormat, + w: bufio.NewWriter(output), + level: level, + } + if opts.TimeFormat != "" { + ret.timeFormat = opts.TimeFormat + } + return ret +} + +// The internal logger implementation. Internal in that it is defined entirely +// by this package. +type intLogger struct { + json bool + caller bool + name string + timeFormat string + + // this is a pointer so that it's shared by any derived loggers, since + // those derived loggers share the bufio.Writer as well. + m *sync.Mutex + w *bufio.Writer + level Level + + implied []interface{} +} + +// Make sure that intLogger is a Logger +var _ Logger = &intLogger{} + +// The time format to use for logging. This is a version of RFC3339 that +// contains millisecond precision +const TimeFormat = "2006-01-02T15:04:05.000Z0700" + +// Log a message and a set of key/value pairs if the given level is at +// or more severe that the threshold configured in the Logger. +func (z *intLogger) Log(level Level, msg string, args ...interface{}) { + if level < z.level { + return + } + + t := time.Now() + + z.m.Lock() + defer z.m.Unlock() + + if z.json { + z.logJson(t, level, msg, args...) + } else { + z.log(t, level, msg, args...) + } + + z.w.Flush() +} + +// Cleanup a path by returning the last 2 segments of the path only. +func trimCallerPath(path string) string { + // lovely borrowed from zap + // nb. To make sure we trim the path correctly on Windows too, we + // counter-intuitively need to use '/' and *not* os.PathSeparator here, + // because the path given originates from Go stdlib, specifically + // runtime.Caller() which (as of Mar/17) returns forward slashes even on + // Windows. + // + // See https://github.com/golang/go/issues/3335 + // and https://github.com/golang/go/issues/18151 + // + // for discussion on the issue on Go side. + // + + // Find the last separator. + // + idx := strings.LastIndexByte(path, '/') + if idx == -1 { + return path + } + + // Find the penultimate separator. + idx = strings.LastIndexByte(path[:idx], '/') + if idx == -1 { + return path + } + + return path[idx+1:] +} + +// Non-JSON logging format function +func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) { + z.w.WriteString(t.Format(z.timeFormat)) + z.w.WriteByte(' ') + + s, ok := _levelToBracket[level] + if ok { + z.w.WriteString(s) + } else { + z.w.WriteString("[UNKN ]") + } + + if z.caller { + if _, file, line, ok := runtime.Caller(3); ok { + z.w.WriteByte(' ') + z.w.WriteString(trimCallerPath(file)) + z.w.WriteByte(':') + z.w.WriteString(strconv.Itoa(line)) + z.w.WriteByte(':') + } + } + + z.w.WriteByte(' ') + + if z.name != "" { + z.w.WriteString(z.name) + z.w.WriteString(": ") + } + + z.w.WriteString(msg) + + args = append(z.implied, args...) + + var stacktrace CapturedStacktrace + + if args != nil && len(args) > 0 { + if len(args)%2 != 0 { + cs, ok := args[len(args)-1].(CapturedStacktrace) + if ok { + args = args[:len(args)-1] + stacktrace = cs + } else { + args = append(args, "") + } + } + + z.w.WriteByte(':') + + FOR: + for i := 0; i < len(args); i = i + 2 { + var val string + + switch st := args[i+1].(type) { + case string: + val = st + case int: + val = strconv.FormatInt(int64(st), 10) + case int64: + val = strconv.FormatInt(int64(st), 10) + case int32: + val = strconv.FormatInt(int64(st), 10) + case int16: + val = strconv.FormatInt(int64(st), 10) + case int8: + val = strconv.FormatInt(int64(st), 10) + case uint: + val = strconv.FormatUint(uint64(st), 10) + case uint64: + val = strconv.FormatUint(uint64(st), 10) + case uint32: + val = strconv.FormatUint(uint64(st), 10) + case uint16: + val = strconv.FormatUint(uint64(st), 10) + case uint8: + val = strconv.FormatUint(uint64(st), 10) + case CapturedStacktrace: + stacktrace = st + continue FOR + case Format: + val = fmt.Sprintf(st[0].(string), st[1:]...) + default: + val = fmt.Sprintf("%v", st) + } + + z.w.WriteByte(' ') + z.w.WriteString(args[i].(string)) + z.w.WriteByte('=') + + if strings.ContainsAny(val, " \t\n\r") { + z.w.WriteByte('"') + z.w.WriteString(val) + z.w.WriteByte('"') + } else { + z.w.WriteString(val) + } + } + } + + z.w.WriteString("\n") + + if stacktrace != "" { + z.w.WriteString(string(stacktrace)) + } +} + +// JSON logging function +func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interface{}) { + vals := map[string]interface{}{ + "@message": msg, + "@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"), + } + + var levelStr string + switch level { + case Error: + levelStr = "error" + case Warn: + levelStr = "warn" + case Info: + levelStr = "info" + case Debug: + levelStr = "debug" + case Trace: + levelStr = "trace" + default: + levelStr = "all" + } + + vals["@level"] = levelStr + + if z.name != "" { + vals["@module"] = z.name + } + + if z.caller { + if _, file, line, ok := runtime.Caller(3); ok { + vals["@caller"] = fmt.Sprintf("%s:%d", file, line) + } + } + + args = append(z.implied, args...) + + if args != nil && len(args) > 0 { + if len(args)%2 != 0 { + cs, ok := args[len(args)-1].(CapturedStacktrace) + if ok { + args = args[:len(args)-1] + vals["stacktrace"] = cs + } else { + args = append(args, "") + } + } + + for i := 0; i < len(args); i = i + 2 { + if _, ok := args[i].(string); !ok { + // As this is the logging function not much we can do here + // without injecting into logs... + continue + } + val := args[i+1] + switch sv := val.(type) { + case error: + // Check if val is of type error. If error type doesn't + // implement json.Marshaler or encoding.TextMarshaler + // then set val to err.Error() so that it gets marshaled + switch sv.(type) { + case json.Marshaler, encoding.TextMarshaler: + default: + val = sv.Error() + } + case Format: + val = fmt.Sprintf(sv[0].(string), sv[1:]...) + } + + vals[args[i].(string)] = val + } + } + + err := json.NewEncoder(z.w).Encode(vals) + if err != nil { + panic(err) + } +} + +// Emit the message and args at DEBUG level +func (z *intLogger) Debug(msg string, args ...interface{}) { + z.Log(Debug, msg, args...) +} + +// Emit the message and args at TRACE level +func (z *intLogger) Trace(msg string, args ...interface{}) { + z.Log(Trace, msg, args...) +} + +// Emit the message and args at INFO level +func (z *intLogger) Info(msg string, args ...interface{}) { + z.Log(Info, msg, args...) +} + +// Emit the message and args at WARN level +func (z *intLogger) Warn(msg string, args ...interface{}) { + z.Log(Warn, msg, args...) +} + +// Emit the message and args at ERROR level +func (z *intLogger) Error(msg string, args ...interface{}) { + z.Log(Error, msg, args...) +} + +// Indicate that the logger would emit TRACE level logs +func (z *intLogger) IsTrace() bool { + return z.level == Trace +} + +// Indicate that the logger would emit DEBUG level logs +func (z *intLogger) IsDebug() bool { + return z.level <= Debug +} + +// Indicate that the logger would emit INFO level logs +func (z *intLogger) IsInfo() bool { + return z.level <= Info +} + +// Indicate that the logger would emit WARN level logs +func (z *intLogger) IsWarn() bool { + return z.level <= Warn +} + +// Indicate that the logger would emit ERROR level logs +func (z *intLogger) IsError() bool { + return z.level <= Error +} + +// Return a sub-Logger for which every emitted log message will contain +// the given key/value pairs. This is used to create a context specific +// Logger. +func (z *intLogger) With(args ...interface{}) Logger { + var nz intLogger = *z + + nz.implied = make([]interface{}, 0, len(z.implied)+len(args)) + nz.implied = append(nz.implied, z.implied...) + nz.implied = append(nz.implied, args...) + + return &nz +} + +// Create a new sub-Logger that a name decending from the current name. +// This is used to create a subsystem specific Logger. +func (z *intLogger) Named(name string) Logger { + var nz intLogger = *z + + if nz.name != "" { + nz.name = nz.name + "." + name + } else { + nz.name = name + } + + return &nz +} + +// Create a new sub-Logger with an explicit name. This ignores the current +// name. This is used to create a standalone logger that doesn't fall +// within the normal hierarchy. +func (z *intLogger) ResetNamed(name string) Logger { + var nz intLogger = *z + + nz.name = name + + return &nz +} + +// Create a *log.Logger that will send it's data through this Logger. This +// allows packages that expect to be using the standard library log to actually +// use this logger. +func (z *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger { + if opts == nil { + opts = &StandardLoggerOptions{} + } + + return log.New(&stdlogAdapter{z, opts.InferLevels}, "", 0) +} diff --git a/vendor/github.com/hashicorp/go-hclog/log.go b/vendor/github.com/hashicorp/go-hclog/log.go new file mode 100644 index 0000000..3629248 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/log.go @@ -0,0 +1,157 @@ +package hclog + +import ( + "io" + "log" + "os" + "strings" + "sync" +) + +var ( + DefaultOutput = os.Stderr + DefaultLevel = Info +) + +type Level int + +const ( + // This is a special level used to indicate that no level has been + // set and allow for a default to be used. + NoLevel Level = 0 + + // The most verbose level. Intended to be used for the tracing of actions + // in code, such as function enters/exits, etc. + Trace Level = 1 + + // For programmer lowlevel analysis. + Debug Level = 2 + + // For information about steady state operations. + Info Level = 3 + + // For information about rare but handled events. + Warn Level = 4 + + // For information about unrecoverable events. + Error Level = 5 +) + +// When processing a value of this type, the logger automatically treats the first +// argument as a Printf formatting string and passes the rest as the values to be +// formatted. For example: L.Info(Fmt{"%d beans/day", beans}). This is a simple +// convience type for when formatting is required. +type Format []interface{} + +// Fmt returns a Format type. This is a convience function for creating a Format +// type. +func Fmt(str string, args ...interface{}) Format { + return append(Format{str}, args...) +} + +// LevelFromString returns a Level type for the named log level, or "NoLevel" if +// the level string is invalid. This facilitates setting the log level via +// config or environment variable by name in a predictable way. +func LevelFromString(levelStr string) Level { + // We don't care about case. Accept "INFO" or "info" + levelStr = strings.ToLower(strings.TrimSpace(levelStr)) + switch levelStr { + case "trace": + return Trace + case "debug": + return Debug + case "info": + return Info + case "warn": + return Warn + case "error": + return Error + default: + return NoLevel + } +} + +// The main Logger interface. All code should code against this interface only. +type Logger interface { + // Args are alternating key, val pairs + // keys must be strings + // vals can be any type, but display is implementation specific + // Emit a message and key/value pairs at the TRACE level + Trace(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the DEBUG level + Debug(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the INFO level + Info(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the WARN level + Warn(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the ERROR level + Error(msg string, args ...interface{}) + + // Indicate if TRACE logs would be emitted. This and the other Is* guards + // are used to elide expensive logging code based on the current level. + IsTrace() bool + + // Indicate if DEBUG logs would be emitted. This and the other Is* guards + IsDebug() bool + + // Indicate if INFO logs would be emitted. This and the other Is* guards + IsInfo() bool + + // Indicate if WARN logs would be emitted. This and the other Is* guards + IsWarn() bool + + // Indicate if ERROR logs would be emitted. This and the other Is* guards + IsError() bool + + // Creates a sublogger that will always have the given key/value pairs + With(args ...interface{}) Logger + + // Create a logger that will prepend the name string on the front of all messages. + // If the logger already has a name, the new value will be appended to the current + // name. That way, a major subsystem can use this to decorate all it's own logs + // without losing context. + Named(name string) Logger + + // Create a logger that will prepend the name string on the front of all messages. + // This sets the name of the logger to the value directly, unlike Named which honor + // the current name as well. + ResetNamed(name string) Logger + + // Return a value that conforms to the stdlib log.Logger interface + StandardLogger(opts *StandardLoggerOptions) *log.Logger +} + +type StandardLoggerOptions struct { + // Indicate that some minimal parsing should be done on strings to try + // and detect their level and re-emit them. + // This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO], + // [DEBUG] and strip it off before reapplying it. + InferLevels bool +} + +type LoggerOptions struct { + // Name of the subsystem to prefix logs with + Name string + + // The threshold for the logger. Anything less severe is supressed + Level Level + + // Where to write the logs to. Defaults to os.Stdout if nil + Output io.Writer + + // An optional mutex pointer in case Output is shared + Mutex *sync.Mutex + + // Control if the output should be in JSON. + JSONFormat bool + + // Include file and line information in each log line + IncludeLocation bool + + // The time format to use instead of the default + TimeFormat string +} diff --git a/vendor/github.com/hashicorp/go-hclog/nulllogger.go b/vendor/github.com/hashicorp/go-hclog/nulllogger.go new file mode 100644 index 0000000..c10ce6e --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/nulllogger.go @@ -0,0 +1,45 @@ +package hclog + +import ( + "log" + "io/ioutil" +) + +// NewNullLogger instantiates a Logger for which all calls +// will succeed without doing anything. +// Useful for testing purposes. +func NewNullLogger() Logger { + return &nullLogger{} +} + +type nullLogger struct{} + +func (l *nullLogger) Trace(msg string, args ...interface{}) {} + +func (l *nullLogger) Debug(msg string, args ...interface{}) {} + +func (l *nullLogger) Info(msg string, args ...interface{}) {} + +func (l *nullLogger) Warn(msg string, args ...interface{}) {} + +func (l *nullLogger) Error(msg string, args ...interface{}) {} + +func (l *nullLogger) IsTrace() bool { return false } + +func (l *nullLogger) IsDebug() bool { return false } + +func (l *nullLogger) IsInfo() bool { return false } + +func (l *nullLogger) IsWarn() bool { return false } + +func (l *nullLogger) IsError() bool { return false } + +func (l *nullLogger) With(args ...interface{}) Logger { return l } + +func (l *nullLogger) Named(name string) Logger { return l } + +func (l *nullLogger) ResetNamed(name string) Logger { return l } + +func (l *nullLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger { + return log.New(ioutil.Discard, "", log.LstdFlags) +} \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-hclog/stacktrace.go b/vendor/github.com/hashicorp/go-hclog/stacktrace.go new file mode 100644 index 0000000..8af1a3b --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/stacktrace.go @@ -0,0 +1,108 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// 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. + +package hclog + +import ( + "bytes" + "runtime" + "strconv" + "strings" + "sync" +) + +var ( + _stacktraceIgnorePrefixes = []string{ + "runtime.goexit", + "runtime.main", + } + _stacktracePool = sync.Pool{ + New: func() interface{} { + return newProgramCounters(64) + }, + } +) + +// A stacktrace gathered by a previous call to log.Stacktrace. If passed +// to a logging function, the stacktrace will be appended. +type CapturedStacktrace string + +// Gather a stacktrace of the current goroutine and return it to be passed +// to a logging function. +func Stacktrace() CapturedStacktrace { + return CapturedStacktrace(takeStacktrace()) +} + +func takeStacktrace() string { + programCounters := _stacktracePool.Get().(*programCounters) + defer _stacktracePool.Put(programCounters) + + var buffer bytes.Buffer + + for { + // Skip the call to runtime.Counters and takeStacktrace so that the + // program counters start at the caller of takeStacktrace. + n := runtime.Callers(2, programCounters.pcs) + if n < cap(programCounters.pcs) { + programCounters.pcs = programCounters.pcs[:n] + break + } + // Don't put the too-short counter slice back into the pool; this lets + // the pool adjust if we consistently take deep stacktraces. + programCounters = newProgramCounters(len(programCounters.pcs) * 2) + } + + i := 0 + frames := runtime.CallersFrames(programCounters.pcs) + for frame, more := frames.Next(); more; frame, more = frames.Next() { + if shouldIgnoreStacktraceFunction(frame.Function) { + continue + } + if i != 0 { + buffer.WriteByte('\n') + } + i++ + buffer.WriteString(frame.Function) + buffer.WriteByte('\n') + buffer.WriteByte('\t') + buffer.WriteString(frame.File) + buffer.WriteByte(':') + buffer.WriteString(strconv.Itoa(int(frame.Line))) + } + + return buffer.String() +} + +func shouldIgnoreStacktraceFunction(function string) bool { + for _, prefix := range _stacktraceIgnorePrefixes { + if strings.HasPrefix(function, prefix) { + return true + } + } + return false +} + +type programCounters struct { + pcs []uintptr +} + +func newProgramCounters(size int) *programCounters { + return &programCounters{make([]uintptr, size)} +} diff --git a/vendor/github.com/hashicorp/go-hclog/stdlog.go b/vendor/github.com/hashicorp/go-hclog/stdlog.go new file mode 100644 index 0000000..2bb927f --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/stdlog.go @@ -0,0 +1,62 @@ +package hclog + +import ( + "bytes" + "strings" +) + +// Provides a io.Writer to shim the data out of *log.Logger +// and back into our Logger. This is basically the only way to +// build upon *log.Logger. +type stdlogAdapter struct { + hl Logger + inferLevels bool +} + +// Take the data, infer the levels if configured, and send it through +// a regular Logger +func (s *stdlogAdapter) Write(data []byte) (int, error) { + str := string(bytes.TrimRight(data, " \t\n")) + + if s.inferLevels { + level, str := s.pickLevel(str) + switch level { + case Trace: + s.hl.Trace(str) + case Debug: + s.hl.Debug(str) + case Info: + s.hl.Info(str) + case Warn: + s.hl.Warn(str) + case Error: + s.hl.Error(str) + default: + s.hl.Info(str) + } + } else { + s.hl.Info(str) + } + + return len(data), nil +} + +// Detect, based on conventions, what log level this is +func (s *stdlogAdapter) pickLevel(str string) (Level, string) { + switch { + case strings.HasPrefix(str, "[DEBUG]"): + return Debug, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[TRACE]"): + return Trace, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[INFO]"): + return Info, strings.TrimSpace(str[6:]) + case strings.HasPrefix(str, "[WARN]"): + return Warn, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[ERROR]"): + return Error, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[ERR]"): + return Error, strings.TrimSpace(str[5:]) + default: + return Info, str + } +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/.gitignore b/vendor/github.com/hashicorp/go-immutable-radix/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml b/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml new file mode 100644 index 0000000..1a0bbea --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml @@ -0,0 +1,3 @@ +language: go +go: + - tip diff --git a/vendor/github.com/hashicorp/go-immutable-radix/LICENSE b/vendor/github.com/hashicorp/go-immutable-radix/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-immutable-radix/README.md b/vendor/github.com/hashicorp/go-immutable-radix/README.md new file mode 100644 index 0000000..8910fcc --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/README.md @@ -0,0 +1,41 @@ +go-immutable-radix [![Build Status](https://travis-ci.org/hashicorp/go-immutable-radix.png)](https://travis-ci.org/hashicorp/go-immutable-radix) +========= + +Provides the `iradix` package that implements an immutable [radix tree](http://en.wikipedia.org/wiki/Radix_tree). +The package only provides a single `Tree` implementation, optimized for sparse nodes. + +As a radix tree, it provides the following: + * O(k) operations. In many cases, this can be faster than a hash table since + the hash function is an O(k) operation, and hash tables have very poor cache locality. + * Minimum / Maximum value lookups + * Ordered iteration + +A tree supports using a transaction to batch multiple updates (insert, delete) +in a more efficient manner than performing each operation one at a time. + +For a mutable variant, see [go-radix](https://github.com/armon/go-radix). + +Documentation +============= + +The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-immutable-radix). + +Example +======= + +Below is a simple example of usage + +```go +// Create a tree +r := iradix.New() +r, _, _ = r.Insert([]byte("foo"), 1) +r, _, _ = r.Insert([]byte("bar"), 2) +r, _, _ = r.Insert([]byte("foobar"), 2) + +// Find the longest prefix match +m, _, _ := r.Root().LongestPrefix([]byte("foozip")) +if string(m) != "foo" { + panic("should be foo") +} +``` + diff --git a/vendor/github.com/hashicorp/go-immutable-radix/edges.go b/vendor/github.com/hashicorp/go-immutable-radix/edges.go new file mode 100644 index 0000000..a636747 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/edges.go @@ -0,0 +1,21 @@ +package iradix + +import "sort" + +type edges []edge + +func (e edges) Len() int { + return len(e) +} + +func (e edges) Less(i, j int) bool { + return e[i].label < e[j].label +} + +func (e edges) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e edges) Sort() { + sort.Sort(e) +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iradix.go b/vendor/github.com/hashicorp/go-immutable-radix/iradix.go new file mode 100644 index 0000000..e5e6e57 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/iradix.go @@ -0,0 +1,662 @@ +package iradix + +import ( + "bytes" + "strings" + + "github.com/hashicorp/golang-lru/simplelru" +) + +const ( + // defaultModifiedCache is the default size of the modified node + // cache used per transaction. This is used to cache the updates + // to the nodes near the root, while the leaves do not need to be + // cached. This is important for very large transactions to prevent + // the modified cache from growing to be enormous. This is also used + // to set the max size of the mutation notify maps since those should + // also be bounded in a similar way. + defaultModifiedCache = 8192 +) + +// Tree implements an immutable radix tree. This can be treated as a +// Dictionary abstract data type. The main advantage over a standard +// hash map is prefix-based lookups and ordered iteration. The immutability +// means that it is safe to concurrently read from a Tree without any +// coordination. +type Tree struct { + root *Node + size int +} + +// New returns an empty Tree +func New() *Tree { + t := &Tree{ + root: &Node{ + mutateCh: make(chan struct{}), + }, + } + return t +} + +// Len is used to return the number of elements in the tree +func (t *Tree) Len() int { + return t.size +} + +// Txn is a transaction on the tree. This transaction is applied +// atomically and returns a new tree when committed. A transaction +// is not thread safe, and should only be used by a single goroutine. +type Txn struct { + // root is the modified root for the transaction. + root *Node + + // snap is a snapshot of the root node for use if we have to run the + // slow notify algorithm. + snap *Node + + // size tracks the size of the tree as it is modified during the + // transaction. + size int + + // writable is a cache of writable nodes that have been created during + // the course of the transaction. This allows us to re-use the same + // nodes for further writes and avoid unnecessary copies of nodes that + // have never been exposed outside the transaction. This will only hold + // up to defaultModifiedCache number of entries. + writable *simplelru.LRU + + // trackChannels is used to hold channels that need to be notified to + // signal mutation of the tree. This will only hold up to + // defaultModifiedCache number of entries, after which we will set the + // trackOverflow flag, which will cause us to use a more expensive + // algorithm to perform the notifications. Mutation tracking is only + // performed if trackMutate is true. + trackChannels map[chan struct{}]struct{} + trackOverflow bool + trackMutate bool +} + +// Txn starts a new transaction that can be used to mutate the tree +func (t *Tree) Txn() *Txn { + txn := &Txn{ + root: t.root, + snap: t.root, + size: t.size, + } + return txn +} + +// TrackMutate can be used to toggle if mutations are tracked. If this is enabled +// then notifications will be issued for affected internal nodes and leaves when +// the transaction is committed. +func (t *Txn) TrackMutate(track bool) { + t.trackMutate = track +} + +// trackChannel safely attempts to track the given mutation channel, setting the +// overflow flag if we can no longer track any more. This limits the amount of +// state that will accumulate during a transaction and we have a slower algorithm +// to switch to if we overflow. +func (t *Txn) trackChannel(ch chan struct{}) { + // In overflow, make sure we don't store any more objects. + if t.trackOverflow { + return + } + + // If this would overflow the state we reject it and set the flag (since + // we aren't tracking everything that's required any longer). + if len(t.trackChannels) >= defaultModifiedCache { + // Mark that we are in the overflow state + t.trackOverflow = true + + // Clear the map so that the channels can be garbage collected. It is + // safe to do this since we have already overflowed and will be using + // the slow notify algorithm. + t.trackChannels = nil + return + } + + // Create the map on the fly when we need it. + if t.trackChannels == nil { + t.trackChannels = make(map[chan struct{}]struct{}) + } + + // Otherwise we are good to track it. + t.trackChannels[ch] = struct{}{} +} + +// writeNode returns a node to be modified, if the current node has already been +// modified during the course of the transaction, it is used in-place. Set +// forLeafUpdate to true if you are getting a write node to update the leaf, +// which will set leaf mutation tracking appropriately as well. +func (t *Txn) writeNode(n *Node, forLeafUpdate bool) *Node { + // Ensure the writable set exists. + if t.writable == nil { + lru, err := simplelru.NewLRU(defaultModifiedCache, nil) + if err != nil { + panic(err) + } + t.writable = lru + } + + // If this node has already been modified, we can continue to use it + // during this transaction. We know that we don't need to track it for + // a node update since the node is writable, but if this is for a leaf + // update we track it, in case the initial write to this node didn't + // update the leaf. + if _, ok := t.writable.Get(n); ok { + if t.trackMutate && forLeafUpdate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + return n + } + + // Mark this node as being mutated. + if t.trackMutate { + t.trackChannel(n.mutateCh) + } + + // Mark its leaf as being mutated, if appropriate. + if t.trackMutate && forLeafUpdate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + + // Copy the existing node. If you have set forLeafUpdate it will be + // safe to replace this leaf with another after you get your node for + // writing. You MUST replace it, because the channel associated with + // this leaf will be closed when this transaction is committed. + nc := &Node{ + mutateCh: make(chan struct{}), + leaf: n.leaf, + } + if n.prefix != nil { + nc.prefix = make([]byte, len(n.prefix)) + copy(nc.prefix, n.prefix) + } + if len(n.edges) != 0 { + nc.edges = make([]edge, len(n.edges)) + copy(nc.edges, n.edges) + } + + // Mark this node as writable. + t.writable.Add(nc, nil) + return nc +} + +// Visit all the nodes in the tree under n, and add their mutateChannels to the transaction +// Returns the size of the subtree visited +func (t *Txn) trackChannelsAndCount(n *Node) int { + // Count only leaf nodes + leaves := 0 + if n.leaf != nil { + leaves = 1 + } + // Mark this node as being mutated. + if t.trackMutate { + t.trackChannel(n.mutateCh) + } + + // Mark its leaf as being mutated, if appropriate. + if t.trackMutate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + + // Recurse on the children + for _, e := range n.edges { + leaves += t.trackChannelsAndCount(e.node) + } + return leaves +} + +// mergeChild is called to collapse the given node with its child. This is only +// called when the given node is not a leaf and has a single edge. +func (t *Txn) mergeChild(n *Node) { + // Mark the child node as being mutated since we are about to abandon + // it. We don't need to mark the leaf since we are retaining it if it + // is there. + e := n.edges[0] + child := e.node + if t.trackMutate { + t.trackChannel(child.mutateCh) + } + + // Merge the nodes. + n.prefix = concat(n.prefix, child.prefix) + n.leaf = child.leaf + if len(child.edges) != 0 { + n.edges = make([]edge, len(child.edges)) + copy(n.edges, child.edges) + } else { + n.edges = nil + } +} + +// insert does a recursive insertion +func (t *Txn) insert(n *Node, k, search []byte, v interface{}) (*Node, interface{}, bool) { + // Handle key exhaustion + if len(search) == 0 { + var oldVal interface{} + didUpdate := false + if n.isLeaf() { + oldVal = n.leaf.val + didUpdate = true + } + + nc := t.writeNode(n, true) + nc.leaf = &leafNode{ + mutateCh: make(chan struct{}), + key: k, + val: v, + } + return nc, oldVal, didUpdate + } + + // Look for the edge + idx, child := n.getEdge(search[0]) + + // No edge, create one + if child == nil { + e := edge{ + label: search[0], + node: &Node{ + mutateCh: make(chan struct{}), + leaf: &leafNode{ + mutateCh: make(chan struct{}), + key: k, + val: v, + }, + prefix: search, + }, + } + nc := t.writeNode(n, false) + nc.addEdge(e) + return nc, nil, false + } + + // Determine longest prefix of the search key on match + commonPrefix := longestPrefix(search, child.prefix) + if commonPrefix == len(child.prefix) { + search = search[commonPrefix:] + newChild, oldVal, didUpdate := t.insert(child, k, search, v) + if newChild != nil { + nc := t.writeNode(n, false) + nc.edges[idx].node = newChild + return nc, oldVal, didUpdate + } + return nil, oldVal, didUpdate + } + + // Split the node + nc := t.writeNode(n, false) + splitNode := &Node{ + mutateCh: make(chan struct{}), + prefix: search[:commonPrefix], + } + nc.replaceEdge(edge{ + label: search[0], + node: splitNode, + }) + + // Restore the existing child node + modChild := t.writeNode(child, false) + splitNode.addEdge(edge{ + label: modChild.prefix[commonPrefix], + node: modChild, + }) + modChild.prefix = modChild.prefix[commonPrefix:] + + // Create a new leaf node + leaf := &leafNode{ + mutateCh: make(chan struct{}), + key: k, + val: v, + } + + // If the new key is a subset, add to to this node + search = search[commonPrefix:] + if len(search) == 0 { + splitNode.leaf = leaf + return nc, nil, false + } + + // Create a new edge for the node + splitNode.addEdge(edge{ + label: search[0], + node: &Node{ + mutateCh: make(chan struct{}), + leaf: leaf, + prefix: search, + }, + }) + return nc, nil, false +} + +// delete does a recursive deletion +func (t *Txn) delete(parent, n *Node, search []byte) (*Node, *leafNode) { + // Check for key exhaustion + if len(search) == 0 { + if !n.isLeaf() { + return nil, nil + } + // Copy the pointer in case we are in a transaction that already + // modified this node since the node will be reused. Any changes + // made to the node will not affect returning the original leaf + // value. + oldLeaf := n.leaf + + // Remove the leaf node + nc := t.writeNode(n, true) + nc.leaf = nil + + // Check if this node should be merged + if n != t.root && len(nc.edges) == 1 { + t.mergeChild(nc) + } + return nc, oldLeaf + } + + // Look for an edge + label := search[0] + idx, child := n.getEdge(label) + if child == nil || !bytes.HasPrefix(search, child.prefix) { + return nil, nil + } + + // Consume the search prefix + search = search[len(child.prefix):] + newChild, leaf := t.delete(n, child, search) + if newChild == nil { + return nil, nil + } + + // Copy this node. WATCH OUT - it's safe to pass "false" here because we + // will only ADD a leaf via nc.mergeChild() if there isn't one due to + // the !nc.isLeaf() check in the logic just below. This is pretty subtle, + // so be careful if you change any of the logic here. + nc := t.writeNode(n, false) + + // Delete the edge if the node has no edges + if newChild.leaf == nil && len(newChild.edges) == 0 { + nc.delEdge(label) + if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() { + t.mergeChild(nc) + } + } else { + nc.edges[idx].node = newChild + } + return nc, leaf +} + +// delete does a recursive deletion +func (t *Txn) deletePrefix(parent, n *Node, search []byte) (*Node, int) { + // Check for key exhaustion + if len(search) == 0 { + nc := t.writeNode(n, true) + if n.isLeaf() { + nc.leaf = nil + } + nc.edges = nil + return nc, t.trackChannelsAndCount(n) + } + + // Look for an edge + label := search[0] + idx, child := n.getEdge(label) + // We make sure that either the child node's prefix starts with the search term, or the search term starts with the child node's prefix + // Need to do both so that we can delete prefixes that don't correspond to any node in the tree + if child == nil || (!bytes.HasPrefix(child.prefix, search) && !bytes.HasPrefix(search, child.prefix)) { + return nil, 0 + } + + // Consume the search prefix + if len(child.prefix) > len(search) { + search = []byte("") + } else { + search = search[len(child.prefix):] + } + newChild, numDeletions := t.deletePrefix(n, child, search) + if newChild == nil { + return nil, 0 + } + // Copy this node. WATCH OUT - it's safe to pass "false" here because we + // will only ADD a leaf via nc.mergeChild() if there isn't one due to + // the !nc.isLeaf() check in the logic just below. This is pretty subtle, + // so be careful if you change any of the logic here. + + nc := t.writeNode(n, false) + + // Delete the edge if the node has no edges + if newChild.leaf == nil && len(newChild.edges) == 0 { + nc.delEdge(label) + if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() { + t.mergeChild(nc) + } + } else { + nc.edges[idx].node = newChild + } + return nc, numDeletions +} + +// Insert is used to add or update a given key. The return provides +// the previous value and a bool indicating if any was set. +func (t *Txn) Insert(k []byte, v interface{}) (interface{}, bool) { + newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v) + if newRoot != nil { + t.root = newRoot + } + if !didUpdate { + t.size++ + } + return oldVal, didUpdate +} + +// Delete is used to delete a given key. Returns the old value if any, +// and a bool indicating if the key was set. +func (t *Txn) Delete(k []byte) (interface{}, bool) { + newRoot, leaf := t.delete(nil, t.root, k) + if newRoot != nil { + t.root = newRoot + } + if leaf != nil { + t.size-- + return leaf.val, true + } + return nil, false +} + +// DeletePrefix is used to delete an entire subtree that matches the prefix +// This will delete all nodes under that prefix +func (t *Txn) DeletePrefix(prefix []byte) bool { + newRoot, numDeletions := t.deletePrefix(nil, t.root, prefix) + if newRoot != nil { + t.root = newRoot + t.size = t.size - numDeletions + return true + } + return false + +} + +// Root returns the current root of the radix tree within this +// transaction. The root is not safe across insert and delete operations, +// but can be used to read the current state during a transaction. +func (t *Txn) Root() *Node { + return t.root +} + +// Get is used to lookup a specific key, returning +// the value and if it was found +func (t *Txn) Get(k []byte) (interface{}, bool) { + return t.root.Get(k) +} + +// GetWatch is used to lookup a specific key, returning +// the watch channel, value and if it was found +func (t *Txn) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) { + return t.root.GetWatch(k) +} + +// Commit is used to finalize the transaction and return a new tree. If mutation +// tracking is turned on then notifications will also be issued. +func (t *Txn) Commit() *Tree { + nt := t.CommitOnly() + if t.trackMutate { + t.Notify() + } + return nt +} + +// CommitOnly is used to finalize the transaction and return a new tree, but +// does not issue any notifications until Notify is called. +func (t *Txn) CommitOnly() *Tree { + nt := &Tree{t.root, t.size} + t.writable = nil + return nt +} + +// slowNotify does a complete comparison of the before and after trees in order +// to trigger notifications. This doesn't require any additional state but it +// is very expensive to compute. +func (t *Txn) slowNotify() { + snapIter := t.snap.rawIterator() + rootIter := t.root.rawIterator() + for snapIter.Front() != nil || rootIter.Front() != nil { + // If we've exhausted the nodes in the old snapshot, we know + // there's nothing remaining to notify. + if snapIter.Front() == nil { + return + } + snapElem := snapIter.Front() + + // If we've exhausted the nodes in the new root, we know we need + // to invalidate everything that remains in the old snapshot. We + // know from the loop condition there's something in the old + // snapshot. + if rootIter.Front() == nil { + close(snapElem.mutateCh) + if snapElem.isLeaf() { + close(snapElem.leaf.mutateCh) + } + snapIter.Next() + continue + } + + // Do one string compare so we can check the various conditions + // below without repeating the compare. + cmp := strings.Compare(snapIter.Path(), rootIter.Path()) + + // If the snapshot is behind the root, then we must have deleted + // this node during the transaction. + if cmp < 0 { + close(snapElem.mutateCh) + if snapElem.isLeaf() { + close(snapElem.leaf.mutateCh) + } + snapIter.Next() + continue + } + + // If the snapshot is ahead of the root, then we must have added + // this node during the transaction. + if cmp > 0 { + rootIter.Next() + continue + } + + // If we have the same path, then we need to see if we mutated a + // node and possibly the leaf. + rootElem := rootIter.Front() + if snapElem != rootElem { + close(snapElem.mutateCh) + if snapElem.leaf != nil && (snapElem.leaf != rootElem.leaf) { + close(snapElem.leaf.mutateCh) + } + } + snapIter.Next() + rootIter.Next() + } +} + +// Notify is used along with TrackMutate to trigger notifications. This must +// only be done once a transaction is committed via CommitOnly, and it is called +// automatically by Commit. +func (t *Txn) Notify() { + if !t.trackMutate { + return + } + + // If we've overflowed the tracking state we can't use it in any way and + // need to do a full tree compare. + if t.trackOverflow { + t.slowNotify() + } else { + for ch := range t.trackChannels { + close(ch) + } + } + + // Clean up the tracking state so that a re-notify is safe (will trigger + // the else clause above which will be a no-op). + t.trackChannels = nil + t.trackOverflow = false +} + +// Insert is used to add or update a given key. The return provides +// the new tree, previous value and a bool indicating if any was set. +func (t *Tree) Insert(k []byte, v interface{}) (*Tree, interface{}, bool) { + txn := t.Txn() + old, ok := txn.Insert(k, v) + return txn.Commit(), old, ok +} + +// Delete is used to delete a given key. Returns the new tree, +// old value if any, and a bool indicating if the key was set. +func (t *Tree) Delete(k []byte) (*Tree, interface{}, bool) { + txn := t.Txn() + old, ok := txn.Delete(k) + return txn.Commit(), old, ok +} + +// DeletePrefix is used to delete all nodes starting with a given prefix. Returns the new tree, +// and a bool indicating if the prefix matched any nodes +func (t *Tree) DeletePrefix(k []byte) (*Tree, bool) { + txn := t.Txn() + ok := txn.DeletePrefix(k) + return txn.Commit(), ok +} + +// Root returns the root node of the tree which can be used for richer +// query operations. +func (t *Tree) Root() *Node { + return t.root +} + +// Get is used to lookup a specific key, returning +// the value and if it was found +func (t *Tree) Get(k []byte) (interface{}, bool) { + return t.root.Get(k) +} + +// longestPrefix finds the length of the shared prefix +// of two strings +func longestPrefix(k1, k2 []byte) int { + max := len(k1) + if l := len(k2); l < max { + max = l + } + var i int + for i = 0; i < max; i++ { + if k1[i] != k2[i] { + break + } + } + return i +} + +// concat two byte slices, returning a third new copy +func concat(a, b []byte) []byte { + c := make([]byte, len(a)+len(b)) + copy(c, a) + copy(c[len(a):], b) + return c +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iter.go b/vendor/github.com/hashicorp/go-immutable-radix/iter.go new file mode 100644 index 0000000..9815e02 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/iter.go @@ -0,0 +1,91 @@ +package iradix + +import "bytes" + +// Iterator is used to iterate over a set of nodes +// in pre-order +type Iterator struct { + node *Node + stack []edges +} + +// SeekPrefixWatch is used to seek the iterator to a given prefix +// and returns the watch channel of the finest granularity +func (i *Iterator) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) { + // Wipe the stack + i.stack = nil + n := i.node + watch = n.mutateCh + search := prefix + for { + // Check for key exhaution + if len(search) == 0 { + i.node = n + return + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + i.node = nil + return + } + + // Update to the finest granularity as the search makes progress + watch = n.mutateCh + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + + } else if bytes.HasPrefix(n.prefix, search) { + i.node = n + return + } else { + i.node = nil + return + } + } +} + +// SeekPrefix is used to seek the iterator to a given prefix +func (i *Iterator) SeekPrefix(prefix []byte) { + i.SeekPrefixWatch(prefix) +} + +// Next returns the next node in order +func (i *Iterator) Next() ([]byte, interface{}, bool) { + // Initialize our stack if needed + if i.stack == nil && i.node != nil { + i.stack = []edges{ + edges{ + edge{node: i.node}, + }, + } + } + + for len(i.stack) > 0 { + // Inspect the last element of the stack + n := len(i.stack) + last := i.stack[n-1] + elem := last[0].node + + // Update the stack + if len(last) > 1 { + i.stack[n-1] = last[1:] + } else { + i.stack = i.stack[:n-1] + } + + // Push the edges onto the frontier + if len(elem.edges) > 0 { + i.stack = append(i.stack, elem.edges) + } + + // Return the leaf values if any + if elem.leaf != nil { + return elem.leaf.key, elem.leaf.val, true + } + } + return nil, nil, false +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/node.go b/vendor/github.com/hashicorp/go-immutable-radix/node.go new file mode 100644 index 0000000..7a065e7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/node.go @@ -0,0 +1,292 @@ +package iradix + +import ( + "bytes" + "sort" +) + +// WalkFn is used when walking the tree. Takes a +// key and value, returning if iteration should +// be terminated. +type WalkFn func(k []byte, v interface{}) bool + +// leafNode is used to represent a value +type leafNode struct { + mutateCh chan struct{} + key []byte + val interface{} +} + +// edge is used to represent an edge node +type edge struct { + label byte + node *Node +} + +// Node is an immutable node in the radix tree +type Node struct { + // mutateCh is closed if this node is modified + mutateCh chan struct{} + + // leaf is used to store possible leaf + leaf *leafNode + + // prefix is the common prefix we ignore + prefix []byte + + // Edges should be stored in-order for iteration. + // We avoid a fully materialized slice to save memory, + // since in most cases we expect to be sparse + edges edges +} + +func (n *Node) isLeaf() bool { + return n.leaf != nil +} + +func (n *Node) addEdge(e edge) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= e.label + }) + n.edges = append(n.edges, e) + if idx != num { + copy(n.edges[idx+1:], n.edges[idx:num]) + n.edges[idx] = e + } +} + +func (n *Node) replaceEdge(e edge) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= e.label + }) + if idx < num && n.edges[idx].label == e.label { + n.edges[idx].node = e.node + return + } + panic("replacing missing edge") +} + +func (n *Node) getEdge(label byte) (int, *Node) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + return idx, n.edges[idx].node + } + return -1, nil +} + +func (n *Node) delEdge(label byte) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + copy(n.edges[idx:], n.edges[idx+1:]) + n.edges[len(n.edges)-1] = edge{} + n.edges = n.edges[:len(n.edges)-1] + } +} + +func (n *Node) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) { + search := k + watch := n.mutateCh + for { + // Check for key exhaustion + if len(search) == 0 { + if n.isLeaf() { + return n.leaf.mutateCh, n.leaf.val, true + } + break + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Update to the finest granularity as the search makes progress + watch = n.mutateCh + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + return watch, nil, false +} + +func (n *Node) Get(k []byte) (interface{}, bool) { + _, val, ok := n.GetWatch(k) + return val, ok +} + +// LongestPrefix is like Get, but instead of an +// exact match, it will return the longest prefix match. +func (n *Node) LongestPrefix(k []byte) ([]byte, interface{}, bool) { + var last *leafNode + search := k + for { + // Look for a leaf node + if n.isLeaf() { + last = n.leaf + } + + // Check for key exhaution + if len(search) == 0 { + break + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + if last != nil { + return last.key, last.val, true + } + return nil, nil, false +} + +// Minimum is used to return the minimum value in the tree +func (n *Node) Minimum() ([]byte, interface{}, bool) { + for { + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } + if len(n.edges) > 0 { + n = n.edges[0].node + } else { + break + } + } + return nil, nil, false +} + +// Maximum is used to return the maximum value in the tree +func (n *Node) Maximum() ([]byte, interface{}, bool) { + for { + if num := len(n.edges); num > 0 { + n = n.edges[num-1].node + continue + } + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } else { + break + } + } + return nil, nil, false +} + +// Iterator is used to return an iterator at +// the given node to walk the tree +func (n *Node) Iterator() *Iterator { + return &Iterator{node: n} +} + +// rawIterator is used to return a raw iterator at the given node to walk the +// tree. +func (n *Node) rawIterator() *rawIterator { + iter := &rawIterator{node: n} + iter.Next() + return iter +} + +// Walk is used to walk the tree +func (n *Node) Walk(fn WalkFn) { + recursiveWalk(n, fn) +} + +// WalkPrefix is used to walk the tree under a prefix +func (n *Node) WalkPrefix(prefix []byte, fn WalkFn) { + search := prefix + for { + // Check for key exhaution + if len(search) == 0 { + recursiveWalk(n, fn) + return + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + + } else if bytes.HasPrefix(n.prefix, search) { + // Child may be under our search prefix + recursiveWalk(n, fn) + return + } else { + break + } + } +} + +// WalkPath is used to walk the tree, but only visiting nodes +// from the root down to a given leaf. Where WalkPrefix walks +// all the entries *under* the given prefix, this walks the +// entries *above* the given prefix. +func (n *Node) WalkPath(path []byte, fn WalkFn) { + search := path + for { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return + } + + // Check for key exhaution + if len(search) == 0 { + return + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + return + } + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } +} + +// recursiveWalk is used to do a pre-order walk of a node +// recursively. Returns true if the walk should be aborted +func recursiveWalk(n *Node, fn WalkFn) bool { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return true + } + + // Recurse on the children + for _, e := range n.edges { + if recursiveWalk(e.node, fn) { + return true + } + } + return false +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go new file mode 100644 index 0000000..04814c1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go @@ -0,0 +1,78 @@ +package iradix + +// rawIterator visits each of the nodes in the tree, even the ones that are not +// leaves. It keeps track of the effective path (what a leaf at a given node +// would be called), which is useful for comparing trees. +type rawIterator struct { + // node is the starting node in the tree for the iterator. + node *Node + + // stack keeps track of edges in the frontier. + stack []rawStackEntry + + // pos is the current position of the iterator. + pos *Node + + // path is the effective path of the current iterator position, + // regardless of whether the current node is a leaf. + path string +} + +// rawStackEntry is used to keep track of the cumulative common path as well as +// its associated edges in the frontier. +type rawStackEntry struct { + path string + edges edges +} + +// Front returns the current node that has been iterated to. +func (i *rawIterator) Front() *Node { + return i.pos +} + +// Path returns the effective path of the current node, even if it's not actually +// a leaf. +func (i *rawIterator) Path() string { + return i.path +} + +// Next advances the iterator to the next node. +func (i *rawIterator) Next() { + // Initialize our stack if needed. + if i.stack == nil && i.node != nil { + i.stack = []rawStackEntry{ + rawStackEntry{ + edges: edges{ + edge{node: i.node}, + }, + }, + } + } + + for len(i.stack) > 0 { + // Inspect the last element of the stack. + n := len(i.stack) + last := i.stack[n-1] + elem := last.edges[0].node + + // Update the stack. + if len(last.edges) > 1 { + i.stack[n-1].edges = last.edges[1:] + } else { + i.stack = i.stack[:n-1] + } + + // Push the edges onto the frontier. + if len(elem.edges) > 0 { + path := last.path + string(elem.prefix) + i.stack = append(i.stack, rawStackEntry{path, elem.edges}) + } + + i.pos = elem + i.path = last.path + string(elem.prefix) + return + } + + i.pos = nil + i.path = "" +} diff --git a/vendor/github.com/hashicorp/go-memdb/.gitignore b/vendor/github.com/hashicorp/go-memdb/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/hashicorp/go-memdb/.travis.yml b/vendor/github.com/hashicorp/go-memdb/.travis.yml new file mode 100644 index 0000000..9e770fa --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - "1.10" + +script: + - go test diff --git a/vendor/github.com/hashicorp/go-memdb/LICENSE b/vendor/github.com/hashicorp/go-memdb/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-memdb/README.md b/vendor/github.com/hashicorp/go-memdb/README.md new file mode 100644 index 0000000..65e1eae --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/README.md @@ -0,0 +1,98 @@ +# go-memdb + +Provides the `memdb` package that implements a simple in-memory database +built on immutable radix trees. The database provides Atomicity, Consistency +and Isolation from ACID. Being that it is in-memory, it does not provide durability. +The database is instantiated with a schema that specifies the tables and indices +that exist and allows transactions to be executed. + +The database provides the following: + +* Multi-Version Concurrency Control (MVCC) - By leveraging immutable radix trees + the database is able to support any number of concurrent readers without locking, + and allows a writer to make progress. + +* Transaction Support - The database allows for rich transactions, in which multiple + objects are inserted, updated or deleted. The transactions can span multiple tables, + and are applied atomically. The database provides atomicity and isolation in ACID + terminology, such that until commit the updates are not visible. + +* Rich Indexing - Tables can support any number of indexes, which can be simple like + a single field index, or more advanced compound field indexes. Certain types like + UUID can be efficiently compressed from strings into byte indexes for reduced + storage requirements. + +* Watches - Callers can populate a watch set as part of a query, which can be used to + detect when a modification has been made to the database which affects the query + results. This lets callers easily watch for changes in the database in a very general + way. + +For the underlying immutable radix trees, see [go-immutable-radix](https://github.com/hashicorp/go-immutable-radix). + +Documentation +============= + +The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-memdb). + +Example +======= + +Below is a simple example of usage + +```go +// Create a sample struct +type Person struct { + Email string + Name string + Age int +} + +// Create the DB schema +schema := &memdb.DBSchema{ + Tables: map[string]*memdb.TableSchema{ + "person": &memdb.TableSchema{ + Name: "person", + Indexes: map[string]*memdb.IndexSchema{ + "id": &memdb.IndexSchema{ + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{Field: "Email"}, + }, + }, + }, + }, +} + +// Create a new data base +db, err := memdb.NewMemDB(schema) +if err != nil { + panic(err) +} + +// Create a write transaction +txn := db.Txn(true) + +// Insert a new person +p := &Person{"joe@aol.com", "Joe", 30} +if err := txn.Insert("person", p); err != nil { + panic(err) +} + +// Commit the transaction +txn.Commit() + +// Create read-only transaction +txn = db.Txn(false) +defer txn.Abort() + +// Lookup by email +raw, err := txn.First("person", "id", "joe@aol.com") +if err != nil { + panic(err) +} + +// Say hi! +fmt.Printf("Hello %s!", raw.(*Person).Name) + +``` + diff --git a/vendor/github.com/hashicorp/go-memdb/filter.go b/vendor/github.com/hashicorp/go-memdb/filter.go new file mode 100644 index 0000000..2e3a9b3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/filter.go @@ -0,0 +1,33 @@ +package memdb + +// FilterFunc is a function that takes the results of an iterator and returns +// whether the result should be filtered out. +type FilterFunc func(interface{}) bool + +// FilterIterator is used to wrap a ResultIterator and apply a filter over it. +type FilterIterator struct { + // filter is the filter function applied over the base iterator. + filter FilterFunc + + // iter is the iterator that is being wrapped. + iter ResultIterator +} + +func NewFilterIterator(wrap ResultIterator, filter FilterFunc) *FilterIterator { + return &FilterIterator{ + filter: filter, + iter: wrap, + } +} + +// WatchCh returns the watch channel of the wrapped iterator. +func (f *FilterIterator) WatchCh() <-chan struct{} { return f.iter.WatchCh() } + +// Next returns the next non-filtered result from the wrapped iterator +func (f *FilterIterator) Next() interface{} { + for { + if value := f.iter.Next(); value == nil || !f.filter(value) { + return value + } + } +} diff --git a/vendor/github.com/hashicorp/go-memdb/index.go b/vendor/github.com/hashicorp/go-memdb/index.go new file mode 100644 index 0000000..cca853c --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/index.go @@ -0,0 +1,581 @@ +package memdb + +import ( + "encoding/binary" + "encoding/hex" + "fmt" + "reflect" + "strings" +) + +// Indexer is an interface used for defining indexes. Indexes are used +// for efficient lookup of objects in a MemDB table. An Indexer must also +// implement one of SingleIndexer or MultiIndexer. +// +// Indexers are primarily responsible for returning the lookup key as +// a byte slice. The byte slice is the key data in the underlying data storage. +type Indexer interface { + // FromArgs is called to build the exact index key from a list of arguments. + FromArgs(args ...interface{}) ([]byte, error) +} + +// SingleIndexer is an interface used for defining indexes that generate a +// single value per object +type SingleIndexer interface { + // FromObject extracts the index value from an object. The return values + // are whether the index value was found, the index value, and any error + // while extracting the index value, respectively. + FromObject(raw interface{}) (bool, []byte, error) +} + +// MultiIndexer is an interface used for defining indexes that generate +// multiple values per object. Each value is stored as a seperate index +// pointing to the same object. +// +// For example, an index that extracts the first and last name of a person +// and allows lookup based on eitherd would be a MultiIndexer. The FromObject +// of this example would split the first and last name and return both as +// values. +type MultiIndexer interface { + // FromObject extracts index values from an object. The return values + // are the same as a SingleIndexer except there can be multiple index + // values. + FromObject(raw interface{}) (bool, [][]byte, error) +} + +// PrefixIndexer is an optional interface on top of an Indexer that allows +// indexes to support prefix-based iteration. +type PrefixIndexer interface { + // PrefixFromArgs is the same as FromArgs for an Indexer except that + // the index value returned should return all prefix-matched values. + PrefixFromArgs(args ...interface{}) ([]byte, error) +} + +// StringFieldIndex is used to extract a field from an object +// using reflection and builds an index on that field. +type StringFieldIndex struct { + Field string + Lowercase bool +} + +func (s *StringFieldIndex) FromObject(obj interface{}) (bool, []byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(s.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", s.Field, obj) + } + + val := fv.String() + if val == "" { + return false, nil, nil + } + + if s.Lowercase { + val = strings.ToLower(val) + } + + // Add the null character as a terminator + val += "\x00" + return true, []byte(val), nil +} + +func (s *StringFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + arg, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[0]) + } + if s.Lowercase { + arg = strings.ToLower(arg) + } + // Add the null character as a terminator + arg += "\x00" + return []byte(arg), nil +} + +func (s *StringFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { + val, err := s.FromArgs(args...) + if err != nil { + return nil, err + } + + // Strip the null terminator, the rest is a prefix + n := len(val) + if n > 0 { + return val[:n-1], nil + } + return val, nil +} + +// StringSliceFieldIndex builds an index from a field on an object that is a +// string slice ([]string). Each value within the string slice can be used for +// lookup. +type StringSliceFieldIndex struct { + Field string + Lowercase bool +} + +func (s *StringSliceFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(s.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", s.Field, obj) + } + + if fv.Kind() != reflect.Slice || fv.Type().Elem().Kind() != reflect.String { + return false, nil, fmt.Errorf("field '%s' is not a string slice", s.Field) + } + + length := fv.Len() + vals := make([][]byte, 0, length) + for i := 0; i < fv.Len(); i++ { + val := fv.Index(i).String() + if val == "" { + continue + } + + if s.Lowercase { + val = strings.ToLower(val) + } + + // Add the null character as a terminator + val += "\x00" + vals = append(vals, []byte(val)) + } + if len(vals) == 0 { + return false, nil, nil + } + return true, vals, nil +} + +func (s *StringSliceFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + arg, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[0]) + } + if s.Lowercase { + arg = strings.ToLower(arg) + } + // Add the null character as a terminator + arg += "\x00" + return []byte(arg), nil +} + +func (s *StringSliceFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { + val, err := s.FromArgs(args...) + if err != nil { + return nil, err + } + + // Strip the null terminator, the rest is a prefix + n := len(val) + if n > 0 { + return val[:n-1], nil + } + return val, nil +} + +// StringMapFieldIndex is used to extract a field of type map[string]string +// from an object using reflection and builds an index on that field. +type StringMapFieldIndex struct { + Field string + Lowercase bool +} + +var MapType = reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf("")).Kind() + +func (s *StringMapFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(s.Field) + if !fv.IsValid() { + return false, nil, fmt.Errorf("field '%s' for %#v is invalid", s.Field, obj) + } + + if fv.Kind() != MapType { + return false, nil, fmt.Errorf("field '%s' is not a map[string]string", s.Field) + } + + length := fv.Len() + vals := make([][]byte, 0, length) + for _, key := range fv.MapKeys() { + k := key.String() + if k == "" { + continue + } + val := fv.MapIndex(key).String() + + if s.Lowercase { + k = strings.ToLower(k) + val = strings.ToLower(val) + } + + // Add the null character as a terminator + k += "\x00" + val + "\x00" + + vals = append(vals, []byte(k)) + } + if len(vals) == 0 { + return false, nil, nil + } + return true, vals, nil +} + +func (s *StringMapFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) > 2 || len(args) == 0 { + return nil, fmt.Errorf("must provide one or two arguments") + } + key, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[0]) + } + if s.Lowercase { + key = strings.ToLower(key) + } + // Add the null character as a terminator + key += "\x00" + + if len(args) == 2 { + val, ok := args[1].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[1]) + } + if s.Lowercase { + val = strings.ToLower(val) + } + // Add the null character as a terminator + key += val + "\x00" + } + + return []byte(key), nil +} + +// UintFieldIndex is used to extract a uint field from an object using +// reflection and builds an index on that field. +type UintFieldIndex struct { + Field string +} + +func (u *UintFieldIndex) FromObject(obj interface{}) (bool, []byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(u.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", u.Field, obj) + } + + // Check the type + k := fv.Kind() + size, ok := IsUintType(k) + if !ok { + return false, nil, fmt.Errorf("field %q is of type %v; want a uint", u.Field, k) + } + + // Get the value and encode it + val := fv.Uint() + buf := make([]byte, size) + binary.PutUvarint(buf, val) + + return true, buf, nil +} + +func (u *UintFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + + v := reflect.ValueOf(args[0]) + if !v.IsValid() { + return nil, fmt.Errorf("%#v is invalid", args[0]) + } + + k := v.Kind() + size, ok := IsUintType(k) + if !ok { + return nil, fmt.Errorf("arg is of type %v; want a uint", k) + } + + val := v.Uint() + buf := make([]byte, size) + binary.PutUvarint(buf, val) + + return buf, nil +} + +// IsUintType returns whether the passed type is a type of uint and the number +// of bytes needed to encode the type. +func IsUintType(k reflect.Kind) (size int, okay bool) { + switch k { + case reflect.Uint: + return binary.MaxVarintLen64, true + case reflect.Uint8: + return 2, true + case reflect.Uint16: + return binary.MaxVarintLen16, true + case reflect.Uint32: + return binary.MaxVarintLen32, true + case reflect.Uint64: + return binary.MaxVarintLen64, true + default: + return 0, false + } +} + +// UUIDFieldIndex is used to extract a field from an object +// using reflection and builds an index on that field by treating +// it as a UUID. This is an optimization to using a StringFieldIndex +// as the UUID can be more compactly represented in byte form. +type UUIDFieldIndex struct { + Field string +} + +func (u *UUIDFieldIndex) FromObject(obj interface{}) (bool, []byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(u.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", u.Field, obj) + } + + val := fv.String() + if val == "" { + return false, nil, nil + } + + buf, err := u.parseString(val, true) + return true, buf, err +} + +func (u *UUIDFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + switch arg := args[0].(type) { + case string: + return u.parseString(arg, true) + case []byte: + if len(arg) != 16 { + return nil, fmt.Errorf("byte slice must be 16 characters") + } + return arg, nil + default: + return nil, + fmt.Errorf("argument must be a string or byte slice: %#v", args[0]) + } +} + +func (u *UUIDFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + switch arg := args[0].(type) { + case string: + return u.parseString(arg, false) + case []byte: + return arg, nil + default: + return nil, + fmt.Errorf("argument must be a string or byte slice: %#v", args[0]) + } +} + +// parseString parses a UUID from the string. If enforceLength is false, it will +// parse a partial UUID. An error is returned if the input, stripped of hyphens, +// is not even length. +func (u *UUIDFieldIndex) parseString(s string, enforceLength bool) ([]byte, error) { + // Verify the length + l := len(s) + if enforceLength && l != 36 { + return nil, fmt.Errorf("UUID must be 36 characters") + } else if l > 36 { + return nil, fmt.Errorf("Invalid UUID length. UUID have 36 characters; got %d", l) + } + + hyphens := strings.Count(s, "-") + if hyphens > 4 { + return nil, fmt.Errorf(`UUID should have maximum of 4 "-"; got %d`, hyphens) + } + + // The sanitized length is the length of the original string without the "-". + sanitized := strings.Replace(s, "-", "", -1) + sanitizedLength := len(sanitized) + if sanitizedLength%2 != 0 { + return nil, fmt.Errorf("Input (without hyphens) must be even length") + } + + dec, err := hex.DecodeString(sanitized) + if err != nil { + return nil, fmt.Errorf("Invalid UUID: %v", err) + } + + return dec, nil +} + +// FieldSetIndex is used to extract a field from an object using reflection and +// builds an index on whether the field is set by comparing it against its +// type's nil value. +type FieldSetIndex struct { + Field string +} + +func (f *FieldSetIndex) FromObject(obj interface{}) (bool, []byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(f.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", f.Field, obj) + } + + if fv.Interface() == reflect.Zero(fv.Type()).Interface() { + return true, []byte{0}, nil + } + + return true, []byte{1}, nil +} + +func (f *FieldSetIndex) FromArgs(args ...interface{}) ([]byte, error) { + return fromBoolArgs(args) +} + +// ConditionalIndex builds an index based on a condition specified by a passed +// user function. This function may examine the passed object and return a +// boolean to encapsulate an arbitrarily complex conditional. +type ConditionalIndex struct { + Conditional ConditionalIndexFunc +} + +// ConditionalIndexFunc is the required function interface for a +// ConditionalIndex. +type ConditionalIndexFunc func(obj interface{}) (bool, error) + +func (c *ConditionalIndex) FromObject(obj interface{}) (bool, []byte, error) { + // Call the user's function + res, err := c.Conditional(obj) + if err != nil { + return false, nil, fmt.Errorf("ConditionalIndexFunc(%#v) failed: %v", obj, err) + } + + if res { + return true, []byte{1}, nil + } + + return true, []byte{0}, nil +} + +func (c *ConditionalIndex) FromArgs(args ...interface{}) ([]byte, error) { + return fromBoolArgs(args) +} + +// fromBoolArgs is a helper that expects only a single boolean argument and +// returns a single length byte array containing either a one or zero depending +// on whether the passed input is true or false respectively. +func fromBoolArgs(args []interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + + if val, ok := args[0].(bool); !ok { + return nil, fmt.Errorf("argument must be a boolean type: %#v", args[0]) + } else if val { + return []byte{1}, nil + } + + return []byte{0}, nil +} + +// CompoundIndex is used to build an index using multiple sub-indexes +// Prefix based iteration is supported as long as the appropriate prefix +// of indexers support it. All sub-indexers are only assumed to expect +// a single argument. +type CompoundIndex struct { + Indexes []Indexer + + // AllowMissing results in an index based on only the indexers + // that return data. If true, you may end up with 2/3 columns + // indexed which might be useful for an index scan. Otherwise, + // the CompoundIndex requires all indexers to be satisfied. + AllowMissing bool +} + +func (c *CompoundIndex) FromObject(raw interface{}) (bool, []byte, error) { + var out []byte + for i, idxRaw := range c.Indexes { + idx, ok := idxRaw.(SingleIndexer) + if !ok { + return false, nil, fmt.Errorf("sub-index %d error: %s", i, "sub-index must be a SingleIndexer") + } + ok, val, err := idx.FromObject(raw) + if err != nil { + return false, nil, fmt.Errorf("sub-index %d error: %v", i, err) + } + if !ok { + if c.AllowMissing { + break + } else { + return false, nil, nil + } + } + out = append(out, val...) + } + return true, out, nil +} + +func (c *CompoundIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != len(c.Indexes) { + return nil, fmt.Errorf("less arguments than index fields") + } + var out []byte + for i, arg := range args { + val, err := c.Indexes[i].FromArgs(arg) + if err != nil { + return nil, fmt.Errorf("sub-index %d error: %v", i, err) + } + out = append(out, val...) + } + return out, nil +} + +func (c *CompoundIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { + if len(args) > len(c.Indexes) { + return nil, fmt.Errorf("more arguments than index fields") + } + var out []byte + for i, arg := range args { + if i+1 < len(args) { + val, err := c.Indexes[i].FromArgs(arg) + if err != nil { + return nil, fmt.Errorf("sub-index %d error: %v", i, err) + } + out = append(out, val...) + } else { + prefixIndexer, ok := c.Indexes[i].(PrefixIndexer) + if !ok { + return nil, fmt.Errorf("sub-index %d does not support prefix scanning", i) + } + val, err := prefixIndexer.PrefixFromArgs(arg) + if err != nil { + return nil, fmt.Errorf("sub-index %d error: %v", i, err) + } + out = append(out, val...) + } + } + return out, nil +} diff --git a/vendor/github.com/hashicorp/go-memdb/memdb.go b/vendor/github.com/hashicorp/go-memdb/memdb.go new file mode 100644 index 0000000..65c9207 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/memdb.go @@ -0,0 +1,97 @@ +// Package memdb provides an in-memory database that supports transactions +// and MVCC. +package memdb + +import ( + "sync" + "sync/atomic" + "unsafe" + + "github.com/hashicorp/go-immutable-radix" +) + +// MemDB is an in-memory database. +// +// MemDB provides a table abstraction to store objects (rows) with multiple +// indexes based on inserted values. The database makes use of immutable radix +// trees to provide transactions and MVCC. +type MemDB struct { + schema *DBSchema + root unsafe.Pointer // *iradix.Tree underneath + primary bool + + // There can only be a single writer at once + writer sync.Mutex +} + +// NewMemDB creates a new MemDB with the given schema +func NewMemDB(schema *DBSchema) (*MemDB, error) { + // Validate the schema + if err := schema.Validate(); err != nil { + return nil, err + } + + // Create the MemDB + db := &MemDB{ + schema: schema, + root: unsafe.Pointer(iradix.New()), + primary: true, + } + if err := db.initialize(); err != nil { + return nil, err + } + + return db, nil +} + +// getRoot is used to do an atomic load of the root pointer +func (db *MemDB) getRoot() *iradix.Tree { + root := (*iradix.Tree)(atomic.LoadPointer(&db.root)) + return root +} + +// Txn is used to start a new transaction, in either read or write mode. +// There can only be a single concurrent writer, but any number of readers. +func (db *MemDB) Txn(write bool) *Txn { + if write { + db.writer.Lock() + } + txn := &Txn{ + db: db, + write: write, + rootTxn: db.getRoot().Txn(), + } + return txn +} + +// Snapshot is used to capture a point-in-time snapshot +// of the database that will not be affected by any write +// operations to the existing DB. +func (db *MemDB) Snapshot() *MemDB { + clone := &MemDB{ + schema: db.schema, + root: unsafe.Pointer(db.getRoot()), + primary: false, + } + return clone +} + +// initialize is used to setup the DB for use after creation. This should +// be called only once after allocating a MemDB. +func (db *MemDB) initialize() error { + root := db.getRoot() + for tName, tableSchema := range db.schema.Tables { + for iName := range tableSchema.Indexes { + index := iradix.New() + path := indexPath(tName, iName) + root, _, _ = root.Insert(path, index) + } + } + db.root = unsafe.Pointer(root) + return nil +} + +// indexPath returns the path from the root to the given table index +func indexPath(table, index string) []byte { + return []byte(table + "." + index) +} diff --git a/vendor/github.com/hashicorp/go-memdb/schema.go b/vendor/github.com/hashicorp/go-memdb/schema.go new file mode 100644 index 0000000..e6a9b52 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/schema.go @@ -0,0 +1,114 @@ +package memdb + +import "fmt" + +// DBSchema is the schema to use for the full database with a MemDB instance. +// +// MemDB will require a valid schema. Schema validation can be tested using +// the Validate function. Calling this function is recommended in unit tests. +type DBSchema struct { + // Tables is the set of tables within this database. The key is the + // table name and must match the Name in TableSchema. + Tables map[string]*TableSchema +} + +// Validate validates the schema. +func (s *DBSchema) Validate() error { + if s == nil { + return fmt.Errorf("schema is nil") + } + + if len(s.Tables) == 0 { + return fmt.Errorf("schema has no tables defined") + } + + for name, table := range s.Tables { + if name != table.Name { + return fmt.Errorf("table name mis-match for '%s'", name) + } + + if err := table.Validate(); err != nil { + return fmt.Errorf("table %q: %s", name, err) + } + } + + return nil +} + +// TableSchema is the schema for a single table. +type TableSchema struct { + // Name of the table. This must match the key in the Tables map in DBSchema. + Name string + + // Indexes is the set of indexes for querying this table. The key + // is a unique name for the index and must match the Name in the + // IndexSchema. + Indexes map[string]*IndexSchema +} + +// Validate is used to validate the table schema +func (s *TableSchema) Validate() error { + if s.Name == "" { + return fmt.Errorf("missing table name") + } + + if len(s.Indexes) == 0 { + return fmt.Errorf("missing table indexes for '%s'", s.Name) + } + + if _, ok := s.Indexes["id"]; !ok { + return fmt.Errorf("must have id index") + } + + if !s.Indexes["id"].Unique { + return fmt.Errorf("id index must be unique") + } + + if _, ok := s.Indexes["id"].Indexer.(SingleIndexer); !ok { + return fmt.Errorf("id index must be a SingleIndexer") + } + + for name, index := range s.Indexes { + if name != index.Name { + return fmt.Errorf("index name mis-match for '%s'", name) + } + + if err := index.Validate(); err != nil { + return fmt.Errorf("index %q: %s", name, err) + } + } + + return nil +} + +// IndexSchema is the schema for an index. An index defines how a table is +// queried. +type IndexSchema struct { + // Name of the index. This must be unique among a tables set of indexes. + // This must match the key in the map of Indexes for a TableSchema. + Name string + + // AllowMissing if true ignores this index if it doesn't produce a + // value. For example, an index that extracts a field that doesn't + // exist from a structure. + AllowMissing bool + + Unique bool + Indexer Indexer +} + +func (s *IndexSchema) Validate() error { + if s.Name == "" { + return fmt.Errorf("missing index name") + } + if s.Indexer == nil { + return fmt.Errorf("missing index function for '%s'", s.Name) + } + switch s.Indexer.(type) { + case SingleIndexer: + case MultiIndexer: + default: + return fmt.Errorf("indexer for '%s' must be a SingleIndexer or MultiIndexer", s.Name) + } + return nil +} diff --git a/vendor/github.com/hashicorp/go-memdb/txn.go b/vendor/github.com/hashicorp/go-memdb/txn.go new file mode 100644 index 0000000..2b85087 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/txn.go @@ -0,0 +1,644 @@ +package memdb + +import ( + "bytes" + "fmt" + "strings" + "sync/atomic" + "unsafe" + + "github.com/hashicorp/go-immutable-radix" +) + +const ( + id = "id" +) + +var ( + // ErrNotFound is returned when the requested item is not found + ErrNotFound = fmt.Errorf("not found") +) + +// tableIndex is a tuple of (Table, Index) used for lookups +type tableIndex struct { + Table string + Index string +} + +// Txn is a transaction against a MemDB. +// This can be a read or write transaction. +type Txn struct { + db *MemDB + write bool + rootTxn *iradix.Txn + after []func() + + modified map[tableIndex]*iradix.Txn +} + +// readableIndex returns a transaction usable for reading the given +// index in a table. If a write transaction is in progress, we may need +// to use an existing modified txn. +func (txn *Txn) readableIndex(table, index string) *iradix.Txn { + // Look for existing transaction + if txn.write && txn.modified != nil { + key := tableIndex{table, index} + exist, ok := txn.modified[key] + if ok { + return exist + } + } + + // Create a read transaction + path := indexPath(table, index) + raw, _ := txn.rootTxn.Get(path) + indexTxn := raw.(*iradix.Tree).Txn() + return indexTxn +} + +// writableIndex returns a transaction usable for modifying the +// given index in a table. +func (txn *Txn) writableIndex(table, index string) *iradix.Txn { + if txn.modified == nil { + txn.modified = make(map[tableIndex]*iradix.Txn) + } + + // Look for existing transaction + key := tableIndex{table, index} + exist, ok := txn.modified[key] + if ok { + return exist + } + + // Start a new transaction + path := indexPath(table, index) + raw, _ := txn.rootTxn.Get(path) + indexTxn := raw.(*iradix.Tree).Txn() + + // If we are the primary DB, enable mutation tracking. Snapshots should + // not notify, otherwise we will trigger watches on the primary DB when + // the writes will not be visible. + indexTxn.TrackMutate(txn.db.primary) + + // Keep this open for the duration of the txn + txn.modified[key] = indexTxn + return indexTxn +} + +// Abort is used to cancel this transaction. +// This is a noop for read transactions. +func (txn *Txn) Abort() { + // Noop for a read transaction + if !txn.write { + return + } + + // Check if already aborted or committed + if txn.rootTxn == nil { + return + } + + // Clear the txn + txn.rootTxn = nil + txn.modified = nil + + // Release the writer lock since this is invalid + txn.db.writer.Unlock() +} + +// Commit is used to finalize this transaction. +// This is a noop for read transactions. +func (txn *Txn) Commit() { + // Noop for a read transaction + if !txn.write { + return + } + + // Check if already aborted or committed + if txn.rootTxn == nil { + return + } + + // Commit each sub-transaction scoped to (table, index) + for key, subTxn := range txn.modified { + path := indexPath(key.Table, key.Index) + final := subTxn.CommitOnly() + txn.rootTxn.Insert(path, final) + } + + // Update the root of the DB + newRoot := txn.rootTxn.CommitOnly() + atomic.StorePointer(&txn.db.root, unsafe.Pointer(newRoot)) + + // Now issue all of the mutation updates (this is safe to call + // even if mutation tracking isn't enabled); we do this after + // the root pointer is swapped so that waking responders will + // see the new state. + for _, subTxn := range txn.modified { + subTxn.Notify() + } + txn.rootTxn.Notify() + + // Clear the txn + txn.rootTxn = nil + txn.modified = nil + + // Release the writer lock since this is invalid + txn.db.writer.Unlock() + + // Run the deferred functions, if any + for i := len(txn.after); i > 0; i-- { + fn := txn.after[i-1] + fn() + } +} + +// Insert is used to add or update an object into the given table +func (txn *Txn) Insert(table string, obj interface{}) error { + if !txn.write { + return fmt.Errorf("cannot insert in read-only transaction") + } + + // Get the table schema + tableSchema, ok := txn.db.schema.Tables[table] + if !ok { + return fmt.Errorf("invalid table '%s'", table) + } + + // Get the primary ID of the object + idSchema := tableSchema.Indexes[id] + idIndexer := idSchema.Indexer.(SingleIndexer) + ok, idVal, err := idIndexer.FromObject(obj) + if err != nil { + return fmt.Errorf("failed to build primary index: %v", err) + } + if !ok { + return fmt.Errorf("object missing primary index") + } + + // Lookup the object by ID first, to see if this is an update + idTxn := txn.writableIndex(table, id) + existing, update := idTxn.Get(idVal) + + // On an update, there is an existing object with the given + // primary ID. We do the update by deleting the current object + // and inserting the new object. + for name, indexSchema := range tableSchema.Indexes { + indexTxn := txn.writableIndex(table, name) + + // Determine the new index value + var ( + ok bool + vals [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var val []byte + ok, val, err = indexer.FromObject(obj) + vals = [][]byte{val} + case MultiIndexer: + ok, vals, err = indexer.FromObject(obj) + } + if err != nil { + return fmt.Errorf("failed to build index '%s': %v", name, err) + } + + // Handle non-unique index by computing a unique index. + // This is done by appending the primary key which must + // be unique anyways. + if ok && !indexSchema.Unique { + for i := range vals { + vals[i] = append(vals[i], idVal...) + } + } + + // Handle the update by deleting from the index first + if update { + var ( + okExist bool + valsExist [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var valExist []byte + okExist, valExist, err = indexer.FromObject(existing) + valsExist = [][]byte{valExist} + case MultiIndexer: + okExist, valsExist, err = indexer.FromObject(existing) + } + if err != nil { + return fmt.Errorf("failed to build index '%s': %v", name, err) + } + if okExist { + for i, valExist := range valsExist { + // Handle non-unique index by computing a unique index. + // This is done by appending the primary key which must + // be unique anyways. + if !indexSchema.Unique { + valExist = append(valExist, idVal...) + } + + // If we are writing to the same index with the same value, + // we can avoid the delete as the insert will overwrite the + // value anyways. + if i >= len(vals) || !bytes.Equal(valExist, vals[i]) { + indexTxn.Delete(valExist) + } + } + } + } + + // If there is no index value, either this is an error or an expected + // case and we can skip updating + if !ok { + if indexSchema.AllowMissing { + continue + } else { + return fmt.Errorf("missing value for index '%s'", name) + } + } + + // Update the value of the index + for _, val := range vals { + indexTxn.Insert(val, obj) + } + } + return nil +} + +// Delete is used to delete a single object from the given table +// This object must already exist in the table +func (txn *Txn) Delete(table string, obj interface{}) error { + if !txn.write { + return fmt.Errorf("cannot delete in read-only transaction") + } + + // Get the table schema + tableSchema, ok := txn.db.schema.Tables[table] + if !ok { + return fmt.Errorf("invalid table '%s'", table) + } + + // Get the primary ID of the object + idSchema := tableSchema.Indexes[id] + idIndexer := idSchema.Indexer.(SingleIndexer) + ok, idVal, err := idIndexer.FromObject(obj) + if err != nil { + return fmt.Errorf("failed to build primary index: %v", err) + } + if !ok { + return fmt.Errorf("object missing primary index") + } + + // Lookup the object by ID first, check fi we should continue + idTxn := txn.writableIndex(table, id) + existing, ok := idTxn.Get(idVal) + if !ok { + return ErrNotFound + } + + // Remove the object from all the indexes + for name, indexSchema := range tableSchema.Indexes { + indexTxn := txn.writableIndex(table, name) + + // Handle the update by deleting from the index first + var ( + ok bool + vals [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var val []byte + ok, val, err = indexer.FromObject(existing) + vals = [][]byte{val} + case MultiIndexer: + ok, vals, err = indexer.FromObject(existing) + } + if err != nil { + return fmt.Errorf("failed to build index '%s': %v", name, err) + } + if ok { + // Handle non-unique index by computing a unique index. + // This is done by appending the primary key which must + // be unique anyways. + for _, val := range vals { + if !indexSchema.Unique { + val = append(val, idVal...) + } + indexTxn.Delete(val) + } + } + } + return nil +} + +// DeletePrefix is used to delete an entire subtree based on a prefix. +// The given index must be a prefix index, and will be used to perform a scan and enumerate the set of objects to delete. +// These will be removed from all other indexes, and then a special prefix operation will delete the objects from the given index in an efficient subtree delete operation. +// This is useful when you have a very large number of objects indexed by the given index, along with a much smaller number of entries in the other indexes for those objects. +func (txn *Txn) DeletePrefix(table string, prefix_index string, prefix string) (bool, error) { + if !txn.write { + return false, fmt.Errorf("cannot delete in read-only transaction") + } + + if !strings.HasSuffix(prefix_index, "_prefix") { + return false, fmt.Errorf("Index name for DeletePrefix must be a prefix index, Got %v ", prefix_index) + } + + deletePrefixIndex := strings.TrimSuffix(prefix_index, "_prefix") + + // Get an iterator over all of the keys with the given prefix. + entries, err := txn.Get(table, prefix_index, prefix) + if err != nil { + return false, fmt.Errorf("failed kvs lookup: %s", err) + } + // Get the table schema + tableSchema, ok := txn.db.schema.Tables[table] + if !ok { + return false, fmt.Errorf("invalid table '%s'", table) + } + + foundAny := false + for entry := entries.Next(); entry != nil; entry = entries.Next() { + if !foundAny { + foundAny = true + } + // Get the primary ID of the object + idSchema := tableSchema.Indexes[id] + idIndexer := idSchema.Indexer.(SingleIndexer) + ok, idVal, err := idIndexer.FromObject(entry) + if err != nil { + return false, fmt.Errorf("failed to build primary index: %v", err) + } + if !ok { + return false, fmt.Errorf("object missing primary index") + } + // Remove the object from all the indexes except the given prefix index + for name, indexSchema := range tableSchema.Indexes { + if name == deletePrefixIndex { + continue + } + indexTxn := txn.writableIndex(table, name) + + // Handle the update by deleting from the index first + var ( + ok bool + vals [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var val []byte + ok, val, err = indexer.FromObject(entry) + vals = [][]byte{val} + case MultiIndexer: + ok, vals, err = indexer.FromObject(entry) + } + if err != nil { + return false, fmt.Errorf("failed to build index '%s': %v", name, err) + } + + if ok { + // Handle non-unique index by computing a unique index. + // This is done by appending the primary key which must + // be unique anyways. + for _, val := range vals { + if !indexSchema.Unique { + val = append(val, idVal...) + } + indexTxn.Delete(val) + } + } + } + } + if foundAny { + indexTxn := txn.writableIndex(table, deletePrefixIndex) + ok = indexTxn.DeletePrefix([]byte(prefix)) + if !ok { + panic(fmt.Errorf("prefix %v matched some entries but DeletePrefix did not delete any ", prefix)) + } + return true, nil + } + return false, nil +} + +// DeleteAll is used to delete all the objects in a given table +// matching the constraints on the index +func (txn *Txn) DeleteAll(table, index string, args ...interface{}) (int, error) { + if !txn.write { + return 0, fmt.Errorf("cannot delete in read-only transaction") + } + + // Get all the objects + iter, err := txn.Get(table, index, args...) + if err != nil { + return 0, err + } + + // Put them into a slice so there are no safety concerns while actually + // performing the deletes + var objs []interface{} + for { + obj := iter.Next() + if obj == nil { + break + } + + objs = append(objs, obj) + } + + // Do the deletes + num := 0 + for _, obj := range objs { + if err := txn.Delete(table, obj); err != nil { + return num, err + } + num++ + } + return num, nil +} + +// FirstWatch is used to return the first matching object for +// the given constraints on the index along with the watch channel +func (txn *Txn) FirstWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error) { + // Get the index value + indexSchema, val, err := txn.getIndexValue(table, index, args...) + if err != nil { + return nil, nil, err + } + + // Get the index itself + indexTxn := txn.readableIndex(table, indexSchema.Name) + + // Do an exact lookup + if indexSchema.Unique && val != nil && indexSchema.Name == index { + watch, obj, ok := indexTxn.GetWatch(val) + if !ok { + return watch, nil, nil + } + return watch, obj, nil + } + + // Handle non-unique index by using an iterator and getting the first value + iter := indexTxn.Root().Iterator() + watch := iter.SeekPrefixWatch(val) + _, value, _ := iter.Next() + return watch, value, nil +} + +// First is used to return the first matching object for +// the given constraints on the index +func (txn *Txn) First(table, index string, args ...interface{}) (interface{}, error) { + _, val, err := txn.FirstWatch(table, index, args...) + return val, err +} + +// LongestPrefix is used to fetch the longest prefix match for the given +// constraints on the index. Note that this will not work with the memdb +// StringFieldIndex because it adds null terminators which prevent the +// algorithm from correctly finding a match (it will get to right before the +// null and fail to find a leaf node). This should only be used where the prefix +// given is capable of matching indexed entries directly, which typically only +// applies to a custom indexer. See the unit test for an example. +func (txn *Txn) LongestPrefix(table, index string, args ...interface{}) (interface{}, error) { + // Enforce that this only works on prefix indexes. + if !strings.HasSuffix(index, "_prefix") { + return nil, fmt.Errorf("must use '%s_prefix' on index", index) + } + + // Get the index value. + indexSchema, val, err := txn.getIndexValue(table, index, args...) + if err != nil { + return nil, err + } + + // This algorithm only makes sense against a unique index, otherwise the + // index keys will have the IDs appended to them. + if !indexSchema.Unique { + return nil, fmt.Errorf("index '%s' is not unique", index) + } + + // Find the longest prefix match with the given index. + indexTxn := txn.readableIndex(table, indexSchema.Name) + if _, value, ok := indexTxn.Root().LongestPrefix(val); ok { + return value, nil + } + return nil, nil +} + +// getIndexValue is used to get the IndexSchema and the value +// used to scan the index given the parameters. This handles prefix based +// scans when the index has the "_prefix" suffix. The index must support +// prefix iteration. +func (txn *Txn) getIndexValue(table, index string, args ...interface{}) (*IndexSchema, []byte, error) { + // Get the table schema + tableSchema, ok := txn.db.schema.Tables[table] + if !ok { + return nil, nil, fmt.Errorf("invalid table '%s'", table) + } + + // Check for a prefix scan + prefixScan := false + if strings.HasSuffix(index, "_prefix") { + index = strings.TrimSuffix(index, "_prefix") + prefixScan = true + } + + // Get the index schema + indexSchema, ok := tableSchema.Indexes[index] + if !ok { + return nil, nil, fmt.Errorf("invalid index '%s'", index) + } + + // Hot-path for when there are no arguments + if len(args) == 0 { + return indexSchema, nil, nil + } + + // Special case the prefix scanning + if prefixScan { + prefixIndexer, ok := indexSchema.Indexer.(PrefixIndexer) + if !ok { + return indexSchema, nil, + fmt.Errorf("index '%s' does not support prefix scanning", index) + } + + val, err := prefixIndexer.PrefixFromArgs(args...) + if err != nil { + return indexSchema, nil, fmt.Errorf("index error: %v", err) + } + return indexSchema, val, err + } + + // Get the exact match index + val, err := indexSchema.Indexer.FromArgs(args...) + if err != nil { + return indexSchema, nil, fmt.Errorf("index error: %v", err) + } + return indexSchema, val, err +} + +// ResultIterator is used to iterate over a list of results +// from a Get query on a table. +type ResultIterator interface { + WatchCh() <-chan struct{} + Next() interface{} +} + +// Get is used to construct a ResultIterator over all the +// rows that match the given constraints of an index. +func (txn *Txn) Get(table, index string, args ...interface{}) (ResultIterator, error) { + // Get the index value to scan + indexSchema, val, err := txn.getIndexValue(table, index, args...) + if err != nil { + return nil, err + } + + // Get the index itself + indexTxn := txn.readableIndex(table, indexSchema.Name) + indexRoot := indexTxn.Root() + + // Get an interator over the index + indexIter := indexRoot.Iterator() + + // Seek the iterator to the appropriate sub-set + watchCh := indexIter.SeekPrefixWatch(val) + + // Create an iterator + iter := &radixIterator{ + iter: indexIter, + watchCh: watchCh, + } + return iter, nil +} + +// Defer is used to push a new arbitrary function onto a stack which +// gets called when a transaction is committed and finished. Deferred +// functions are called in LIFO order, and only invoked at the end of +// write transactions. +func (txn *Txn) Defer(fn func()) { + txn.after = append(txn.after, fn) +} + +// radixIterator is used to wrap an underlying iradix iterator. +// This is much more efficient than a sliceIterator as we are not +// materializing the entire view. +type radixIterator struct { + iter *iradix.Iterator + watchCh <-chan struct{} +} + +func (r *radixIterator) WatchCh() <-chan struct{} { + return r.watchCh +} + +func (r *radixIterator) Next() interface{} { + _, value, ok := r.iter.Next() + if !ok { + return nil + } + return value +} diff --git a/vendor/github.com/hashicorp/go-memdb/watch.go b/vendor/github.com/hashicorp/go-memdb/watch.go new file mode 100644 index 0000000..a6f0121 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/watch.go @@ -0,0 +1,129 @@ +package memdb + +import ( + "context" + "time" +) + +// WatchSet is a collection of watch channels. +type WatchSet map[<-chan struct{}]struct{} + +// NewWatchSet constructs a new watch set. +func NewWatchSet() WatchSet { + return make(map[<-chan struct{}]struct{}) +} + +// Add appends a watchCh to the WatchSet if non-nil. +func (w WatchSet) Add(watchCh <-chan struct{}) { + if w == nil { + return + } + + if _, ok := w[watchCh]; !ok { + w[watchCh] = struct{}{} + } +} + +// AddWithLimit appends a watchCh to the WatchSet if non-nil, and if the given +// softLimit hasn't been exceeded. Otherwise, it will watch the given alternate +// channel. It's expected that the altCh will be the same on many calls to this +// function, so you will exceed the soft limit a little bit if you hit this, but +// not by much. +// +// This is useful if you want to track individual items up to some limit, after +// which you watch a higher-level channel (usually a channel from start start of +// an iterator higher up in the radix tree) that will watch a superset of items. +func (w WatchSet) AddWithLimit(softLimit int, watchCh <-chan struct{}, altCh <-chan struct{}) { + // This is safe for a nil WatchSet so we don't need to check that here. + if len(w) < softLimit { + w.Add(watchCh) + } else { + w.Add(altCh) + } +} + +// Watch is used to wait for either the watch set to trigger or a timeout. +// Returns true on timeout. +func (w WatchSet) Watch(timeoutCh <-chan time.Time) bool { + if w == nil { + return false + } + + // Create a context that gets cancelled when the timeout is triggered + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + select { + case <-timeoutCh: + cancel() + case <-ctx.Done(): + } + }() + + return w.WatchCtx(ctx) == context.Canceled +} + +// WatchCtx is used to wait for either the watch set to trigger or for the +// context to be cancelled. Watch with a timeout channel can be mimicked by +// creating a context with a deadline. WatchCtx should be preferred over Watch. +func (w WatchSet) WatchCtx(ctx context.Context) error { + if w == nil { + return nil + } + + if n := len(w); n <= aFew { + idx := 0 + chunk := make([]<-chan struct{}, aFew) + for watchCh := range w { + chunk[idx] = watchCh + idx++ + } + return watchFew(ctx, chunk) + } + + return w.watchMany(ctx) +} + +// watchMany is used if there are many watchers. +func (w WatchSet) watchMany(ctx context.Context) error { + // Set up a goroutine for each watcher. + triggerCh := make(chan struct{}, 1) + watcher := func(chunk []<-chan struct{}) { + if err := watchFew(ctx, chunk); err == nil { + select { + case triggerCh <- struct{}{}: + default: + } + } + } + + // Apportion the watch channels into chunks we can feed into the + // watchFew helper. + idx := 0 + chunk := make([]<-chan struct{}, aFew) + for watchCh := range w { + subIdx := idx % aFew + chunk[subIdx] = watchCh + idx++ + + // Fire off this chunk and start a fresh one. + if idx%aFew == 0 { + go watcher(chunk) + chunk = make([]<-chan struct{}, aFew) + } + } + + // Make sure to watch any residual channels in the last chunk. + if idx%aFew != 0 { + go watcher(chunk) + } + + // Wait for a channel to trigger or timeout. + select { + case <-triggerCh: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/vendor/github.com/hashicorp/go-memdb/watch_few.go b/vendor/github.com/hashicorp/go-memdb/watch_few.go new file mode 100644 index 0000000..880f098 --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/watch_few.go @@ -0,0 +1,117 @@ +package memdb + +//go:generate sh -c "go run watch-gen/main.go >watch_few.go" + +import( + "context" +) + +// aFew gives how many watchers this function is wired to support. You must +// always pass a full slice of this length, but unused channels can be nil. +const aFew = 32 + +// watchFew is used if there are only a few watchers as a performance +// optimization. +func watchFew(ctx context.Context, ch []<-chan struct{}) error { + select { + + case <-ch[0]: + return nil + + case <-ch[1]: + return nil + + case <-ch[2]: + return nil + + case <-ch[3]: + return nil + + case <-ch[4]: + return nil + + case <-ch[5]: + return nil + + case <-ch[6]: + return nil + + case <-ch[7]: + return nil + + case <-ch[8]: + return nil + + case <-ch[9]: + return nil + + case <-ch[10]: + return nil + + case <-ch[11]: + return nil + + case <-ch[12]: + return nil + + case <-ch[13]: + return nil + + case <-ch[14]: + return nil + + case <-ch[15]: + return nil + + case <-ch[16]: + return nil + + case <-ch[17]: + return nil + + case <-ch[18]: + return nil + + case <-ch[19]: + return nil + + case <-ch[20]: + return nil + + case <-ch[21]: + return nil + + case <-ch[22]: + return nil + + case <-ch[23]: + return nil + + case <-ch[24]: + return nil + + case <-ch[25]: + return nil + + case <-ch[26]: + return nil + + case <-ch[27]: + return nil + + case <-ch[28]: + return nil + + case <-ch[29]: + return nil + + case <-ch[30]: + return nil + + case <-ch[31]: + return nil + + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/vendor/github.com/hashicorp/go-multierror/.travis.yml b/vendor/github.com/hashicorp/go-multierror/.travis.yml new file mode 100644 index 0000000..304a835 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/.travis.yml @@ -0,0 +1,12 @@ +sudo: false + +language: go + +go: + - 1.x + +branches: + only: + - master + +script: make test testrace diff --git a/vendor/github.com/hashicorp/go-multierror/LICENSE b/vendor/github.com/hashicorp/go-multierror/LICENSE new file mode 100644 index 0000000..82b4de9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/LICENSE @@ -0,0 +1,353 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-multierror/Makefile b/vendor/github.com/hashicorp/go-multierror/Makefile new file mode 100644 index 0000000..b97cd6e --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/Makefile @@ -0,0 +1,31 @@ +TEST?=./... + +default: test + +# test runs the test suite and vets the code. +test: generate + @echo "==> Running tests..." + @go list $(TEST) \ + | grep -v "/vendor/" \ + | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS} + +# testrace runs the race checker +testrace: generate + @echo "==> Running tests (race)..." + @go list $(TEST) \ + | grep -v "/vendor/" \ + | xargs -n1 go test -timeout=60s -race ${TESTARGS} + +# updatedeps installs all the dependencies needed to run and build. +updatedeps: + @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'" + +# generate runs `go generate` to build the dynamically generated source files. +generate: + @echo "==> Generating..." + @find . -type f -name '.DS_Store' -delete + @go list ./... \ + | grep -v "/vendor/" \ + | xargs -n1 go generate + +.PHONY: default test testrace updatedeps generate diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md new file mode 100644 index 0000000..ead5830 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/README.md @@ -0,0 +1,97 @@ +# go-multierror + +[![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis] +[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] + +[travis]: https://travis-ci.org/hashicorp/go-multierror +[godocs]: https://godoc.org/github.com/hashicorp/go-multierror + +`go-multierror` is a package for Go that provides a mechanism for +representing a list of `error` values as a single `error`. + +This allows a function in Go to return an `error` that might actually +be a list of errors. If the caller knows this, they can unwrap the +list and access the errors. If the caller doesn't know, the error +formats to a nice human-readable format. + +`go-multierror` implements the +[errwrap](https://github.com/hashicorp/errwrap) interface so that it can +be used with that library, as well. + +## Installation and Docs + +Install using `go get github.com/hashicorp/go-multierror`. + +Full documentation is available at +http://godoc.org/github.com/hashicorp/go-multierror + +## Usage + +go-multierror is easy to use and purposely built to be unobtrusive in +existing Go applications/libraries that may not be aware of it. + +**Building a list of errors** + +The `Append` function is used to create a list of errors. This function +behaves a lot like the Go built-in `append` function: it doesn't matter +if the first argument is nil, a `multierror.Error`, or any other `error`, +the function behaves as you would expect. + +```go +var result error + +if err := step1(); err != nil { + result = multierror.Append(result, err) +} +if err := step2(); err != nil { + result = multierror.Append(result, err) +} + +return result +``` + +**Customizing the formatting of the errors** + +By specifying a custom `ErrorFormat`, you can customize the format +of the `Error() string` function: + +```go +var result *multierror.Error + +// ... accumulate errors here, maybe using Append + +if result != nil { + result.ErrorFormat = func([]error) string { + return "errors!" + } +} +``` + +**Accessing the list of errors** + +`multierror.Error` implements `error` so if the caller doesn't know about +multierror, it will work just fine. But if you're aware a multierror might +be returned, you can use type switches to access the list of errors: + +```go +if err := something(); err != nil { + if merr, ok := err.(*multierror.Error); ok { + // Use merr.Errors + } +} +``` + +**Returning a multierror only if there are errors** + +If you build a `multierror.Error`, you can use the `ErrorOrNil` function +to return an `error` implementation only if there are errors to return: + +```go +var result *multierror.Error + +// ... accumulate errors here + +// Return the `error` only if errors were added to the multierror, otherwise +// return nil since there are no errors. +return result.ErrorOrNil() +``` diff --git a/vendor/github.com/hashicorp/go-multierror/append.go b/vendor/github.com/hashicorp/go-multierror/append.go new file mode 100644 index 0000000..775b6e7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/append.go @@ -0,0 +1,41 @@ +package multierror + +// Append is a helper function that will append more errors +// onto an Error in order to create a larger multi-error. +// +// If err is not a multierror.Error, then it will be turned into +// one. If any of the errs are multierr.Error, they will be flattened +// one level into err. +func Append(err error, errs ...error) *Error { + switch err := err.(type) { + case *Error: + // Typed nils can reach here, so initialize if we are nil + if err == nil { + err = new(Error) + } + + // Go through each error and flatten + for _, e := range errs { + switch e := e.(type) { + case *Error: + if e != nil { + err.Errors = append(err.Errors, e.Errors...) + } + default: + if e != nil { + err.Errors = append(err.Errors, e) + } + } + } + + return err + default: + newErrs := make([]error, 0, len(errs)+1) + if err != nil { + newErrs = append(newErrs, err) + } + newErrs = append(newErrs, errs...) + + return Append(&Error{}, newErrs...) + } +} diff --git a/vendor/github.com/hashicorp/go-multierror/flatten.go b/vendor/github.com/hashicorp/go-multierror/flatten.go new file mode 100644 index 0000000..aab8e9a --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/flatten.go @@ -0,0 +1,26 @@ +package multierror + +// Flatten flattens the given error, merging any *Errors together into +// a single *Error. +func Flatten(err error) error { + // If it isn't an *Error, just return the error as-is + if _, ok := err.(*Error); !ok { + return err + } + + // Otherwise, make the result and flatten away! + flatErr := new(Error) + flatten(err, flatErr) + return flatErr +} + +func flatten(err error, flatErr *Error) { + switch err := err.(type) { + case *Error: + for _, e := range err.Errors { + flatten(e, flatErr) + } + default: + flatErr.Errors = append(flatErr.Errors, err) + } +} diff --git a/vendor/github.com/hashicorp/go-multierror/format.go b/vendor/github.com/hashicorp/go-multierror/format.go new file mode 100644 index 0000000..6c7a3cc --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/format.go @@ -0,0 +1,27 @@ +package multierror + +import ( + "fmt" + "strings" +) + +// ErrorFormatFunc is a function callback that is called by Error to +// turn the list of errors into a string. +type ErrorFormatFunc func([]error) string + +// ListFormatFunc is a basic formatter that outputs the number of errors +// that occurred along with a bullet point list of the errors. +func ListFormatFunc(es []error) string { + if len(es) == 1 { + return fmt.Sprintf("1 error occurred:\n\n* %s", es[0]) + } + + points := make([]string, len(es)) + for i, err := range es { + points[i] = fmt.Sprintf("* %s", err) + } + + return fmt.Sprintf( + "%d errors occurred:\n\n%s", + len(es), strings.Join(points, "\n")) +} diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go new file mode 100644 index 0000000..89b1422 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/multierror.go @@ -0,0 +1,51 @@ +package multierror + +import ( + "fmt" +) + +// Error is an error type to track multiple errors. This is used to +// accumulate errors in cases and return them as a single "error". +type Error struct { + Errors []error + ErrorFormat ErrorFormatFunc +} + +func (e *Error) Error() string { + fn := e.ErrorFormat + if fn == nil { + fn = ListFormatFunc + } + + return fn(e.Errors) +} + +// ErrorOrNil returns an error interface if this Error represents +// a list of errors, or returns nil if the list of errors is empty. This +// function is useful at the end of accumulation to make sure that the value +// returned represents the existence of errors. +func (e *Error) ErrorOrNil() error { + if e == nil { + return nil + } + if len(e.Errors) == 0 { + return nil + } + + return e +} + +func (e *Error) GoString() string { + return fmt.Sprintf("*%#v", *e) +} + +// WrappedErrors returns the list of errors that this Error is wrapping. +// It is an implementation of the errwrap.Wrapper interface so that +// multierror.Error can be used with that library. +// +// This method is not safe to be called concurrently and is no different +// than accessing the Errors field directly. It is implemented only to +// satisfy the errwrap.Wrapper interface. +func (e *Error) WrappedErrors() []error { + return e.Errors +} diff --git a/vendor/github.com/hashicorp/go-multierror/prefix.go b/vendor/github.com/hashicorp/go-multierror/prefix.go new file mode 100644 index 0000000..5c477ab --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/prefix.go @@ -0,0 +1,37 @@ +package multierror + +import ( + "fmt" + + "github.com/hashicorp/errwrap" +) + +// Prefix is a helper function that will prefix some text +// to the given error. If the error is a multierror.Error, then +// it will be prefixed to each wrapped error. +// +// This is useful to use when appending multiple multierrors +// together in order to give better scoping. +func Prefix(err error, prefix string) error { + if err == nil { + return nil + } + + format := fmt.Sprintf("%s {{err}}", prefix) + switch err := err.(type) { + case *Error: + // Typed nils can reach here, so initialize if we are nil + if err == nil { + err = new(Error) + } + + // Wrap each of the errors + for i, e := range err.Errors { + err.Errors[i] = errwrap.Wrapf(format, e) + } + + return err + default: + return errwrap.Wrapf(format, err) + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/.gitignore b/vendor/github.com/hashicorp/go-plugin/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/vendor/github.com/hashicorp/go-plugin/LICENSE b/vendor/github.com/hashicorp/go-plugin/LICENSE new file mode 100644 index 0000000..82b4de9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/LICENSE @@ -0,0 +1,353 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-plugin/README.md b/vendor/github.com/hashicorp/go-plugin/README.md new file mode 100644 index 0000000..e4558db --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/README.md @@ -0,0 +1,168 @@ +# Go Plugin System over RPC + +`go-plugin` is a Go (golang) plugin system over RPC. It is the plugin system +that has been in use by HashiCorp tooling for over 4 years. While initially +created for [Packer](https://www.packer.io), it is additionally in use by +[Terraform](https://www.terraform.io), [Nomad](https://www.nomadproject.io), and +[Vault](https://www.vaultproject.io). + +While the plugin system is over RPC, it is currently only designed to work +over a local [reliable] network. Plugins over a real network are not supported +and will lead to unexpected behavior. + +This plugin system has been used on millions of machines across many different +projects and has proven to be battle hardened and ready for production use. + +## Features + +The HashiCorp plugin system supports a number of features: + +**Plugins are Go interface implementations.** This makes writing and consuming +plugins feel very natural. To a plugin author: you just implement an +interface as if it were going to run in the same process. For a plugin user: +you just use and call functions on an interface as if it were in the same +process. This plugin system handles the communication in between. + +**Cross-language support.** Plugins can be written (and consumed) by +almost every major language. This library supports serving plugins via +[gRPC](http://www.grpc.io). gRPC-based plugins enable plugins to be written +in any language. + +**Complex arguments and return values are supported.** This library +provides APIs for handling complex arguments and return values such +as interfaces, `io.Reader/Writer`, etc. We do this by giving you a library +(`MuxBroker`) for creating new connections between the client/server to +serve additional interfaces or transfer raw data. + +**Bidirectional communication.** Because the plugin system supports +complex arguments, the host process can send it interface implementations +and the plugin can call back into the host process. + +**Built-in Logging.** Any plugins that use the `log` standard library +will have log data automatically sent to the host process. The host +process will mirror this output prefixed with the path to the plugin +binary. This makes debugging with plugins simple. If the host system +uses [hclog](https://github.com/hashicorp/go-hclog) then the log data +will be structured. If the plugin also uses hclog, logs from the plugin +will be sent to the host hclog and be structured. + +**Protocol Versioning.** A very basic "protocol version" is supported that +can be incremented to invalidate any previous plugins. This is useful when +interface signatures are changing, protocol level changes are necessary, +etc. When a protocol version is incompatible, a human friendly error +message is shown to the end user. + +**Stdout/Stderr Syncing.** While plugins are subprocesses, they can continue +to use stdout/stderr as usual and the output will get mirrored back to +the host process. The host process can control what `io.Writer` these +streams go to to prevent this from happening. + +**TTY Preservation.** Plugin subprocesses are connected to the identical +stdin file descriptor as the host process, allowing software that requires +a TTY to work. For example, a plugin can execute `ssh` and even though there +are multiple subprocesses and RPC happening, it will look and act perfectly +to the end user. + +**Host upgrade while a plugin is running.** Plugins can be "reattached" +so that the host process can be upgraded while the plugin is still running. +This requires the host/plugin to know this is possible and daemonize +properly. `NewClient` takes a `ReattachConfig` to determine if and how to +reattach. + +**Cryptographically Secure Plugins.** Plugins can be verified with an expected +checksum and RPC communications can be configured to use TLS. The host process +must be properly secured to protect this configuration. + +## Architecture + +The HashiCorp plugin system works by launching subprocesses and communicating +over RPC (using standard `net/rpc` or [gRPC](http://www.grpc.io)). A single +connection is made between any plugin and the host process. For net/rpc-based +plugins, we use a [connection multiplexing](https://github.com/hashicorp/yamux) +library to multiplex any other connections on top. For gRPC-based plugins, +the HTTP2 protocol handles multiplexing. + +This architecture has a number of benefits: + + * Plugins can't crash your host process: A panic in a plugin doesn't + panic the plugin user. + + * Plugins are very easy to write: just write a Go application and `go build`. + Or use any other language to write a gRPC server with a tiny amount of + boilerplate to support go-plugin. + + * Plugins are very easy to install: just put the binary in a location where + the host will find it (depends on the host but this library also provides + helpers), and the plugin host handles the rest. + + * Plugins can be relatively secure: The plugin only has access to the + interfaces and args given to it, not to the entire memory space of the + process. Additionally, go-plugin can communicate with the plugin over + TLS. + +## Usage + +To use the plugin system, you must take the following steps. These are +high-level steps that must be done. Examples are available in the +`examples/` directory. + + 1. Choose the interface(s) you want to expose for plugins. + + 2. For each interface, implement an implementation of that interface + that communicates over a `net/rpc` connection or other a + [gRPC](http://www.grpc.io) connection or both. You'll have to implement + both a client and server implementation. + + 3. Create a `Plugin` implementation that knows how to create the RPC + client/server for a given plugin type. + + 4. Plugin authors call `plugin.Serve` to serve a plugin from the + `main` function. + + 5. Plugin users use `plugin.Client` to launch a subprocess and request + an interface implementation over RPC. + +That's it! In practice, step 2 is the most tedious and time consuming step. +Even so, it isn't very difficult and you can see examples in the `examples/` +directory as well as throughout our various open source projects. + +For complete API documentation, see [GoDoc](https://godoc.org/github.com/hashicorp/go-plugin). + +## Roadmap + +Our plugin system is constantly evolving. As we use the plugin system for +new projects or for new features in existing projects, we constantly find +improvements we can make. + +At this point in time, the roadmap for the plugin system is: + +**Semantic Versioning.** Plugins will be able to implement a semantic version. +This plugin system will give host processes a system for constraining +versions. This is in addition to the protocol versioning already present +which is more for larger underlying changes. + +**Plugin fetching.** We will integrate with [go-getter](https://github.com/hashicorp/go-getter) +to support automatic download + install of plugins. Paired with cryptographically +secure plugins (above), we can make this a safe operation for an amazing +user experience. + +## What About Shared Libraries? + +When we started using plugins (late 2012, early 2013), plugins over RPC +were the only option since Go didn't support dynamic library loading. Today, +Go still doesn't support dynamic library loading, but they do intend to. +Since 2012, our plugin system has stabilized from millions of users using it, +and has many benefits we've come to value greatly. + +For example, we intend to use this plugin system in +[Vault](https://www.vaultproject.io), and dynamic library loading will +simply never be acceptable in Vault for security reasons. That is an extreme +example, but we believe our library system has more upsides than downsides +over dynamic library loading and since we've had it built and tested for years, +we'll likely continue to use it. + +Shared libraries have one major advantage over our system which is much +higher performance. In real world scenarios across our various tools, +we've never required any more performance out of our plugin system and it +has seen very high throughput, so this isn't a concern for us at the moment. + diff --git a/vendor/github.com/hashicorp/go-plugin/client.go b/vendor/github.com/hashicorp/go-plugin/client.go new file mode 100644 index 0000000..fce0614 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/client.go @@ -0,0 +1,792 @@ +package plugin + +import ( + "bufio" + "context" + "crypto/subtle" + "crypto/tls" + "errors" + "fmt" + "hash" + "io" + "io/ioutil" + "net" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unicode" + + hclog "github.com/hashicorp/go-hclog" +) + +// If this is 1, then we've called CleanupClients. This can be used +// by plugin RPC implementations to change error behavior since you +// can expected network connection errors at this point. This should be +// read by using sync/atomic. +var Killed uint32 = 0 + +// This is a slice of the "managed" clients which are cleaned up when +// calling Cleanup +var managedClients = make([]*Client, 0, 5) +var managedClientsLock sync.Mutex + +// Error types +var ( + // ErrProcessNotFound is returned when a client is instantiated to + // reattach to an existing process and it isn't found. + ErrProcessNotFound = errors.New("Reattachment process not found") + + // ErrChecksumsDoNotMatch is returned when binary's checksum doesn't match + // the one provided in the SecureConfig. + ErrChecksumsDoNotMatch = errors.New("checksums did not match") + + // ErrSecureNoChecksum is returned when an empty checksum is provided to the + // SecureConfig. + ErrSecureConfigNoChecksum = errors.New("no checksum provided") + + // ErrSecureNoHash is returned when a nil Hash object is provided to the + // SecureConfig. + ErrSecureConfigNoHash = errors.New("no hash implementation provided") + + // ErrSecureConfigAndReattach is returned when both Reattach and + // SecureConfig are set. + ErrSecureConfigAndReattach = errors.New("only one of Reattach or SecureConfig can be set") +) + +// Client handles the lifecycle of a plugin application. It launches +// plugins, connects to them, dispenses interface implementations, and handles +// killing the process. +// +// Plugin hosts should use one Client for each plugin executable. To +// dispense a plugin type, use the `Client.Client` function, and then +// cal `Dispense`. This awkward API is mostly historical but is used to split +// the client that deals with subprocess management and the client that +// does RPC management. +// +// See NewClient and ClientConfig for using a Client. +type Client struct { + config *ClientConfig + exited bool + doneLogging chan struct{} + l sync.Mutex + address net.Addr + process *os.Process + client ClientProtocol + protocol Protocol + logger hclog.Logger + doneCtx context.Context +} + +// ClientConfig is the configuration used to initialize a new +// plugin client. After being used to initialize a plugin client, +// that configuration must not be modified again. +type ClientConfig struct { + // HandshakeConfig is the configuration that must match servers. + HandshakeConfig + + // Plugins are the plugins that can be consumed. + Plugins map[string]Plugin + + // One of the following must be set, but not both. + // + // Cmd is the unstarted subprocess for starting the plugin. If this is + // set, then the Client starts the plugin process on its own and connects + // to it. + // + // Reattach is configuration for reattaching to an existing plugin process + // that is already running. This isn't common. + Cmd *exec.Cmd + Reattach *ReattachConfig + + // SecureConfig is configuration for verifying the integrity of the + // executable. It can not be used with Reattach. + SecureConfig *SecureConfig + + // TLSConfig is used to enable TLS on the RPC client. + TLSConfig *tls.Config + + // Managed represents if the client should be managed by the + // plugin package or not. If true, then by calling CleanupClients, + // it will automatically be cleaned up. Otherwise, the client + // user is fully responsible for making sure to Kill all plugin + // clients. By default the client is _not_ managed. + Managed bool + + // The minimum and maximum port to use for communicating with + // the subprocess. If not set, this defaults to 10,000 and 25,000 + // respectively. + MinPort, MaxPort uint + + // StartTimeout is the timeout to wait for the plugin to say it + // has started successfully. + StartTimeout time.Duration + + // If non-nil, then the stderr of the client will be written to here + // (as well as the log). This is the original os.Stderr of the subprocess. + // This isn't the output of synced stderr. + Stderr io.Writer + + // SyncStdout, SyncStderr can be set to override the + // respective os.Std* values in the plugin. Care should be taken to + // avoid races here. If these are nil, then this will automatically be + // hooked up to os.Stdin, Stdout, and Stderr, respectively. + // + // If the default values (nil) are used, then this package will not + // sync any of these streams. + SyncStdout io.Writer + SyncStderr io.Writer + + // AllowedProtocols is a list of allowed protocols. If this isn't set, + // then only netrpc is allowed. This is so that older go-plugin systems + // can show friendly errors if they see a plugin with an unknown + // protocol. + // + // By setting this, you can cause an error immediately on plugin start + // if an unsupported protocol is used with a good error message. + // + // If this isn't set at all (nil value), then only net/rpc is accepted. + // This is done for legacy reasons. You must explicitly opt-in to + // new protocols. + AllowedProtocols []Protocol + + // Logger is the logger that the client will used. If none is provided, + // it will default to hclog's default logger. + Logger hclog.Logger +} + +// ReattachConfig is used to configure a client to reattach to an +// already-running plugin process. You can retrieve this information by +// calling ReattachConfig on Client. +type ReattachConfig struct { + Protocol Protocol + Addr net.Addr + Pid int +} + +// SecureConfig is used to configure a client to verify the integrity of an +// executable before running. It does this by verifying the checksum is +// expected. Hash is used to specify the hashing method to use when checksumming +// the file. The configuration is verified by the client by calling the +// SecureConfig.Check() function. +// +// The host process should ensure the checksum was provided by a trusted and +// authoritative source. The binary should be installed in such a way that it +// can not be modified by an unauthorized user between the time of this check +// and the time of execution. +type SecureConfig struct { + Checksum []byte + Hash hash.Hash +} + +// Check takes the filepath to an executable and returns true if the checksum of +// the file matches the checksum provided in the SecureConfig. +func (s *SecureConfig) Check(filePath string) (bool, error) { + if len(s.Checksum) == 0 { + return false, ErrSecureConfigNoChecksum + } + + if s.Hash == nil { + return false, ErrSecureConfigNoHash + } + + file, err := os.Open(filePath) + if err != nil { + return false, err + } + defer file.Close() + + _, err = io.Copy(s.Hash, file) + if err != nil { + return false, err + } + + sum := s.Hash.Sum(nil) + + return subtle.ConstantTimeCompare(sum, s.Checksum) == 1, nil +} + +// This makes sure all the managed subprocesses are killed and properly +// logged. This should be called before the parent process running the +// plugins exits. +// +// This must only be called _once_. +func CleanupClients() { + // Set the killed to true so that we don't get unexpected panics + atomic.StoreUint32(&Killed, 1) + + // Kill all the managed clients in parallel and use a WaitGroup + // to wait for them all to finish up. + var wg sync.WaitGroup + managedClientsLock.Lock() + for _, client := range managedClients { + wg.Add(1) + + go func(client *Client) { + client.Kill() + wg.Done() + }(client) + } + managedClientsLock.Unlock() + + wg.Wait() +} + +// Creates a new plugin client which manages the lifecycle of an external +// plugin and gets the address for the RPC connection. +// +// The client must be cleaned up at some point by calling Kill(). If +// the client is a managed client (created with NewManagedClient) you +// can just call CleanupClients at the end of your program and they will +// be properly cleaned. +func NewClient(config *ClientConfig) (c *Client) { + if config.MinPort == 0 && config.MaxPort == 0 { + config.MinPort = 10000 + config.MaxPort = 25000 + } + + if config.StartTimeout == 0 { + config.StartTimeout = 1 * time.Minute + } + + if config.Stderr == nil { + config.Stderr = ioutil.Discard + } + + if config.SyncStdout == nil { + config.SyncStdout = ioutil.Discard + } + if config.SyncStderr == nil { + config.SyncStderr = ioutil.Discard + } + + if config.AllowedProtocols == nil { + config.AllowedProtocols = []Protocol{ProtocolNetRPC} + } + + if config.Logger == nil { + config.Logger = hclog.New(&hclog.LoggerOptions{ + Output: hclog.DefaultOutput, + Level: hclog.Trace, + Name: "plugin", + }) + } + + c = &Client{ + config: config, + logger: config.Logger, + } + if config.Managed { + managedClientsLock.Lock() + managedClients = append(managedClients, c) + managedClientsLock.Unlock() + } + + return +} + +// Client returns the protocol client for this connection. +// +// Subsequent calls to this will return the same client. +func (c *Client) Client() (ClientProtocol, error) { + _, err := c.Start() + if err != nil { + return nil, err + } + + c.l.Lock() + defer c.l.Unlock() + + if c.client != nil { + return c.client, nil + } + + switch c.protocol { + case ProtocolNetRPC: + c.client, err = newRPCClient(c) + + case ProtocolGRPC: + c.client, err = newGRPCClient(c.doneCtx, c) + + default: + return nil, fmt.Errorf("unknown server protocol: %s", c.protocol) + } + + if err != nil { + c.client = nil + return nil, err + } + + return c.client, nil +} + +// Tells whether or not the underlying process has exited. +func (c *Client) Exited() bool { + c.l.Lock() + defer c.l.Unlock() + return c.exited +} + +// End the executing subprocess (if it is running) and perform any cleanup +// tasks necessary such as capturing any remaining logs and so on. +// +// This method blocks until the process successfully exits. +// +// This method can safely be called multiple times. +func (c *Client) Kill() { + // Grab a lock to read some private fields. + c.l.Lock() + process := c.process + addr := c.address + doneCh := c.doneLogging + c.l.Unlock() + + // If there is no process, we never started anything. Nothing to kill. + if process == nil { + return + } + + // We need to check for address here. It is possible that the plugin + // started (process != nil) but has no address (addr == nil) if the + // plugin failed at startup. If we do have an address, we need to close + // the plugin net connections. + graceful := false + if addr != nil { + // Close the client to cleanly exit the process. + client, err := c.Client() + if err == nil { + err = client.Close() + + // If there is no error, then we attempt to wait for a graceful + // exit. If there was an error, we assume that graceful cleanup + // won't happen and just force kill. + graceful = err == nil + if err != nil { + // If there was an error just log it. We're going to force + // kill in a moment anyways. + c.logger.Warn("error closing client during Kill", "err", err) + } + } + } + + // If we're attempting a graceful exit, then we wait for a short period + // of time to allow that to happen. To wait for this we just wait on the + // doneCh which would be closed if the process exits. + if graceful { + select { + case <-doneCh: + return + case <-time.After(250 * time.Millisecond): + } + } + + // If graceful exiting failed, just kill it + process.Kill() + + // Wait for the client to finish logging so we have a complete log + <-doneCh +} + +// Starts the underlying subprocess, communicating with it to negotiate +// a port for RPC connections, and returning the address to connect via RPC. +// +// This method is safe to call multiple times. Subsequent calls have no effect. +// Once a client has been started once, it cannot be started again, even if +// it was killed. +func (c *Client) Start() (addr net.Addr, err error) { + c.l.Lock() + defer c.l.Unlock() + + if c.address != nil { + return c.address, nil + } + + // If one of cmd or reattach isn't set, then it is an error. We wrap + // this in a {} for scoping reasons, and hopeful that the escape + // analysis will pop the stock here. + { + cmdSet := c.config.Cmd != nil + attachSet := c.config.Reattach != nil + secureSet := c.config.SecureConfig != nil + if cmdSet == attachSet { + return nil, fmt.Errorf("Only one of Cmd or Reattach must be set") + } + + if secureSet && attachSet { + return nil, ErrSecureConfigAndReattach + } + } + + // Create the logging channel for when we kill + c.doneLogging = make(chan struct{}) + // Create a context for when we kill + var ctxCancel context.CancelFunc + c.doneCtx, ctxCancel = context.WithCancel(context.Background()) + + if c.config.Reattach != nil { + // Verify the process still exists. If not, then it is an error + p, err := os.FindProcess(c.config.Reattach.Pid) + if err != nil { + return nil, err + } + + // Attempt to connect to the addr since on Unix systems FindProcess + // doesn't actually return an error if it can't find the process. + conn, err := net.Dial( + c.config.Reattach.Addr.Network(), + c.config.Reattach.Addr.String()) + if err != nil { + p.Kill() + return nil, ErrProcessNotFound + } + conn.Close() + + // Goroutine to mark exit status + go func(pid int) { + // Wait for the process to die + pidWait(pid) + + // Log so we can see it + c.logger.Debug("reattached plugin process exited") + + // Mark it + c.l.Lock() + defer c.l.Unlock() + c.exited = true + + // Close the logging channel since that doesn't work on reattach + close(c.doneLogging) + + // Cancel the context + ctxCancel() + }(p.Pid) + + // Set the address and process + c.address = c.config.Reattach.Addr + c.process = p + c.protocol = c.config.Reattach.Protocol + if c.protocol == "" { + // Default the protocol to net/rpc for backwards compatibility + c.protocol = ProtocolNetRPC + } + + return c.address, nil + } + + env := []string{ + fmt.Sprintf("%s=%s", c.config.MagicCookieKey, c.config.MagicCookieValue), + fmt.Sprintf("PLUGIN_MIN_PORT=%d", c.config.MinPort), + fmt.Sprintf("PLUGIN_MAX_PORT=%d", c.config.MaxPort), + } + + stdout_r, stdout_w := io.Pipe() + stderr_r, stderr_w := io.Pipe() + + cmd := c.config.Cmd + cmd.Env = append(cmd.Env, os.Environ()...) + cmd.Env = append(cmd.Env, env...) + cmd.Stdin = os.Stdin + cmd.Stderr = stderr_w + cmd.Stdout = stdout_w + + if c.config.SecureConfig != nil { + if ok, err := c.config.SecureConfig.Check(cmd.Path); err != nil { + return nil, fmt.Errorf("error verifying checksum: %s", err) + } else if !ok { + return nil, ErrChecksumsDoNotMatch + } + } + + c.logger.Debug("starting plugin", "path", cmd.Path, "args", cmd.Args) + err = cmd.Start() + if err != nil { + return + } + + // Set the process + c.process = cmd.Process + + // Make sure the command is properly cleaned up if there is an error + defer func() { + r := recover() + + if err != nil || r != nil { + cmd.Process.Kill() + } + + if r != nil { + panic(r) + } + }() + + // Start goroutine to wait for process to exit + exitCh := make(chan struct{}) + go func() { + // Make sure we close the write end of our stderr/stdout so + // that the readers send EOF properly. + defer stderr_w.Close() + defer stdout_w.Close() + + // Wait for the command to end. + cmd.Wait() + + // Log and make sure to flush the logs write away + c.logger.Debug("plugin process exited", "path", cmd.Path) + os.Stderr.Sync() + + // Mark that we exited + close(exitCh) + + // Cancel the context, marking that we exited + ctxCancel() + + // Set that we exited, which takes a lock + c.l.Lock() + defer c.l.Unlock() + c.exited = true + }() + + // Start goroutine that logs the stderr + go c.logStderr(stderr_r) + + // Start a goroutine that is going to be reading the lines + // out of stdout + linesCh := make(chan []byte) + go func() { + defer close(linesCh) + + buf := bufio.NewReader(stdout_r) + for { + line, err := buf.ReadBytes('\n') + if line != nil { + linesCh <- line + } + + if err == io.EOF { + return + } + } + }() + + // Make sure after we exit we read the lines from stdout forever + // so they don't block since it is an io.Pipe + defer func() { + go func() { + for _ = range linesCh { + } + }() + }() + + // Some channels for the next step + timeout := time.After(c.config.StartTimeout) + + // Start looking for the address + c.logger.Debug("waiting for RPC address", "path", cmd.Path) + select { + case <-timeout: + err = errors.New("timeout while waiting for plugin to start") + case <-exitCh: + err = errors.New("plugin exited before we could connect") + case lineBytes := <-linesCh: + // Trim the line and split by "|" in order to get the parts of + // the output. + line := strings.TrimSpace(string(lineBytes)) + parts := strings.SplitN(line, "|", 6) + if len(parts) < 4 { + err = fmt.Errorf( + "Unrecognized remote plugin message: %s\n\n"+ + "This usually means that the plugin is either invalid or simply\n"+ + "needs to be recompiled to support the latest protocol.", line) + return + } + + // Check the core protocol. Wrapped in a {} for scoping. + { + var coreProtocol int64 + coreProtocol, err = strconv.ParseInt(parts[0], 10, 0) + if err != nil { + err = fmt.Errorf("Error parsing core protocol version: %s", err) + return + } + + if int(coreProtocol) != CoreProtocolVersion { + err = fmt.Errorf("Incompatible core API version with plugin. "+ + "Plugin version: %s, Core version: %d\n\n"+ + "To fix this, the plugin usually only needs to be recompiled.\n"+ + "Please report this to the plugin author.", parts[0], CoreProtocolVersion) + return + } + } + + // Parse the protocol version + var protocol int64 + protocol, err = strconv.ParseInt(parts[1], 10, 0) + if err != nil { + err = fmt.Errorf("Error parsing protocol version: %s", err) + return + } + + // Test the API version + if uint(protocol) != c.config.ProtocolVersion { + err = fmt.Errorf("Incompatible API version with plugin. "+ + "Plugin version: %s, Core version: %d", parts[1], c.config.ProtocolVersion) + return + } + + switch parts[2] { + case "tcp": + addr, err = net.ResolveTCPAddr("tcp", parts[3]) + case "unix": + addr, err = net.ResolveUnixAddr("unix", parts[3]) + default: + err = fmt.Errorf("Unknown address type: %s", parts[3]) + } + + // If we have a server type, then record that. We default to net/rpc + // for backwards compatibility. + c.protocol = ProtocolNetRPC + if len(parts) >= 5 { + c.protocol = Protocol(parts[4]) + } + + found := false + for _, p := range c.config.AllowedProtocols { + if p == c.protocol { + found = true + break + } + } + if !found { + err = fmt.Errorf("Unsupported plugin protocol %q. Supported: %v", + c.protocol, c.config.AllowedProtocols) + return + } + + } + + c.address = addr + return +} + +// ReattachConfig returns the information that must be provided to NewClient +// to reattach to the plugin process that this client started. This is +// useful for plugins that detach from their parent process. +// +// If this returns nil then the process hasn't been started yet. Please +// call Start or Client before calling this. +func (c *Client) ReattachConfig() *ReattachConfig { + c.l.Lock() + defer c.l.Unlock() + + if c.address == nil { + return nil + } + + if c.config.Cmd != nil && c.config.Cmd.Process == nil { + return nil + } + + // If we connected via reattach, just return the information as-is + if c.config.Reattach != nil { + return c.config.Reattach + } + + return &ReattachConfig{ + Protocol: c.protocol, + Addr: c.address, + Pid: c.config.Cmd.Process.Pid, + } +} + +// Protocol returns the protocol of server on the remote end. This will +// start the plugin process if it isn't already started. Errors from +// starting the plugin are surpressed and ProtocolInvalid is returned. It +// is recommended you call Start explicitly before calling Protocol to ensure +// no errors occur. +func (c *Client) Protocol() Protocol { + _, err := c.Start() + if err != nil { + return ProtocolInvalid + } + + return c.protocol +} + +func netAddrDialer(addr net.Addr) func(string, time.Duration) (net.Conn, error) { + return func(_ string, _ time.Duration) (net.Conn, error) { + // Connect to the client + conn, err := net.Dial(addr.Network(), addr.String()) + if err != nil { + return nil, err + } + if tcpConn, ok := conn.(*net.TCPConn); ok { + // Make sure to set keep alive so that the connection doesn't die + tcpConn.SetKeepAlive(true) + } + + return conn, nil + } +} + +// dialer is compatible with grpc.WithDialer and creates the connection +// to the plugin. +func (c *Client) dialer(_ string, timeout time.Duration) (net.Conn, error) { + conn, err := netAddrDialer(c.address)("", timeout) + if err != nil { + return nil, err + } + + // If we have a TLS config we wrap our connection. We only do this + // for net/rpc since gRPC uses its own mechanism for TLS. + if c.protocol == ProtocolNetRPC && c.config.TLSConfig != nil { + conn = tls.Client(conn, c.config.TLSConfig) + } + + return conn, nil +} + +func (c *Client) logStderr(r io.Reader) { + bufR := bufio.NewReader(r) + l := c.logger.Named(filepath.Base(c.config.Cmd.Path)) + + for { + line, err := bufR.ReadString('\n') + if line != "" { + c.config.Stderr.Write([]byte(line)) + line = strings.TrimRightFunc(line, unicode.IsSpace) + + entry, err := parseJSON(line) + // If output is not JSON format, print directly to Debug + if err != nil { + l.Debug(line) + } else { + out := flattenKVPairs(entry.KVPairs) + + out = append(out, "timestamp", entry.Timestamp.Format(hclog.TimeFormat)) + switch hclog.LevelFromString(entry.Level) { + case hclog.Trace: + l.Trace(entry.Message, out...) + case hclog.Debug: + l.Debug(entry.Message, out...) + case hclog.Info: + l.Info(entry.Message, out...) + case hclog.Warn: + l.Warn(entry.Message, out...) + case hclog.Error: + l.Error(entry.Message, out...) + } + } + } + + if err == io.EOF { + break + } + } + + // Flag that we've completed logging for others + close(c.doneLogging) +} diff --git a/vendor/github.com/hashicorp/go-plugin/discover.go b/vendor/github.com/hashicorp/go-plugin/discover.go new file mode 100644 index 0000000..d22c566 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/discover.go @@ -0,0 +1,28 @@ +package plugin + +import ( + "path/filepath" +) + +// Discover discovers plugins that are in a given directory. +// +// The directory doesn't need to be absolute. For example, "." will work fine. +// +// This currently assumes any file matching the glob is a plugin. +// In the future this may be smarter about checking that a file is +// executable and so on. +// +// TODO: test +func Discover(glob, dir string) ([]string, error) { + var err error + + // Make the directory absolute if it isn't already + if !filepath.IsAbs(dir) { + dir, err = filepath.Abs(dir) + if err != nil { + return nil, err + } + } + + return filepath.Glob(filepath.Join(dir, glob)) +} diff --git a/vendor/github.com/hashicorp/go-plugin/error.go b/vendor/github.com/hashicorp/go-plugin/error.go new file mode 100644 index 0000000..22a7baa --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/error.go @@ -0,0 +1,24 @@ +package plugin + +// This is a type that wraps error types so that they can be messaged +// across RPC channels. Since "error" is an interface, we can't always +// gob-encode the underlying structure. This is a valid error interface +// implementer that we will push across. +type BasicError struct { + Message string +} + +// NewBasicError is used to create a BasicError. +// +// err is allowed to be nil. +func NewBasicError(err error) *BasicError { + if err == nil { + return nil + } + + return &BasicError{err.Error()} +} + +func (e *BasicError) Error() string { + return e.Message +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.go b/vendor/github.com/hashicorp/go-plugin/grpc_broker.go new file mode 100644 index 0000000..49fd21c --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_broker.go @@ -0,0 +1,455 @@ +package plugin + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/oklog/run" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +// streamer interface is used in the broker to send/receive connection +// information. +type streamer interface { + Send(*ConnInfo) error + Recv() (*ConnInfo, error) + Close() +} + +// sendErr is used to pass errors back during a send. +type sendErr struct { + i *ConnInfo + ch chan error +} + +// gRPCBrokerServer is used by the plugin to start a stream and to send +// connection information to/from the plugin. Implements GRPCBrokerServer and +// streamer interfaces. +type gRPCBrokerServer struct { + // send is used to send connection info to the gRPC stream. + send chan *sendErr + + // recv is used to receive connection info from the gRPC stream. + recv chan *ConnInfo + + // quit closes down the stream. + quit chan struct{} + + // o is used to ensure we close the quit channel only once. + o sync.Once +} + +func newGRPCBrokerServer() *gRPCBrokerServer { + return &gRPCBrokerServer{ + send: make(chan *sendErr), + recv: make(chan *ConnInfo), + quit: make(chan struct{}), + } +} + +// StartStream implements the GRPCBrokerServer interface and will block until +// the quit channel is closed or the context reports Done. The stream will pass +// connection information to/from the client. +func (s *gRPCBrokerServer) StartStream(stream GRPCBroker_StartStreamServer) error { + doneCh := stream.Context().Done() + defer s.Close() + + // Proccess send stream + go func() { + for { + select { + case <-doneCh: + return + case <-s.quit: + return + case se := <-s.send: + err := stream.Send(se.i) + se.ch <- err + } + } + }() + + // Process receive stream + for { + i, err := stream.Recv() + if err != nil { + return err + } + select { + case <-doneCh: + return nil + case <-s.quit: + return nil + case s.recv <- i: + } + } + + return nil +} + +// Send is used by the GRPCBroker to pass connection information into the stream +// to the client. +func (s *gRPCBrokerServer) Send(i *ConnInfo) error { + ch := make(chan error) + defer close(ch) + + select { + case <-s.quit: + return errors.New("broker closed") + case s.send <- &sendErr{ + i: i, + ch: ch, + }: + } + + return <-ch +} + +// Recv is used by the GRPCBroker to pass connection information that has been +// sent from the client from the stream to the broker. +func (s *gRPCBrokerServer) Recv() (*ConnInfo, error) { + select { + case <-s.quit: + return nil, errors.New("broker closed") + case i := <-s.recv: + return i, nil + } +} + +// Close closes the quit channel, shutting down the stream. +func (s *gRPCBrokerServer) Close() { + s.o.Do(func() { + close(s.quit) + }) +} + +// gRPCBrokerClientImpl is used by the client to start a stream and to send +// connection information to/from the client. Implements GRPCBrokerClient and +// streamer interfaces. +type gRPCBrokerClientImpl struct { + // client is the underlying GRPC client used to make calls to the server. + client GRPCBrokerClient + + // send is used to send connection info to the gRPC stream. + send chan *sendErr + + // recv is used to receive connection info from the gRPC stream. + recv chan *ConnInfo + + // quit closes down the stream. + quit chan struct{} + + // o is used to ensure we close the quit channel only once. + o sync.Once +} + +func newGRPCBrokerClient(conn *grpc.ClientConn) *gRPCBrokerClientImpl { + return &gRPCBrokerClientImpl{ + client: NewGRPCBrokerClient(conn), + send: make(chan *sendErr), + recv: make(chan *ConnInfo), + quit: make(chan struct{}), + } +} + +// StartStream implements the GRPCBrokerClient interface and will block until +// the quit channel is closed or the context reports Done. The stream will pass +// connection information to/from the plugin. +func (s *gRPCBrokerClientImpl) StartStream() error { + ctx, cancelFunc := context.WithCancel(context.Background()) + defer cancelFunc() + defer s.Close() + + stream, err := s.client.StartStream(ctx) + if err != nil { + return err + } + doneCh := stream.Context().Done() + + go func() { + for { + select { + case <-doneCh: + return + case <-s.quit: + return + case se := <-s.send: + err := stream.Send(se.i) + se.ch <- err + } + } + }() + + for { + i, err := stream.Recv() + if err != nil { + return err + } + select { + case <-doneCh: + return nil + case <-s.quit: + return nil + case s.recv <- i: + } + } + + return nil +} + +// Send is used by the GRPCBroker to pass connection information into the stream +// to the plugin. +func (s *gRPCBrokerClientImpl) Send(i *ConnInfo) error { + ch := make(chan error) + defer close(ch) + + select { + case <-s.quit: + return errors.New("broker closed") + case s.send <- &sendErr{ + i: i, + ch: ch, + }: + } + + return <-ch +} + +// Recv is used by the GRPCBroker to pass connection information that has been +// sent from the plugin to the broker. +func (s *gRPCBrokerClientImpl) Recv() (*ConnInfo, error) { + select { + case <-s.quit: + return nil, errors.New("broker closed") + case i := <-s.recv: + return i, nil + } +} + +// Close closes the quit channel, shutting down the stream. +func (s *gRPCBrokerClientImpl) Close() { + s.o.Do(func() { + close(s.quit) + }) +} + +// GRPCBroker is responsible for brokering connections by unique ID. +// +// It is used by plugins to create multiple gRPC connections and data +// streams between the plugin process and the host process. +// +// This allows a plugin to request a channel with a specific ID to connect to +// or accept a connection from, and the broker handles the details of +// holding these channels open while they're being negotiated. +// +// The Plugin interface has access to these for both Server and Client. +// The broker can be used by either (optionally) to reserve and connect to +// new streams. This is useful for complex args and return values, +// or anything else you might need a data stream for. +type GRPCBroker struct { + nextId uint32 + streamer streamer + streams map[uint32]*gRPCBrokerPending + tls *tls.Config + doneCh chan struct{} + o sync.Once + + sync.Mutex +} + +type gRPCBrokerPending struct { + ch chan *ConnInfo + doneCh chan struct{} +} + +func newGRPCBroker(s streamer, tls *tls.Config) *GRPCBroker { + return &GRPCBroker{ + streamer: s, + streams: make(map[uint32]*gRPCBrokerPending), + tls: tls, + doneCh: make(chan struct{}), + } +} + +// Accept accepts a connection by ID. +// +// This should not be called multiple times with the same ID at one time. +func (b *GRPCBroker) Accept(id uint32) (net.Listener, error) { + listener, err := serverListener() + if err != nil { + return nil, err + } + + err = b.streamer.Send(&ConnInfo{ + ServiceId: id, + Network: listener.Addr().Network(), + Address: listener.Addr().String(), + }) + if err != nil { + return nil, err + } + + return listener, nil +} + +// AcceptAndServe is used to accept a specific stream ID and immediately +// serve a gRPC server on that stream ID. This is used to easily serve +// complex arguments. Each AcceptAndServe call opens a new listener socket and +// sends the connection info down the stream to the dialer. Since a new +// connection is opened every call, these calls should be used sparingly. +// Multiple gRPC server implementations can be registered to a single +// AcceptAndServe call. +func (b *GRPCBroker) AcceptAndServe(id uint32, s func([]grpc.ServerOption) *grpc.Server) { + listener, err := b.Accept(id) + if err != nil { + log.Printf("[ERR] plugin: plugin acceptAndServe error: %s", err) + return + } + defer listener.Close() + + var opts []grpc.ServerOption + if b.tls != nil { + opts = []grpc.ServerOption{grpc.Creds(credentials.NewTLS(b.tls))} + } + + server := s(opts) + + // Here we use a run group to close this goroutine if the server is shutdown + // or the broker is shutdown. + var g run.Group + { + // Serve on the listener, if shutting down call GracefulStop. + g.Add(func() error { + return server.Serve(listener) + }, func(err error) { + server.GracefulStop() + }) + } + { + // block on the closeCh or the doneCh. If we are shutting down close the + // closeCh. + closeCh := make(chan struct{}) + g.Add(func() error { + select { + case <-b.doneCh: + case <-closeCh: + } + return nil + }, func(err error) { + close(closeCh) + }) + } + + // Block until we are done + g.Run() +} + +// Close closes the stream and all servers. +func (b *GRPCBroker) Close() error { + b.streamer.Close() + b.o.Do(func() { + close(b.doneCh) + }) + return nil +} + +// Dial opens a connection by ID. +func (b *GRPCBroker) Dial(id uint32) (conn *grpc.ClientConn, err error) { + var c *ConnInfo + + // Open the stream + p := b.getStream(id) + select { + case c = <-p.ch: + close(p.doneCh) + case <-time.After(5 * time.Second): + return nil, fmt.Errorf("timeout waiting for connection info") + } + + var addr net.Addr + switch c.Network { + case "tcp": + addr, err = net.ResolveTCPAddr("tcp", c.Address) + case "unix": + addr, err = net.ResolveUnixAddr("unix", c.Address) + default: + err = fmt.Errorf("Unknown address type: %s", c.Address) + } + if err != nil { + return nil, err + } + + return dialGRPCConn(b.tls, netAddrDialer(addr)) +} + +// NextId returns a unique ID to use next. +// +// It is possible for very long-running plugin hosts to wrap this value, +// though it would require a very large amount of calls. In practice +// we've never seen it happen. +func (m *GRPCBroker) NextId() uint32 { + return atomic.AddUint32(&m.nextId, 1) +} + +// Run starts the brokering and should be executed in a goroutine, since it +// blocks forever, or until the session closes. +// +// Uses of GRPCBroker never need to call this. It is called internally by +// the plugin host/client. +func (m *GRPCBroker) Run() { + for { + stream, err := m.streamer.Recv() + if err != nil { + // Once we receive an error, just exit + break + } + + // Initialize the waiter + p := m.getStream(stream.ServiceId) + select { + case p.ch <- stream: + default: + } + + go m.timeoutWait(stream.ServiceId, p) + } +} + +func (m *GRPCBroker) getStream(id uint32) *gRPCBrokerPending { + m.Lock() + defer m.Unlock() + + p, ok := m.streams[id] + if ok { + return p + } + + m.streams[id] = &gRPCBrokerPending{ + ch: make(chan *ConnInfo, 1), + doneCh: make(chan struct{}), + } + return m.streams[id] +} + +func (m *GRPCBroker) timeoutWait(id uint32, p *gRPCBrokerPending) { + // Wait for the stream to either be picked up and connected, or + // for a timeout. + select { + case <-p.doneCh: + case <-time.After(5 * time.Second): + } + + m.Lock() + defer m.Unlock() + + // Delete the stream so no one else can grab it + delete(m.streams, id) +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go b/vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go new file mode 100644 index 0000000..d490daf --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go @@ -0,0 +1,190 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: grpc_broker.proto + +/* +Package plugin is a generated protocol buffer package. + +It is generated from these files: + grpc_broker.proto + +It has these top-level messages: + ConnInfo +*/ +package plugin + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type ConnInfo struct { + ServiceId uint32 `protobuf:"varint,1,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` + Network string `protobuf:"bytes,2,opt,name=network" json:"network,omitempty"` + Address string `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` +} + +func (m *ConnInfo) Reset() { *m = ConnInfo{} } +func (m *ConnInfo) String() string { return proto.CompactTextString(m) } +func (*ConnInfo) ProtoMessage() {} +func (*ConnInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *ConnInfo) GetServiceId() uint32 { + if m != nil { + return m.ServiceId + } + return 0 +} + +func (m *ConnInfo) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +func (m *ConnInfo) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func init() { + proto.RegisterType((*ConnInfo)(nil), "plugin.ConnInfo") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for GRPCBroker service + +type GRPCBrokerClient interface { + StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) +} + +type gRPCBrokerClient struct { + cc *grpc.ClientConn +} + +func NewGRPCBrokerClient(cc *grpc.ClientConn) GRPCBrokerClient { + return &gRPCBrokerClient{cc} +} + +func (c *gRPCBrokerClient) StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) { + stream, err := grpc.NewClientStream(ctx, &_GRPCBroker_serviceDesc.Streams[0], c.cc, "/plugin.GRPCBroker/StartStream", opts...) + if err != nil { + return nil, err + } + x := &gRPCBrokerStartStreamClient{stream} + return x, nil +} + +type GRPCBroker_StartStreamClient interface { + Send(*ConnInfo) error + Recv() (*ConnInfo, error) + grpc.ClientStream +} + +type gRPCBrokerStartStreamClient struct { + grpc.ClientStream +} + +func (x *gRPCBrokerStartStreamClient) Send(m *ConnInfo) error { + return x.ClientStream.SendMsg(m) +} + +func (x *gRPCBrokerStartStreamClient) Recv() (*ConnInfo, error) { + m := new(ConnInfo) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for GRPCBroker service + +type GRPCBrokerServer interface { + StartStream(GRPCBroker_StartStreamServer) error +} + +func RegisterGRPCBrokerServer(s *grpc.Server, srv GRPCBrokerServer) { + s.RegisterService(&_GRPCBroker_serviceDesc, srv) +} + +func _GRPCBroker_StartStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(GRPCBrokerServer).StartStream(&gRPCBrokerStartStreamServer{stream}) +} + +type GRPCBroker_StartStreamServer interface { + Send(*ConnInfo) error + Recv() (*ConnInfo, error) + grpc.ServerStream +} + +type gRPCBrokerStartStreamServer struct { + grpc.ServerStream +} + +func (x *gRPCBrokerStartStreamServer) Send(m *ConnInfo) error { + return x.ServerStream.SendMsg(m) +} + +func (x *gRPCBrokerStartStreamServer) Recv() (*ConnInfo, error) { + m := new(ConnInfo) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _GRPCBroker_serviceDesc = grpc.ServiceDesc{ + ServiceName: "plugin.GRPCBroker", + HandlerType: (*GRPCBrokerServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "StartStream", + Handler: _GRPCBroker_StartStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "grpc_broker.proto", +} + +func init() { proto.RegisterFile("grpc_broker.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 170 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4c, 0x2f, 0x2a, 0x48, + 0x8e, 0x4f, 0x2a, 0xca, 0xcf, 0x4e, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, + 0xc8, 0x29, 0x4d, 0xcf, 0xcc, 0x53, 0x8a, 0xe5, 0xe2, 0x70, 0xce, 0xcf, 0xcb, 0xf3, 0xcc, 0x4b, + 0xcb, 0x17, 0x92, 0xe5, 0xe2, 0x2a, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x8d, 0xcf, 0x4c, 0x91, + 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0xe2, 0x84, 0x8a, 0x78, 0xa6, 0x08, 0x49, 0x70, 0xb1, 0xe7, + 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0x4b, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xb8, 0x20, + 0x99, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x66, 0x88, 0x0c, 0x94, 0x6b, 0xe4, 0xcc, + 0xc5, 0xe5, 0x1e, 0x14, 0xe0, 0xec, 0x04, 0xb6, 0x5a, 0xc8, 0x94, 0x8b, 0x3b, 0xb8, 0x24, 0xb1, + 0xa8, 0x24, 0xb8, 0xa4, 0x28, 0x35, 0x31, 0x57, 0x48, 0x40, 0x0f, 0xe2, 0x08, 0x3d, 0x98, 0x0b, + 0xa4, 0x30, 0x44, 0x34, 0x18, 0x0d, 0x18, 0x93, 0xd8, 0xc0, 0x4e, 0x36, 0x06, 0x04, 0x00, 0x00, + 0xff, 0xff, 0x7b, 0x5d, 0xfb, 0xe1, 0xc7, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.proto b/vendor/github.com/hashicorp/go-plugin/grpc_broker.proto new file mode 100644 index 0000000..f578348 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_broker.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package plugin; + +message ConnInfo { + uint32 service_id = 1; + string network = 2; + string address = 3; +} + +service GRPCBroker { + rpc StartStream(stream ConnInfo) returns (stream ConnInfo); +} + + diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_client.go b/vendor/github.com/hashicorp/go-plugin/grpc_client.go new file mode 100644 index 0000000..44294d0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_client.go @@ -0,0 +1,107 @@ +package plugin + +import ( + "crypto/tls" + "fmt" + "net" + "time" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health/grpc_health_v1" +) + +func dialGRPCConn(tls *tls.Config, dialer func(string, time.Duration) (net.Conn, error)) (*grpc.ClientConn, error) { + // Build dialing options. + opts := make([]grpc.DialOption, 0, 5) + + // We use a custom dialer so that we can connect over unix domain sockets + opts = append(opts, grpc.WithDialer(dialer)) + + // go-plugin expects to block the connection + opts = append(opts, grpc.WithBlock()) + + // Fail right away + opts = append(opts, grpc.FailOnNonTempDialError(true)) + + // If we have no TLS configuration set, we need to explicitly tell grpc + // that we're connecting with an insecure connection. + if tls == nil { + opts = append(opts, grpc.WithInsecure()) + } else { + opts = append(opts, grpc.WithTransportCredentials( + credentials.NewTLS(tls))) + } + + // Connect. Note the first parameter is unused because we use a custom + // dialer that has the state to see the address. + conn, err := grpc.Dial("unused", opts...) + if err != nil { + return nil, err + } + + return conn, nil +} + +// newGRPCClient creates a new GRPCClient. The Client argument is expected +// to be successfully started already with a lock held. +func newGRPCClient(doneCtx context.Context, c *Client) (*GRPCClient, error) { + conn, err := dialGRPCConn(c.config.TLSConfig, c.dialer) + if err != nil { + return nil, err + } + + // Start the broker. + brokerGRPCClient := newGRPCBrokerClient(conn) + broker := newGRPCBroker(brokerGRPCClient, c.config.TLSConfig) + go broker.Run() + go brokerGRPCClient.StartStream() + + return &GRPCClient{ + Conn: conn, + Plugins: c.config.Plugins, + doneCtx: doneCtx, + broker: broker, + }, nil +} + +// GRPCClient connects to a GRPCServer over gRPC to dispense plugin types. +type GRPCClient struct { + Conn *grpc.ClientConn + Plugins map[string]Plugin + + doneCtx context.Context + broker *GRPCBroker +} + +// ClientProtocol impl. +func (c *GRPCClient) Close() error { + c.broker.Close() + return c.Conn.Close() +} + +// ClientProtocol impl. +func (c *GRPCClient) Dispense(name string) (interface{}, error) { + raw, ok := c.Plugins[name] + if !ok { + return nil, fmt.Errorf("unknown plugin type: %s", name) + } + + p, ok := raw.(GRPCPlugin) + if !ok { + return nil, fmt.Errorf("plugin %q doesn't support gRPC", name) + } + + return p.GRPCClient(c.doneCtx, c.broker, c.Conn) +} + +// ClientProtocol impl. +func (c *GRPCClient) Ping() error { + client := grpc_health_v1.NewHealthClient(c.Conn) + _, err := client.Check(context.Background(), &grpc_health_v1.HealthCheckRequest{ + Service: GRPCServiceName, + }) + + return err +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_server.go b/vendor/github.com/hashicorp/go-plugin/grpc_server.go new file mode 100644 index 0000000..3a72739 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_server.go @@ -0,0 +1,132 @@ +package plugin + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" +) + +// GRPCServiceName is the name of the service that the health check should +// return as passing. +const GRPCServiceName = "plugin" + +// DefaultGRPCServer can be used with the "GRPCServer" field for Server +// as a default factory method to create a gRPC server with no extra options. +func DefaultGRPCServer(opts []grpc.ServerOption) *grpc.Server { + return grpc.NewServer(opts...) +} + +// GRPCServer is a ServerType implementation that serves plugins over +// gRPC. This allows plugins to easily be written for other languages. +// +// The GRPCServer outputs a custom configuration as a base64-encoded +// JSON structure represented by the GRPCServerConfig config structure. +type GRPCServer struct { + // Plugins are the list of plugins to serve. + Plugins map[string]Plugin + + // Server is the actual server that will accept connections. This + // will be used for plugin registration as well. + Server func([]grpc.ServerOption) *grpc.Server + + // TLS should be the TLS configuration if available. If this is nil, + // the connection will not have transport security. + TLS *tls.Config + + // DoneCh is the channel that is closed when this server has exited. + DoneCh chan struct{} + + // Stdout/StderrLis are the readers for stdout/stderr that will be copied + // to the stdout/stderr connection that is output. + Stdout io.Reader + Stderr io.Reader + + config GRPCServerConfig + server *grpc.Server + broker *GRPCBroker +} + +// ServerProtocol impl. +func (s *GRPCServer) Init() error { + // Create our server + var opts []grpc.ServerOption + if s.TLS != nil { + opts = append(opts, grpc.Creds(credentials.NewTLS(s.TLS))) + } + s.server = s.Server(opts) + + // Register the health service + healthCheck := health.NewServer() + healthCheck.SetServingStatus( + GRPCServiceName, grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s.server, healthCheck) + + // Register the broker service + brokerServer := newGRPCBrokerServer() + RegisterGRPCBrokerServer(s.server, brokerServer) + s.broker = newGRPCBroker(brokerServer, s.TLS) + go s.broker.Run() + + // Register all our plugins onto the gRPC server. + for k, raw := range s.Plugins { + p, ok := raw.(GRPCPlugin) + if !ok { + return fmt.Errorf("%q is not a GRPC-compatible plugin", k) + } + + if err := p.GRPCServer(s.broker, s.server); err != nil { + return fmt.Errorf("error registring %q: %s", k, err) + } + } + + return nil +} + +// Stop calls Stop on the underlying grpc.Server +func (s *GRPCServer) Stop() { + s.server.Stop() +} + +// GracefulStop calls GracefulStop on the underlying grpc.Server +func (s *GRPCServer) GracefulStop() { + s.server.GracefulStop() +} + +// Config is the GRPCServerConfig encoded as JSON then base64. +func (s *GRPCServer) Config() string { + // Create a buffer that will contain our final contents + var buf bytes.Buffer + + // Wrap the base64 encoding with JSON encoding. + if err := json.NewEncoder(&buf).Encode(s.config); err != nil { + // We panic since ths shouldn't happen under any scenario. We + // carefully control the structure being encoded here and it should + // always be successful. + panic(err) + } + + return buf.String() +} + +func (s *GRPCServer) Serve(lis net.Listener) { + // Start serving in a goroutine + go s.server.Serve(lis) + + // Wait until graceful completion + <-s.DoneCh +} + +// GRPCServerConfig is the extra configuration passed along for consumers +// to facilitate using GRPC plugins. +type GRPCServerConfig struct { + StdoutAddr string `json:"stdout_addr"` + StderrAddr string `json:"stderr_addr"` +} diff --git a/vendor/github.com/hashicorp/go-plugin/log_entry.go b/vendor/github.com/hashicorp/go-plugin/log_entry.go new file mode 100644 index 0000000..2996c14 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/log_entry.go @@ -0,0 +1,73 @@ +package plugin + +import ( + "encoding/json" + "time" +) + +// logEntry is the JSON payload that gets sent to Stderr from the plugin to the host +type logEntry struct { + Message string `json:"@message"` + Level string `json:"@level"` + Timestamp time.Time `json:"timestamp"` + KVPairs []*logEntryKV `json:"kv_pairs"` +} + +// logEntryKV is a key value pair within the Output payload +type logEntryKV struct { + Key string `json:"key"` + Value interface{} `json:"value"` +} + +// flattenKVPairs is used to flatten KVPair slice into []interface{} +// for hclog consumption. +func flattenKVPairs(kvs []*logEntryKV) []interface{} { + var result []interface{} + for _, kv := range kvs { + result = append(result, kv.Key) + result = append(result, kv.Value) + } + + return result +} + +// parseJSON handles parsing JSON output +func parseJSON(input string) (*logEntry, error) { + var raw map[string]interface{} + entry := &logEntry{} + + err := json.Unmarshal([]byte(input), &raw) + if err != nil { + return nil, err + } + + // Parse hclog-specific objects + if v, ok := raw["@message"]; ok { + entry.Message = v.(string) + delete(raw, "@message") + } + + if v, ok := raw["@level"]; ok { + entry.Level = v.(string) + delete(raw, "@level") + } + + if v, ok := raw["@timestamp"]; ok { + t, err := time.Parse("2006-01-02T15:04:05.000000Z07:00", v.(string)) + if err != nil { + return nil, err + } + entry.Timestamp = t + delete(raw, "@timestamp") + } + + // Parse dynamic KV args from the hclog payload. + for k, v := range raw { + entry.KVPairs = append(entry.KVPairs, &logEntryKV{ + Key: k, + Value: v, + }) + } + + return entry, nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/mux_broker.go b/vendor/github.com/hashicorp/go-plugin/mux_broker.go new file mode 100644 index 0000000..01c45ad --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/mux_broker.go @@ -0,0 +1,204 @@ +package plugin + +import ( + "encoding/binary" + "fmt" + "log" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/yamux" +) + +// MuxBroker is responsible for brokering multiplexed connections by unique ID. +// +// It is used by plugins to multiplex multiple RPC connections and data +// streams on top of a single connection between the plugin process and the +// host process. +// +// This allows a plugin to request a channel with a specific ID to connect to +// or accept a connection from, and the broker handles the details of +// holding these channels open while they're being negotiated. +// +// The Plugin interface has access to these for both Server and Client. +// The broker can be used by either (optionally) to reserve and connect to +// new multiplexed streams. This is useful for complex args and return values, +// or anything else you might need a data stream for. +type MuxBroker struct { + nextId uint32 + session *yamux.Session + streams map[uint32]*muxBrokerPending + + sync.Mutex +} + +type muxBrokerPending struct { + ch chan net.Conn + doneCh chan struct{} +} + +func newMuxBroker(s *yamux.Session) *MuxBroker { + return &MuxBroker{ + session: s, + streams: make(map[uint32]*muxBrokerPending), + } +} + +// Accept accepts a connection by ID. +// +// This should not be called multiple times with the same ID at one time. +func (m *MuxBroker) Accept(id uint32) (net.Conn, error) { + var c net.Conn + p := m.getStream(id) + select { + case c = <-p.ch: + close(p.doneCh) + case <-time.After(5 * time.Second): + m.Lock() + defer m.Unlock() + delete(m.streams, id) + + return nil, fmt.Errorf("timeout waiting for accept") + } + + // Ack our connection + if err := binary.Write(c, binary.LittleEndian, id); err != nil { + c.Close() + return nil, err + } + + return c, nil +} + +// AcceptAndServe is used to accept a specific stream ID and immediately +// serve an RPC server on that stream ID. This is used to easily serve +// complex arguments. +// +// The served interface is always registered to the "Plugin" name. +func (m *MuxBroker) AcceptAndServe(id uint32, v interface{}) { + conn, err := m.Accept(id) + if err != nil { + log.Printf("[ERR] plugin: plugin acceptAndServe error: %s", err) + return + } + + serve(conn, "Plugin", v) +} + +// Close closes the connection and all sub-connections. +func (m *MuxBroker) Close() error { + return m.session.Close() +} + +// Dial opens a connection by ID. +func (m *MuxBroker) Dial(id uint32) (net.Conn, error) { + // Open the stream + stream, err := m.session.OpenStream() + if err != nil { + return nil, err + } + + // Write the stream ID onto the wire. + if err := binary.Write(stream, binary.LittleEndian, id); err != nil { + stream.Close() + return nil, err + } + + // Read the ack that we connected. Then we're off! + var ack uint32 + if err := binary.Read(stream, binary.LittleEndian, &ack); err != nil { + stream.Close() + return nil, err + } + if ack != id { + stream.Close() + return nil, fmt.Errorf("bad ack: %d (expected %d)", ack, id) + } + + return stream, nil +} + +// NextId returns a unique ID to use next. +// +// It is possible for very long-running plugin hosts to wrap this value, +// though it would require a very large amount of RPC calls. In practice +// we've never seen it happen. +func (m *MuxBroker) NextId() uint32 { + return atomic.AddUint32(&m.nextId, 1) +} + +// Run starts the brokering and should be executed in a goroutine, since it +// blocks forever, or until the session closes. +// +// Uses of MuxBroker never need to call this. It is called internally by +// the plugin host/client. +func (m *MuxBroker) Run() { + for { + stream, err := m.session.AcceptStream() + if err != nil { + // Once we receive an error, just exit + break + } + + // Read the stream ID from the stream + var id uint32 + if err := binary.Read(stream, binary.LittleEndian, &id); err != nil { + stream.Close() + continue + } + + // Initialize the waiter + p := m.getStream(id) + select { + case p.ch <- stream: + default: + } + + // Wait for a timeout + go m.timeoutWait(id, p) + } +} + +func (m *MuxBroker) getStream(id uint32) *muxBrokerPending { + m.Lock() + defer m.Unlock() + + p, ok := m.streams[id] + if ok { + return p + } + + m.streams[id] = &muxBrokerPending{ + ch: make(chan net.Conn, 1), + doneCh: make(chan struct{}), + } + return m.streams[id] +} + +func (m *MuxBroker) timeoutWait(id uint32, p *muxBrokerPending) { + // Wait for the stream to either be picked up and connected, or + // for a timeout. + timeout := false + select { + case <-p.doneCh: + case <-time.After(5 * time.Second): + timeout = true + } + + m.Lock() + defer m.Unlock() + + // Delete the stream so no one else can grab it + delete(m.streams, id) + + // If we timed out, then check if we have a channel in the buffer, + // and if so, close it. + if timeout { + select { + case s := <-p.ch: + s.Close() + } + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/plugin.go b/vendor/github.com/hashicorp/go-plugin/plugin.go new file mode 100644 index 0000000..79d9674 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/plugin.go @@ -0,0 +1,58 @@ +// The plugin package exposes functions and helpers for communicating to +// plugins which are implemented as standalone binary applications. +// +// plugin.Client fully manages the lifecycle of executing the application, +// connecting to it, and returning the RPC client for dispensing plugins. +// +// plugin.Serve fully manages listeners to expose an RPC server from a binary +// that plugin.Client can connect to. +package plugin + +import ( + "context" + "errors" + "net/rpc" + + "google.golang.org/grpc" +) + +// Plugin is the interface that is implemented to serve/connect to an +// inteface implementation. +type Plugin interface { + // Server should return the RPC server compatible struct to serve + // the methods that the Client calls over net/rpc. + Server(*MuxBroker) (interface{}, error) + + // Client returns an interface implementation for the plugin you're + // serving that communicates to the server end of the plugin. + Client(*MuxBroker, *rpc.Client) (interface{}, error) +} + +// GRPCPlugin is the interface that is implemented to serve/connect to +// a plugin over gRPC. +type GRPCPlugin interface { + // GRPCServer should register this plugin for serving with the + // given GRPCServer. Unlike Plugin.Server, this is only called once + // since gRPC plugins serve singletons. + GRPCServer(*GRPCBroker, *grpc.Server) error + + // GRPCClient should return the interface implementation for the plugin + // you're serving via gRPC. The provided context will be canceled by + // go-plugin in the event of the plugin process exiting. + GRPCClient(context.Context, *GRPCBroker, *grpc.ClientConn) (interface{}, error) +} + +// NetRPCUnsupportedPlugin implements Plugin but returns errors for the +// Server and Client functions. This will effectively disable support for +// net/rpc based plugins. +// +// This struct can be embedded in your struct. +type NetRPCUnsupportedPlugin struct{} + +func (p NetRPCUnsupportedPlugin) Server(*MuxBroker) (interface{}, error) { + return nil, errors.New("net/rpc plugin protocol not supported") +} + +func (p NetRPCUnsupportedPlugin) Client(*MuxBroker, *rpc.Client) (interface{}, error) { + return nil, errors.New("net/rpc plugin protocol not supported") +} diff --git a/vendor/github.com/hashicorp/go-plugin/process.go b/vendor/github.com/hashicorp/go-plugin/process.go new file mode 100644 index 0000000..88c999a --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process.go @@ -0,0 +1,24 @@ +package plugin + +import ( + "time" +) + +// pidAlive checks whether a pid is alive. +func pidAlive(pid int) bool { + return _pidAlive(pid) +} + +// pidWait blocks for a process to exit. +func pidWait(pid int) error { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for range ticker.C { + if !pidAlive(pid) { + break + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/process_posix.go b/vendor/github.com/hashicorp/go-plugin/process_posix.go new file mode 100644 index 0000000..70ba546 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process_posix.go @@ -0,0 +1,19 @@ +// +build !windows + +package plugin + +import ( + "os" + "syscall" +) + +// _pidAlive tests whether a process is alive or not by sending it Signal 0, +// since Go otherwise has no way to test this. +func _pidAlive(pid int) bool { + proc, err := os.FindProcess(pid) + if err == nil { + err = proc.Signal(syscall.Signal(0)) + } + + return err == nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/process_windows.go b/vendor/github.com/hashicorp/go-plugin/process_windows.go new file mode 100644 index 0000000..9f7b018 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process_windows.go @@ -0,0 +1,29 @@ +package plugin + +import ( + "syscall" +) + +const ( + // Weird name but matches the MSDN docs + exit_STILL_ACTIVE = 259 + + processDesiredAccess = syscall.STANDARD_RIGHTS_READ | + syscall.PROCESS_QUERY_INFORMATION | + syscall.SYNCHRONIZE +) + +// _pidAlive tests whether a process is alive or not +func _pidAlive(pid int) bool { + h, err := syscall.OpenProcess(processDesiredAccess, false, uint32(pid)) + if err != nil { + return false + } + + var ec uint32 + if e := syscall.GetExitCodeProcess(h, &ec); e != nil { + return false + } + + return ec == exit_STILL_ACTIVE +} diff --git a/vendor/github.com/hashicorp/go-plugin/protocol.go b/vendor/github.com/hashicorp/go-plugin/protocol.go new file mode 100644 index 0000000..0cfc19e --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/protocol.go @@ -0,0 +1,45 @@ +package plugin + +import ( + "io" + "net" +) + +// Protocol is an enum representing the types of protocols. +type Protocol string + +const ( + ProtocolInvalid Protocol = "" + ProtocolNetRPC Protocol = "netrpc" + ProtocolGRPC Protocol = "grpc" +) + +// ServerProtocol is an interface that must be implemented for new plugin +// protocols to be servers. +type ServerProtocol interface { + // Init is called once to configure and initialize the protocol, but + // not start listening. This is the point at which all validation should + // be done and errors returned. + Init() error + + // Config is extra configuration to be outputted to stdout. This will + // be automatically base64 encoded to ensure it can be parsed properly. + // This can be an empty string if additional configuration is not needed. + Config() string + + // Serve is called to serve connections on the given listener. This should + // continue until the listener is closed. + Serve(net.Listener) +} + +// ClientProtocol is an interface that must be implemented for new plugin +// protocols to be clients. +type ClientProtocol interface { + io.Closer + + // Dispense dispenses a new instance of the plugin with the given name. + Dispense(string) (interface{}, error) + + // Ping checks that the client connection is still healthy. + Ping() error +} diff --git a/vendor/github.com/hashicorp/go-plugin/rpc_client.go b/vendor/github.com/hashicorp/go-plugin/rpc_client.go new file mode 100644 index 0000000..f30a4b1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/rpc_client.go @@ -0,0 +1,170 @@ +package plugin + +import ( + "crypto/tls" + "fmt" + "io" + "net" + "net/rpc" + + "github.com/hashicorp/yamux" +) + +// RPCClient connects to an RPCServer over net/rpc to dispense plugin types. +type RPCClient struct { + broker *MuxBroker + control *rpc.Client + plugins map[string]Plugin + + // These are the streams used for the various stdout/err overrides + stdout, stderr net.Conn +} + +// newRPCClient creates a new RPCClient. The Client argument is expected +// to be successfully started already with a lock held. +func newRPCClient(c *Client) (*RPCClient, error) { + // Connect to the client + conn, err := net.Dial(c.address.Network(), c.address.String()) + if err != nil { + return nil, err + } + if tcpConn, ok := conn.(*net.TCPConn); ok { + // Make sure to set keep alive so that the connection doesn't die + tcpConn.SetKeepAlive(true) + } + + if c.config.TLSConfig != nil { + conn = tls.Client(conn, c.config.TLSConfig) + } + + // Create the actual RPC client + result, err := NewRPCClient(conn, c.config.Plugins) + if err != nil { + conn.Close() + return nil, err + } + + // Begin the stream syncing so that stdin, out, err work properly + err = result.SyncStreams( + c.config.SyncStdout, + c.config.SyncStderr) + if err != nil { + result.Close() + return nil, err + } + + return result, nil +} + +// NewRPCClient creates a client from an already-open connection-like value. +// Dial is typically used instead. +func NewRPCClient(conn io.ReadWriteCloser, plugins map[string]Plugin) (*RPCClient, error) { + // Create the yamux client so we can multiplex + mux, err := yamux.Client(conn, nil) + if err != nil { + conn.Close() + return nil, err + } + + // Connect to the control stream. + control, err := mux.Open() + if err != nil { + mux.Close() + return nil, err + } + + // Connect stdout, stderr streams + stdstream := make([]net.Conn, 2) + for i, _ := range stdstream { + stdstream[i], err = mux.Open() + if err != nil { + mux.Close() + return nil, err + } + } + + // Create the broker and start it up + broker := newMuxBroker(mux) + go broker.Run() + + // Build the client using our broker and control channel. + return &RPCClient{ + broker: broker, + control: rpc.NewClient(control), + plugins: plugins, + stdout: stdstream[0], + stderr: stdstream[1], + }, nil +} + +// SyncStreams should be called to enable syncing of stdout, +// stderr with the plugin. +// +// This will return immediately and the syncing will continue to happen +// in the background. You do not need to launch this in a goroutine itself. +// +// This should never be called multiple times. +func (c *RPCClient) SyncStreams(stdout io.Writer, stderr io.Writer) error { + go copyStream("stdout", stdout, c.stdout) + go copyStream("stderr", stderr, c.stderr) + return nil +} + +// Close closes the connection. The client is no longer usable after this +// is called. +func (c *RPCClient) Close() error { + // Call the control channel and ask it to gracefully exit. If this + // errors, then we save it so that we always return an error but we + // want to try to close the other channels anyways. + var empty struct{} + returnErr := c.control.Call("Control.Quit", true, &empty) + + // Close the other streams we have + if err := c.control.Close(); err != nil { + return err + } + if err := c.stdout.Close(); err != nil { + return err + } + if err := c.stderr.Close(); err != nil { + return err + } + if err := c.broker.Close(); err != nil { + return err + } + + // Return back the error we got from Control.Quit. This is very important + // since we MUST return non-nil error if this fails so that Client.Kill + // will properly try a process.Kill. + return returnErr +} + +func (c *RPCClient) Dispense(name string) (interface{}, error) { + p, ok := c.plugins[name] + if !ok { + return nil, fmt.Errorf("unknown plugin type: %s", name) + } + + var id uint32 + if err := c.control.Call( + "Dispenser.Dispense", name, &id); err != nil { + return nil, err + } + + conn, err := c.broker.Dial(id) + if err != nil { + return nil, err + } + + return p.Client(c.broker, rpc.NewClient(conn)) +} + +// Ping pings the connection to ensure it is still alive. +// +// The error from the RPC call is returned exactly if you want to inspect +// it for further error analysis. Any error returned from here would indicate +// that the connection to the plugin is not healthy. +func (c *RPCClient) Ping() error { + var empty struct{} + return c.control.Call("Control.Ping", true, &empty) +} diff --git a/vendor/github.com/hashicorp/go-plugin/rpc_server.go b/vendor/github.com/hashicorp/go-plugin/rpc_server.go new file mode 100644 index 0000000..5bb18dd --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/rpc_server.go @@ -0,0 +1,197 @@ +package plugin + +import ( + "errors" + "fmt" + "io" + "log" + "net" + "net/rpc" + "sync" + + "github.com/hashicorp/yamux" +) + +// RPCServer listens for network connections and then dispenses interface +// implementations over net/rpc. +// +// After setting the fields below, they shouldn't be read again directly +// from the structure which may be reading/writing them concurrently. +type RPCServer struct { + Plugins map[string]Plugin + + // Stdout, Stderr are what this server will use instead of the + // normal stdin/out/err. This is because due to the multi-process nature + // of our plugin system, we can't use the normal process values so we + // make our own custom one we pipe across. + Stdout io.Reader + Stderr io.Reader + + // DoneCh should be set to a non-nil channel that will be closed + // when the control requests the RPC server to end. + DoneCh chan<- struct{} + + lock sync.Mutex +} + +// ServerProtocol impl. +func (s *RPCServer) Init() error { return nil } + +// ServerProtocol impl. +func (s *RPCServer) Config() string { return "" } + +// ServerProtocol impl. +func (s *RPCServer) Serve(lis net.Listener) { + for { + conn, err := lis.Accept() + if err != nil { + log.Printf("[ERR] plugin: plugin server: %s", err) + return + } + + go s.ServeConn(conn) + } +} + +// ServeConn runs a single connection. +// +// ServeConn blocks, serving the connection until the client hangs up. +func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) { + // First create the yamux server to wrap this connection + mux, err := yamux.Server(conn, nil) + if err != nil { + conn.Close() + log.Printf("[ERR] plugin: error creating yamux server: %s", err) + return + } + + // Accept the control connection + control, err := mux.Accept() + if err != nil { + mux.Close() + if err != io.EOF { + log.Printf("[ERR] plugin: error accepting control connection: %s", err) + } + + return + } + + // Connect the stdstreams (in, out, err) + stdstream := make([]net.Conn, 2) + for i, _ := range stdstream { + stdstream[i], err = mux.Accept() + if err != nil { + mux.Close() + log.Printf("[ERR] plugin: accepting stream %d: %s", i, err) + return + } + } + + // Copy std streams out to the proper place + go copyStream("stdout", stdstream[0], s.Stdout) + go copyStream("stderr", stdstream[1], s.Stderr) + + // Create the broker and start it up + broker := newMuxBroker(mux) + go broker.Run() + + // Use the control connection to build the dispenser and serve the + // connection. + server := rpc.NewServer() + server.RegisterName("Control", &controlServer{ + server: s, + }) + server.RegisterName("Dispenser", &dispenseServer{ + broker: broker, + plugins: s.Plugins, + }) + server.ServeConn(control) +} + +// done is called internally by the control server to trigger the +// doneCh to close which is listened to by the main process to cleanly +// exit. +func (s *RPCServer) done() { + s.lock.Lock() + defer s.lock.Unlock() + + if s.DoneCh != nil { + close(s.DoneCh) + s.DoneCh = nil + } +} + +// dispenseServer dispenses variousinterface implementations for Terraform. +type controlServer struct { + server *RPCServer +} + +// Ping can be called to verify the connection (and likely the binary) +// is still alive to a plugin. +func (c *controlServer) Ping( + null bool, response *struct{}) error { + *response = struct{}{} + return nil +} + +func (c *controlServer) Quit( + null bool, response *struct{}) error { + // End the server + c.server.done() + + // Always return true + *response = struct{}{} + + return nil +} + +// dispenseServer dispenses variousinterface implementations for Terraform. +type dispenseServer struct { + broker *MuxBroker + plugins map[string]Plugin +} + +func (d *dispenseServer) Dispense( + name string, response *uint32) error { + // Find the function to create this implementation + p, ok := d.plugins[name] + if !ok { + return fmt.Errorf("unknown plugin type: %s", name) + } + + // Create the implementation first so we know if there is an error. + impl, err := p.Server(d.broker) + if err != nil { + // We turn the error into an errors error so that it works across RPC + return errors.New(err.Error()) + } + + // Reserve an ID for our implementation + id := d.broker.NextId() + *response = id + + // Run the rest in a goroutine since it can only happen once this RPC + // call returns. We wait for a connection for the plugin implementation + // and serve it. + go func() { + conn, err := d.broker.Accept(id) + if err != nil { + log.Printf("[ERR] go-plugin: plugin dispense error: %s: %s", name, err) + return + } + + serve(conn, "Plugin", impl) + }() + + return nil +} + +func serve(conn io.ReadWriteCloser, name string, v interface{}) { + server := rpc.NewServer() + if err := server.RegisterName(name, v); err != nil { + log.Printf("[ERR] go-plugin: plugin dispense error: %s", err) + return + } + + server.ServeConn(conn) +} diff --git a/vendor/github.com/hashicorp/go-plugin/server.go b/vendor/github.com/hashicorp/go-plugin/server.go new file mode 100644 index 0000000..1e808b9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/server.go @@ -0,0 +1,317 @@ +package plugin + +import ( + "crypto/tls" + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + "log" + "net" + "os" + "os/signal" + "runtime" + "strconv" + "sync/atomic" + + "github.com/hashicorp/go-hclog" + + "google.golang.org/grpc" +) + +// CoreProtocolVersion is the ProtocolVersion of the plugin system itself. +// We will increment this whenever we change any protocol behavior. This +// will invalidate any prior plugins but will at least allow us to iterate +// on the core in a safe way. We will do our best to do this very +// infrequently. +const CoreProtocolVersion = 1 + +// HandshakeConfig is the configuration used by client and servers to +// handshake before starting a plugin connection. This is embedded by +// both ServeConfig and ClientConfig. +// +// In practice, the plugin host creates a HandshakeConfig that is exported +// and plugins then can easily consume it. +type HandshakeConfig struct { + // ProtocolVersion is the version that clients must match on to + // agree they can communicate. This should match the ProtocolVersion + // set on ClientConfig when using a plugin. + ProtocolVersion uint + + // MagicCookieKey and value are used as a very basic verification + // that a plugin is intended to be launched. This is not a security + // measure, just a UX feature. If the magic cookie doesn't match, + // we show human-friendly output. + MagicCookieKey string + MagicCookieValue string +} + +// ServeConfig configures what sorts of plugins are served. +type ServeConfig struct { + // HandshakeConfig is the configuration that must match clients. + HandshakeConfig + + // TLSProvider is a function that returns a configured tls.Config. + TLSProvider func() (*tls.Config, error) + + // Plugins are the plugins that are served. + Plugins map[string]Plugin + + // GRPCServer should be non-nil to enable serving the plugins over + // gRPC. This is a function to create the server when needed with the + // given server options. The server options populated by go-plugin will + // be for TLS if set. You may modify the input slice. + // + // Note that the grpc.Server will automatically be registered with + // the gRPC health checking service. This is not optional since go-plugin + // relies on this to implement Ping(). + GRPCServer func([]grpc.ServerOption) *grpc.Server + + // Logger is used to pass a logger into the server. If none is provided the + // server will create a default logger. + Logger hclog.Logger +} + +// Protocol returns the protocol that this server should speak. +func (c *ServeConfig) Protocol() Protocol { + result := ProtocolNetRPC + if c.GRPCServer != nil { + result = ProtocolGRPC + } + + return result +} + +// Serve serves the plugins given by ServeConfig. +// +// Serve doesn't return until the plugin is done being executed. Any +// errors will be outputted to os.Stderr. +// +// This is the method that plugins should call in their main() functions. +func Serve(opts *ServeConfig) { + // Validate the handshake config + if opts.MagicCookieKey == "" || opts.MagicCookieValue == "" { + fmt.Fprintf(os.Stderr, + "Misconfigured ServeConfig given to serve this plugin: no magic cookie\n"+ + "key or value was set. Please notify the plugin author and report\n"+ + "this as a bug.\n") + os.Exit(1) + } + + // First check the cookie + if os.Getenv(opts.MagicCookieKey) != opts.MagicCookieValue { + fmt.Fprintf(os.Stderr, + "This binary is a plugin. These are not meant to be executed directly.\n"+ + "Please execute the program that consumes these plugins, which will\n"+ + "load any plugins automatically\n") + os.Exit(1) + } + + // Logging goes to the original stderr + log.SetOutput(os.Stderr) + + logger := opts.Logger + if logger == nil { + // internal logger to os.Stderr + logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: os.Stderr, + JSONFormat: true, + }) + } + + // Create our new stdout, stderr files. These will override our built-in + // stdout/stderr so that it works across the stream boundary. + stdout_r, stdout_w, err := os.Pipe() + if err != nil { + fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err) + os.Exit(1) + } + stderr_r, stderr_w, err := os.Pipe() + if err != nil { + fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err) + os.Exit(1) + } + + // Register a listener so we can accept a connection + listener, err := serverListener() + if err != nil { + logger.Error("plugin init error", "error", err) + return + } + + // Close the listener on return. We wrap this in a func() on purpose + // because the "listener" reference may change to TLS. + defer func() { + listener.Close() + }() + + var tlsConfig *tls.Config + if opts.TLSProvider != nil { + tlsConfig, err = opts.TLSProvider() + if err != nil { + logger.Error("plugin tls init", "error", err) + return + } + } + + // Create the channel to tell us when we're done + doneCh := make(chan struct{}) + + // Build the server type + var server ServerProtocol + switch opts.Protocol() { + case ProtocolNetRPC: + // If we have a TLS configuration then we wrap the listener + // ourselves and do it at that level. + if tlsConfig != nil { + listener = tls.NewListener(listener, tlsConfig) + } + + // Create the RPC server to dispense + server = &RPCServer{ + Plugins: opts.Plugins, + Stdout: stdout_r, + Stderr: stderr_r, + DoneCh: doneCh, + } + + case ProtocolGRPC: + // Create the gRPC server + server = &GRPCServer{ + Plugins: opts.Plugins, + Server: opts.GRPCServer, + TLS: tlsConfig, + Stdout: stdout_r, + Stderr: stderr_r, + DoneCh: doneCh, + } + + default: + panic("unknown server protocol: " + opts.Protocol()) + } + + // Initialize the servers + if err := server.Init(); err != nil { + logger.Error("protocol init", "error", err) + return + } + + // Build the extra configuration + extra := "" + if v := server.Config(); v != "" { + extra = base64.StdEncoding.EncodeToString([]byte(v)) + } + if extra != "" { + extra = "|" + extra + } + + logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String()) + + // Output the address and service name to stdout so that core can bring it up. + fmt.Printf("%d|%d|%s|%s|%s%s\n", + CoreProtocolVersion, + opts.ProtocolVersion, + listener.Addr().Network(), + listener.Addr().String(), + opts.Protocol(), + extra) + os.Stdout.Sync() + + // Eat the interrupts + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt) + go func() { + var count int32 = 0 + for { + <-ch + newCount := atomic.AddInt32(&count, 1) + logger.Debug("plugin received interrupt signal, ignoring", "count", newCount) + } + }() + + // Set our new out, err + os.Stdout = stdout_w + os.Stderr = stderr_w + + // Accept connections and wait for completion + go server.Serve(listener) + <-doneCh +} + +func serverListener() (net.Listener, error) { + if runtime.GOOS == "windows" { + return serverListener_tcp() + } + + return serverListener_unix() +} + +func serverListener_tcp() (net.Listener, error) { + minPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MIN_PORT"), 10, 32) + if err != nil { + return nil, err + } + + maxPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MAX_PORT"), 10, 32) + if err != nil { + return nil, err + } + + for port := minPort; port <= maxPort; port++ { + address := fmt.Sprintf("127.0.0.1:%d", port) + listener, err := net.Listen("tcp", address) + if err == nil { + return listener, nil + } + } + + return nil, errors.New("Couldn't bind plugin TCP listener") +} + +func serverListener_unix() (net.Listener, error) { + tf, err := ioutil.TempFile("", "plugin") + if err != nil { + return nil, err + } + path := tf.Name() + + // Close the file and remove it because it has to not exist for + // the domain socket. + if err := tf.Close(); err != nil { + return nil, err + } + if err := os.Remove(path); err != nil { + return nil, err + } + + l, err := net.Listen("unix", path) + if err != nil { + return nil, err + } + + // Wrap the listener in rmListener so that the Unix domain socket file + // is removed on close. + return &rmListener{ + Listener: l, + Path: path, + }, nil +} + +// rmListener is an implementation of net.Listener that forwards most +// calls to the listener but also removes a file as part of the close. We +// use this to cleanup the unix domain socket on close. +type rmListener struct { + net.Listener + Path string +} + +func (l *rmListener) Close() error { + // Close the listener itself + if err := l.Listener.Close(); err != nil { + return err + } + + // Remove the file + return os.Remove(l.Path) +} diff --git a/vendor/github.com/hashicorp/go-plugin/server_mux.go b/vendor/github.com/hashicorp/go-plugin/server_mux.go new file mode 100644 index 0000000..033079e --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/server_mux.go @@ -0,0 +1,31 @@ +package plugin + +import ( + "fmt" + "os" +) + +// ServeMuxMap is the type that is used to configure ServeMux +type ServeMuxMap map[string]*ServeConfig + +// ServeMux is like Serve, but serves multiple types of plugins determined +// by the argument given on the command-line. +// +// This command doesn't return until the plugin is done being executed. Any +// errors are logged or output to stderr. +func ServeMux(m ServeMuxMap) { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, + "Invoked improperly. This is an internal command that shouldn't\n"+ + "be manually invoked.\n") + os.Exit(1) + } + + opts, ok := m[os.Args[1]] + if !ok { + fmt.Fprintf(os.Stderr, "Unknown plugin: %s\n", os.Args[1]) + os.Exit(1) + } + + Serve(opts) +} diff --git a/vendor/github.com/hashicorp/go-plugin/stream.go b/vendor/github.com/hashicorp/go-plugin/stream.go new file mode 100644 index 0000000..1d547aa --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/stream.go @@ -0,0 +1,18 @@ +package plugin + +import ( + "io" + "log" +) + +func copyStream(name string, dst io.Writer, src io.Reader) { + if src == nil { + panic(name + ": src is nil") + } + if dst == nil { + panic(name + ": dst is nil") + } + if _, err := io.Copy(dst, src); err != nil && err != io.EOF { + log.Printf("[ERR] plugin: stream copy '%s' error: %s", name, err) + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/testing.go b/vendor/github.com/hashicorp/go-plugin/testing.go new file mode 100644 index 0000000..2f541d9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/testing.go @@ -0,0 +1,175 @@ +package plugin + +import ( + "bytes" + "context" + "io" + "net" + "net/rpc" + + "github.com/mitchellh/go-testing-interface" + "google.golang.org/grpc" +) + +// TestOptions allows specifying options that can affect the behavior of the +// test functions +type TestOptions struct { + //ServerStdout causes the given value to be used in place of a blank buffer + //for RPCServer's Stdout + ServerStdout io.ReadCloser + + //ServerStderr causes the given value to be used in place of a blank buffer + //for RPCServer's Stderr + ServerStderr io.ReadCloser +} + +// The testing file contains test helpers that you can use outside of +// this package for making it easier to test plugins themselves. + +// TestConn is a helper function for returning a client and server +// net.Conn connected to each other. +func TestConn(t testing.T) (net.Conn, net.Conn) { + // Listen to any local port. This listener will be closed + // after a single connection is established. + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %s", err) + } + + // Start a goroutine to accept our client connection + var serverConn net.Conn + doneCh := make(chan struct{}) + go func() { + defer close(doneCh) + defer l.Close() + var err error + serverConn, err = l.Accept() + if err != nil { + t.Fatalf("err: %s", err) + } + }() + + // Connect to the server + clientConn, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + t.Fatalf("err: %s", err) + } + + // Wait for the server side to acknowledge it has connected + <-doneCh + + return clientConn, serverConn +} + +// TestRPCConn returns a rpc client and server connected to each other. +func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) { + clientConn, serverConn := TestConn(t) + + server := rpc.NewServer() + go server.ServeConn(serverConn) + + client := rpc.NewClient(clientConn) + return client, server +} + +// TestPluginRPCConn returns a plugin RPC client and server that are connected +// together and configured. +func TestPluginRPCConn(t testing.T, ps map[string]Plugin, opts *TestOptions) (*RPCClient, *RPCServer) { + // Create two net.Conns we can use to shuttle our control connection + clientConn, serverConn := TestConn(t) + + // Start up the server + server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)} + if opts != nil { + if opts.ServerStdout != nil { + server.Stdout = opts.ServerStdout + } + if opts.ServerStderr != nil { + server.Stderr = opts.ServerStderr + } + } + go server.ServeConn(serverConn) + + // Connect the client to the server + client, err := NewRPCClient(clientConn, ps) + if err != nil { + t.Fatalf("err: %s", err) + } + + return client, server +} + +// TestGRPCConn returns a gRPC client conn and grpc server that are connected +// together and configured. The register function is used to register services +// prior to the Serve call. This is used to test gRPC connections. +func TestGRPCConn(t testing.T, register func(*grpc.Server)) (*grpc.ClientConn, *grpc.Server) { + // Create a listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %s", err) + } + + server := grpc.NewServer() + register(server) + go server.Serve(l) + + // Connect to the server + conn, err := grpc.Dial( + l.Addr().String(), + grpc.WithBlock(), + grpc.WithInsecure()) + if err != nil { + t.Fatalf("err: %s", err) + } + + // Connection successful, close the listener + l.Close() + + return conn, server +} + +// TestPluginGRPCConn returns a plugin gRPC client and server that are connected +// together and configured. This is used to test gRPC connections. +func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) { + // Create a listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %s", err) + } + + // Start up the server + server := &GRPCServer{ + Plugins: ps, + Server: DefaultGRPCServer, + Stdout: new(bytes.Buffer), + Stderr: new(bytes.Buffer), + } + if err := server.Init(); err != nil { + t.Fatalf("err: %s", err) + } + go server.Serve(l) + + // Connect to the server + conn, err := grpc.Dial( + l.Addr().String(), + grpc.WithBlock(), + grpc.WithInsecure()) + if err != nil { + t.Fatalf("err: %s", err) + } + + brokerGRPCClient := newGRPCBrokerClient(conn) + broker := newGRPCBroker(brokerGRPCClient, nil) + go broker.Run() + go brokerGRPCClient.StartStream() + + // Create the client + client := &GRPCClient{ + Conn: conn, + Plugins: ps, + broker: broker, + doneCtx: context.Background(), + } + + return client, server +} diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore new file mode 100644 index 0000000..caab963 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore @@ -0,0 +1,3 @@ +.idea/ +*.iml +*.test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml new file mode 100644 index 0000000..2df4e7d --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml @@ -0,0 +1,12 @@ +sudo: false + +language: go + +go: + - 1.8.1 + +branches: + only: + - master + +script: make updatedeps test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-retryablehttp/Makefile b/vendor/github.com/hashicorp/go-retryablehttp/Makefile new file mode 100644 index 0000000..da17640 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/Makefile @@ -0,0 +1,11 @@ +default: test + +test: + go vet ./... + go test -race ./... + +updatedeps: + go get -f -t -u ./... + go get -f -u ./... + +.PHONY: default test updatedeps diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md new file mode 100644 index 0000000..ccdc7e8 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/README.md @@ -0,0 +1,46 @@ +go-retryablehttp +================ + +[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis] +[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] + +[travis]: http://travis-ci.org/hashicorp/go-retryablehttp +[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp + +The `retryablehttp` package provides a familiar HTTP client interface with +automatic retries and exponential backoff. It is a thin wrapper over the +standard `net/http` client library and exposes nearly the same public API. This +makes `retryablehttp` very easy to drop into existing programs. + +`retryablehttp` performs automatic retries under certain conditions. Mainly, if +an error is returned by the client (connection errors, etc.), or if a 500-range +response code is received (except 501), then a retry is invoked after a wait +period. Otherwise, the response is returned and left to the caller to +interpret. + +The main difference from `net/http` is that requests which take a request body +(POST/PUT et. al) can have the body provided in a number of ways (some more or +less efficient) that allow "rewinding" the request body if the initial request +fails so that the full request can be attempted again. See the +[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more +details. + +Example Use +=========== + +Using this library should look almost identical to what you would do with +`net/http`. The most simple example of a GET request is shown below: + +```go +resp, err := retryablehttp.Get("/foo") +if err != nil { + panic(err) +} +``` + +The returned response object is an `*http.Response`, the same thing you would +usually get from `net/http`. Had the request failed one or more times, the above +call would block and retry with exponential backoff. + +For more usage and examples see the +[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp). diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go new file mode 100644 index 0000000..c016939 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -0,0 +1,487 @@ +// The retryablehttp package provides a familiar HTTP client interface with +// automatic retries and exponential backoff. It is a thin wrapper over the +// standard net/http client library and exposes nearly the same public API. +// This makes retryablehttp very easy to drop into existing programs. +// +// retryablehttp performs automatic retries under certain conditions. Mainly, if +// an error is returned by the client (connection errors etc), or if a 500-range +// response is received, then a retry is invoked. Otherwise, the response is +// returned and left to the caller to interpret. +// +// Requests which take a request body should provide a non-nil function +// parameter. The best choice is to provide either a function satisfying +// ReaderFunc which provides multiple io.Readers in an efficient manner, a +// *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte +// slice. As it is a reference type, and we will wrap it as needed by readers, +// we can efficiently re-use the request body without needing to copy it. If an +// io.Reader (such as a *bytes.Reader) is provided, the full body will be read +// prior to the first request, and will be efficiently re-used for any retries. +// ReadSeeker can be used, but some users have observed occasional data races +// between the net/http library and the Seek functionality of some +// implementations of ReadSeeker, so should be avoided if possible. +package retryablehttp + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "log" + "math" + "math/rand" + "net/http" + "net/url" + "os" + "strings" + "time" + + "github.com/hashicorp/go-cleanhttp" +) + +var ( + // Default retry configuration + defaultRetryWaitMin = 1 * time.Second + defaultRetryWaitMax = 30 * time.Second + defaultRetryMax = 4 + + // defaultClient is used for performing requests without explicitly making + // a new client. It is purposely private to avoid modifications. + defaultClient = NewClient() + + // We need to consume response bodies to maintain http connections, but + // limit the size we consume to respReadLimit. + respReadLimit = int64(4096) +) + +// ReaderFunc is the type of function that can be given natively to NewRequest +type ReaderFunc func() (io.Reader, error) + +// LenReader is an interface implemented by many in-memory io.Reader's. Used +// for automatically sending the right Content-Length header when possible. +type LenReader interface { + Len() int +} + +// Request wraps the metadata needed to create HTTP requests. +type Request struct { + // body is a seekable reader over the request body payload. This is + // used to rewind the request data in between retries. + body ReaderFunc + + // Embed an HTTP request directly. This makes a *Request act exactly + // like an *http.Request so that all meta methods are supported. + *http.Request +} + +// NewRequest creates a new wrapped request. +func NewRequest(method, url string, rawBody interface{}) (*Request, error) { + var err error + var body ReaderFunc + var contentLength int64 + + if rawBody != nil { + switch rawBody.(type) { + // If they gave us a function already, great! Use it. + case ReaderFunc: + body = rawBody.(ReaderFunc) + tmp, err := body() + if err != nil { + return nil, err + } + if lr, ok := tmp.(LenReader); ok { + contentLength = int64(lr.Len()) + } + if c, ok := tmp.(io.Closer); ok { + c.Close() + } + + case func() (io.Reader, error): + body = rawBody.(func() (io.Reader, error)) + tmp, err := body() + if err != nil { + return nil, err + } + if lr, ok := tmp.(LenReader); ok { + contentLength = int64(lr.Len()) + } + if c, ok := tmp.(io.Closer); ok { + c.Close() + } + + // If a regular byte slice, we can read it over and over via new + // readers + case []byte: + buf := rawBody.([]byte) + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + // If a bytes.Buffer we can read the underlying byte slice over and + // over + case *bytes.Buffer: + buf := rawBody.(*bytes.Buffer) + body = func() (io.Reader, error) { + return bytes.NewReader(buf.Bytes()), nil + } + contentLength = int64(buf.Len()) + + // We prioritize *bytes.Reader here because we don't really want to + // deal with it seeking so want it to match here instead of the + // io.ReadSeeker case. + case *bytes.Reader: + buf, err := ioutil.ReadAll(rawBody.(*bytes.Reader)) + if err != nil { + return nil, err + } + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + // Compat case + case io.ReadSeeker: + raw := rawBody.(io.ReadSeeker) + body = func() (io.Reader, error) { + raw.Seek(0, 0) + return ioutil.NopCloser(raw), nil + } + if lr, ok := raw.(LenReader); ok { + contentLength = int64(lr.Len()) + } + + // Read all in so we can reset + case io.Reader: + buf, err := ioutil.ReadAll(rawBody.(io.Reader)) + if err != nil { + return nil, err + } + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + default: + return nil, fmt.Errorf("cannot handle type %T", rawBody) + } + } + + httpReq, err := http.NewRequest(method, url, nil) + if err != nil { + return nil, err + } + httpReq.ContentLength = contentLength + + return &Request{body, httpReq}, nil +} + +// RequestLogHook allows a function to run before each retry. The HTTP +// request which will be made, and the retry number (0 for the initial +// request) are available to users. The internal logger is exposed to +// consumers. +type RequestLogHook func(*log.Logger, *http.Request, int) + +// ResponseLogHook is like RequestLogHook, but allows running a function +// on each HTTP response. This function will be invoked at the end of +// every HTTP request executed, regardless of whether a subsequent retry +// needs to be performed or not. If the response body is read or closed +// from this method, this will affect the response returned from Do(). +type ResponseLogHook func(*log.Logger, *http.Response) + +// CheckRetry specifies a policy for handling retries. It is called +// following each request with the response and error values returned by +// the http.Client. If CheckRetry returns false, the Client stops retrying +// and returns the response to the caller. If CheckRetry returns an error, +// that error value is returned in lieu of the error from the request. The +// Client will close any response body when retrying, but if the retry is +// aborted it is up to the CheckResponse callback to properly close any +// response body before returning. +type CheckRetry func(resp *http.Response, err error) (bool, error) + +// Backoff specifies a policy for how long to wait between retries. +// It is called after a failing request to determine the amount of time +// that should pass before trying again. +type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration + +// ErrorHandler is called if retries are expired, containing the last status +// from the http library. If not specified, default behavior for the library is +// to close the body and return an error indicating how many tries were +// attempted. If overriding this, be sure to close the body if needed. +type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error) + +// Client is used to make HTTP requests. It adds additional functionality +// like automatic retries to tolerate minor outages. +type Client struct { + HTTPClient *http.Client // Internal HTTP client. + Logger *log.Logger // Customer logger instance. + + RetryWaitMin time.Duration // Minimum time to wait + RetryWaitMax time.Duration // Maximum time to wait + RetryMax int // Maximum number of retries + + // RequestLogHook allows a user-supplied function to be called + // before each retry. + RequestLogHook RequestLogHook + + // ResponseLogHook allows a user-supplied function to be called + // with the response from each HTTP request executed. + ResponseLogHook ResponseLogHook + + // CheckRetry specifies the policy for handling retries, and is called + // after each request. The default policy is DefaultRetryPolicy. + CheckRetry CheckRetry + + // Backoff specifies the policy for how long to wait between retries + Backoff Backoff + + // ErrorHandler specifies the custom error handler to use, if any + ErrorHandler ErrorHandler +} + +// NewClient creates a new Client with default settings. +func NewClient() *Client { + return &Client{ + HTTPClient: cleanhttp.DefaultClient(), + Logger: log.New(os.Stderr, "", log.LstdFlags), + RetryWaitMin: defaultRetryWaitMin, + RetryWaitMax: defaultRetryWaitMax, + RetryMax: defaultRetryMax, + CheckRetry: DefaultRetryPolicy, + Backoff: DefaultBackoff, + } +} + +// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which +// will retry on connection errors and server errors. +func DefaultRetryPolicy(resp *http.Response, err error) (bool, error) { + if err != nil { + return true, err + } + // Check the response code. We retry on 500-range responses to allow + // the server time to recover, as 500's are typically not permanent + // errors and may relate to outages on the server side. This will catch + // invalid response codes as well, like 0 and 999. + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { + return true, nil + } + + return false, nil +} + +// DefaultBackoff provides a default callback for Client.Backoff which +// will perform exponential backoff based on the attempt number and limited +// by the provided minimum and maximum durations. +func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { + mult := math.Pow(2, float64(attemptNum)) * float64(min) + sleep := time.Duration(mult) + if float64(sleep) != mult || sleep > max { + sleep = max + } + return sleep +} + +// LinearJitterBackoff provides a callback for Client.Backoff which will +// perform linear backoff based on the attempt number and with jitter to +// prevent a thundering herd. +// +// min and max here are *not* absolute values. The number to be multipled by +// the attempt number will be chosen at random from between them, thus they are +// bounding the jitter. +// +// For instance: +// * To get strictly linear backoff of one second increasing each retry, set +// both to one second (1s, 2s, 3s, 4s, ...) +// * To get a small amount of jitter centered around one second increasing each +// retry, set to around one second, such as a min of 800ms and max of 1200ms +// (892ms, 2102ms, 2945ms, 4312ms, ...) +// * To get extreme jitter, set to a very wide spread, such as a min of 100ms +// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...) +func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { + // attemptNum always starts at zero but we want to start at 1 for multiplication + attemptNum++ + + if max <= min { + // Unclear what to do here, or they are the same, so return min * + // attemptNum + return min * time.Duration(attemptNum) + } + + // Seed rand; doing this every time is fine + rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + + // Pick a random number that lies somewhere between the min and max and + // multiply by the attemptNum. attemptNum starts at zero so we always + // increment here. We first get a random percentage, then apply that to the + // difference between min and max, and add to min. + jitter := rand.Float64() * float64(max-min) + jitterMin := int64(jitter) + int64(min) + return time.Duration(jitterMin * int64(attemptNum)) +} + +// PassthroughErrorHandler is an ErrorHandler that directly passes through the +// values from the net/http library for the final request. The body is not +// closed. +func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) { + return resp, err +} + +// Do wraps calling an HTTP method with retries. +func (c *Client) Do(req *Request) (*http.Response, error) { + if c.Logger != nil { + c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL) + } + + var resp *http.Response + var err error + + for i := 0; ; i++ { + var code int // HTTP response code + + // Always rewind the request body when non-nil. + if req.body != nil { + body, err := req.body() + if err != nil { + return resp, err + } + if c, ok := body.(io.ReadCloser); ok { + req.Request.Body = c + } else { + req.Request.Body = ioutil.NopCloser(body) + } + } + + if c.RequestLogHook != nil { + c.RequestLogHook(c.Logger, req.Request, i) + } + + // Attempt the request + resp, err = c.HTTPClient.Do(req.Request) + if resp != nil { + code = resp.StatusCode + } + + // Check if we should continue with retries. + checkOK, checkErr := c.CheckRetry(resp, err) + + if err != nil { + if c.Logger != nil { + c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) + } + } else { + // Call this here to maintain the behavior of logging all requests, + // even if CheckRetry signals to stop. + if c.ResponseLogHook != nil { + // Call the response logger function if provided. + c.ResponseLogHook(c.Logger, resp) + } + } + + // Now decide if we should continue. + if !checkOK { + if checkErr != nil { + err = checkErr + } + return resp, err + } + + // We do this before drainBody beause there's no need for the I/O if + // we're breaking out + remain := c.RetryMax - i + if remain <= 0 { + break + } + + // We're going to retry, consume any response to reuse the connection. + if err == nil && resp != nil { + c.drainBody(resp.Body) + } + + wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp) + desc := fmt.Sprintf("%s %s", req.Method, req.URL) + if code > 0 { + desc = fmt.Sprintf("%s (status: %d)", desc, code) + } + if c.Logger != nil { + c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) + } + time.Sleep(wait) + } + + if c.ErrorHandler != nil { + return c.ErrorHandler(resp, err, c.RetryMax+1) + } + + // By default, we close the response body and return an error without + // returning the response + if resp != nil { + resp.Body.Close() + } + return nil, fmt.Errorf("%s %s giving up after %d attempts", + req.Method, req.URL, c.RetryMax+1) +} + +// Try to read the response body so we can reuse this connection. +func (c *Client) drainBody(body io.ReadCloser) { + defer body.Close() + _, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit)) + if err != nil { + if c.Logger != nil { + c.Logger.Printf("[ERR] error reading response body: %v", err) + } + } +} + +// Get is a shortcut for doing a GET request without making a new client. +func Get(url string) (*http.Response, error) { + return defaultClient.Get(url) +} + +// Get is a convenience helper for doing simple GET requests. +func (c *Client) Get(url string) (*http.Response, error) { + req, err := NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + return c.Do(req) +} + +// Head is a shortcut for doing a HEAD request without making a new client. +func Head(url string) (*http.Response, error) { + return defaultClient.Head(url) +} + +// Head is a convenience method for doing simple HEAD requests. +func (c *Client) Head(url string) (*http.Response, error) { + req, err := NewRequest("HEAD", url, nil) + if err != nil { + return nil, err + } + return c.Do(req) +} + +// Post is a shortcut for doing a POST request without making a new client. +func Post(url, bodyType string, body interface{}) (*http.Response, error) { + return defaultClient.Post(url, bodyType, body) +} + +// Post is a convenience method for doing simple POST requests. +func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) { + req, err := NewRequest("POST", url, body) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", bodyType) + return c.Do(req) +} + +// PostForm is a shortcut to perform a POST with form data without creating +// a new client. +func PostForm(url string, data url.Values) (*http.Response, error) { + return defaultClient.PostForm(url, data) +} + +// PostForm is a convenience method for doing simple POST operations using +// pre-filled url.Values form data. +func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) { + return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) +} diff --git a/vendor/github.com/hashicorp/go-rootcerts/.travis.yml b/vendor/github.com/hashicorp/go-rootcerts/.travis.yml new file mode 100644 index 0000000..80e1de4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/.travis.yml @@ -0,0 +1,12 @@ +sudo: false + +language: go + +go: + - 1.6 + +branches: + only: + - master + +script: make test diff --git a/vendor/github.com/hashicorp/go-rootcerts/LICENSE b/vendor/github.com/hashicorp/go-rootcerts/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-rootcerts/Makefile b/vendor/github.com/hashicorp/go-rootcerts/Makefile new file mode 100644 index 0000000..c3989e7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/Makefile @@ -0,0 +1,8 @@ +TEST?=./... + +test: + go test $(TEST) $(TESTARGS) -timeout=3s -parallel=4 + go vet $(TEST) + go test $(TEST) -race + +.PHONY: test diff --git a/vendor/github.com/hashicorp/go-rootcerts/README.md b/vendor/github.com/hashicorp/go-rootcerts/README.md new file mode 100644 index 0000000..f5abffc --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/README.md @@ -0,0 +1,43 @@ +# rootcerts + +Functions for loading root certificates for TLS connections. + +----- + +Go's standard library `crypto/tls` provides a common mechanism for configuring +TLS connections in `tls.Config`. The `RootCAs` field on this struct is a pool +of certificates for the client to use as a trust store when verifying server +certificates. + +This library contains utility functions for loading certificates destined for +that field, as well as one other important thing: + +When the `RootCAs` field is `nil`, the standard library attempts to load the +host's root CA set. This behavior is OS-specific, and the Darwin +implementation contains [a bug that prevents trusted certificates from the +System and Login keychains from being loaded][1]. This library contains +Darwin-specific behavior that works around that bug. + +[1]: https://github.com/golang/go/issues/14514 + +## Example Usage + +Here's a snippet demonstrating how this library is meant to be used: + +```go +func httpClient() (*http.Client, error) + tlsConfig := &tls.Config{} + err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{ + CAFile: os.Getenv("MYAPP_CAFILE"), + CAPath: os.Getenv("MYAPP_CAPATH"), + }) + if err != nil { + return nil, err + } + c := cleanhttp.DefaultClient() + t := cleanhttp.DefaultTransport() + t.TLSClientConfig = tlsConfig + c.Transport = t + return c, nil +} +``` diff --git a/vendor/github.com/hashicorp/go-rootcerts/doc.go b/vendor/github.com/hashicorp/go-rootcerts/doc.go new file mode 100644 index 0000000..b55cc62 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/doc.go @@ -0,0 +1,9 @@ +// Package rootcerts contains functions to aid in loading CA certificates for +// TLS connections. +// +// In addition, its default behavior on Darwin works around an open issue [1] +// in Go's crypto/x509 that prevents certicates from being loaded from the +// System or Login keychains. +// +// [1] https://github.com/golang/go/issues/14514 +package rootcerts diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go new file mode 100644 index 0000000..aeb30ec --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go @@ -0,0 +1,103 @@ +package rootcerts + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +// Config determines where LoadCACerts will load certificates from. When both +// CAFile and CAPath are blank, this library's functions will either load +// system roots explicitly and return them, or set the CertPool to nil to allow +// Go's standard library to load system certs. +type Config struct { + // CAFile is a path to a PEM-encoded certificate file or bundle. Takes + // precedence over CAPath. + CAFile string + + // CAPath is a path to a directory populated with PEM-encoded certificates. + CAPath string +} + +// ConfigureTLS sets up the RootCAs on the provided tls.Config based on the +// Config specified. +func ConfigureTLS(t *tls.Config, c *Config) error { + if t == nil { + return nil + } + pool, err := LoadCACerts(c) + if err != nil { + return err + } + t.RootCAs = pool + return nil +} + +// LoadCACerts loads a CertPool based on the Config specified. +func LoadCACerts(c *Config) (*x509.CertPool, error) { + if c == nil { + c = &Config{} + } + if c.CAFile != "" { + return LoadCAFile(c.CAFile) + } + if c.CAPath != "" { + return LoadCAPath(c.CAPath) + } + + return LoadSystemCAs() +} + +// LoadCAFile loads a single PEM-encoded file from the path specified. +func LoadCAFile(caFile string) (*x509.CertPool, error) { + pool := x509.NewCertPool() + + pem, err := ioutil.ReadFile(caFile) + if err != nil { + return nil, fmt.Errorf("Error loading CA File: %s", err) + } + + ok := pool.AppendCertsFromPEM(pem) + if !ok { + return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", caFile) + } + + return pool, nil +} + +// LoadCAPath walks the provided path and loads all certificates encounted into +// a pool. +func LoadCAPath(caPath string) (*x509.CertPool, error) { + pool := x509.NewCertPool() + walkFn := func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + pem, err := ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("Error loading file from CAPath: %s", err) + } + + ok := pool.AppendCertsFromPEM(pem) + if !ok { + return fmt.Errorf("Error loading CA Path: Couldn't parse PEM in: %s", path) + } + + return nil + } + + err := filepath.Walk(caPath, walkFn) + if err != nil { + return nil, err + } + + return pool, nil +} diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go new file mode 100644 index 0000000..66b1472 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go @@ -0,0 +1,12 @@ +// +build !darwin + +package rootcerts + +import "crypto/x509" + +// LoadSystemCAs does nothing on non-Darwin systems. We return nil so that +// default behavior of standard TLS config libraries is triggered, which is to +// load system certs. +func LoadSystemCAs() (*x509.CertPool, error) { + return nil, nil +} diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go new file mode 100644 index 0000000..a9a0406 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go @@ -0,0 +1,48 @@ +package rootcerts + +import ( + "crypto/x509" + "os/exec" + "path" + + "github.com/mitchellh/go-homedir" +) + +// LoadSystemCAs has special behavior on Darwin systems to work around +func LoadSystemCAs() (*x509.CertPool, error) { + pool := x509.NewCertPool() + + for _, keychain := range certKeychains() { + err := addCertsFromKeychain(pool, keychain) + if err != nil { + return nil, err + } + } + + return pool, nil +} + +func addCertsFromKeychain(pool *x509.CertPool, keychain string) error { + cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", keychain) + data, err := cmd.Output() + if err != nil { + return err + } + + pool.AppendCertsFromPEM(data) + + return nil +} + +func certKeychains() []string { + keychains := []string{ + "/System/Library/Keychains/SystemRootCertificates.keychain", + "/Library/Keychains/System.keychain", + } + home, err := homedir.Dir() + if err == nil { + loginKeychain := path.Join(home, "Library", "Keychains", "login.keychain") + keychains = append(keychains, loginKeychain) + } + return keychains +} diff --git a/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/securetrust.pem b/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/securetrust.pem new file mode 120000 index 0000000..dda0574 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/securetrust.pem @@ -0,0 +1 @@ +../capath/securetrust.pem \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/thawte.pem b/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/thawte.pem new file mode 120000 index 0000000..37ed4f0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath-with-symlinks/thawte.pem @@ -0,0 +1 @@ +../capath/thawte.pem \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-sockaddr/.gitignore b/vendor/github.com/hashicorp/go-sockaddr/.gitignore new file mode 100644 index 0000000..41720b8 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +.cover.out* +coverage.html diff --git a/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile new file mode 100644 index 0000000..f3dfd24 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile @@ -0,0 +1,65 @@ +TOOLS= golang.org/x/tools/cover +GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp +GOCOVER_FILE?= .cover.out +GOCOVERHTML?= coverage.html +FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1` +XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1` + +test:: $(GOCOVER_FILE) + @$(MAKE) -C cmd/sockaddr test + +cover:: coverage_report + +$(GOCOVER_FILE):: + @${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)" + + @echo 'mode: set' > $(GOCOVER_FILE) + @${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE) + +$(GOCOVERHTML): $(GOCOVER_FILE) + go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML) + +coverage_report:: $(GOCOVER_FILE) + go tool cover -html=$(GOCOVER_FILE) + +audit_tools:: + @go get -u github.com/golang/lint/golint && echo "Installed golint:" + @go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:" + @go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:" + @go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:" + @go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:" + +audit:: + deadcode + go tool vet -all *.go + go tool vet -shadow=true *.go + golint *.go + ineffassign . + gocyclo -over 65 *.go + misspell *.go + +clean:: + rm -f $(GOCOVER_FILE) $(GOCOVERHTML) + +dev:: + @go build + @$(MAKE) -B -C cmd/sockaddr sockaddr + +install:: + @go install + @$(MAKE) -C cmd/sockaddr install + +doc:: + @echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/ + godoc -http=:6161 -goroot $GOROOT + +world:: + @set -e; \ + for os in solaris darwin freebsd linux windows; do \ + for arch in amd64; do \ + printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \ + env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \ + done; \ + done + + $(MAKE) -C cmd/sockaddr world diff --git a/vendor/github.com/hashicorp/go-sockaddr/LICENSE b/vendor/github.com/hashicorp/go-sockaddr/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-sockaddr/README.md b/vendor/github.com/hashicorp/go-sockaddr/README.md new file mode 100644 index 0000000..a2e170a --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/README.md @@ -0,0 +1,118 @@ +# go-sockaddr + +## `sockaddr` Library + +Socket address convenience functions for Go. `go-sockaddr` is a convenience +library that makes doing the right thing with IP addresses easy. `go-sockaddr` +is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family +of `sockaddr_t` types (see below for an ascii diagram). Library documentation +is available +at +[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr). +The primary intent of the library was to make it possible to define heuristics +for selecting the correct IP addresses when a configuration is evaluated at +runtime. See +the +[docs](https://godoc.org/github.com/hashicorp/go-sockaddr), +[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template), +tests, +and +[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr) +for details and hints as to how to use this library. + +For example, with this library it is possible to find an IP address that: + +* is attached to a default route + ([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces)) +* is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork)) +* is an RFC1918 address + ([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC)) +* is ordered + ([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where + `args` includes, but is not limited + to, + [`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType), + [`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize)) +* excludes all IPv6 addresses + ([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType)) +* is larger than a `/32` + ([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize)) +* is not on a `down` interface + ([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs)) +* preferences an IPv6 address over an IPv4 address + ([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) + + [`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and +* excludes any IP in RFC6890 address + ([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC)) + +Or any combination or variation therein. + +There are also a few simple helper functions such as `GetPublicIP` and +`GetPrivateIP` which both return strings and select the first public or private +IP address on the default interface, respectively. Similarly, there is also a +helper function called `GetInterfaceIP` which returns the first usable IP +address on the named interface. + +## `sockaddr` CLI + +Given the possible complexity of the `sockaddr` library, there is a CLI utility +that accompanies the library, also +called +[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr). +The +[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr) +utility exposes nearly all of the functionality of the library and can be used +either as an administrative tool or testing tool. To install +the +[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr), +run: + +```text +$ go get -u github.com/hashicorp/go-sockaddr/cmd/sockaddr +``` + +If you're familiar with UNIX's `sockaddr` struct's, the following diagram +mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and +interfaces will be helpful: + +``` ++-------------------------------------------------------+ +| | +| sockaddr | +| SockAddr | +| | +| +--------------+ +----------------------------------+ | +| | sockaddr_un | | | | +| | SockAddrUnix | | sockaddr_in{,6} | | +| +--------------+ | IPAddr | | +| | | | +| | +-------------+ +--------------+ | | +| | | sockaddr_in | | sockaddr_in6 | | | +| | | IPv4Addr | | IPv6Addr | | | +| | +-------------+ +--------------+ | | +| | | | +| +----------------------------------+ | +| | ++-------------------------------------------------------+ +``` + +## Inspiration and Design + +There were many subtle inspirations that led to this design, but the most direct +inspiration for the filtering syntax was +OpenBSD's +[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall +syntax that lets you select the first IP address on a given named interface. +The original problem stemmed from: + +* needing to create immutable images using [Packer](https://www.packer.io) that + ran the [Consul](https://www.consul.io) process (Consul can only use one IP + address at a time); +* images that may or may not have multiple interfaces or IP addresses at + runtime; and +* we didn't want to rely on configuration management to render out the correct + IP address if the VM image was being used in an auto-scaling group. + +Instead we needed some way to codify a heuristic that would correctly select the +right IP address but the input parameters were not known when the image was +created. diff --git a/vendor/github.com/hashicorp/go-sockaddr/doc.go b/vendor/github.com/hashicorp/go-sockaddr/doc.go new file mode 100644 index 0000000..90671de --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/doc.go @@ -0,0 +1,5 @@ +/* +Package sockaddr is a Go implementation of the UNIX socket family data types and +related helper functions. +*/ +package sockaddr diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go new file mode 100644 index 0000000..0811b27 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go @@ -0,0 +1,254 @@ +package sockaddr + +import "strings" + +// ifAddrAttrMap is a map of the IfAddr type-specific attributes. +var ifAddrAttrMap map[AttrName]func(IfAddr) string +var ifAddrAttrs []AttrName + +func init() { + ifAddrAttrInit() +} + +// GetPrivateIP returns a string with a single IP address that is part of RFC +// 6890 and has a default route. If the system can't determine its IP address +// or find an RFC 6890 IP address, an empty string will be returned instead. +// This function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}' +/// ``` +func GetPrivateIP() (string, error) { + privateIfs, err := GetPrivateInterfaces() + if err != nil { + return "", err + } + if len(privateIfs) < 1 { + return "", nil + } + + ifAddr := privateIfs[0] + ip := *ToIPAddr(ifAddr.SockAddr) + return ip.NetIP().String(), nil +} + +// GetPrivateIPs returns a string with all IP addresses that are part of RFC +// 6890 (regardless of whether or not there is a default route, unlike +// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty +// string will be returned instead. This function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}' +/// ``` +func GetPrivateIPs() (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } else if len(ifAddrs) < 1 { + return "", nil + } + + ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) + if len(ifAddrs) == 0 { + return "", nil + } + + OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) + + ifAddrs, _, err = IfByRFC("6890", ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + +// GetPublicIP returns a string with a single IP address that is NOT part of RFC +// 6890 and has a default route. If the system can't determine its IP address +// or find a non RFC 6890 IP address, an empty string will be returned instead. +// This function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}' +/// ``` +func GetPublicIP() (string, error) { + publicIfs, err := GetPublicInterfaces() + if err != nil { + return "", err + } else if len(publicIfs) < 1 { + return "", nil + } + + ifAddr := publicIfs[0] + ip := *ToIPAddr(ifAddr.SockAddr) + return ip.NetIP().String(), nil +} + +// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC +// 6890 (regardless of whether or not there is a default route, unlike +// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an +// empty string will be returned instead. This function is the `eval` +// equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}' +/// ``` +func GetPublicIPs() (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } else if len(ifAddrs) < 1 { + return "", nil + } + + ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) + if len(ifAddrs) == 0 { + return "", nil + } + + OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) + + _, ifAddrs, err = IfByRFC("6890", ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + +// GetInterfaceIP returns a string with a single IP address sorted by the size +// of the network (i.e. IP addresses with a smaller netmask, larger network +// size, are sorted first). This function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | include "flag" "forwardable" | attr "address" }}' +/// ``` +func GetInterfaceIP(namedIfRE string) (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } + + ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) + if err != nil { + return "", err + } + + ifAddrs, _, err = IfByFlag("forwardable", ifAddrs) + if err != nil { + return "", err + } + + ifAddrs, err = SortIfBy("+type,+size", ifAddrs) + if err != nil { + return "", err + } + + if len(ifAddrs) == 0 { + return "", err + } + + ip := ToIPAddr(ifAddrs[0].SockAddr) + if ip == nil { + return "", err + } + + return IPAddrAttr(*ip, "address"), nil +} + +// GetInterfaceIPs returns a string with all IPs, sorted by the size of the +// network (i.e. IP addresses with a smaller netmask, larger network size, are +// sorted first), on a named interface. This function is the `eval` equivalent +// of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}' +/// ``` +func GetInterfaceIPs(namedIfRE string) (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } + + ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) + if err != nil { + return "", err + } + + ifAddrs, err = SortIfBy("+type,+size", ifAddrs) + if err != nil { + return "", err + } + + if len(ifAddrs) == 0 { + return "", err + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + +// IfAddrAttrs returns a list of attributes supported by the IfAddr type +func IfAddrAttrs() []AttrName { + return ifAddrAttrs +} + +// IfAddrAttr returns a string representation of an attribute for the given +// IfAddr. +func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string { + fn, found := ifAddrAttrMap[attrName] + if !found { + return "" + } + + return fn(ifAddr) +} + +// ifAddrAttrInit is called once at init() +func ifAddrAttrInit() { + // Sorted for human readability + ifAddrAttrs = []AttrName{ + "flags", + "name", + } + + ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{ + "flags": func(ifAddr IfAddr) string { + return ifAddr.Interface.Flags.String() + }, + "name": func(ifAddr IfAddr) string { + return ifAddr.Interface.Name + }, + } +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go new file mode 100644 index 0000000..2a706c3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go @@ -0,0 +1,1281 @@ +package sockaddr + +import ( + "encoding/binary" + "errors" + "fmt" + "math/big" + "net" + "regexp" + "sort" + "strconv" + "strings" +) + +var ( + // Centralize all regexps and regexp.Copy() where necessary. + signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`) + whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`) + ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`) + ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) +) + +// IfAddrs is a slice of IfAddr +type IfAddrs []IfAddr + +func (ifs IfAddrs) Len() int { return len(ifs) } + +// CmpIfFunc is the function signature that must be met to be used in the +// OrderedIfAddrBy multiIfAddrSorter +type CmpIfAddrFunc func(p1, p2 *IfAddr) int + +// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within. +type multiIfAddrSorter struct { + ifAddrs IfAddrs + cmp []CmpIfAddrFunc +} + +// Sort sorts the argument slice according to the Cmp functions passed to +// OrderedIfAddrBy. +func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) { + ms.ifAddrs = ifAddrs + sort.Sort(ms) +} + +// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers. +func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter { + return &multiIfAddrSorter{ + cmp: cmpFuncs, + } +} + +// Len is part of sort.Interface. +func (ms *multiIfAddrSorter) Len() int { + return len(ms.ifAddrs) +} + +// Less is part of sort.Interface. It is implemented by looping along the Cmp() +// functions until it finds a comparison that is either less than or greater +// than. A return value of 0 defers sorting to the next function in the +// multisorter (which means the results of sorting may leave the resutls in a +// non-deterministic order). +func (ms *multiIfAddrSorter) Less(i, j int) bool { + p, q := &ms.ifAddrs[i], &ms.ifAddrs[j] + // Try all but the last comparison. + var k int + for k = 0; k < len(ms.cmp)-1; k++ { + cmp := ms.cmp[k] + x := cmp(p, q) + switch x { + case -1: + // p < q, so we have a decision. + return true + case 1: + // p > q, so we have a decision. + return false + } + // p == q; try the next comparison. + } + // All comparisons to here said "equal", so just return whatever the + // final comparison reports. + switch ms.cmp[k](p, q) { + case -1: + return true + case 1: + return false + default: + // Still a tie! Now what? + return false + panic("undefined sort order for remaining items in the list") + } +} + +// Swap is part of sort.Interface. +func (ms *multiIfAddrSorter) Swap(i, j int) { + ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i] +} + +// AscIfAddress is a sorting function to sort IfAddrs by their respective +// address type. Non-equal types are deferred in the sort. +func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int { + return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// AscIfDefault is a sorting function to sort IfAddrs by whether or not they +// have a default route or not. Non-equal types are deferred in the sort. +// +// FIXME: This is a particularly expensive sorting operation because of the +// non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data +// once at the start of the sort and pass it along as a context or by wrapping +// the IfAddr type with this information (this would also solve the inability to +// return errors and the possibility of failing silently). Fortunately, +// N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth +// optimizing today. The common case is this gets called once or twice. +// Patches welcome. +func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int { + ri, err := NewRouteInfo() + if err != nil { + return sortDeferDecision + } + + defaultIfName, err := ri.GetDefaultInterfaceName() + if err != nil { + return sortDeferDecision + } + + switch { + case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName: + return sortDeferDecision + case p1Ptr.Interface.Name == defaultIfName: + return sortReceiverBeforeArg + case p2Ptr.Interface.Name == defaultIfName: + return sortArgBeforeReceiver + default: + return sortDeferDecision + } +} + +// AscIfName is a sorting function to sort IfAddrs by their interface names. +func AscIfName(p1Ptr, p2Ptr *IfAddr) int { + return strings.Compare(p1Ptr.Name, p2Ptr.Name) +} + +// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective +// network mask size. +func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { + return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// AscIfPort is a sorting function to sort IfAddrs by their respective +// port type. Non-equal types are deferred in the sort. +func AscIfPort(p1Ptr, p2Ptr *IfAddr) int { + return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before +// "public" values. Both IPv4 and IPv6 are compared against RFC6890 (RFC6890 +// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6 +// includes RFC4193). +func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int { + return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// AscIfType is a sorting function to sort IfAddrs by their respective address +// type. Non-equal types are deferred in the sort. +func AscIfType(p1Ptr, p2Ptr *IfAddr) int { + return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// DescIfAddress is identical to AscIfAddress but reverse ordered. +func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// DescIfDefault is identical to AscIfDefault but reverse ordered. +func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscIfDefault(p1Ptr, p2Ptr) +} + +// DescIfName is identical to AscIfName but reverse ordered. +func DescIfName(p1Ptr, p2Ptr *IfAddr) int { + return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name) +} + +// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered. +func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// DescIfPort is identical to AscIfPort but reverse ordered. +func DescIfPort(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// DescIfPrivate is identical to AscIfPrivate but reverse ordered. +func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// DescIfType is identical to AscIfType but reverse ordered. +func DescIfType(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) +} + +// FilterIfByType filters IfAddrs and returns a list of the matching type +func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) { + excludedIfs = make(IfAddrs, 0, len(ifAddrs)) + matchedIfs = make(IfAddrs, 0, len(ifAddrs)) + + for _, ifAddr := range ifAddrs { + if ifAddr.SockAddr.Type()&type_ != 0 { + matchedIfs = append(matchedIfs, ifAddr) + } else { + excludedIfs = append(excludedIfs, ifAddr) + } + } + return matchedIfs, excludedIfs +} + +// IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is +// more than one IfAddr, only the first IfAddr is used. +func IfAttr(selectorName string, ifAddr IfAddr) (string, error) { + attrName := AttrName(strings.ToLower(selectorName)) + attrVal, err := ifAddr.Attr(attrName) + return attrVal, err +} + +// IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is +// more than one IfAddr, only the first IfAddr is used. +func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) { + if len(ifAddrs) == 0 { + return "", nil + } + + attrName := AttrName(strings.ToLower(selectorName)) + attrVal, err := ifAddrs[0].Attr(attrName) + return attrVal, err +} + +// GetAllInterfaces iterates over all available network interfaces and finds all +// available IP addresses on each interface and converts them to +// sockaddr.IPAddrs, and returning the result as an array of IfAddr. +func GetAllInterfaces() (IfAddrs, error) { + ifs, err := net.Interfaces() + if err != nil { + return nil, err + } + + ifAddrs := make(IfAddrs, 0, len(ifs)) + for _, intf := range ifs { + addrs, err := intf.Addrs() + if err != nil { + return nil, err + } + + for _, addr := range addrs { + var ipAddr IPAddr + ipAddr, err = NewIPAddr(addr.String()) + if err != nil { + return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String()) + } + + ifAddr := IfAddr{ + SockAddr: ipAddr, + Interface: intf, + } + ifAddrs = append(ifAddrs, ifAddr) + } + } + + return ifAddrs, nil +} + +// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default +// route. +func GetDefaultInterfaces() (IfAddrs, error) { + ri, err := NewRouteInfo() + if err != nil { + return nil, err + } + + defaultIfName, err := ri.GetDefaultInterfaceName() + if err != nil { + return nil, err + } + + var defaultIfs, ifAddrs IfAddrs + ifAddrs, err = GetAllInterfaces() + for _, ifAddr := range ifAddrs { + if ifAddr.Name == defaultIfName { + defaultIfs = append(defaultIfs, ifAddr) + } + } + + return defaultIfs, nil +} + +// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a +// default route. If the system can't determine its IP address or find an RFC +// 6890 IP address, an empty IfAddrs will be returned instead. This function is +// the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}' +/// ``` +func GetPrivateInterfaces() (IfAddrs, error) { + privateIfs, err := GetAllInterfaces() + if err != nil { + return IfAddrs{}, err + } + if len(privateIfs) == 0 { + return IfAddrs{}, nil + } + + privateIfs, _ = FilterIfByType(privateIfs, TypeIP) + if len(privateIfs) == 0 { + return IfAddrs{}, nil + } + + privateIfs, _, err = IfByFlag("forwardable", privateIfs) + if err != nil { + return IfAddrs{}, err + } + + privateIfs, _, err = IfByFlag("up", privateIfs) + if err != nil { + return IfAddrs{}, err + } + + if len(privateIfs) == 0 { + return IfAddrs{}, nil + } + + OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs) + + privateIfs, _, err = IfByRFC("6890", privateIfs) + if err != nil { + return IfAddrs{}, err + } else if len(privateIfs) == 0 { + return IfAddrs{}, nil + } + + return privateIfs, nil +} + +// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a +// default route. If the system can't determine its IP address or find a non +// RFC 6890 IP address, an empty IfAddrs will be returned instead. This +// function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}' +/// ``` +func GetPublicInterfaces() (IfAddrs, error) { + publicIfs, err := GetAllInterfaces() + if err != nil { + return IfAddrs{}, err + } + if len(publicIfs) == 0 { + return IfAddrs{}, nil + } + + publicIfs, _ = FilterIfByType(publicIfs, TypeIP) + if len(publicIfs) == 0 { + return IfAddrs{}, nil + } + + publicIfs, _, err = IfByFlag("forwardable", publicIfs) + if err != nil { + return IfAddrs{}, err + } + + publicIfs, _, err = IfByFlag("up", publicIfs) + if err != nil { + return IfAddrs{}, err + } + + if len(publicIfs) == 0 { + return IfAddrs{}, nil + } + + OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs) + + _, publicIfs, err = IfByRFC("6890", publicIfs) + if err != nil { + return IfAddrs{}, err + } else if len(publicIfs) == 0 { + return IfAddrs{}, nil + } + + return publicIfs, nil +} + +// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if +// the regexp fails to compile. +func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + re, err := regexp.Compile(inputRe) + if err != nil { + return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err) + } + + matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) + excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) + for _, addr := range ifAddrs { + if re.MatchString(addr.SockAddr.String()) { + matchedAddrs = append(matchedAddrs, addr) + } else { + excludedAddrs = append(excludedAddrs, addr) + } + } + + return matchedAddrs, excludedAddrs, nil +} + +// IfByName returns a list of matched and non-matched IfAddrs, or an error if +// the regexp fails to compile. +func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + re, err := regexp.Compile(inputRe) + if err != nil { + return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err) + } + + matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) + excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) + for _, addr := range ifAddrs { + if re.MatchString(addr.Name) { + matchedAddrs = append(matchedAddrs, addr) + } else { + excludedAddrs = append(excludedAddrs, addr) + } + } + + return matchedAddrs, excludedAddrs, nil +} + +// IfByPort returns a list of matched and non-matched IfAddrs, or an error if +// the regexp fails to compile. +func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { + re, err := regexp.Compile(inputRe) + if err != nil { + return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err) + } + + ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) + matchedIfs = make(IfAddrs, 0, len(ipIfs)) + excludedIfs = append(IfAddrs(nil), nonIfs...) + for _, addr := range ipIfs { + ipAddr := ToIPAddr(addr.SockAddr) + if ipAddr == nil { + continue + } + + port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10) + if re.MatchString(port) { + matchedIfs = append(matchedIfs, addr) + } else { + excludedIfs = append(excludedIfs, addr) + } + } + + return matchedIfs, excludedIfs, nil +} + +// IfByRFC returns a list of matched and non-matched IfAddrs that contain the +// relevant RFC-specified traits. +func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + inputRFC, err := strconv.ParseUint(selectorParam, 10, 64) + if err != nil { + return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err) + } + + matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs)) + remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) + + rfcNetMap := KnownRFCs() + rfcNets, ok := rfcNetMap[uint(inputRFC)] + if !ok { + return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC) + } + + for _, ifAddr := range ifAddrs { + var contained bool + for _, rfcNet := range rfcNets { + if rfcNet.Contains(ifAddr.SockAddr) { + matchedIfAddrs = append(matchedIfAddrs, ifAddr) + contained = true + break + } + } + if !contained { + remainingIfAddrs = append(remainingIfAddrs, ifAddr) + } + } + + return matchedIfAddrs, remainingIfAddrs, nil +} + +// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the +// relevant RFC-specified traits. Multiple RFCs can be specified and separated +// by the `|` symbol. No protection is taken to ensure an IfAddr does not end +// up in both the included and excluded list. +func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + var includedIfs, excludedIfs IfAddrs + for _, rfcStr := range strings.Split(selectorParam, "|") { + includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs) + if err != nil { + return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err) + } + includedIfs = append(includedIfs, includedRFCIfs...) + excludedIfs = append(excludedIfs, excludedRFCIfs...) + } + + return includedIfs, excludedIfs, nil +} + +// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the +// matching mask size. +func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { + maskSize, err := strconv.ParseUint(selectorParam, 10, 64) + if err != nil { + return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err) + } + + ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) + matchedIfs = make(IfAddrs, 0, len(ipIfs)) + excludedIfs = append(IfAddrs(nil), nonIfs...) + for _, addr := range ipIfs { + ipAddr := ToIPAddr(addr.SockAddr) + if ipAddr == nil { + return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String()) + } + + switch { + case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32: + return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize) + case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128: + return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize) + } + + if (*ipAddr).Maskbits() == int(maskSize) { + matchedIfs = append(matchedIfs, addr) + } else { + excludedIfs = append(excludedIfs, addr) + } + } + + return matchedIfs, excludedIfs, nil +} + +// IfByType returns a list of matching and non-matching IfAddr that match the +// specified type. For instance: +// +// include "type" "IPv4,IPv6" +// +// will include any IfAddrs that is either an IPv4 or IPv6 address. Any +// addresses on those interfaces that don't match will be included in the +// remainder results. +func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) + remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) + + ifTypes := strings.Split(strings.ToLower(inputTypes), "|") + for _, ifType := range ifTypes { + switch ifType { + case "ip", "ipv4", "ipv6", "unix": + // Valid types + default: + return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes) + } + } + + for _, ifAddr := range ifAddrs { + for _, ifType := range ifTypes { + var matched bool + switch { + case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0: + matched = true + case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0: + matched = true + case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0: + matched = true + case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0: + matched = true + } + + if matched { + matchingIfAddrs = append(matchingIfAddrs, ifAddr) + } else { + remainingIfAddrs = append(remainingIfAddrs, ifAddr) + } + } + } + + return matchingIfAddrs, remainingIfAddrs, nil +} + +// IfByFlag returns a list of matching and non-matching IfAddrs that match the +// specified type. For instance: +// +// include "flag" "up,broadcast" +// +// will include any IfAddrs that have both the "up" and "broadcast" flags set. +// Any addresses on those interfaces that don't match will be omitted from the +// results. +func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { + matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) + excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) + + var wantForwardable, + wantGlobalUnicast, + wantInterfaceLocalMulticast, + wantLinkLocalMulticast, + wantLinkLocalUnicast, + wantLoopback, + wantMulticast, + wantUnspecified bool + var ifFlags net.Flags + var checkFlags, checkAttrs bool + for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") { + switch flagName { + case "broadcast": + checkFlags = true + ifFlags = ifFlags | net.FlagBroadcast + case "down": + checkFlags = true + ifFlags = (ifFlags &^ net.FlagUp) + case "forwardable": + checkAttrs = true + wantForwardable = true + case "global unicast": + checkAttrs = true + wantGlobalUnicast = true + case "interface-local multicast": + checkAttrs = true + wantInterfaceLocalMulticast = true + case "link-local multicast": + checkAttrs = true + wantLinkLocalMulticast = true + case "link-local unicast": + checkAttrs = true + wantLinkLocalUnicast = true + case "loopback": + checkAttrs = true + checkFlags = true + ifFlags = ifFlags | net.FlagLoopback + wantLoopback = true + case "multicast": + checkAttrs = true + checkFlags = true + ifFlags = ifFlags | net.FlagMulticast + wantMulticast = true + case "point-to-point": + checkFlags = true + ifFlags = ifFlags | net.FlagPointToPoint + case "unspecified": + checkAttrs = true + wantUnspecified = true + case "up": + checkFlags = true + ifFlags = ifFlags | net.FlagUp + default: + return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName) + } + } + + for _, ifAddr := range ifAddrs { + var matched bool + if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags { + matched = true + } + if checkAttrs { + if ip := ToIPAddr(ifAddr.SockAddr); ip != nil { + netIP := (*ip).NetIP() + switch { + case wantGlobalUnicast && netIP.IsGlobalUnicast(): + matched = true + case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast(): + matched = true + case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast(): + matched = true + case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast(): + matched = true + case wantLoopback && netIP.IsLoopback(): + matched = true + case wantMulticast && netIP.IsMulticast(): + matched = true + case wantUnspecified && netIP.IsUnspecified(): + matched = true + case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr): + matched = true + } + } + } + if matched { + matchedAddrs = append(matchedAddrs, ifAddr) + } else { + excludedAddrs = append(excludedAddrs, ifAddr) + } + } + return matchedAddrs, excludedAddrs, nil +} + +// IfByNetwork returns an IfAddrs that are equal to or included within the +// network passed in by selector. +func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) { + var includedIfs, excludedIfs IfAddrs + for _, netStr := range strings.Split(selectorParam, "|") { + netAddr, err := NewIPAddr(netStr) + if err != nil { + return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err) + } + + for _, ifAddr := range inputIfAddrs { + if netAddr.Contains(ifAddr.SockAddr) { + includedIfs = append(includedIfs, ifAddr) + } else { + excludedIfs = append(excludedIfs, ifAddr) + } + } + } + + return includedIfs, excludedIfs, nil +} + +// IfAddrMath will return a new IfAddr struct with a mutated value. +func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) { + // Regexp used to enforce the sign being a required part of the grammar for + // some values. + signRe := signRE.Copy() + + switch strings.ToLower(operation) { + case "address": + // "address" operates on the IP address and is allowed to overflow or + // underflow networks, however it will wrap along the underlying address's + // underlying type. + + if !signRe.MatchString(value) { + return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) + } + + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + // 33 == Accept any uint32 value + // TODO(seanc@): Add the ability to parse hex + i, err := strconv.ParseInt(value, 10, 33) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + ipv4Uint32 := uint32(ipv4.Address) + ipv4Uint32 += uint32(i) + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: ipv4.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + // 64 == Accept any int32 value + // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. + i, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + ipv6BigIntA := new(big.Int) + ipv6BigIntA.Set(ipv6.Address) + ipv6BigIntB := big.NewInt(i) + + ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB) + ipv6Addr.And(ipv6Addr, ipv6HostMask) + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(ipv6Addr), + Mask: ipv6.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + case "network": + // "network" operates on the network address. Positive values start at the + // network address and negative values wrap at the network address, which + // means a "-1" value on a network will be the broadcast address after + // wrapping is applied. + + if !signRe.MatchString(value) { + return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) + } + + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + // 33 == Accept any uint32 value + // TODO(seanc@): Add the ability to parse hex + i, err := strconv.ParseInt(value, 10, 33) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + ipv4Uint32 := uint32(ipv4.NetworkAddress()) + + // Wrap along network mask boundaries. EZ-mode wrapping made possible by + // use of int64 vs a uint. + var wrappedMask int64 + if i >= 0 { + wrappedMask = i + } else { + wrappedMask = 1 + i + int64(^uint32(ipv4.Mask)) + } + + ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask)) + + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: ipv4.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + // 64 == Accept any int32 value + // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. + i, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + ipv6BigInt := new(big.Int) + ipv6BigInt.Set(ipv6.NetworkAddress()) + + mask := new(big.Int) + mask.Set(ipv6.Mask) + if i > 0 { + wrappedMask := new(big.Int) + wrappedMask.SetInt64(i) + + wrappedMask.AndNot(wrappedMask, mask) + ipv6BigInt.Add(ipv6BigInt, wrappedMask) + } else { + // Mask off any bits that exceed the network size. Subtract the + // wrappedMask from the last usable - 1 + wrappedMask := new(big.Int) + wrappedMask.SetInt64(-1 * i) + wrappedMask.Sub(wrappedMask, big.NewInt(1)) + + wrappedMask.AndNot(wrappedMask, mask) + + lastUsable := new(big.Int) + lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address) + + ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask) + } + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(ipv6BigInt), + Mask: ipv6.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + case "mask": + // "mask" operates on the IP address and returns the IP address on + // which the given integer mask has been applied. If the applied mask + // corresponds to a larger network than the mask of the IP address, + // the latter will be replaced by the former. + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + i, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + if i > 32 { + return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + + ipv4Mask := net.CIDRMask(int(i), 32) + ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask) + + maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask) + maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4) + + maskedIpv4MaskUint32 := uint32(ipv4.Mask) + + if ipv4MaskUint32 < maskedIpv4MaskUint32 { + maskedIpv4MaskUint32 = ipv4MaskUint32 + } + + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(maskedIpv4Uint32), + Mask: IPv4Mask(maskedIpv4MaskUint32), + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + i, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + if i > 128 { + return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + + ipv6Mask := net.CIDRMask(int(i), 128) + ipv6MaskBigInt := new(big.Int) + ipv6MaskBigInt.SetBytes(ipv6Mask) + + maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask) + maskedIpv6BigInt := new(big.Int) + maskedIpv6BigInt.SetBytes(maskedIpv6) + + maskedIpv6MaskBigInt := new(big.Int) + maskedIpv6MaskBigInt.Set(ipv6.Mask) + + if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 { + maskedIpv6MaskBigInt = ipv6MaskBigInt + } + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(maskedIpv6BigInt), + Mask: IPv6Mask(maskedIpv6MaskBigInt), + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + default: + return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation) + } +} + +// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any +// failure will result in zero results. +func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) { + outputAddrs := make(IfAddrs, 0, len(inputIfAddrs)) + for _, ifAddr := range inputIfAddrs { + result, err := IfAddrMath(operation, value, ifAddr) + if err != nil { + return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err) + } + outputAddrs = append(outputAddrs, result) + } + return outputAddrs, nil +} + +// IncludeIfs returns an IfAddrs based on the passed in selector. +func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { + var includedIfs IfAddrs + var err error + + switch strings.ToLower(selectorName) { + case "address": + includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs) + case "flag", "flags": + includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs) + case "name": + includedIfs, _, err = IfByName(selectorParam, inputIfAddrs) + case "network": + includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs) + case "port": + includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs) + case "rfc", "rfcs": + includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs) + case "size": + includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs) + case "type": + includedIfs, _, err = IfByType(selectorParam, inputIfAddrs) + default: + return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName) + } + + if err != nil { + return IfAddrs{}, err + } + + return includedIfs, nil +} + +// ExcludeIfs returns an IfAddrs based on the passed in selector. +func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { + var excludedIfs IfAddrs + var err error + + switch strings.ToLower(selectorName) { + case "address": + _, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs) + case "flag", "flags": + _, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs) + case "name": + _, excludedIfs, err = IfByName(selectorParam, inputIfAddrs) + case "network": + _, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs) + case "port": + _, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs) + case "rfc", "rfcs": + _, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs) + case "size": + _, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs) + case "type": + _, excludedIfs, err = IfByType(selectorParam, inputIfAddrs) + default: + return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName) + } + + if err != nil { + return IfAddrs{}, err + } + + return excludedIfs, nil +} + +// SortIfBy returns an IfAddrs sorted based on the passed in selector. Multiple +// sort clauses can be passed in as a comma delimited list without whitespace. +func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { + sortedIfs := append(IfAddrs(nil), inputIfAddrs...) + + clauses := strings.Split(selectorParam, ",") + sortFuncs := make([]CmpIfAddrFunc, len(clauses)) + + for i, clause := range clauses { + switch strings.TrimSpace(strings.ToLower(clause)) { + case "+address", "address": + // The "address" selector returns an array of IfAddrs + // ordered by the network address. IfAddrs that are not + // comparable will be at the end of the list and in a + // non-deterministic order. + sortFuncs[i] = AscIfAddress + case "-address": + sortFuncs[i] = DescIfAddress + case "+default", "default": + sortFuncs[i] = AscIfDefault + case "-default": + sortFuncs[i] = DescIfDefault + case "+name", "name": + // The "name" selector returns an array of IfAddrs + // ordered by the interface name. + sortFuncs[i] = AscIfName + case "-name": + sortFuncs[i] = DescIfName + case "+port", "port": + // The "port" selector returns an array of IfAddrs + // ordered by the port, if included in the IfAddr. + // IfAddrs that are not comparable will be at the end of + // the list and in a non-deterministic order. + sortFuncs[i] = AscIfPort + case "-port": + sortFuncs[i] = DescIfPort + case "+private", "private": + // The "private" selector returns an array of IfAddrs + // ordered by private addresses first. IfAddrs that are + // not comparable will be at the end of the list and in + // a non-deterministic order. + sortFuncs[i] = AscIfPrivate + case "-private": + sortFuncs[i] = DescIfPrivate + case "+size", "size": + // The "size" selector returns an array of IfAddrs + // ordered by the size of the network mask, smaller mask + // (larger number of hosts per network) to largest + // (e.g. a /24 sorts before a /32). + sortFuncs[i] = AscIfNetworkSize + case "-size": + sortFuncs[i] = DescIfNetworkSize + case "+type", "type": + // The "type" selector returns an array of IfAddrs + // ordered by the type of the IfAddr. The sort order is + // Unix, IPv4, then IPv6. + sortFuncs[i] = AscIfType + case "-type": + sortFuncs[i] = DescIfType + default: + // Return an empty list for invalid sort types. + return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause) + } + } + + OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs) + + return sortedIfs, nil +} + +// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching +// selector. UniqueIfAddrsBy assumes the input has already been sorted. +func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) { + attrName := strings.ToLower(selectorName) + + ifs := make(IfAddrs, 0, len(inputIfAddrs)) + var lastMatch string + for _, ifAddr := range inputIfAddrs { + var out string + switch attrName { + case "address": + out = ifAddr.SockAddr.String() + case "name": + out = ifAddr.Name + default: + return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName) + } + + switch { + case lastMatch == "", lastMatch != out: + lastMatch = out + ifs = append(ifs, ifAddr) + case lastMatch == out: + continue + } + } + + return ifs, nil +} + +// JoinIfAddrs joins an IfAddrs and returns a string +func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) { + outputs := make([]string, 0, len(inputIfAddrs)) + attrName := AttrName(strings.ToLower(selectorName)) + + for _, ifAddr := range inputIfAddrs { + var attrVal string + var err error + attrVal, err = ifAddr.Attr(attrName) + if err != nil { + return "", err + } + outputs = append(outputs, attrVal) + } + return strings.Join(outputs, joinStr), nil +} + +// LimitIfAddrs returns a slice of IfAddrs based on the specified limit. +func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) { + // Clamp the limit to the length of the array + if int(lim) > len(in) { + lim = uint(len(in)) + } + + return in[0:lim], nil +} + +// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset. +func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) { + var end bool + if off < 0 { + end = true + off = off * -1 + } + + if off > len(in) { + return IfAddrs{}, fmt.Errorf("unable to seek past the end of the interface array: offset (%d) exceeds the number of interfaces (%d)", off, len(in)) + } + + if end { + return in[len(in)-off:], nil + } + return in[off:], nil +} + +func (ifAddr IfAddr) String() string { + return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface) +} + +// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs +// and Solaris. +func parseDefaultIfNameFromRoute(routeOut string) (string, error) { + lines := strings.Split(routeOut, "\n") + for _, line := range lines { + kvs := strings.SplitN(line, ":", 2) + if len(kvs) != 2 { + continue + } + + if strings.TrimSpace(kvs[0]) == "interface" { + ifName := strings.TrimSpace(kvs[1]) + return ifName, nil + } + } + + return "", errors.New("No default interface found") +} + +// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for +// Linux. +func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) { + lines := strings.Split(routeOut, "\n") + re := whitespaceRE.Copy() + for _, line := range lines { + kvs := re.Split(line, -1) + if len(kvs) < 5 { + continue + } + + if kvs[0] == "default" && + kvs[1] == "via" && + kvs[3] == "dev" { + ifName := strings.TrimSpace(kvs[4]) + return ifName, nil + } + } + + return "", errors.New("No default interface found") +} + +// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and +// `ipconfig` on Windows. +func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) { + defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut) + if err != nil { + return "", err + } + + ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut) + if err != nil { + return "", err + } + + return ifName, nil +} + +// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface +// `netstat -rn`. +// +// NOTES(sean): Only IPv4 addresses are parsed at this time. If you have an +// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with +// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6 +// support added. +func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) { + lines := strings.Split(routeOut, "\n") + re := whitespaceRE.Copy() + for _, line := range lines { + kvs := re.Split(strings.TrimSpace(line), -1) + if len(kvs) < 3 { + continue + } + + if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" { + defaultIPAddr := strings.TrimSpace(kvs[3]) + return defaultIPAddr, nil + } + } + + return "", errors.New("No IP on default interface found") +} + +// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the +// interface name forwarding traffic to the default gateway. +func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) { + lines := strings.Split(routeOut, "\n") + ifNameRe := ifNameRE.Copy() + ipAddrRe := ipAddrRE.Copy() + var ifName string + for _, line := range lines { + switch ifNameMatches := ifNameRe.FindStringSubmatch(line); { + case len(ifNameMatches) > 1: + ifName = ifNameMatches[1] + continue + } + + switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); { + case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr: + return ifName, nil + } + } + + return "", errors.New("No default interface found with matching IP") +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifattr.go b/vendor/github.com/hashicorp/go-sockaddr/ifattr.go new file mode 100644 index 0000000..6984cb4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ifattr.go @@ -0,0 +1,65 @@ +package sockaddr + +import ( + "fmt" + "net" +) + +// IfAddr is a union of a SockAddr and a net.Interface. +type IfAddr struct { + SockAddr + net.Interface +} + +// Attr returns the named attribute as a string +func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) { + val := IfAddrAttr(ifAddr, attrName) + if val != "" { + return val, nil + } + + return Attr(ifAddr.SockAddr, attrName) +} + +// Attr returns the named attribute as a string +func Attr(sa SockAddr, attrName AttrName) (string, error) { + switch sockType := sa.Type(); { + case sockType&TypeIP != 0: + ip := *ToIPAddr(sa) + attrVal := IPAddrAttr(ip, attrName) + if attrVal != "" { + return attrVal, nil + } + + if sockType == TypeIPv4 { + ipv4 := *ToIPv4Addr(sa) + attrVal := IPv4AddrAttr(ipv4, attrName) + if attrVal != "" { + return attrVal, nil + } + } else if sockType == TypeIPv6 { + ipv6 := *ToIPv6Addr(sa) + attrVal := IPv6AddrAttr(ipv6, attrName) + if attrVal != "" { + return attrVal, nil + } + } + + case sockType == TypeUnix: + us := *ToUnixSock(sa) + attrVal := UnixSockAttr(us, attrName) + if attrVal != "" { + return attrVal, nil + } + } + + // Non type-specific attributes + switch attrName { + case "string": + return sa.String(), nil + case "type": + return sa.Type().String(), nil + } + + return "", fmt.Errorf("unsupported attribute name %q", attrName) +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go new file mode 100644 index 0000000..b47d15c --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go @@ -0,0 +1,169 @@ +package sockaddr + +import ( + "fmt" + "math/big" + "net" + "strings" +) + +// Constants for the sizes of IPv3, IPv4, and IPv6 address types. +const ( + IPv3len = 6 + IPv4len = 4 + IPv6len = 16 +) + +// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses, +// networks, and socket endpoints. +type IPAddr interface { + SockAddr + AddressBinString() string + AddressHexString() string + Cmp(SockAddr) int + CmpAddress(SockAddr) int + CmpPort(SockAddr) int + FirstUsable() IPAddr + Host() IPAddr + IPPort() IPPort + LastUsable() IPAddr + Maskbits() int + NetIP() *net.IP + NetIPMask() *net.IPMask + NetIPNet() *net.IPNet + Network() IPAddr + Octets() []int +} + +// IPPort is the type for an IP port number for the TCP and UDP IP transports. +type IPPort uint16 + +// IPPrefixLen is a typed integer representing the prefix length for a given +// IPAddr. +type IPPrefixLen byte + +// ipAddrAttrMap is a map of the IPAddr type-specific attributes. +var ipAddrAttrMap map[AttrName]func(IPAddr) string +var ipAddrAttrs []AttrName + +func init() { + ipAddrInit() +} + +// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is +// not an IPv4 or an IPv6 address. +func NewIPAddr(addr string) (IPAddr, error) { + ipv4Addr, err := NewIPv4Addr(addr) + if err == nil { + return ipv4Addr, nil + } + + ipv6Addr, err := NewIPv6Addr(addr) + if err == nil { + return ipv6Addr, nil + } + + return nil, fmt.Errorf("invalid IPAddr %v", addr) +} + +// IPAddrAttr returns a string representation of an attribute for the given +// IPAddr. +func IPAddrAttr(ip IPAddr, selector AttrName) string { + fn, found := ipAddrAttrMap[selector] + if !found { + return "" + } + + return fn(ip) +} + +// IPAttrs returns a list of attributes supported by the IPAddr type +func IPAttrs() []AttrName { + return ipAddrAttrs +} + +// MustIPAddr is a helper method that must return an IPAddr or panic on invalid +// input. +func MustIPAddr(addr string) IPAddr { + ip, err := NewIPAddr(addr) + if err != nil { + panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err)) + } + return ip +} + +// ipAddrInit is called once at init() +func ipAddrInit() { + // Sorted for human readability + ipAddrAttrs = []AttrName{ + "host", + "address", + "port", + "netmask", + "network", + "mask_bits", + "binary", + "hex", + "first_usable", + "last_usable", + "octets", + } + + ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{ + "address": func(ip IPAddr) string { + return ip.NetIP().String() + }, + "binary": func(ip IPAddr) string { + return ip.AddressBinString() + }, + "first_usable": func(ip IPAddr) string { + return ip.FirstUsable().String() + }, + "hex": func(ip IPAddr) string { + return ip.AddressHexString() + }, + "host": func(ip IPAddr) string { + return ip.Host().String() + }, + "last_usable": func(ip IPAddr) string { + return ip.LastUsable().String() + }, + "mask_bits": func(ip IPAddr) string { + return fmt.Sprintf("%d", ip.Maskbits()) + }, + "netmask": func(ip IPAddr) string { + switch v := ip.(type) { + case IPv4Addr: + ipv4Mask := IPv4Addr{ + Address: IPv4Address(v.Mask), + Mask: IPv4HostMask, + } + return ipv4Mask.String() + case IPv6Addr: + ipv6Mask := new(big.Int) + ipv6Mask.Set(v.Mask) + ipv6MaskAddr := IPv6Addr{ + Address: IPv6Address(ipv6Mask), + Mask: ipv6HostMask, + } + return ipv6MaskAddr.String() + default: + return fmt.Sprintf("", ip) + } + }, + "network": func(ip IPAddr) string { + return ip.Network().NetIP().String() + }, + "octets": func(ip IPAddr) string { + octets := ip.Octets() + octetStrs := make([]string, 0, len(octets)) + for _, octet := range octets { + octetStrs = append(octetStrs, fmt.Sprintf("%d", octet)) + } + return strings.Join(octetStrs, " ") + }, + "port": func(ip IPAddr) string { + return fmt.Sprintf("%d", ip.IPPort()) + }, + } +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go new file mode 100644 index 0000000..6eeb7dd --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go @@ -0,0 +1,98 @@ +package sockaddr + +import "bytes" + +type IPAddrs []IPAddr + +func (s IPAddrs) Len() int { return len(s) } +func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used +// // by the routines in this package. The SortIPAddrsByCmp type is used to +// // sort IPAddrs by Cmp() +// type SortIPAddrsByCmp struct{ IPAddrs } + +// // Less reports whether the element with index i should sort before the +// // element with index j. +// func (s SortIPAddrsByCmp) Less(i, j int) bool { +// // Sort by Type, then address, then port number. +// return Less(s.IPAddrs[i], s.IPAddrs[j]) +// } + +// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and +// can be used by the routines in this package. The +// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest +// network (most specific to largest network). +type SortIPAddrsByNetworkSize struct{ IPAddrs } + +// Less reports whether the element with index i should sort before the +// element with index j. +func (s SortIPAddrsByNetworkSize) Less(i, j int) bool { + // Sort masks with a larger binary value (i.e. fewer hosts per network + // prefix) after masks with a smaller value (larger number of hosts per + // prefix). + switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) { + case 0: + // Fall through to the second test if the net.IPMasks are the + // same. + break + case 1: + return true + case -1: + return false + default: + panic("bad, m'kay?") + } + + // Sort IPs based on the length (i.e. prefer IPv4 over IPv6). + iLen := len(*s.IPAddrs[i].NetIP()) + jLen := len(*s.IPAddrs[j].NetIP()) + if iLen != jLen { + return iLen > jLen + } + + // Sort IPs based on their network address from lowest to highest. + switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) { + case 0: + break + case 1: + return false + case -1: + return true + default: + panic("lol wut?") + } + + // If a host does not have a port set, it always sorts after hosts + // that have a port (e.g. a host with a /32 and port number is more + // specific and should sort first over a host with a /32 but no port + // set). + if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 { + return false + } + return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort() +} + +// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and +// can be used by the routines in this package. The +// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest +// network (most specific to largest network). +type SortIPAddrsBySpecificMaskLen struct{ IPAddrs } + +// Less reports whether the element with index i should sort before the +// element with index j. +func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool { + return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits() +} + +// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can +// be used by the routines in this package. The SortIPAddrsByBroadMaskLen +// type is used to sort IPAddrs by largest network (i.e. largest subnets +// first). +type SortIPAddrsByBroadMaskLen struct{ IPAddrs } + +// Less reports whether the element with index i should sort before the +// element with index j. +func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool { + return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits() +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go new file mode 100644 index 0000000..4d395dc --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go @@ -0,0 +1,516 @@ +package sockaddr + +import ( + "encoding/binary" + "fmt" + "net" + "regexp" + "strconv" + "strings" +) + +type ( + // IPv4Address is a named type representing an IPv4 address. + IPv4Address uint32 + + // IPv4Network is a named type representing an IPv4 network. + IPv4Network uint32 + + // IPv4Mask is a named type representing an IPv4 network mask. + IPv4Mask uint32 +) + +// IPv4HostMask is a constant represents a /32 IPv4 Address +// (i.e. 255.255.255.255). +const IPv4HostMask = IPv4Mask(0xffffffff) + +// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes. +var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string +var ipv4AddrAttrs []AttrName +var trailingHexNetmaskRE *regexp.Regexp + +// IPv4Addr implements a convenience wrapper around the union of Go's +// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements +// `sockaddr` when the the address family is set to AF_INET +// (i.e. `sockaddr_in`). +type IPv4Addr struct { + IPAddr + Address IPv4Address + Mask IPv4Mask + Port IPPort +} + +func init() { + ipv4AddrInit() + trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`) +} + +// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form +// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is +// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32` +// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port +// initialized to zero). ipv4Str can not be a hostname. +// +// NOTE: Many net.*() routines will initialize and return an IPv6 address. +// To create uint32 values from net.IP, always test to make sure the address +// returned can be converted to a 4 byte array using To4(). +func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) { + // Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In + // particular, clients with the Barracuda VPN client will see something like: + // `192.168.3.51/00ffffff` as their IP address. + trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() + if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil { + ipv4Str = ipv4Str[:match[0]] + } + + // Parse as an IPv4 CIDR + ipAddr, network, err := net.ParseCIDR(ipv4Str) + if err == nil { + ipv4 := ipAddr.To4() + if ipv4 == nil { + return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str) + } + + // If we see an IPv6 netmask, convert it to an IPv4 mask. + netmaskSepPos := strings.LastIndexByte(ipv4Str, '/') + if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) { + netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8) + if err != nil { + return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err) + } else if netMask > 128 { + return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str) + } + + if netMask >= 96 { + // Convert the IPv6 netmask to an IPv4 netmask + network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8) + } + } + ipv4Addr := IPv4Addr{ + Address: IPv4Address(binary.BigEndian.Uint32(ipv4)), + Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)), + } + return ipv4Addr, nil + } + + // Attempt to parse ipv4Str as a /32 host with a port number. + tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str) + if err == nil { + ipv4 := tcpAddr.IP.To4() + if ipv4 == nil { + return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str) + } + + ipv4Uint32 := binary.BigEndian.Uint32(ipv4) + ipv4Addr := IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: IPv4HostMask, + Port: IPPort(tcpAddr.Port), + } + + return ipv4Addr, nil + } + + // Parse as a naked IPv4 address + ip := net.ParseIP(ipv4Str) + if ip != nil { + ipv4 := ip.To4() + if ipv4 == nil { + return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str) + } + + ipv4Uint32 := binary.BigEndian.Uint32(ipv4) + ipv4Addr := IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: IPv4HostMask, + } + return ipv4Addr, nil + } + + return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err) +} + +// AddressBinString returns a string with the IPv4Addr's Address represented +// as a sequence of '0' and '1' characters. This method is useful for +// debugging or by operators who want to inspect an address. +func (ipv4 IPv4Addr) AddressBinString() string { + return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2)) +} + +// AddressHexString returns a string with the IPv4Addr address represented as +// a sequence of hex characters. This method is useful for debugging or by +// operators who want to inspect an address. +func (ipv4 IPv4Addr) AddressHexString() string { + return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16)) +} + +// Broadcast is an IPv4Addr-only method that returns the broadcast address of +// the network. +// +// NOTE: IPv6 only supports multicast, so this method only exists for +// IPv4Addr. +func (ipv4 IPv4Addr) Broadcast() IPAddr { + // Nothing should listen on a broadcast address. + return IPv4Addr{ + Address: IPv4Address(ipv4.BroadcastAddress()), + Mask: IPv4HostMask, + } +} + +// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast +// address. +func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network { + return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask)) +} + +// CmpAddress follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because its address is lower than arg +// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is +// of a different type. +// - 1 If the argument should sort first. +func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int { + ipv4b, ok := sa.(IPv4Addr) + if !ok { + return sortDeferDecision + } + + switch { + case ipv4.Address == ipv4b.Address: + return sortDeferDecision + case ipv4.Address < ipv4b.Address: + return sortReceiverBeforeArg + default: + return sortArgBeforeReceiver + } +} + +// CmpPort follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because its port is lower than arg +// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr, +// regardless of type. +// - 1 If the argument should sort first. +func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int { + var saPort IPPort + switch v := sa.(type) { + case IPv4Addr: + saPort = v.Port + case IPv6Addr: + saPort = v.Port + default: + return sortDeferDecision + } + + switch { + case ipv4.Port == saPort: + return sortDeferDecision + case ipv4.Port < saPort: + return sortReceiverBeforeArg + default: + return sortArgBeforeReceiver + } +} + +// CmpRFC follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because it belongs to the RFC and its +// arg does not +// - 0 if the receiver and arg both belong to the same RFC or neither do. +// - 1 If the arg belongs to the RFC but receiver does not. +func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int { + recvInRFC := IsRFC(rfcNum, ipv4) + ipv4b, ok := sa.(IPv4Addr) + if !ok { + // If the receiver is part of the desired RFC and the SockAddr + // argument is not, return -1 so that the receiver sorts before + // the non-IPv4 SockAddr. Conversely, if the receiver is not + // part of the RFC, punt on sorting and leave it for the next + // sorter. + if recvInRFC { + return sortReceiverBeforeArg + } else { + return sortDeferDecision + } + } + + argInRFC := IsRFC(rfcNum, ipv4b) + switch { + case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): + // If a and b both belong to the RFC, or neither belong to + // rfcNum, defer sorting to the next sorter. + return sortDeferDecision + case recvInRFC && !argInRFC: + return sortReceiverBeforeArg + default: + return sortArgBeforeReceiver + } +} + +// Contains returns true if the SockAddr is contained within the receiver. +func (ipv4 IPv4Addr) Contains(sa SockAddr) bool { + ipv4b, ok := sa.(IPv4Addr) + if !ok { + return false + } + + return ipv4.ContainsNetwork(ipv4b) +} + +// ContainsAddress returns true if the IPv4Address is contained within the +// receiver. +func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool { + return IPv4Address(ipv4.NetworkAddress()) <= x && + IPv4Address(ipv4.BroadcastAddress()) >= x +} + +// ContainsNetwork returns true if the network from IPv4Addr is contained +// within the receiver. +func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool { + return ipv4.NetworkAddress() <= x.NetworkAddress() && + ipv4.BroadcastAddress() >= x.BroadcastAddress() +} + +// DialPacketArgs returns the arguments required to be passed to +// net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0, +// DialPacketArgs() will fail. See Host() to create an IPv4Addr with its +// mask set to /32. +func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) { + if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { + return "udp4", "" + } + return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) +} + +// DialStreamArgs returns the arguments required to be passed to +// net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0, +// DialStreamArgs() will fail. See Host() to create an IPv4Addr with its +// mask set to /32. +func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) { + if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { + return "tcp4", "" + } + return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) +} + +// Equal returns true if a SockAddr is equal to the receiving IPv4Addr. +func (ipv4 IPv4Addr) Equal(sa SockAddr) bool { + ipv4b, ok := sa.(IPv4Addr) + if !ok { + return false + } + + if ipv4.Port != ipv4b.Port { + return false + } + + if ipv4.Address != ipv4b.Address { + return false + } + + if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() { + return false + } + + return true +} + +// FirstUsable returns an IPv4Addr set to the first address following the +// network prefix. The first usable address in a network is normally the +// gateway and should not be used except by devices forwarding packets +// between two administratively distinct networks (i.e. a router). This +// function does not discriminate against first usable vs "first address that +// should be used." For example, FirstUsable() on "192.168.1.10/24" would +// return the address "192.168.1.1/24". +func (ipv4 IPv4Addr) FirstUsable() IPAddr { + addr := ipv4.NetworkAddress() + + // If /32, return the address itself. If /31 assume a point-to-point + // link and return the lower address. + if ipv4.Maskbits() < 31 { + addr++ + } + + return IPv4Addr{ + Address: IPv4Address(addr), + Mask: IPv4HostMask, + } +} + +// Host returns a copy of ipv4 with its mask set to /32 so that it can be +// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or +// ListenStreamArgs(). +func (ipv4 IPv4Addr) Host() IPAddr { + // Nothing should listen on a broadcast address. + return IPv4Addr{ + Address: ipv4.Address, + Mask: IPv4HostMask, + Port: ipv4.Port, + } +} + +// IPPort returns the Port number attached to the IPv4Addr +func (ipv4 IPv4Addr) IPPort() IPPort { + return ipv4.Port +} + +// LastUsable returns the last address before the broadcast address in a +// given network. +func (ipv4 IPv4Addr) LastUsable() IPAddr { + addr := ipv4.BroadcastAddress() + + // If /32, return the address itself. If /31 assume a point-to-point + // link and return the upper address. + if ipv4.Maskbits() < 31 { + addr-- + } + + return IPv4Addr{ + Address: IPv4Address(addr), + Mask: IPv4HostMask, + } +} + +// ListenPacketArgs returns the arguments required to be passed to +// net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs() +// will fail. See Host() to create an IPv4Addr with its mask set to /32. +func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) { + if ipv4.Mask != IPv4HostMask { + return "udp4", "" + } + return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) +} + +// ListenStreamArgs returns the arguments required to be passed to +// net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs() +// will fail. See Host() to create an IPv4Addr with its mask set to /32. +func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) { + if ipv4.Mask != IPv4HostMask { + return "tcp4", "" + } + return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) +} + +// Maskbits returns the number of network mask bits in a given IPv4Addr. For +// example, the Maskbits() of "192.168.1.1/24" would return 24. +func (ipv4 IPv4Addr) Maskbits() int { + mask := make(net.IPMask, IPv4len) + binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask)) + maskOnes, _ := mask.Size() + return maskOnes +} + +// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on +// invalid input. +func MustIPv4Addr(addr string) IPv4Addr { + ipv4, err := NewIPv4Addr(addr) + if err != nil { + panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err)) + } + return ipv4 +} + +// NetIP returns the address as a net.IP (address is always presized to +// IPv4). +func (ipv4 IPv4Addr) NetIP() *net.IP { + x := make(net.IP, IPv4len) + binary.BigEndian.PutUint32(x, uint32(ipv4.Address)) + return &x +} + +// NetIPMask create a new net.IPMask from the IPv4Addr. +func (ipv4 IPv4Addr) NetIPMask() *net.IPMask { + ipv4Mask := net.IPMask{} + ipv4Mask = make(net.IPMask, IPv4len) + binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask)) + return &ipv4Mask +} + +// NetIPNet create a new net.IPNet from the IPv4Addr. +func (ipv4 IPv4Addr) NetIPNet() *net.IPNet { + ipv4net := &net.IPNet{} + ipv4net.IP = make(net.IP, IPv4len) + binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress())) + ipv4net.Mask = *ipv4.NetIPMask() + return ipv4net +} + +// Network returns the network prefix or network address for a given network. +func (ipv4 IPv4Addr) Network() IPAddr { + return IPv4Addr{ + Address: IPv4Address(ipv4.NetworkAddress()), + Mask: ipv4.Mask, + } +} + +// NetworkAddress returns an IPv4Network of the IPv4Addr's network address. +func (ipv4 IPv4Addr) NetworkAddress() IPv4Network { + return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask)) +} + +// Octets returns a slice of the four octets in an IPv4Addr's Address. The +// order of the bytes is big endian. +func (ipv4 IPv4Addr) Octets() []int { + return []int{ + int(ipv4.Address >> 24), + int((ipv4.Address >> 16) & 0xff), + int((ipv4.Address >> 8) & 0xff), + int(ipv4.Address & 0xff), + } +} + +// String returns a string representation of the IPv4Addr +func (ipv4 IPv4Addr) String() string { + if ipv4.Port != 0 { + return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) + } + + if ipv4.Maskbits() == 32 { + return ipv4.NetIP().String() + } + + return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits()) +} + +// Type is used as a type switch and returns TypeIPv4 +func (IPv4Addr) Type() SockAddrType { + return TypeIPv4 +} + +// IPv4AddrAttr returns a string representation of an attribute for the given +// IPv4Addr. +func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string { + fn, found := ipv4AddrAttrMap[selector] + if !found { + return "" + } + + return fn(ipv4) +} + +// IPv4Attrs returns a list of attributes supported by the IPv4Addr type +func IPv4Attrs() []AttrName { + return ipv4AddrAttrs +} + +// ipv4AddrInit is called once at init() +func ipv4AddrInit() { + // Sorted for human readability + ipv4AddrAttrs = []AttrName{ + "size", // Same position as in IPv6 for output consistency + "broadcast", + "uint32", + } + + ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{ + "broadcast": func(ipv4 IPv4Addr) string { + return ipv4.Broadcast().String() + }, + "size": func(ipv4 IPv4Addr) string { + return fmt.Sprintf("%d", 1< 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' { + ipv6Str = ipv6Str[1 : len(ipv6Str)-1] + } + ip := net.ParseIP(ipv6Str) + if ip != nil { + ipv6 := ip.To16() + if ipv6 == nil { + return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str) + } + + ipv6BigIntAddr := new(big.Int) + ipv6BigIntAddr.SetBytes(ipv6) + + ipv6BigIntMask := new(big.Int) + ipv6BigIntMask.Set(ipv6HostMask) + + return IPv6Addr{ + Address: IPv6Address(ipv6BigIntAddr), + Mask: IPv6Mask(ipv6BigIntMask), + }, nil + } + + // Parse as an IPv6 CIDR + ipAddr, network, err := net.ParseCIDR(ipv6Str) + if err == nil { + ipv6 := ipAddr.To16() + if ipv6 == nil { + return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str) + } + + ipv6BigIntAddr := new(big.Int) + ipv6BigIntAddr.SetBytes(ipv6) + + ipv6BigIntMask := new(big.Int) + ipv6BigIntMask.SetBytes(network.Mask) + + ipv6Addr := IPv6Addr{ + Address: IPv6Address(ipv6BigIntAddr), + Mask: IPv6Mask(ipv6BigIntMask), + } + return ipv6Addr, nil + } + + return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err) +} + +// AddressBinString returns a string with the IPv6Addr's Address represented +// as a sequence of '0' and '1' characters. This method is useful for +// debugging or by operators who want to inspect an address. +func (ipv6 IPv6Addr) AddressBinString() string { + bi := big.Int(*ipv6.Address) + return fmt.Sprintf("%0128s", bi.Text(2)) +} + +// AddressHexString returns a string with the IPv6Addr address represented as +// a sequence of hex characters. This method is useful for debugging or by +// operators who want to inspect an address. +func (ipv6 IPv6Addr) AddressHexString() string { + bi := big.Int(*ipv6.Address) + return fmt.Sprintf("%032s", bi.Text(16)) +} + +// CmpAddress follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because its address is lower than arg +// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a +// different type. +// - 1 If the argument should sort first. +func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int { + ipv6b, ok := sa.(IPv6Addr) + if !ok { + return sortDeferDecision + } + + ipv6aBigInt := new(big.Int) + ipv6aBigInt.Set(ipv6.Address) + ipv6bBigInt := new(big.Int) + ipv6bBigInt.Set(ipv6b.Address) + + return ipv6aBigInt.Cmp(ipv6bBigInt) +} + +// CmpPort follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because its port is lower than arg +// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr, +// regardless of type. +// - 1 If the argument should sort first. +func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int { + var saPort IPPort + switch v := sa.(type) { + case IPv4Addr: + saPort = v.Port + case IPv6Addr: + saPort = v.Port + default: + return sortDeferDecision + } + + switch { + case ipv6.Port == saPort: + return sortDeferDecision + case ipv6.Port < saPort: + return sortReceiverBeforeArg + default: + return sortArgBeforeReceiver + } +} + +// CmpRFC follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because it belongs to the RFC and its +// arg does not +// - 0 if the receiver and arg both belong to the same RFC or neither do. +// - 1 If the arg belongs to the RFC but receiver does not. +func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int { + recvInRFC := IsRFC(rfcNum, ipv6) + ipv6b, ok := sa.(IPv6Addr) + if !ok { + // If the receiver is part of the desired RFC and the SockAddr + // argument is not, sort receiver before the non-IPv6 SockAddr. + // Conversely, if the receiver is not part of the RFC, punt on + // sorting and leave it for the next sorter. + if recvInRFC { + return sortReceiverBeforeArg + } else { + return sortDeferDecision + } + } + + argInRFC := IsRFC(rfcNum, ipv6b) + switch { + case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): + // If a and b both belong to the RFC, or neither belong to + // rfcNum, defer sorting to the next sorter. + return sortDeferDecision + case recvInRFC && !argInRFC: + return sortReceiverBeforeArg + default: + return sortArgBeforeReceiver + } +} + +// Contains returns true if the SockAddr is contained within the receiver. +func (ipv6 IPv6Addr) Contains(sa SockAddr) bool { + ipv6b, ok := sa.(IPv6Addr) + if !ok { + return false + } + + return ipv6.ContainsNetwork(ipv6b) +} + +// ContainsAddress returns true if the IPv6Address is contained within the +// receiver. +func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool { + xAddr := IPv6Addr{ + Address: x, + Mask: ipv6HostMask, + } + + { + xIPv6 := xAddr.FirstUsable().(IPv6Addr) + yIPv6 := ipv6.FirstUsable().(IPv6Addr) + if xIPv6.CmpAddress(yIPv6) >= 1 { + return false + } + } + + { + xIPv6 := xAddr.LastUsable().(IPv6Addr) + yIPv6 := ipv6.LastUsable().(IPv6Addr) + if xIPv6.CmpAddress(yIPv6) <= -1 { + return false + } + } + return true +} + +// ContainsNetwork returns true if the network from IPv6Addr is contained within +// the receiver. +func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool { + { + xIPv6 := x.FirstUsable().(IPv6Addr) + yIPv6 := y.FirstUsable().(IPv6Addr) + if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 { + return false + } + } + + { + xIPv6 := x.LastUsable().(IPv6Addr) + yIPv6 := y.LastUsable().(IPv6Addr) + if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 { + return false + } + } + return true +} + +// DialPacketArgs returns the arguments required to be passed to +// net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0, +// DialPacketArgs() will fail. See Host() to create an IPv6Addr with its +// mask set to /128. +func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) { + ipv6Mask := big.Int(*ipv6.Mask) + if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { + return "udp6", "" + } + return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) +} + +// DialStreamArgs returns the arguments required to be passed to +// net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0, +// DialStreamArgs() will fail. See Host() to create an IPv6Addr with its +// mask set to /128. +func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) { + ipv6Mask := big.Int(*ipv6.Mask) + if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { + return "tcp6", "" + } + return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) +} + +// Equal returns true if a SockAddr is equal to the receiving IPv4Addr. +func (ipv6a IPv6Addr) Equal(sa SockAddr) bool { + ipv6b, ok := sa.(IPv6Addr) + if !ok { + return false + } + + if ipv6a.NetIP().String() != ipv6b.NetIP().String() { + return false + } + + if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() { + return false + } + + if ipv6a.Port != ipv6b.Port { + return false + } + + return true +} + +// FirstUsable returns an IPv6Addr set to the first address following the +// network prefix. The first usable address in a network is normally the +// gateway and should not be used except by devices forwarding packets +// between two administratively distinct networks (i.e. a router). This +// function does not discriminate against first usable vs "first address that +// should be used." For example, FirstUsable() on "2001:0db8::0003/64" would +// return "2001:0db8::00011". +func (ipv6 IPv6Addr) FirstUsable() IPAddr { + return IPv6Addr{ + Address: IPv6Address(ipv6.NetworkAddress()), + Mask: ipv6HostMask, + } +} + +// Host returns a copy of ipv6 with its mask set to /128 so that it can be +// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or +// ListenStreamArgs(). +func (ipv6 IPv6Addr) Host() IPAddr { + // Nothing should listen on a broadcast address. + return IPv6Addr{ + Address: ipv6.Address, + Mask: ipv6HostMask, + Port: ipv6.Port, + } +} + +// IPPort returns the Port number attached to the IPv6Addr +func (ipv6 IPv6Addr) IPPort() IPPort { + return ipv6.Port +} + +// LastUsable returns the last address in a given network. +func (ipv6 IPv6Addr) LastUsable() IPAddr { + addr := new(big.Int) + addr.Set(ipv6.Address) + + mask := new(big.Int) + mask.Set(ipv6.Mask) + + negMask := new(big.Int) + negMask.Xor(ipv6HostMask, mask) + + lastAddr := new(big.Int) + lastAddr.And(addr, mask) + lastAddr.Or(lastAddr, negMask) + + return IPv6Addr{ + Address: IPv6Address(lastAddr), + Mask: ipv6HostMask, + } +} + +// ListenPacketArgs returns the arguments required to be passed to +// net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs() +// will fail. See Host() to create an IPv6Addr with its mask set to /128. +func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) { + ipv6Mask := big.Int(*ipv6.Mask) + if ipv6Mask.Cmp(ipv6HostMask) != 0 { + return "udp6", "" + } + return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) +} + +// ListenStreamArgs returns the arguments required to be passed to +// net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs() +// will fail. See Host() to create an IPv6Addr with its mask set to /128. +func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) { + ipv6Mask := big.Int(*ipv6.Mask) + if ipv6Mask.Cmp(ipv6HostMask) != 0 { + return "tcp6", "" + } + return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) +} + +// Maskbits returns the number of network mask bits in a given IPv6Addr. For +// example, the Maskbits() of "2001:0db8::0003/64" would return 64. +func (ipv6 IPv6Addr) Maskbits() int { + maskOnes, _ := ipv6.NetIPNet().Mask.Size() + + return maskOnes +} + +// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on +// invalid input. +func MustIPv6Addr(addr string) IPv6Addr { + ipv6, err := NewIPv6Addr(addr) + if err != nil { + panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err)) + } + return ipv6 +} + +// NetIP returns the address as a net.IP. +func (ipv6 IPv6Addr) NetIP() *net.IP { + return bigIntToNetIPv6(ipv6.Address) +} + +// NetIPMask create a new net.IPMask from the IPv6Addr. +func (ipv6 IPv6Addr) NetIPMask() *net.IPMask { + ipv6Mask := make(net.IPMask, IPv6len) + m := big.Int(*ipv6.Mask) + copy(ipv6Mask, m.Bytes()) + return &ipv6Mask +} + +// Network returns a pointer to the net.IPNet within IPv4Addr receiver. +func (ipv6 IPv6Addr) NetIPNet() *net.IPNet { + ipv6net := &net.IPNet{} + ipv6net.IP = make(net.IP, IPv6len) + copy(ipv6net.IP, *ipv6.NetIP()) + ipv6net.Mask = *ipv6.NetIPMask() + return ipv6net +} + +// Network returns the network prefix or network address for a given network. +func (ipv6 IPv6Addr) Network() IPAddr { + return IPv6Addr{ + Address: IPv6Address(ipv6.NetworkAddress()), + Mask: ipv6.Mask, + } +} + +// NetworkAddress returns an IPv6Network of the IPv6Addr's network address. +func (ipv6 IPv6Addr) NetworkAddress() IPv6Network { + addr := new(big.Int) + addr.SetBytes((*ipv6.Address).Bytes()) + + mask := new(big.Int) + mask.SetBytes(*ipv6.NetIPMask()) + + netAddr := new(big.Int) + netAddr.And(addr, mask) + + return IPv6Network(netAddr) +} + +// Octets returns a slice of the 16 octets in an IPv6Addr's Address. The +// order of the bytes is big endian. +func (ipv6 IPv6Addr) Octets() []int { + x := make([]int, IPv6len) + for i, b := range *bigIntToNetIPv6(ipv6.Address) { + x[i] = int(b) + } + + return x +} + +// String returns a string representation of the IPv6Addr +func (ipv6 IPv6Addr) String() string { + if ipv6.Port != 0 { + return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) + } + + if ipv6.Maskbits() == 128 { + return ipv6.NetIP().String() + } + + return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits()) +} + +// Type is used as a type switch and returns TypeIPv6 +func (IPv6Addr) Type() SockAddrType { + return TypeIPv6 +} + +// IPv6Attrs returns a list of attributes supported by the IPv6Addr type +func IPv6Attrs() []AttrName { + return ipv6AddrAttrs +} + +// IPv6AddrAttr returns a string representation of an attribute for the given +// IPv6Addr. +func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string { + fn, found := ipv6AddrAttrMap[selector] + if !found { + return "" + } + + return fn(ipv6) +} + +// ipv6AddrInit is called once at init() +func ipv6AddrInit() { + // Sorted for human readability + ipv6AddrAttrs = []AttrName{ + "size", // Same position as in IPv6 for output consistency + "uint128", + } + + ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{ + "size": func(ipv6 IPv6Addr) string { + netSize := big.NewInt(1) + netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits())) + return netSize.Text(10) + }, + "uint128": func(ipv6 IPv6Addr) string { + b := big.Int(*ipv6.Address) + return b.Text(10) + }, + } +} + +// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the +// correctly padded values. +func bigIntToNetIPv6(bi *big.Int) *net.IP { + x := make(net.IP, IPv6len) + ipv6Bytes := bi.Bytes() + + // It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If + // they are different sizes we to pad the size of response. + if len(ipv6Bytes) < IPv6len { + buf := new(bytes.Buffer) + buf.Grow(IPv6len) + + for i := len(ipv6Bytes); i < IPv6len; i++ { + if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil { + panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err)) + } + } + + for _, b := range ipv6Bytes { + if err := binary.Write(buf, binary.BigEndian, b); err != nil { + panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err)) + } + } + + ipv6Bytes = buf.Bytes() + } + i := copy(x, ipv6Bytes) + if i != IPv6len { + panic("IPv6 wrong size") + } + return &x +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/rfc.go new file mode 100644 index 0000000..02e188f --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/rfc.go @@ -0,0 +1,948 @@ +package sockaddr + +// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP +// blocks. +const ForwardingBlacklist = 4294967295 +const ForwardingBlacklistRFC = "4294967295" + +// IsRFC tests to see if an SockAddr matches the specified RFC +func IsRFC(rfcNum uint, sa SockAddr) bool { + rfcNetMap := KnownRFCs() + rfcNets, ok := rfcNetMap[rfcNum] + if !ok { + return false + } + + var contained bool + for _, rfcNet := range rfcNets { + if rfcNet.Contains(sa) { + contained = true + break + } + } + return contained +} + +// KnownRFCs returns an initial set of known RFCs. +// +// NOTE (sean@): As this list evolves over time, please submit patches to keep +// this list current. If something isn't right, inquire, as it may just be a +// bug on my part. Some of the inclusions were based on my judgement as to what +// would be a useful value (e.g. RFC3330). +// +// Useful resources: +// +// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml +// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml +// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml +func KnownRFCs() map[uint]SockAddrs { + // NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a + // RADIX tree, but `ENOTIME`. Patches welcome. + return map[uint]SockAddrs{ + 919: { + // [RFC919] Broadcasting Internet Datagrams + MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards + }, + 1122: { + // [RFC1122] Requirements for Internet Hosts -- Communication Layers + MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3 + MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3 + }, + 1112: { + // [RFC1112] Host Extensions for IP Multicasting + MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses + }, + 1918: { + // [RFC1918] Address Allocation for Private Internets + MustIPv4Addr("10.0.0.0/8"), + MustIPv4Addr("172.16.0.0/12"), + MustIPv4Addr("192.168.0.0/16"), + }, + 2544: { + // [RFC2544] Benchmarking Methodology for Network + // Interconnect Devices + MustIPv4Addr("198.18.0.0/15"), + }, + 2765: { + // [RFC2765] Stateless IP/ICMP Translation Algorithm + // (SIIT) (obsoleted by RFCs 6145, which itself was + // later obsoleted by 7915). + + // [RFC2765], §2.1 Addresses + MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"), + }, + 2928: { + // [RFC2928] Initial IPv6 Sub-TLA ID Assignments + MustIPv6Addr("2001::/16"), // Superblock + //MustIPv6Addr("2001:0000::/23"), // IANA + //MustIPv6Addr("2001:0200::/23"), // APNIC + //MustIPv6Addr("2001:0400::/23"), // ARIN + //MustIPv6Addr("2001:0600::/23"), // RIPE NCC + //MustIPv6Addr("2001:0800::/23"), // (future assignment) + // ... + //MustIPv6Addr("2001:FE00::/23"), // (future assignment) + }, + 3056: { // 6to4 address + // [RFC3056] Connection of IPv6 Domains via IPv4 Clouds + + // [RFC3056], §2 IPv6 Prefix Allocation + MustIPv6Addr("2002::/16"), + }, + 3068: { + // [RFC3068] An Anycast Prefix for 6to4 Relay Routers + // (obsolete by RFC7526) + + // [RFC3068], § 6to4 Relay anycast address + MustIPv4Addr("192.88.99.0/24"), + + // [RFC3068], §2.5 6to4 IPv6 relay anycast address + // + // NOTE: /120 == 128-(32-24) + MustIPv6Addr("2002:c058:6301::/120"), + }, + 3171: { + // [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments + MustIPv4Addr("224.0.0.0/4"), + }, + 3330: { + // [RFC3330] Special-Use IPv4 Addresses + + // Addresses in this block refer to source hosts on + // "this" network. Address 0.0.0.0/32 may be used as a + // source address for this host on this network; other + // addresses within 0.0.0.0/8 may be used to refer to + // specified hosts on this network [RFC1700, page 4]. + MustIPv4Addr("0.0.0.0/8"), + + // 10.0.0.0/8 - This block is set aside for use in + // private networks. Its intended use is documented in + // [RFC1918]. Addresses within this block should not + // appear on the public Internet. + MustIPv4Addr("10.0.0.0/8"), + + // 14.0.0.0/8 - This block is set aside for assignments + // to the international system of Public Data Networks + // [RFC1700, page 181]. The registry of assignments + // within this block can be accessed from the "Public + // Data Network Numbers" link on the web page at + // http://www.iana.org/numbers.html. Addresses within + // this block are assigned to users and should be + // treated as such. + + // 24.0.0.0/8 - This block was allocated in early 1996 + // for use in provisioning IP service over cable + // television systems. Although the IANA initially was + // involved in making assignments to cable operators, + // this responsibility was transferred to American + // Registry for Internet Numbers (ARIN) in May 2001. + // Addresses within this block are assigned in the + // normal manner and should be treated as such. + + // 39.0.0.0/8 - This block was used in the "Class A + // Subnet Experiment" that commenced in May 1995, as + // documented in [RFC1797]. The experiment has been + // completed and this block has been returned to the + // pool of addresses reserved for future allocation or + // assignment. This block therefore no longer has a + // special use and is subject to allocation to a + // Regional Internet Registry for assignment in the + // normal manner. + + // 127.0.0.0/8 - This block is assigned for use as the Internet host + // loopback address. A datagram sent by a higher level protocol to an + // address anywhere within this block should loop back inside the host. + // This is ordinarily implemented using only 127.0.0.1/32 for loopback, + // but no addresses within this block should ever appear on any network + // anywhere [RFC1700, page 5]. + MustIPv4Addr("127.0.0.0/8"), + + // 128.0.0.0/16 - This block, corresponding to the + // numerically lowest of the former Class B addresses, + // was initially and is still reserved by the IANA. + // Given the present classless nature of the IP address + // space, the basis for the reservation no longer + // applies and addresses in this block are subject to + // future allocation to a Regional Internet Registry for + // assignment in the normal manner. + + // 169.254.0.0/16 - This is the "link local" block. It + // is allocated for communication between hosts on a + // single link. Hosts obtain these addresses by + // auto-configuration, such as when a DHCP server may + // not be found. + MustIPv4Addr("169.254.0.0/16"), + + // 172.16.0.0/12 - This block is set aside for use in + // private networks. Its intended use is documented in + // [RFC1918]. Addresses within this block should not + // appear on the public Internet. + MustIPv4Addr("172.16.0.0/12"), + + // 191.255.0.0/16 - This block, corresponding to the numerically highest + // to the former Class B addresses, was initially and is still reserved + // by the IANA. Given the present classless nature of the IP address + // space, the basis for the reservation no longer applies and addresses + // in this block are subject to future allocation to a Regional Internet + // Registry for assignment in the normal manner. + + // 192.0.0.0/24 - This block, corresponding to the + // numerically lowest of the former Class C addresses, + // was initially and is still reserved by the IANA. + // Given the present classless nature of the IP address + // space, the basis for the reservation no longer + // applies and addresses in this block are subject to + // future allocation to a Regional Internet Registry for + // assignment in the normal manner. + + // 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in + // documentation and example code. It is often used in conjunction with + // domain names example.com or example.net in vendor and protocol + // documentation. Addresses within this block should not appear on the + // public Internet. + MustIPv4Addr("192.0.2.0/24"), + + // 192.88.99.0/24 - This block is allocated for use as 6to4 relay + // anycast addresses, according to [RFC3068]. + MustIPv4Addr("192.88.99.0/24"), + + // 192.168.0.0/16 - This block is set aside for use in private networks. + // Its intended use is documented in [RFC1918]. Addresses within this + // block should not appear on the public Internet. + MustIPv4Addr("192.168.0.0/16"), + + // 198.18.0.0/15 - This block has been allocated for use + // in benchmark tests of network interconnect devices. + // Its use is documented in [RFC2544]. + MustIPv4Addr("198.18.0.0/15"), + + // 223.255.255.0/24 - This block, corresponding to the + // numerically highest of the former Class C addresses, + // was initially and is still reserved by the IANA. + // Given the present classless nature of the IP address + // space, the basis for the reservation no longer + // applies and addresses in this block are subject to + // future allocation to a Regional Internet Registry for + // assignment in the normal manner. + + // 224.0.0.0/4 - This block, formerly known as the Class + // D address space, is allocated for use in IPv4 + // multicast address assignments. The IANA guidelines + // for assignments from this space are described in + // [RFC3171]. + MustIPv4Addr("224.0.0.0/4"), + + // 240.0.0.0/4 - This block, formerly known as the Class E address + // space, is reserved. The "limited broadcast" destination address + // 255.255.255.255 should never be forwarded outside the (sub-)net of + // the source. The remainder of this space is reserved + // for future use. [RFC1700, page 4] + MustIPv4Addr("240.0.0.0/4"), + }, + 3849: { + // [RFC3849] IPv6 Address Prefix Reserved for Documentation + MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations + }, + 3927: { + // [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses + MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection + }, + 4038: { + // [RFC4038] Application Aspects of IPv6 Transition + + // [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node + MustIPv6Addr("0:0:0:0:0:ffff::/96"), + }, + 4193: { + // [RFC4193] Unique Local IPv6 Unicast Addresses + MustIPv6Addr("fc00::/7"), + }, + 4291: { + // [RFC4291] IP Version 6 Addressing Architecture + + // [RFC4291], §2.5.2 The Unspecified Address + MustIPv6Addr("::/128"), + + // [RFC4291], §2.5.3 The Loopback Address + MustIPv6Addr("::1/128"), + + // [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address + MustIPv6Addr("::/96"), + + // [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address + MustIPv6Addr("::ffff:0:0/96"), + + // [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses + MustIPv6Addr("fe80::/10"), + + // [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses + // (depreciated) + MustIPv6Addr("fec0::/10"), + + // [RFC4291], §2.7 Multicast Addresses + MustIPv6Addr("ff00::/8"), + + // IPv6 Multicast Information. + // + // In the following "table" below, `ff0x` is replaced + // with the following values depending on the scope of + // the query: + // + // IPv6 Multicast Scopes: + // * ff00/9 // reserved + // * ff01/9 // interface-local + // * ff02/9 // link-local + // * ff03/9 // realm-local + // * ff04/9 // admin-local + // * ff05/9 // site-local + // * ff08/9 // organization-local + // * ff0e/9 // global + // * ff0f/9 // reserved + // + // IPv6 Multicast Addresses: + // * ff0x::2 // All routers + // * ff02::5 // OSPFIGP + // * ff02::6 // OSPFIGP Designated Routers + // * ff02::9 // RIP Routers + // * ff02::a // EIGRP Routers + // * ff02::d // All PIM Routers + // * ff02::1a // All RPL Routers + // * ff0x::fb // mDNSv6 + // * ff0x::101 // All Network Time Protocol (NTP) servers + // * ff02::1:1 // Link Name + // * ff02::1:2 // All-dhcp-agents + // * ff02::1:3 // Link-local Multicast Name Resolution + // * ff05::1:3 // All-dhcp-servers + // * ff02::1:ff00:0/104 // Solicited-node multicast address. + // * ff02::2:ff00:0/104 // Node Information Queries + }, + 4380: { + // [RFC4380] Teredo: Tunneling IPv6 over UDP through + // Network Address Translations (NATs) + + // [RFC4380], §2.6 Global Teredo IPv6 Service Prefix + MustIPv6Addr("2001:0000::/32"), + }, + 4773: { + // [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block + MustIPv6Addr("2001:0000::/23"), // IANA + }, + 4843: { + // [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID) + MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations + }, + 5180: { + // [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices + MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations + }, + 5735: { + // [RFC5735] Special Use IPv4 Addresses + MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1 + MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2 + MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3 + MustIPv4Addr("198.18.0.0/15"), // Benchmarks + }, + 5737: { + // [RFC5737] IPv4 Address Blocks Reserved for Documentation + MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1 + MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2 + MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3 + }, + 6052: { + // [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators + MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix + }, + 6333: { + // [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion + MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address + }, + 6598: { + // [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space + MustIPv4Addr("100.64.0.0/10"), + }, + 6666: { + // [RFC6666] A Discard Prefix for IPv6 + MustIPv6Addr("0100::/64"), + }, + 6890: { + // [RFC6890] Special-Purpose IP Address Registries + + // From "RFC6890 §2.2.1 Information Requirements": + /* + The IPv4 and IPv6 Special-Purpose Address Registries maintain the + following information regarding each entry: + + o Address Block - A block of IPv4 or IPv6 addresses that has been + registered for a special purpose. + + o Name - A descriptive name for the special-purpose address block. + + o RFC - The RFC through which the special-purpose address block was + requested. + + o Allocation Date - The date upon which the special-purpose address + block was allocated. + + o Termination Date - The date upon which the allocation is to be + terminated. This field is applicable for limited-use allocations + only. + + o Source - A boolean value indicating whether an address from the + allocated special-purpose address block is valid when used as the + source address of an IP datagram that transits two devices. + + o Destination - A boolean value indicating whether an address from + the allocated special-purpose address block is valid when used as + the destination address of an IP datagram that transits two + devices. + + o Forwardable - A boolean value indicating whether a router may + forward an IP datagram whose destination address is drawn from the + allocated special-purpose address block between external + interfaces. + + o Global - A boolean value indicating whether an IP datagram whose + destination address is drawn from the allocated special-purpose + address block is forwardable beyond a specified administrative + domain. + + o Reserved-by-Protocol - A boolean value indicating whether the + special-purpose address block is reserved by IP, itself. This + value is "TRUE" if the RFC that created the special-purpose + address block requires all compliant IP implementations to behave + in a special way when processing packets either to or from + addresses contained by the address block. + + If the value of "Destination" is FALSE, the values of "Forwardable" + and "Global" must also be false. + */ + + /*+----------------------+----------------------------+ + * | Attribute | Value | + * +----------------------+----------------------------+ + * | Address Block | 0.0.0.0/8 | + * | Name | "This host on this network"| + * | RFC | [RFC1122], Section 3.2.1.3 | + * | Allocation Date | September 1981 | + * | Termination Date | N/A | + * | Source | True | + * | Destination | False | + * | Forwardable | False | + * | Global | False | + * | Reserved-by-Protocol | True | + * +----------------------+----------------------------+*/ + MustIPv4Addr("0.0.0.0/8"), + + /*+----------------------+---------------+ + * | Attribute | Value | + * +----------------------+---------------+ + * | Address Block | 10.0.0.0/8 | + * | Name | Private-Use | + * | RFC | [RFC1918] | + * | Allocation Date | February 1996 | + * | Termination Date | N/A | + * | Source | True | + * | Destination | True | + * | Forwardable | True | + * | Global | False | + * | Reserved-by-Protocol | False | + * +----------------------+---------------+ */ + MustIPv4Addr("10.0.0.0/8"), + + /*+----------------------+----------------------+ + | Attribute | Value | + +----------------------+----------------------+ + | Address Block | 100.64.0.0/10 | + | Name | Shared Address Space | + | RFC | [RFC6598] | + | Allocation Date | April 2012 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------+*/ + MustIPv4Addr("100.64.0.0/10"), + + /*+----------------------+----------------------------+ + | Attribute | Value | + +----------------------+----------------------------+ + | Address Block | 127.0.0.0/8 | + | Name | Loopback | + | RFC | [RFC1122], Section 3.2.1.3 | + | Allocation Date | September 1981 | + | Termination Date | N/A | + | Source | False [1] | + | Destination | False [1] | + | Forwardable | False [1] | + | Global | False [1] | + | Reserved-by-Protocol | True | + +----------------------+----------------------------+*/ + // [1] Several protocols have been granted exceptions to + // this rule. For examples, see [RFC4379] and + // [RFC5884]. + MustIPv4Addr("127.0.0.0/8"), + + /*+----------------------+----------------+ + | Attribute | Value | + +----------------------+----------------+ + | Address Block | 169.254.0.0/16 | + | Name | Link Local | + | RFC | [RFC3927] | + | Allocation Date | May 2005 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+----------------+*/ + MustIPv4Addr("169.254.0.0/16"), + + /*+----------------------+---------------+ + | Attribute | Value | + +----------------------+---------------+ + | Address Block | 172.16.0.0/12 | + | Name | Private-Use | + | RFC | [RFC1918] | + | Allocation Date | February 1996 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+---------------+*/ + MustIPv4Addr("172.16.0.0/12"), + + /*+----------------------+---------------------------------+ + | Attribute | Value | + +----------------------+---------------------------------+ + | Address Block | 192.0.0.0/24 [2] | + | Name | IETF Protocol Assignments | + | RFC | Section 2.1 of this document | + | Allocation Date | January 2010 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+---------------------------------+*/ + // [2] Not usable unless by virtue of a more specific + // reservation. + MustIPv4Addr("192.0.0.0/24"), + + /*+----------------------+--------------------------------+ + | Attribute | Value | + +----------------------+--------------------------------+ + | Address Block | 192.0.0.0/29 | + | Name | IPv4 Service Continuity Prefix | + | RFC | [RFC6333], [RFC7335] | + | Allocation Date | June 2011 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+--------------------------------+*/ + MustIPv4Addr("192.0.0.0/29"), + + /*+----------------------+----------------------------+ + | Attribute | Value | + +----------------------+----------------------------+ + | Address Block | 192.0.2.0/24 | + | Name | Documentation (TEST-NET-1) | + | RFC | [RFC5737] | + | Allocation Date | January 2010 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------------+*/ + MustIPv4Addr("192.0.2.0/24"), + + /*+----------------------+--------------------+ + | Attribute | Value | + +----------------------+--------------------+ + | Address Block | 192.88.99.0/24 | + | Name | 6to4 Relay Anycast | + | RFC | [RFC3068] | + | Allocation Date | June 2001 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | True | + | Reserved-by-Protocol | False | + +----------------------+--------------------+*/ + MustIPv4Addr("192.88.99.0/24"), + + /*+----------------------+----------------+ + | Attribute | Value | + +----------------------+----------------+ + | Address Block | 192.168.0.0/16 | + | Name | Private-Use | + | RFC | [RFC1918] | + | Allocation Date | February 1996 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------+*/ + MustIPv4Addr("192.168.0.0/16"), + + /*+----------------------+---------------+ + | Attribute | Value | + +----------------------+---------------+ + | Address Block | 198.18.0.0/15 | + | Name | Benchmarking | + | RFC | [RFC2544] | + | Allocation Date | March 1999 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+---------------+*/ + MustIPv4Addr("198.18.0.0/15"), + + /*+----------------------+----------------------------+ + | Attribute | Value | + +----------------------+----------------------------+ + | Address Block | 198.51.100.0/24 | + | Name | Documentation (TEST-NET-2) | + | RFC | [RFC5737] | + | Allocation Date | January 2010 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------------+*/ + MustIPv4Addr("198.51.100.0/24"), + + /*+----------------------+----------------------------+ + | Attribute | Value | + +----------------------+----------------------------+ + | Address Block | 203.0.113.0/24 | + | Name | Documentation (TEST-NET-3) | + | RFC | [RFC5737] | + | Allocation Date | January 2010 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------------+*/ + MustIPv4Addr("203.0.113.0/24"), + + /*+----------------------+----------------------+ + | Attribute | Value | + +----------------------+----------------------+ + | Address Block | 240.0.0.0/4 | + | Name | Reserved | + | RFC | [RFC1112], Section 4 | + | Allocation Date | August 1989 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+----------------------+*/ + MustIPv4Addr("240.0.0.0/4"), + + /*+----------------------+----------------------+ + | Attribute | Value | + +----------------------+----------------------+ + | Address Block | 255.255.255.255/32 | + | Name | Limited Broadcast | + | RFC | [RFC0919], Section 7 | + | Allocation Date | October 1984 | + | Termination Date | N/A | + | Source | False | + | Destination | True | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------+*/ + MustIPv4Addr("255.255.255.255/32"), + + /*+----------------------+------------------+ + | Attribute | Value | + +----------------------+------------------+ + | Address Block | ::1/128 | + | Name | Loopback Address | + | RFC | [RFC4291] | + | Allocation Date | February 2006 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+------------------+*/ + MustIPv6Addr("::1/128"), + + /*+----------------------+---------------------+ + | Attribute | Value | + +----------------------+---------------------+ + | Address Block | ::/128 | + | Name | Unspecified Address | + | RFC | [RFC4291] | + | Allocation Date | February 2006 | + | Termination Date | N/A | + | Source | True | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+---------------------+*/ + MustIPv6Addr("::/128"), + + /*+----------------------+---------------------+ + | Attribute | Value | + +----------------------+---------------------+ + | Address Block | 64:ff9b::/96 | + | Name | IPv4-IPv6 Translat. | + | RFC | [RFC6052] | + | Allocation Date | October 2010 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | True | + | Reserved-by-Protocol | False | + +----------------------+---------------------+*/ + MustIPv6Addr("64:ff9b::/96"), + + /*+----------------------+---------------------+ + | Attribute | Value | + +----------------------+---------------------+ + | Address Block | ::ffff:0:0/96 | + | Name | IPv4-mapped Address | + | RFC | [RFC4291] | + | Allocation Date | February 2006 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+---------------------+*/ + MustIPv6Addr("::ffff:0:0/96"), + + /*+----------------------+----------------------------+ + | Attribute | Value | + +----------------------+----------------------------+ + | Address Block | 100::/64 | + | Name | Discard-Only Address Block | + | RFC | [RFC6666] | + | Allocation Date | June 2012 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------------------+*/ + MustIPv6Addr("100::/64"), + + /*+----------------------+---------------------------+ + | Attribute | Value | + +----------------------+---------------------------+ + | Address Block | 2001::/23 | + | Name | IETF Protocol Assignments | + | RFC | [RFC2928] | + | Allocation Date | September 2000 | + | Termination Date | N/A | + | Source | False[1] | + | Destination | False[1] | + | Forwardable | False[1] | + | Global | False[1] | + | Reserved-by-Protocol | False | + +----------------------+---------------------------+*/ + // [1] Unless allowed by a more specific allocation. + MustIPv6Addr("2001::/16"), + + /*+----------------------+----------------+ + | Attribute | Value | + +----------------------+----------------+ + | Address Block | 2001::/32 | + | Name | TEREDO | + | RFC | [RFC4380] | + | Allocation Date | January 2006 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------+*/ + // Covered by previous entry, included for completeness. + // + // MustIPv6Addr("2001::/16"), + + /*+----------------------+----------------+ + | Attribute | Value | + +----------------------+----------------+ + | Address Block | 2001:2::/48 | + | Name | Benchmarking | + | RFC | [RFC5180] | + | Allocation Date | April 2008 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+----------------+*/ + // Covered by previous entry, included for completeness. + // + // MustIPv6Addr("2001:2::/48"), + + /*+----------------------+---------------+ + | Attribute | Value | + +----------------------+---------------+ + | Address Block | 2001:db8::/32 | + | Name | Documentation | + | RFC | [RFC3849] | + | Allocation Date | July 2004 | + | Termination Date | N/A | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+---------------+*/ + // Covered by previous entry, included for completeness. + // + // MustIPv6Addr("2001:db8::/32"), + + /*+----------------------+--------------+ + | Attribute | Value | + +----------------------+--------------+ + | Address Block | 2001:10::/28 | + | Name | ORCHID | + | RFC | [RFC4843] | + | Allocation Date | March 2007 | + | Termination Date | March 2014 | + | Source | False | + | Destination | False | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+--------------+*/ + // Covered by previous entry, included for completeness. + // + // MustIPv6Addr("2001:10::/28"), + + /*+----------------------+---------------+ + | Attribute | Value | + +----------------------+---------------+ + | Address Block | 2002::/16 [2] | + | Name | 6to4 | + | RFC | [RFC3056] | + | Allocation Date | February 2001 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | N/A [2] | + | Reserved-by-Protocol | False | + +----------------------+---------------+*/ + // [2] See [RFC3056] for details. + MustIPv6Addr("2002::/16"), + + /*+----------------------+--------------+ + | Attribute | Value | + +----------------------+--------------+ + | Address Block | fc00::/7 | + | Name | Unique-Local | + | RFC | [RFC4193] | + | Allocation Date | October 2005 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | True | + | Global | False | + | Reserved-by-Protocol | False | + +----------------------+--------------+*/ + MustIPv6Addr("fc00::/7"), + + /*+----------------------+-----------------------+ + | Attribute | Value | + +----------------------+-----------------------+ + | Address Block | fe80::/10 | + | Name | Linked-Scoped Unicast | + | RFC | [RFC4291] | + | Allocation Date | February 2006 | + | Termination Date | N/A | + | Source | True | + | Destination | True | + | Forwardable | False | + | Global | False | + | Reserved-by-Protocol | True | + +----------------------+-----------------------+*/ + MustIPv6Addr("fe80::/10"), + }, + 7335: { + // [RFC7335] IPv4 Service Continuity Prefix + MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations + }, + ForwardingBlacklist: { // Pseudo-RFC + // Blacklist of non-forwardable IP blocks taken from RFC6890 + // + // TODO: the attributes for forwardable should be + // searcahble and embedded in the main list of RFCs + // above. + MustIPv4Addr("0.0.0.0/8"), + MustIPv4Addr("127.0.0.0/8"), + MustIPv4Addr("169.254.0.0/16"), + MustIPv4Addr("192.0.0.0/24"), + MustIPv4Addr("192.0.2.0/24"), + MustIPv4Addr("198.51.100.0/24"), + MustIPv4Addr("203.0.113.0/24"), + MustIPv4Addr("240.0.0.0/4"), + MustIPv4Addr("255.255.255.255/32"), + MustIPv6Addr("::1/128"), + MustIPv6Addr("::/128"), + MustIPv6Addr("::ffff:0:0/96"), + + // There is no way of expressing a whitelist per RFC2928 + // atm without creating a negative mask, which I don't + // want to do atm. + //MustIPv6Addr("2001::/23"), + + MustIPv6Addr("2001:db8::/32"), + MustIPv6Addr("2001:10::/28"), + MustIPv6Addr("fe80::/10"), + }, + } +} + +// VisitAllRFCs iterates over all known RFCs and calls the visitor +func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) { + rfcNetMap := KnownRFCs() + + // Blacklist of faux-RFCs. Don't show the world that we're abusing the + // RFC system in this library. + rfcBlacklist := map[uint]struct{}{ + ForwardingBlacklist: {}, + } + + for rfcNum, sas := range rfcNetMap { + if _, found := rfcBlacklist[rfcNum]; !found { + fn(rfcNum, sas) + } + } +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info.go b/vendor/github.com/hashicorp/go-sockaddr/route_info.go new file mode 100644 index 0000000..2a3ee1d --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info.go @@ -0,0 +1,19 @@ +package sockaddr + +// RouteInterface specifies an interface for obtaining memoized route table and +// network information from a given OS. +type RouteInterface interface { + // GetDefaultInterfaceName returns the name of the interface that has a + // default route or an error and an empty string if a problem was + // encountered. + GetDefaultInterfaceName() (string, error) +} + +// VisitCommands visits each command used by the platform-specific RouteInfo +// implementation. +func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) { + for k, v := range ri.cmds { + cmds := append([]string(nil), v...) + fn(k, cmds) + } +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go new file mode 100644 index 0000000..705757a --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go @@ -0,0 +1,36 @@ +// +build darwin dragonfly freebsd netbsd openbsd + +package sockaddr + +import "os/exec" + +var cmds map[string][]string = map[string][]string{ + "route": {"/sbin/route", "-n", "get", "default"}, +} + +type routeInfo struct { + cmds map[string][]string +} + +// NewRouteInfo returns a BSD-specific implementation of the RouteInfo +// interface. +func NewRouteInfo() (routeInfo, error) { + return routeInfo{ + cmds: cmds, + }, nil +} + +// GetDefaultInterfaceName returns the interface name attached to the default +// route on the default interface. +func (ri routeInfo) GetDefaultInterfaceName() (string, error) { + out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output() + if err != nil { + return "", err + } + + var ifName string + if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { + return "", err + } + return ifName, nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go new file mode 100644 index 0000000..d1b009f --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go @@ -0,0 +1,10 @@ +// +build android nacl plan9 + +package sockaddr + +import "errors" + +// getDefaultIfName is the default interface function for unsupported platforms. +func getDefaultIfName() (string, error) { + return "", errors.New("No default interface found (unsupported platform)") +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go new file mode 100644 index 0000000..c2ec91e --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go @@ -0,0 +1,40 @@ +package sockaddr + +import ( + "errors" + "os/exec" +) + +type routeInfo struct { + cmds map[string][]string +} + +// NewRouteInfo returns a Linux-specific implementation of the RouteInfo +// interface. +func NewRouteInfo() (routeInfo, error) { + // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on + // $PATH and fallback to /sbin/ip on error. + path, _ := exec.LookPath("ip") + if path == "" { + path = "/sbin/ip" + } + + return routeInfo{ + cmds: map[string][]string{"ip": {path, "route"}}, + }, nil +} + +// GetDefaultInterfaceName returns the interface name attached to the default +// route on the default interface. +func (ri routeInfo) GetDefaultInterfaceName() (string, error) { + out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() + if err != nil { + return "", err + } + + var ifName string + if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil { + return "", errors.New("No default interface found") + } + return ifName, nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go new file mode 100644 index 0000000..ee8e798 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go @@ -0,0 +1,37 @@ +package sockaddr + +import ( + "errors" + "os/exec" +) + +var cmds map[string][]string = map[string][]string{ + "route": {"/usr/sbin/route", "-n", "get", "default"}, +} + +type routeInfo struct { + cmds map[string][]string +} + +// NewRouteInfo returns a BSD-specific implementation of the RouteInfo +// interface. +func NewRouteInfo() (routeInfo, error) { + return routeInfo{ + cmds: cmds, + }, nil +} + +// GetDefaultInterfaceName returns the interface name attached to the default +// route on the default interface. +func (ri routeInfo) GetDefaultInterfaceName() (string, error) { + out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output() + if err != nil { + return "", err + } + + var ifName string + if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { + return "", errors.New("No default interface found") + } + return ifName, nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go new file mode 100644 index 0000000..3da9728 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go @@ -0,0 +1,41 @@ +package sockaddr + +import "os/exec" + +var cmds map[string][]string = map[string][]string{ + "netstat": {"netstat", "-rn"}, + "ipconfig": {"ipconfig"}, +} + +type routeInfo struct { + cmds map[string][]string +} + +// NewRouteInfo returns a BSD-specific implementation of the RouteInfo +// interface. +func NewRouteInfo() (routeInfo, error) { + return routeInfo{ + cmds: cmds, + }, nil +} + +// GetDefaultInterfaceName returns the interface name attached to the default +// route on the default interface. +func (ri routeInfo) GetDefaultInterfaceName() (string, error) { + ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output() + if err != nil { + return "", err + } + + ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output() + if err != nil { + return "", err + } + + ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut)) + if err != nil { + return "", err + } + + return ifName, nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go new file mode 100644 index 0000000..826c91c --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go @@ -0,0 +1,206 @@ +package sockaddr + +import ( + "encoding/json" + "fmt" + "strings" +) + +type SockAddrType int +type AttrName string + +const ( + TypeUnknown SockAddrType = 0x0 + TypeUnix = 0x1 + TypeIPv4 = 0x2 + TypeIPv6 = 0x4 + + // TypeIP is the union of TypeIPv4 and TypeIPv6 + TypeIP = 0x6 +) + +type SockAddr interface { + // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC + // networks, -1 if the receiver is contained within the RFC network, or + // 1 if the address is not contained within the RFC. + CmpRFC(rfcNum uint, sa SockAddr) int + + // Contains returns true if the SockAddr arg is contained within the + // receiver + Contains(SockAddr) bool + + // Equal allows for the comparison of two SockAddrs + Equal(SockAddr) bool + + DialPacketArgs() (string, string) + DialStreamArgs() (string, string) + ListenPacketArgs() (string, string) + ListenStreamArgs() (string, string) + + // String returns the string representation of SockAddr + String() string + + // Type returns the SockAddrType + Type() SockAddrType +} + +// sockAddrAttrMap is a map of the SockAddr type-specific attributes. +var sockAddrAttrMap map[AttrName]func(SockAddr) string +var sockAddrAttrs []AttrName + +func init() { + sockAddrInit() +} + +// New creates a new SockAddr from the string. The order in which New() +// attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix. +// +// NOTE: New() relies on the heuristic wherein if the path begins with either a +// '.' or '/' character before creating a new UnixSock. For UNIX sockets that +// are absolute paths or are nested within a sub-directory, this works as +// expected, however if the UNIX socket is contained in the current working +// directory, this will fail unless the path begins with "./" +// (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer +// this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul +// of this heuristic and be assumed to be a valid UNIX socket path (which they +// are, but it is probably not what you want and you won't realize it until you +// stat(2) the file system to discover it doesn't exist). +func NewSockAddr(s string) (SockAddr, error) { + ipv4Addr, err := NewIPv4Addr(s) + if err == nil { + return ipv4Addr, nil + } + + ipv6Addr, err := NewIPv6Addr(s) + if err == nil { + return ipv6Addr, nil + } + + // Check to make sure the string begins with either a '.' or '/', or + // contains a '/'. + if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) { + unixSock, err := NewUnixSock(s) + if err == nil { + return unixSock, nil + } + } + + return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s) +} + +// ToIPAddr returns an IPAddr type or nil if the type conversion fails. +func ToIPAddr(sa SockAddr) *IPAddr { + ipa, ok := sa.(IPAddr) + if !ok { + return nil + } + return &ipa +} + +// ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails. +func ToIPv4Addr(sa SockAddr) *IPv4Addr { + switch v := sa.(type) { + case IPv4Addr: + return &v + default: + return nil + } +} + +// ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails. +func ToIPv6Addr(sa SockAddr) *IPv6Addr { + switch v := sa.(type) { + case IPv6Addr: + return &v + default: + return nil + } +} + +// ToUnixSock returns a UnixSock type or nil if the type conversion fails. +func ToUnixSock(sa SockAddr) *UnixSock { + switch v := sa.(type) { + case UnixSock: + return &v + default: + return nil + } +} + +// SockAddrAttr returns a string representation of an attribute for the given +// SockAddr. +func SockAddrAttr(sa SockAddr, selector AttrName) string { + fn, found := sockAddrAttrMap[selector] + if !found { + return "" + } + + return fn(sa) +} + +// String() for SockAddrType returns a string representation of the +// SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown"). +func (sat SockAddrType) String() string { + switch sat { + case TypeIPv4: + return "IPv4" + case TypeIPv6: + return "IPv6" + // There is no concrete "IP" type. Leaving here as a reminder. + // case TypeIP: + // return "IP" + case TypeUnix: + return "UNIX" + default: + panic("unsupported type") + } +} + +// sockAddrInit is called once at init() +func sockAddrInit() { + sockAddrAttrs = []AttrName{ + "type", // type should be first + "string", + } + + sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{ + "string": func(sa SockAddr) string { + return sa.String() + }, + "type": func(sa SockAddr) string { + return sa.Type().String() + }, + } +} + +// UnixSockAttrs returns a list of attributes supported by the UnixSock type +func SockAddrAttrs() []AttrName { + return sockAddrAttrs +} + +// Although this is pretty trivial to do in a program, having the logic here is +// useful all around. Note that this marshals into a *string* -- the underlying +// string representation of the sockaddr. If you then unmarshal into this type +// in Go, all will work as expected, but externally you can take what comes out +// and use the string value directly. +type SockAddrMarshaler struct { + SockAddr +} + +func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) { + return json.Marshal(s.SockAddr.String()) +} + +func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error { + var str string + err := json.Unmarshal(in, &str) + if err != nil { + return err + } + sa, err := NewSockAddr(str) + if err != nil { + return err + } + s.SockAddr = sa + return nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go new file mode 100644 index 0000000..75fbffb --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go @@ -0,0 +1,193 @@ +package sockaddr + +import ( + "bytes" + "sort" +) + +// SockAddrs is a slice of SockAddrs +type SockAddrs []SockAddr + +func (s SockAddrs) Len() int { return len(s) } +func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// CmpAddrFunc is the function signature that must be met to be used in the +// OrderedAddrBy multiAddrSorter +type CmpAddrFunc func(p1, p2 *SockAddr) int + +// multiAddrSorter implements the Sort interface, sorting the SockAddrs within. +type multiAddrSorter struct { + addrs SockAddrs + cmp []CmpAddrFunc +} + +// Sort sorts the argument slice according to the Cmp functions passed to +// OrderedAddrBy. +func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) { + ms.addrs = sockAddrs + sort.Sort(ms) +} + +// OrderedAddrBy sorts SockAddr by the list of sort function pointers. +func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter { + return &multiAddrSorter{ + cmp: cmpFuncs, + } +} + +// Len is part of sort.Interface. +func (ms *multiAddrSorter) Len() int { + return len(ms.addrs) +} + +// Less is part of sort.Interface. It is implemented by looping along the +// Cmp() functions until it finds a comparison that is either less than, +// equal to, or greater than. +func (ms *multiAddrSorter) Less(i, j int) bool { + p, q := &ms.addrs[i], &ms.addrs[j] + // Try all but the last comparison. + var k int + for k = 0; k < len(ms.cmp)-1; k++ { + cmp := ms.cmp[k] + x := cmp(p, q) + switch x { + case -1: + // p < q, so we have a decision. + return true + case 1: + // p > q, so we have a decision. + return false + } + // p == q; try the next comparison. + } + // All comparisons to here said "equal", so just return whatever the + // final comparison reports. + switch ms.cmp[k](p, q) { + case -1: + return true + case 1: + return false + default: + // Still a tie! Now what? + return false + } +} + +// Swap is part of sort.Interface. +func (ms *multiAddrSorter) Swap(i, j int) { + ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i] +} + +const ( + // NOTE (sean@): These constants are here for code readability only and + // are sprucing up the code for readability purposes. Some of the + // Cmp*() variants have confusing logic (especially when dealing with + // mixed-type comparisons) and this, I think, has made it easier to grok + // the code faster. + sortReceiverBeforeArg = -1 + sortDeferDecision = 0 + sortArgBeforeReceiver = 1 +) + +// AscAddress is a sorting function to sort SockAddrs by their respective +// address type. Non-equal types are deferred in the sort. +func AscAddress(p1Ptr, p2Ptr *SockAddr) int { + p1 := *p1Ptr + p2 := *p2Ptr + + switch v := p1.(type) { + case IPv4Addr: + return v.CmpAddress(p2) + case IPv6Addr: + return v.CmpAddress(p2) + case UnixSock: + return v.CmpAddress(p2) + default: + return sortDeferDecision + } +} + +// AscPort is a sorting function to sort SockAddrs by their respective address +// type. Non-equal types are deferred in the sort. +func AscPort(p1Ptr, p2Ptr *SockAddr) int { + p1 := *p1Ptr + p2 := *p2Ptr + + switch v := p1.(type) { + case IPv4Addr: + return v.CmpPort(p2) + case IPv6Addr: + return v.CmpPort(p2) + default: + return sortDeferDecision + } +} + +// AscPrivate is a sorting function to sort "more secure" private values before +// "more public" values. Both IPv4 and IPv6 are compared against RFC6890 +// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and +// IPv6 includes RFC4193). +func AscPrivate(p1Ptr, p2Ptr *SockAddr) int { + p1 := *p1Ptr + p2 := *p2Ptr + + switch v := p1.(type) { + case IPv4Addr, IPv6Addr: + return v.CmpRFC(6890, p2) + default: + return sortDeferDecision + } +} + +// AscNetworkSize is a sorting function to sort SockAddrs based on their network +// size. Non-equal types are deferred in the sort. +func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int { + p1 := *p1Ptr + p2 := *p2Ptr + p1Type := p1.Type() + p2Type := p2.Type() + + // Network size operations on non-IP types make no sense + if p1Type != p2Type && p1Type != TypeIP { + return sortDeferDecision + } + + ipA := p1.(IPAddr) + ipB := p2.(IPAddr) + + return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask())) +} + +// AscType is a sorting function to sort "more secure" types before +// "less-secure" types. +func AscType(p1Ptr, p2Ptr *SockAddr) int { + p1 := *p1Ptr + p2 := *p2Ptr + p1Type := p1.Type() + p2Type := p2.Type() + switch { + case p1Type < p2Type: + return sortReceiverBeforeArg + case p1Type == p2Type: + return sortDeferDecision + case p1Type > p2Type: + return sortArgBeforeReceiver + default: + return sortDeferDecision + } +} + +// FilterByType returns two lists: a list of matched and unmatched SockAddrs +func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) { + matched = make(SockAddrs, 0, len(sas)) + excluded = make(SockAddrs, 0, len(sas)) + + for _, sa := range sas { + if sa.Type()&type_ != 0 { + matched = append(matched, sa) + } else { + excluded = append(excluded, sa) + } + } + return matched, excluded +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/unixsock.go b/vendor/github.com/hashicorp/go-sockaddr/unixsock.go new file mode 100644 index 0000000..f3be3f6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/unixsock.go @@ -0,0 +1,135 @@ +package sockaddr + +import ( + "fmt" + "strings" +) + +type UnixSock struct { + SockAddr + path string +} +type UnixSocks []*UnixSock + +// unixAttrMap is a map of the UnixSockAddr type-specific attributes. +var unixAttrMap map[AttrName]func(UnixSock) string +var unixAttrs []AttrName + +func init() { + unixAttrInit() +} + +// NewUnixSock creates an UnixSock from a string path. String can be in the +// form of either URI-based string (e.g. `file:///etc/passwd`), an absolute +// path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`). +func NewUnixSock(s string) (ret UnixSock, err error) { + ret.path = s + return ret, nil +} + +// CmpAddress follows the Cmp() standard protocol and returns: +// +// - -1 If the receiver should sort first because its name lexically sorts before arg +// - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path. +// - 1 If the argument should sort first. +func (us UnixSock) CmpAddress(sa SockAddr) int { + usb, ok := sa.(UnixSock) + if !ok { + return sortDeferDecision + } + + return strings.Compare(us.Path(), usb.Path()) +} + +// DialPacketArgs returns the arguments required to be passed to net.DialUnix() +// with the `unixgram` network type. +func (us UnixSock) DialPacketArgs() (network, dialArgs string) { + return "unixgram", us.path +} + +// DialStreamArgs returns the arguments required to be passed to net.DialUnix() +// with the `unix` network type. +func (us UnixSock) DialStreamArgs() (network, dialArgs string) { + return "unix", us.path +} + +// Equal returns true if a SockAddr is equal to the receiving UnixSock. +func (us UnixSock) Equal(sa SockAddr) bool { + usb, ok := sa.(UnixSock) + if !ok { + return false + } + + if us.Path() != usb.Path() { + return false + } + + return true +} + +// ListenPacketArgs returns the arguments required to be passed to +// net.ListenUnixgram() with the `unixgram` network type. +func (us UnixSock) ListenPacketArgs() (network, dialArgs string) { + return "unixgram", us.path +} + +// ListenStreamArgs returns the arguments required to be passed to +// net.ListenUnix() with the `unix` network type. +func (us UnixSock) ListenStreamArgs() (network, dialArgs string) { + return "unix", us.path +} + +// MustUnixSock is a helper method that must return an UnixSock or panic on +// invalid input. +func MustUnixSock(addr string) UnixSock { + us, err := NewUnixSock(addr) + if err != nil { + panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err)) + } + return us +} + +// Path returns the given path of the UnixSock +func (us UnixSock) Path() string { + return us.path +} + +// String returns the path of the UnixSock +func (us UnixSock) String() string { + return fmt.Sprintf("%+q", us.path) +} + +// Type is used as a type switch and returns TypeUnix +func (UnixSock) Type() SockAddrType { + return TypeUnix +} + +// UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type +func UnixSockAttrs() []AttrName { + return unixAttrs +} + +// UnixSockAttr returns a string representation of an attribute for the given +// UnixSock. +func UnixSockAttr(us UnixSock, attrName AttrName) string { + fn, found := unixAttrMap[attrName] + if !found { + return "" + } + + return fn(us) +} + +// unixAttrInit is called once at init() +func unixAttrInit() { + // Sorted for human readability + unixAttrs = []AttrName{ + "path", + } + + unixAttrMap = map[AttrName]func(us UnixSock) string{ + "path": func(us UnixSock) string { + return us.Path() + }, + } +} diff --git a/vendor/github.com/hashicorp/go-uuid/.travis.yml b/vendor/github.com/hashicorp/go-uuid/.travis.yml new file mode 100644 index 0000000..7698490 --- /dev/null +++ b/vendor/github.com/hashicorp/go-uuid/.travis.yml @@ -0,0 +1,12 @@ +language: go + +sudo: false + +go: + - 1.4 + - 1.5 + - 1.6 + - tip + +script: + - go test -bench . -benchmem -v ./... diff --git a/vendor/github.com/hashicorp/go-uuid/LICENSE b/vendor/github.com/hashicorp/go-uuid/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-uuid/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-uuid/README.md b/vendor/github.com/hashicorp/go-uuid/README.md new file mode 100644 index 0000000..fbde8b9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-uuid/README.md @@ -0,0 +1,8 @@ +# uuid [![Build Status](https://travis-ci.org/hashicorp/go-uuid.svg?branch=master)](https://travis-ci.org/hashicorp/go-uuid) + +Generates UUID-format strings using high quality, _purely random_ bytes. It is **not** intended to be RFC compliant, merely to use a well-understood string representation of a 128-bit value. It can also parse UUID-format strings into their component bytes. + +Documentation +============= + +The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-uuid). diff --git a/vendor/github.com/hashicorp/go-uuid/uuid.go b/vendor/github.com/hashicorp/go-uuid/uuid.go new file mode 100644 index 0000000..ff9364c --- /dev/null +++ b/vendor/github.com/hashicorp/go-uuid/uuid.go @@ -0,0 +1,65 @@ +package uuid + +import ( + "crypto/rand" + "encoding/hex" + "fmt" +) + +// GenerateRandomBytes is used to generate random bytes of given size. +func GenerateRandomBytes(size int) ([]byte, error) { + buf := make([]byte, size) + if _, err := rand.Read(buf); err != nil { + return nil, fmt.Errorf("failed to read random bytes: %v", err) + } + return buf, nil +} + +// GenerateUUID is used to generate a random UUID +func GenerateUUID() (string, error) { + buf, err := GenerateRandomBytes(16) + if err != nil { + return "", err + } + return FormatUUID(buf) +} + +func FormatUUID(buf []byte) (string, error) { + if len(buf) != 16 { + return "", fmt.Errorf("wrong length byte slice (%d)", len(buf)) + } + + return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x", + buf[0:4], + buf[4:6], + buf[6:8], + buf[8:10], + buf[10:16]), nil +} + +func ParseUUID(uuid string) ([]byte, error) { + if len(uuid) != 36 { + return nil, fmt.Errorf("uuid string is wrong length") + } + + hyph := []byte("-") + + if uuid[8] != hyph[0] || + uuid[13] != hyph[0] || + uuid[18] != hyph[0] || + uuid[23] != hyph[0] { + return nil, fmt.Errorf("uuid is improperly formatted") + } + + hexStr := uuid[0:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36] + + ret, err := hex.DecodeString(hexStr) + if err != nil { + return nil, err + } + if len(ret) != 16 { + return nil, fmt.Errorf("decoded hex is the wrong length") + } + + return ret, nil +} diff --git a/vendor/github.com/hashicorp/go-version/.travis.yml b/vendor/github.com/hashicorp/go-version/.travis.yml new file mode 100644 index 0000000..3f45b1e --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.0 + - 1.1 + - 1.2 + - 1.3 + - 1.4 + - 1.9 + +script: + - go test diff --git a/vendor/github.com/hashicorp/go-version/LICENSE b/vendor/github.com/hashicorp/go-version/LICENSE new file mode 100644 index 0000000..c33dcc7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/LICENSE @@ -0,0 +1,354 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md new file mode 100644 index 0000000..6f3a15c --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/README.md @@ -0,0 +1,65 @@ +# Versioning Library for Go +[![Build Status](https://travis-ci.org/hashicorp/go-version.svg?branch=master)](https://travis-ci.org/hashicorp/go-version) + +go-version is a library for parsing versions and version constraints, +and verifying versions against a set of constraints. go-version +can sort a collection of versions properly, handles prerelease/beta +versions, can increment versions, etc. + +Versions used with go-version must follow [SemVer](http://semver.org/). + +## Installation and Usage + +Package documentation can be found on +[GoDoc](http://godoc.org/github.com/hashicorp/go-version). + +Installation can be done with a normal `go get`: + +``` +$ go get github.com/hashicorp/go-version +``` + +#### Version Parsing and Comparison + +```go +v1, err := version.NewVersion("1.2") +v2, err := version.NewVersion("1.5+metadata") + +// Comparison example. There is also GreaterThan, Equal, and just +// a simple Compare that returns an int allowing easy >=, <=, etc. +if v1.LessThan(v2) { + fmt.Printf("%s is less than %s", v1, v2) +} +``` + +#### Version Constraints + +```go +v1, err := version.NewVersion("1.2") + +// Constraints example. +constraints, err := version.NewConstraint(">= 1.0, < 1.4") +if constraints.Check(v1) { + fmt.Printf("%s satisfies constraints %s", v1, constraints) +} +``` + +#### Version Sorting + +```go +versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"} +versions := make([]*version.Version, len(versionsRaw)) +for i, raw := range versionsRaw { + v, _ := version.NewVersion(raw) + versions[i] = v +} + +// After this, the versions are properly sorted +sort.Sort(version.Collection(versions)) +``` + +## Issues and Contributing + +If you find an issue with this library, please report an issue. If you'd +like, we welcome any contributions. Fork this library and submit a pull +request. diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go new file mode 100644 index 0000000..d055759 --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/constraint.go @@ -0,0 +1,204 @@ +package version + +import ( + "fmt" + "reflect" + "regexp" + "strings" +) + +// Constraint represents a single constraint for a version, such as +// ">= 1.0". +type Constraint struct { + f constraintFunc + check *Version + original string +} + +// Constraints is a slice of constraints. We make a custom type so that +// we can add methods to it. +type Constraints []*Constraint + +type constraintFunc func(v, c *Version) bool + +var constraintOperators map[string]constraintFunc + +var constraintRegexp *regexp.Regexp + +func init() { + constraintOperators = map[string]constraintFunc{ + "": constraintEqual, + "=": constraintEqual, + "!=": constraintNotEqual, + ">": constraintGreaterThan, + "<": constraintLessThan, + ">=": constraintGreaterThanEqual, + "<=": constraintLessThanEqual, + "~>": constraintPessimistic, + } + + ops := make([]string, 0, len(constraintOperators)) + for k := range constraintOperators { + ops = append(ops, regexp.QuoteMeta(k)) + } + + constraintRegexp = regexp.MustCompile(fmt.Sprintf( + `^\s*(%s)\s*(%s)\s*$`, + strings.Join(ops, "|"), + VersionRegexpRaw)) +} + +// NewConstraint will parse one or more constraints from the given +// constraint string. The string must be a comma-separated list of +// constraints. +func NewConstraint(v string) (Constraints, error) { + vs := strings.Split(v, ",") + result := make([]*Constraint, len(vs)) + for i, single := range vs { + c, err := parseSingle(single) + if err != nil { + return nil, err + } + + result[i] = c + } + + return Constraints(result), nil +} + +// Check tests if a version satisfies all the constraints. +func (cs Constraints) Check(v *Version) bool { + for _, c := range cs { + if !c.Check(v) { + return false + } + } + + return true +} + +// Returns the string format of the constraints +func (cs Constraints) String() string { + csStr := make([]string, len(cs)) + for i, c := range cs { + csStr[i] = c.String() + } + + return strings.Join(csStr, ",") +} + +// Check tests if a constraint is validated by the given version. +func (c *Constraint) Check(v *Version) bool { + return c.f(v, c.check) +} + +func (c *Constraint) String() string { + return c.original +} + +func parseSingle(v string) (*Constraint, error) { + matches := constraintRegexp.FindStringSubmatch(v) + if matches == nil { + return nil, fmt.Errorf("Malformed constraint: %s", v) + } + + check, err := NewVersion(matches[2]) + if err != nil { + return nil, err + } + + return &Constraint{ + f: constraintOperators[matches[1]], + check: check, + original: v, + }, nil +} + +func prereleaseCheck(v, c *Version) bool { + switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; { + case cPre && vPre: + // A constraint with a pre-release can only match a pre-release version + // with the same base segments. + return reflect.DeepEqual(c.Segments64(), v.Segments64()) + + case !cPre && vPre: + // A constraint without a pre-release can only match a version without a + // pre-release. + return false + + case cPre && !vPre: + // OK, except with the pessimistic operator + case !cPre && !vPre: + // OK + } + return true +} + +//------------------------------------------------------------------- +// Constraint functions +//------------------------------------------------------------------- + +func constraintEqual(v, c *Version) bool { + return v.Equal(c) +} + +func constraintNotEqual(v, c *Version) bool { + return !v.Equal(c) +} + +func constraintGreaterThan(v, c *Version) bool { + return prereleaseCheck(v, c) && v.Compare(c) == 1 +} + +func constraintLessThan(v, c *Version) bool { + return prereleaseCheck(v, c) && v.Compare(c) == -1 +} + +func constraintGreaterThanEqual(v, c *Version) bool { + return prereleaseCheck(v, c) && v.Compare(c) >= 0 +} + +func constraintLessThanEqual(v, c *Version) bool { + return prereleaseCheck(v, c) && v.Compare(c) <= 0 +} + +func constraintPessimistic(v, c *Version) bool { + // Using a pessimistic constraint with a pre-release, restricts versions to pre-releases + if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") { + return false + } + + // If the version being checked is naturally less than the constraint, then there + // is no way for the version to be valid against the constraint + if v.LessThan(c) { + return false + } + // We'll use this more than once, so grab the length now so it's a little cleaner + // to write the later checks + cs := len(c.segments) + + // If the version being checked has less specificity than the constraint, then there + // is no way for the version to be valid against the constraint + if cs > len(v.segments) { + return false + } + + // Check the segments in the constraint against those in the version. If the version + // being checked, at any point, does not have the same values in each index of the + // constraints segments, then it cannot be valid against the constraint. + for i := 0; i < c.si-1; i++ { + if v.segments[i] != c.segments[i] { + return false + } + } + + // Check the last part of the segment in the constraint. If the version segment at + // this index is less than the constraints segment at this index, then it cannot + // be valid against the constraint + if c.segments[cs-1] > v.segments[cs-1] { + return false + } + + // If nothing has rejected the version by now, it's valid + return true +} diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go new file mode 100644 index 0000000..bee527e --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -0,0 +1,326 @@ +package version + +import ( + "bytes" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" +) + +// The compiled regular expression used to test the validity of a version. +var versionRegexp *regexp.Regexp + +// The raw regular expression string used for testing the validity +// of a version. +const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + + `(-?([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + + `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + + `?` + +// Version represents a single version. +type Version struct { + metadata string + pre string + segments []int64 + si int +} + +func init() { + versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") +} + +// NewVersion parses the given version and returns a new +// Version. +func NewVersion(v string) (*Version, error) { + matches := versionRegexp.FindStringSubmatch(v) + if matches == nil { + return nil, fmt.Errorf("Malformed version: %s", v) + } + segmentsStr := strings.Split(matches[1], ".") + segments := make([]int64, len(segmentsStr)) + si := 0 + for i, str := range segmentsStr { + val, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return nil, fmt.Errorf( + "Error parsing version: %s", err) + } + + segments[i] = int64(val) + si++ + } + + // Even though we could support more than three segments, if we + // got less than three, pad it with 0s. This is to cover the basic + // default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum + for i := len(segments); i < 3; i++ { + segments = append(segments, 0) + } + + return &Version{ + metadata: matches[7], + pre: matches[4], + segments: segments, + si: si, + }, nil +} + +// Must is a helper that wraps a call to a function returning (*Version, error) +// and panics if error is non-nil. +func Must(v *Version, err error) *Version { + if err != nil { + panic(err) + } + + return v +} + +// Compare compares this version to another version. This +// returns -1, 0, or 1 if this version is smaller, equal, +// or larger than the other version, respectively. +// +// If you want boolean results, use the LessThan, Equal, +// or GreaterThan methods. +func (v *Version) Compare(other *Version) int { + // A quick, efficient equality check + if v.String() == other.String() { + return 0 + } + + segmentsSelf := v.Segments64() + segmentsOther := other.Segments64() + + // If the segments are the same, we must compare on prerelease info + if reflect.DeepEqual(segmentsSelf, segmentsOther) { + preSelf := v.Prerelease() + preOther := other.Prerelease() + if preSelf == "" && preOther == "" { + return 0 + } + if preSelf == "" { + return 1 + } + if preOther == "" { + return -1 + } + + return comparePrereleases(preSelf, preOther) + } + + // Get the highest specificity (hS), or if they're equal, just use segmentSelf length + lenSelf := len(segmentsSelf) + lenOther := len(segmentsOther) + hS := lenSelf + if lenSelf < lenOther { + hS = lenOther + } + // Compare the segments + // Because a constraint could have more/less specificity than the version it's + // checking, we need to account for a lopsided or jagged comparison + for i := 0; i < hS; i++ { + if i > lenSelf-1 { + // This means Self had the lower specificity + // Check to see if the remaining segments in Other are all zeros + if !allZero(segmentsOther[i:]) { + // if not, it means that Other has to be greater than Self + return -1 + } + break + } else if i > lenOther-1 { + // this means Other had the lower specificity + // Check to see if the remaining segments in Self are all zeros - + if !allZero(segmentsSelf[i:]) { + //if not, it means that Self has to be greater than Other + return 1 + } + break + } + lhs := segmentsSelf[i] + rhs := segmentsOther[i] + if lhs == rhs { + continue + } else if lhs < rhs { + return -1 + } + // Otherwis, rhs was > lhs, they're not equal + return 1 + } + + // if we got this far, they're equal + return 0 +} + +func allZero(segs []int64) bool { + for _, s := range segs { + if s != 0 { + return false + } + } + return true +} + +func comparePart(preSelf string, preOther string) int { + if preSelf == preOther { + return 0 + } + + var selfInt int64 + selfNumeric := true + selfInt, err := strconv.ParseInt(preSelf, 10, 64) + if err != nil { + selfNumeric = false + } + + var otherInt int64 + otherNumeric := true + otherInt, err = strconv.ParseInt(preOther, 10, 64) + if err != nil { + otherNumeric = false + } + + // if a part is empty, we use the other to decide + if preSelf == "" { + if otherNumeric { + return -1 + } + return 1 + } + + if preOther == "" { + if selfNumeric { + return 1 + } + return -1 + } + + if selfNumeric && !otherNumeric { + return -1 + } else if !selfNumeric && otherNumeric { + return 1 + } else if !selfNumeric && !otherNumeric && preSelf > preOther { + return 1 + } else if selfInt > otherInt { + return 1 + } + + return -1 +} + +func comparePrereleases(v string, other string) int { + // the same pre release! + if v == other { + return 0 + } + + // split both pre releases for analyse their parts + selfPreReleaseMeta := strings.Split(v, ".") + otherPreReleaseMeta := strings.Split(other, ".") + + selfPreReleaseLen := len(selfPreReleaseMeta) + otherPreReleaseLen := len(otherPreReleaseMeta) + + biggestLen := otherPreReleaseLen + if selfPreReleaseLen > otherPreReleaseLen { + biggestLen = selfPreReleaseLen + } + + // loop for parts to find the first difference + for i := 0; i < biggestLen; i = i + 1 { + partSelfPre := "" + if i < selfPreReleaseLen { + partSelfPre = selfPreReleaseMeta[i] + } + + partOtherPre := "" + if i < otherPreReleaseLen { + partOtherPre = otherPreReleaseMeta[i] + } + + compare := comparePart(partSelfPre, partOtherPre) + // if parts are equals, continue the loop + if compare != 0 { + return compare + } + } + + return 0 +} + +// Equal tests if two versions are equal. +func (v *Version) Equal(o *Version) bool { + return v.Compare(o) == 0 +} + +// GreaterThan tests if this version is greater than another version. +func (v *Version) GreaterThan(o *Version) bool { + return v.Compare(o) > 0 +} + +// LessThan tests if this version is less than another version. +func (v *Version) LessThan(o *Version) bool { + return v.Compare(o) < 0 +} + +// Metadata returns any metadata that was part of the version +// string. +// +// Metadata is anything that comes after the "+" in the version. +// For example, with "1.2.3+beta", the metadata is "beta". +func (v *Version) Metadata() string { + return v.metadata +} + +// Prerelease returns any prerelease data that is part of the version, +// or blank if there is no prerelease data. +// +// Prerelease information is anything that comes after the "-" in the +// version (but before any metadata). For example, with "1.2.3-beta", +// the prerelease information is "beta". +func (v *Version) Prerelease() string { + return v.pre +} + +// Segments returns the numeric segments of the version as a slice of ints. +// +// This excludes any metadata or pre-release information. For example, +// for a version "1.2.3-beta", segments will return a slice of +// 1, 2, 3. +func (v *Version) Segments() []int { + segmentSlice := make([]int, len(v.segments)) + for i, v := range v.segments { + segmentSlice[i] = int(v) + } + return segmentSlice +} + +// Segments64 returns the numeric segments of the version as a slice of int64s. +// +// This excludes any metadata or pre-release information. For example, +// for a version "1.2.3-beta", segments will return a slice of +// 1, 2, 3. +func (v *Version) Segments64() []int64 { + return v.segments +} + +// String returns the full version string included pre-release +// and metadata information. +func (v *Version) String() string { + var buf bytes.Buffer + fmtParts := make([]string, len(v.segments)) + for i, s := range v.segments { + // We can ignore err here since we've pre-parsed the values in segments + str := strconv.FormatInt(s, 10) + fmtParts[i] = str + } + fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) + if v.pre != "" { + fmt.Fprintf(&buf, "-%s", v.pre) + } + if v.metadata != "" { + fmt.Fprintf(&buf, "+%s", v.metadata) + } + + return buf.String() +} diff --git a/vendor/github.com/hashicorp/go-version/version_collection.go b/vendor/github.com/hashicorp/go-version/version_collection.go new file mode 100644 index 0000000..cc888d4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-version/version_collection.go @@ -0,0 +1,17 @@ +package version + +// Collection is a type that implements the sort.Interface interface +// so that versions can be sorted. +type Collection []*Version + +func (v Collection) Len() int { + return len(v) +} + +func (v Collection) Less(i, j int) bool { + return v[i].LessThan(v[j]) +} + +func (v Collection) Swap(i, j int) { + v[i], v[j] = v[j], v[i] +} diff --git a/vendor/github.com/hashicorp/golang-lru/.gitignore b/vendor/github.com/hashicorp/golang-lru/.gitignore new file mode 100644 index 0000000..8365624 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/hashicorp/golang-lru/2q.go b/vendor/github.com/hashicorp/golang-lru/2q.go new file mode 100644 index 0000000..e474cd0 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/2q.go @@ -0,0 +1,223 @@ +package lru + +import ( + "fmt" + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +const ( + // Default2QRecentRatio is the ratio of the 2Q cache dedicated + // to recently added entries that have only been accessed once. + Default2QRecentRatio = 0.25 + + // Default2QGhostEntries is the default ratio of ghost + // entries kept to track entries recently evicted + Default2QGhostEntries = 0.50 +) + +// TwoQueueCache is a thread-safe fixed size 2Q cache. +// 2Q is an enhancement over the standard LRU cache +// in that it tracks both frequently and recently used +// entries separately. This avoids a burst in access to new +// entries from evicting frequently used entries. It adds some +// additional tracking overhead to the standard LRU cache, and is +// computationally about 2x the cost, and adds some metadata over +// head. The ARCCache is similar, but does not require setting any +// parameters. +type TwoQueueCache struct { + size int + recentSize int + + recent simplelru.LRUCache + frequent simplelru.LRUCache + recentEvict simplelru.LRUCache + lock sync.RWMutex +} + +// New2Q creates a new TwoQueueCache using the default +// values for the parameters. +func New2Q(size int) (*TwoQueueCache, error) { + return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries) +} + +// New2QParams creates a new TwoQueueCache using the provided +// parameter values. +func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCache, error) { + if size <= 0 { + return nil, fmt.Errorf("invalid size") + } + if recentRatio < 0.0 || recentRatio > 1.0 { + return nil, fmt.Errorf("invalid recent ratio") + } + if ghostRatio < 0.0 || ghostRatio > 1.0 { + return nil, fmt.Errorf("invalid ghost ratio") + } + + // Determine the sub-sizes + recentSize := int(float64(size) * recentRatio) + evictSize := int(float64(size) * ghostRatio) + + // Allocate the LRUs + recent, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + frequent, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + recentEvict, err := simplelru.NewLRU(evictSize, nil) + if err != nil { + return nil, err + } + + // Initialize the cache + c := &TwoQueueCache{ + size: size, + recentSize: recentSize, + recent: recent, + frequent: frequent, + recentEvict: recentEvict, + } + return c, nil +} + +// Get looks up a key's value from the cache. +func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if this is a frequent value + if val, ok := c.frequent.Get(key); ok { + return val, ok + } + + // If the value is contained in recent, then we + // promote it to frequent + if val, ok := c.recent.Peek(key); ok { + c.recent.Remove(key) + c.frequent.Add(key, val) + return val, ok + } + + // No hit + return nil, false +} + +// Add adds a value to the cache. +func (c *TwoQueueCache) Add(key, value interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if the value is frequently used already, + // and just update the value + if c.frequent.Contains(key) { + c.frequent.Add(key, value) + return + } + + // Check if the value is recently used, and promote + // the value into the frequent list + if c.recent.Contains(key) { + c.recent.Remove(key) + c.frequent.Add(key, value) + return + } + + // If the value was recently evicted, add it to the + // frequently used list + if c.recentEvict.Contains(key) { + c.ensureSpace(true) + c.recentEvict.Remove(key) + c.frequent.Add(key, value) + return + } + + // Add to the recently seen list + c.ensureSpace(false) + c.recent.Add(key, value) + return +} + +// ensureSpace is used to ensure we have space in the cache +func (c *TwoQueueCache) ensureSpace(recentEvict bool) { + // If we have space, nothing to do + recentLen := c.recent.Len() + freqLen := c.frequent.Len() + if recentLen+freqLen < c.size { + return + } + + // If the recent buffer is larger than + // the target, evict from there + if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) { + k, _, _ := c.recent.RemoveOldest() + c.recentEvict.Add(k, nil) + return + } + + // Remove from the frequent list otherwise + c.frequent.RemoveOldest() +} + +// Len returns the number of items in the cache. +func (c *TwoQueueCache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.recent.Len() + c.frequent.Len() +} + +// Keys returns a slice of the keys in the cache. +// The frequently used keys are first in the returned slice. +func (c *TwoQueueCache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + k1 := c.frequent.Keys() + k2 := c.recent.Keys() + return append(k1, k2...) +} + +// Remove removes the provided key from the cache. +func (c *TwoQueueCache) Remove(key interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + if c.frequent.Remove(key) { + return + } + if c.recent.Remove(key) { + return + } + if c.recentEvict.Remove(key) { + return + } +} + +// Purge is used to completely clear the cache. +func (c *TwoQueueCache) Purge() { + c.lock.Lock() + defer c.lock.Unlock() + c.recent.Purge() + c.frequent.Purge() + c.recentEvict.Purge() +} + +// Contains is used to check if the cache contains a key +// without updating recency or frequency. +func (c *TwoQueueCache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.frequent.Contains(key) || c.recent.Contains(key) +} + +// Peek is used to inspect the cache value of a key +// without updating recency or frequency. +func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + if val, ok := c.frequent.Peek(key); ok { + return val, ok + } + return c.recent.Peek(key) +} diff --git a/vendor/github.com/hashicorp/golang-lru/LICENSE b/vendor/github.com/hashicorp/golang-lru/LICENSE new file mode 100644 index 0000000..be2cc4d --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/golang-lru/README.md b/vendor/github.com/hashicorp/golang-lru/README.md new file mode 100644 index 0000000..33e58cf --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/README.md @@ -0,0 +1,25 @@ +golang-lru +========== + +This provides the `lru` package which implements a fixed-size +thread safe LRU cache. It is based on the cache in Groupcache. + +Documentation +============= + +Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru) + +Example +======= + +Using the LRU is very simple: + +```go +l, _ := New(128) +for i := 0; i < 256; i++ { + l.Add(i, nil) +} +if l.Len() != 128 { + panic(fmt.Sprintf("bad len: %v", l.Len())) +} +``` diff --git a/vendor/github.com/hashicorp/golang-lru/arc.go b/vendor/github.com/hashicorp/golang-lru/arc.go new file mode 100644 index 0000000..555225a --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/arc.go @@ -0,0 +1,257 @@ +package lru + +import ( + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +// ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC). +// ARC is an enhancement over the standard LRU cache in that tracks both +// frequency and recency of use. This avoids a burst in access to new +// entries from evicting the frequently used older entries. It adds some +// additional tracking overhead to a standard LRU cache, computationally +// it is roughly 2x the cost, and the extra memory overhead is linear +// with the size of the cache. ARC has been patented by IBM, but is +// similar to the TwoQueueCache (2Q) which requires setting parameters. +type ARCCache struct { + size int // Size is the total capacity of the cache + p int // P is the dynamic preference towards T1 or T2 + + t1 simplelru.LRUCache // T1 is the LRU for recently accessed items + b1 simplelru.LRUCache // B1 is the LRU for evictions from t1 + + t2 simplelru.LRUCache // T2 is the LRU for frequently accessed items + b2 simplelru.LRUCache // B2 is the LRU for evictions from t2 + + lock sync.RWMutex +} + +// NewARC creates an ARC of the given size +func NewARC(size int) (*ARCCache, error) { + // Create the sub LRUs + b1, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + b2, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + t1, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + t2, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + + // Initialize the ARC + c := &ARCCache{ + size: size, + p: 0, + t1: t1, + b1: b1, + t2: t2, + b2: b2, + } + return c, nil +} + +// Get looks up a key's value from the cache. +func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // If the value is contained in T1 (recent), then + // promote it to T2 (frequent) + if val, ok := c.t1.Peek(key); ok { + c.t1.Remove(key) + c.t2.Add(key, val) + return val, ok + } + + // Check if the value is contained in T2 (frequent) + if val, ok := c.t2.Get(key); ok { + return val, ok + } + + // No hit + return nil, false +} + +// Add adds a value to the cache. +func (c *ARCCache) Add(key, value interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if the value is contained in T1 (recent), and potentially + // promote it to frequent T2 + if c.t1.Contains(key) { + c.t1.Remove(key) + c.t2.Add(key, value) + return + } + + // Check if the value is already in T2 (frequent) and update it + if c.t2.Contains(key) { + c.t2.Add(key, value) + return + } + + // Check if this value was recently evicted as part of the + // recently used list + if c.b1.Contains(key) { + // T1 set is too small, increase P appropriately + delta := 1 + b1Len := c.b1.Len() + b2Len := c.b2.Len() + if b2Len > b1Len { + delta = b2Len / b1Len + } + if c.p+delta >= c.size { + c.p = c.size + } else { + c.p += delta + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(false) + } + + // Remove from B1 + c.b1.Remove(key) + + // Add the key to the frequently used list + c.t2.Add(key, value) + return + } + + // Check if this value was recently evicted as part of the + // frequently used list + if c.b2.Contains(key) { + // T2 set is too small, decrease P appropriately + delta := 1 + b1Len := c.b1.Len() + b2Len := c.b2.Len() + if b1Len > b2Len { + delta = b1Len / b2Len + } + if delta >= c.p { + c.p = 0 + } else { + c.p -= delta + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(true) + } + + // Remove from B2 + c.b2.Remove(key) + + // Add the key to the frequently used list + c.t2.Add(key, value) + return + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(false) + } + + // Keep the size of the ghost buffers trim + if c.b1.Len() > c.size-c.p { + c.b1.RemoveOldest() + } + if c.b2.Len() > c.p { + c.b2.RemoveOldest() + } + + // Add to the recently seen list + c.t1.Add(key, value) + return +} + +// replace is used to adaptively evict from either T1 or T2 +// based on the current learned value of P +func (c *ARCCache) replace(b2ContainsKey bool) { + t1Len := c.t1.Len() + if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) { + k, _, ok := c.t1.RemoveOldest() + if ok { + c.b1.Add(k, nil) + } + } else { + k, _, ok := c.t2.RemoveOldest() + if ok { + c.b2.Add(k, nil) + } + } +} + +// Len returns the number of cached entries +func (c *ARCCache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.t1.Len() + c.t2.Len() +} + +// Keys returns all the cached keys +func (c *ARCCache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + k1 := c.t1.Keys() + k2 := c.t2.Keys() + return append(k1, k2...) +} + +// Remove is used to purge a key from the cache +func (c *ARCCache) Remove(key interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + if c.t1.Remove(key) { + return + } + if c.t2.Remove(key) { + return + } + if c.b1.Remove(key) { + return + } + if c.b2.Remove(key) { + return + } +} + +// Purge is used to clear the cache +func (c *ARCCache) Purge() { + c.lock.Lock() + defer c.lock.Unlock() + c.t1.Purge() + c.t2.Purge() + c.b1.Purge() + c.b2.Purge() +} + +// Contains is used to check if the cache contains a key +// without updating recency or frequency. +func (c *ARCCache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.t1.Contains(key) || c.t2.Contains(key) +} + +// Peek is used to inspect the cache value of a key +// without updating recency or frequency. +func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + if val, ok := c.t1.Peek(key); ok { + return val, ok + } + return c.t2.Peek(key) +} diff --git a/vendor/github.com/hashicorp/golang-lru/doc.go b/vendor/github.com/hashicorp/golang-lru/doc.go new file mode 100644 index 0000000..2547df9 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/doc.go @@ -0,0 +1,21 @@ +// Package lru provides three different LRU caches of varying sophistication. +// +// Cache is a simple LRU cache. It is based on the +// LRU implementation in groupcache: +// https://github.com/golang/groupcache/tree/master/lru +// +// TwoQueueCache tracks frequently used and recently used entries separately. +// This avoids a burst of accesses from taking out frequently used entries, +// at the cost of about 2x computational overhead and some extra bookkeeping. +// +// ARCCache is an adaptive replacement cache. It tracks recent evictions as +// well as recent usage in both the frequent and recent caches. Its +// computational overhead is comparable to TwoQueueCache, but the memory +// overhead is linear with the size of the cache. +// +// ARC has been patented by IBM, so do not use it if that is problematic for +// your program. +// +// All caches in this package take locks while operating, and are therefore +// thread-safe for consumers. +package lru diff --git a/vendor/github.com/hashicorp/golang-lru/lru.go b/vendor/github.com/hashicorp/golang-lru/lru.go new file mode 100644 index 0000000..c8d9b0a --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/lru.go @@ -0,0 +1,110 @@ +package lru + +import ( + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +// Cache is a thread-safe fixed size LRU cache. +type Cache struct { + lru simplelru.LRUCache + lock sync.RWMutex +} + +// New creates an LRU of the given size. +func New(size int) (*Cache, error) { + return NewWithEvict(size, nil) +} + +// NewWithEvict constructs a fixed size cache with the given eviction +// callback. +func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) { + lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted)) + if err != nil { + return nil, err + } + c := &Cache{ + lru: lru, + } + return c, nil +} + +// Purge is used to completely clear the cache. +func (c *Cache) Purge() { + c.lock.Lock() + c.lru.Purge() + c.lock.Unlock() +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +func (c *Cache) Add(key, value interface{}) (evicted bool) { + c.lock.Lock() + defer c.lock.Unlock() + return c.lru.Add(key, value) +} + +// Get looks up a key's value from the cache. +func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + return c.lru.Get(key) +} + +// Contains checks if a key is in the cache, without updating the +// recent-ness or deleting it for being stale. +func (c *Cache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Contains(key) +} + +// Peek returns the key value (or undefined if not found) without updating +// the "recently used"-ness of the key. +func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Peek(key) +} + +// ContainsOrAdd checks if a key is in the cache without updating the +// recent-ness or deleting it for being stale, and if not, adds the value. +// Returns whether found and whether an eviction occurred. +func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.lru.Contains(key) { + return true, false + } + evicted = c.lru.Add(key, value) + return false, evicted +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key interface{}) { + c.lock.Lock() + c.lru.Remove(key) + c.lock.Unlock() +} + +// RemoveOldest removes the oldest item from the cache. +func (c *Cache) RemoveOldest() { + c.lock.Lock() + c.lru.RemoveOldest() + c.lock.Unlock() +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *Cache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Keys() +} + +// Len returns the number of items in the cache. +func (c *Cache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Len() +} diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go new file mode 100644 index 0000000..5673773 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go @@ -0,0 +1,161 @@ +package simplelru + +import ( + "container/list" + "errors" +) + +// EvictCallback is used to get a callback when a cache entry is evicted +type EvictCallback func(key interface{}, value interface{}) + +// LRU implements a non-thread safe fixed size LRU cache +type LRU struct { + size int + evictList *list.List + items map[interface{}]*list.Element + onEvict EvictCallback +} + +// entry is used to hold a value in the evictList +type entry struct { + key interface{} + value interface{} +} + +// NewLRU constructs an LRU of the given size +func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { + if size <= 0 { + return nil, errors.New("Must provide a positive size") + } + c := &LRU{ + size: size, + evictList: list.New(), + items: make(map[interface{}]*list.Element), + onEvict: onEvict, + } + return c, nil +} + +// Purge is used to completely clear the cache. +func (c *LRU) Purge() { + for k, v := range c.items { + if c.onEvict != nil { + c.onEvict(k, v.Value.(*entry).value) + } + delete(c.items, k) + } + c.evictList.Init() +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +func (c *LRU) Add(key, value interface{}) (evicted bool) { + // Check for existing item + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + ent.Value.(*entry).value = value + return false + } + + // Add new item + ent := &entry{key, value} + entry := c.evictList.PushFront(ent) + c.items[key] = entry + + evict := c.evictList.Len() > c.size + // Verify size not exceeded + if evict { + c.removeOldest() + } + return evict +} + +// Get looks up a key's value from the cache. +func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + return ent.Value.(*entry).value, true + } + return +} + +// Contains checks if a key is in the cache, without updating the recent-ness +// or deleting it for being stale. +func (c *LRU) Contains(key interface{}) (ok bool) { + _, ok = c.items[key] + return ok +} + +// Peek returns the key value (or undefined if not found) without updating +// the "recently used"-ness of the key. +func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { + var ent *list.Element + if ent, ok = c.items[key]; ok { + return ent.Value.(*entry).value, true + } + return nil, ok +} + +// Remove removes the provided key from the cache, returning if the +// key was contained. +func (c *LRU) Remove(key interface{}) (present bool) { + if ent, ok := c.items[key]; ok { + c.removeElement(ent) + return true + } + return false +} + +// RemoveOldest removes the oldest item from the cache. +func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) { + ent := c.evictList.Back() + if ent != nil { + c.removeElement(ent) + kv := ent.Value.(*entry) + return kv.key, kv.value, true + } + return nil, nil, false +} + +// GetOldest returns the oldest entry +func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) { + ent := c.evictList.Back() + if ent != nil { + kv := ent.Value.(*entry) + return kv.key, kv.value, true + } + return nil, nil, false +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *LRU) Keys() []interface{} { + keys := make([]interface{}, len(c.items)) + i := 0 + for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() { + keys[i] = ent.Value.(*entry).key + i++ + } + return keys +} + +// Len returns the number of items in the cache. +func (c *LRU) Len() int { + return c.evictList.Len() +} + +// removeOldest removes the oldest item from the cache. +func (c *LRU) removeOldest() { + ent := c.evictList.Back() + if ent != nil { + c.removeElement(ent) + } +} + +// removeElement is used to remove a given list element from the cache +func (c *LRU) removeElement(e *list.Element) { + c.evictList.Remove(e) + kv := e.Value.(*entry) + delete(c.items, kv.key) + if c.onEvict != nil { + c.onEvict(kv.key, kv.value) + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go new file mode 100644 index 0000000..744cac0 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go @@ -0,0 +1,37 @@ +package simplelru + + +// LRUCache is the interface for simple LRU cache. +type LRUCache interface { + // Adds a value to the cache, returns true if an eviction occurred and + // updates the "recently used"-ness of the key. + Add(key, value interface{}) bool + + // Returns key's value from the cache and + // updates the "recently used"-ness of the key. #value, isFound + Get(key interface{}) (value interface{}, ok bool) + + // Check if a key exsists in cache without updating the recent-ness. + Contains(key interface{}) (ok bool) + + // Returns key's value without updating the "recently used"-ness of the key. + Peek(key interface{}) (value interface{}, ok bool) + + // Removes a key from the cache. + Remove(key interface{}) bool + + // Removes the oldest entry from cache. + RemoveOldest() (interface{}, interface{}, bool) + + // Returns the oldest entry from the cache. #key, value, isFound + GetOldest() (interface{}, interface{}, bool) + + // Returns a slice of the keys in the cache, from oldest to newest. + Keys() []interface{} + + // Returns the number of items in the cache. + Len() int + + // Clear all cache entries + Purge() +} diff --git a/vendor/github.com/hashicorp/hcl/.gitignore b/vendor/github.com/hashicorp/hcl/.gitignore new file mode 100644 index 0000000..15586a2 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/.gitignore @@ -0,0 +1,9 @@ +y.output + +# ignore intellij files +.idea +*.iml +*.ipr +*.iws + +*.test diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml new file mode 100644 index 0000000..cb63a32 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/.travis.yml @@ -0,0 +1,13 @@ +sudo: false + +language: go + +go: + - 1.x + - tip + +branches: + only: + - master + +script: make test diff --git a/vendor/github.com/hashicorp/hcl/LICENSE b/vendor/github.com/hashicorp/hcl/LICENSE new file mode 100644 index 0000000..c33dcc7 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/LICENSE @@ -0,0 +1,354 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/hcl/Makefile b/vendor/github.com/hashicorp/hcl/Makefile new file mode 100644 index 0000000..84fd743 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/Makefile @@ -0,0 +1,18 @@ +TEST?=./... + +default: test + +fmt: generate + go fmt ./... + +test: generate + go get -t ./... + go test $(TEST) $(TESTARGS) + +generate: + go generate ./... + +updatedeps: + go get -u golang.org/x/tools/cmd/stringer + +.PHONY: default generate test updatedeps diff --git a/vendor/github.com/hashicorp/hcl/README.md b/vendor/github.com/hashicorp/hcl/README.md new file mode 100644 index 0000000..c822332 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/README.md @@ -0,0 +1,125 @@ +# HCL + +[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) + +HCL (HashiCorp Configuration Language) is a configuration language built +by HashiCorp. The goal of HCL is to build a structured configuration language +that is both human and machine friendly for use with command-line tools, but +specifically targeted towards DevOps tools, servers, etc. + +HCL is also fully JSON compatible. That is, JSON can be used as completely +valid input to a system expecting HCL. This helps makes systems +interoperable with other systems. + +HCL is heavily inspired by +[libucl](https://github.com/vstakhov/libucl), +nginx configuration, and others similar. + +## Why? + +A common question when viewing HCL is to ask the question: why not +JSON, YAML, etc.? + +Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) +used a variety of configuration languages from full programming languages +such as Ruby to complete data structure languages such as JSON. What we +learned is that some people wanted human-friendly configuration languages +and some people wanted machine-friendly languages. + +JSON fits a nice balance in this, but is fairly verbose and most +importantly doesn't support comments. With YAML, we found that beginners +had a really hard time determining what the actual structure was, and +ended up guessing more often than not whether to use a hyphen, colon, etc. +in order to represent some configuration key. + +Full programming languages such as Ruby enable complex behavior +a configuration language shouldn't usually allow, and also forces +people to learn some set of Ruby. + +Because of this, we decided to create our own configuration language +that is JSON-compatible. Our configuration language (HCL) is designed +to be written and modified by humans. The API for HCL allows JSON +as an input so that it is also machine-friendly (machines can generate +JSON instead of trying to generate HCL). + +Our goal with HCL is not to alienate other configuration languages. +It is instead to provide HCL as a specialized language for our tools, +and JSON as the interoperability layer. + +## Syntax + +For a complete grammar, please see the parser itself. A high-level overview +of the syntax and grammar is listed here. + + * Single line comments start with `#` or `//` + + * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments + are not allowed. A multi-line comment (also known as a block comment) + terminates at the first `*/` found. + + * Values are assigned with the syntax `key = value` (whitespace doesn't + matter). The value can be any primitive: a string, number, boolean, + object, or list. + + * Strings are double-quoted and can contain any UTF-8 characters. + Example: `"Hello, World"` + + * Multi-line strings start with `<- + echo %Path% + + go version + + go env + + go get -t ./... + +build_script: +- cmd: go test -v ./... diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go new file mode 100644 index 0000000..bed9ebb --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/decoder.go @@ -0,0 +1,729 @@ +package hcl + +import ( + "errors" + "fmt" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/hcl/hcl/parser" + "github.com/hashicorp/hcl/hcl/token" +) + +// This is the tag to use with structures to have settings for HCL +const tagName = "hcl" + +var ( + // nodeType holds a reference to the type of ast.Node + nodeType reflect.Type = findNodeType() +) + +// Unmarshal accepts a byte slice as input and writes the +// data to the value pointed to by v. +func Unmarshal(bs []byte, v interface{}) error { + root, err := parse(bs) + if err != nil { + return err + } + + return DecodeObject(v, root) +} + +// Decode reads the given input and decodes it into the structure +// given by `out`. +func Decode(out interface{}, in string) error { + obj, err := Parse(in) + if err != nil { + return err + } + + return DecodeObject(out, obj) +} + +// DecodeObject is a lower-level version of Decode. It decodes a +// raw Object into the given output. +func DecodeObject(out interface{}, n ast.Node) error { + val := reflect.ValueOf(out) + if val.Kind() != reflect.Ptr { + return errors.New("result must be a pointer") + } + + // If we have the file, we really decode the root node + if f, ok := n.(*ast.File); ok { + n = f.Node + } + + var d decoder + return d.decode("root", n, val.Elem()) +} + +type decoder struct { + stack []reflect.Kind +} + +func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { + k := result + + // If we have an interface with a valid value, we use that + // for the check. + if result.Kind() == reflect.Interface { + elem := result.Elem() + if elem.IsValid() { + k = elem + } + } + + // Push current onto stack unless it is an interface. + if k.Kind() != reflect.Interface { + d.stack = append(d.stack, k.Kind()) + + // Schedule a pop + defer func() { + d.stack = d.stack[:len(d.stack)-1] + }() + } + + switch k.Kind() { + case reflect.Bool: + return d.decodeBool(name, node, result) + case reflect.Float32, reflect.Float64: + return d.decodeFloat(name, node, result) + case reflect.Int, reflect.Int32, reflect.Int64: + return d.decodeInt(name, node, result) + case reflect.Interface: + // When we see an interface, we make our own thing + return d.decodeInterface(name, node, result) + case reflect.Map: + return d.decodeMap(name, node, result) + case reflect.Ptr: + return d.decodePtr(name, node, result) + case reflect.Slice: + return d.decodeSlice(name, node, result) + case reflect.String: + return d.decodeString(name, node, result) + case reflect.Struct: + return d.decodeStruct(name, node, result) + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), + } + } +} + +func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + if n.Token.Type == token.BOOL { + v, err := strconv.ParseBool(n.Token.Text) + if err != nil { + return err + } + + result.Set(reflect.ValueOf(v)) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER { + v, err := strconv.ParseFloat(n.Token.Text, 64) + if err != nil { + return err + } + + result.Set(reflect.ValueOf(v).Convert(result.Type())) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + switch n.Token.Type { + case token.NUMBER: + v, err := strconv.ParseInt(n.Token.Text, 0, 0) + if err != nil { + return err + } + + if result.Kind() == reflect.Interface { + result.Set(reflect.ValueOf(int(v))) + } else { + result.SetInt(v) + } + return nil + case token.STRING: + v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) + if err != nil { + return err + } + + if result.Kind() == reflect.Interface { + result.Set(reflect.ValueOf(int(v))) + } else { + result.SetInt(v) + } + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { + // When we see an ast.Node, we retain the value to enable deferred decoding. + // Very useful in situations where we want to preserve ast.Node information + // like Pos + if result.Type() == nodeType && result.CanSet() { + result.Set(reflect.ValueOf(node)) + return nil + } + + var set reflect.Value + redecode := true + + // For testing types, ObjectType should just be treated as a list. We + // set this to a temporary var because we want to pass in the real node. + testNode := node + if ot, ok := node.(*ast.ObjectType); ok { + testNode = ot.List + } + + switch n := testNode.(type) { + case *ast.ObjectList: + // If we're at the root or we're directly within a slice, then we + // decode objects into map[string]interface{}, otherwise we decode + // them into lists. + if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { + var temp map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeMap( + reflect.MapOf( + reflect.TypeOf(""), + tempVal.Type().Elem())) + + set = result + } else { + var temp []map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) + set = result + } + case *ast.ObjectType: + // If we're at the root or we're directly within a slice, then we + // decode objects into map[string]interface{}, otherwise we decode + // them into lists. + if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { + var temp map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeMap( + reflect.MapOf( + reflect.TypeOf(""), + tempVal.Type().Elem())) + + set = result + } else { + var temp []map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, 1) + set = result + } + case *ast.ListType: + var temp []interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, 0) + set = result + case *ast.LiteralType: + switch n.Token.Type { + case token.BOOL: + var result bool + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.FLOAT: + var result float64 + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.NUMBER: + var result int + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.STRING, token.HEREDOC: + set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), + } + } + default: + return fmt.Errorf( + "%s: cannot decode into interface: %T", + name, node) + } + + // Set the result to what its supposed to be, then reset + // result so we don't reflect into this method anymore. + result.Set(set) + + if redecode { + // Revisit the node so that we can use the newly instantiated + // thing and populate it. + if err := d.decode(name, node, result); err != nil { + return err + } + } + + return nil +} + +func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { + if item, ok := node.(*ast.ObjectItem); ok { + node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} + } + + if ot, ok := node.(*ast.ObjectType); ok { + node = ot.List + } + + n, ok := node.(*ast.ObjectList) + if !ok { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), + } + } + + // If we have an interface, then we can address the interface, + // but not the slice itself, so get the element but set the interface + set := result + if result.Kind() == reflect.Interface { + result = result.Elem() + } + + resultType := result.Type() + resultElemType := resultType.Elem() + resultKeyType := resultType.Key() + if resultKeyType.Kind() != reflect.String { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: map must have string keys", name), + } + } + + // Make a map if it is nil + resultMap := result + if result.IsNil() { + resultMap = reflect.MakeMap( + reflect.MapOf(resultKeyType, resultElemType)) + } + + // Go through each element and decode it. + done := make(map[string]struct{}) + for _, item := range n.Items { + if item.Val == nil { + continue + } + + // github.com/hashicorp/terraform/issue/5740 + if len(item.Keys) == 0 { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: map must have string keys", name), + } + } + + // Get the key we're dealing with, which is the first item + keyStr := item.Keys[0].Token.Value().(string) + + // If we've already processed this key, then ignore it + if _, ok := done[keyStr]; ok { + continue + } + + // Determine the value. If we have more than one key, then we + // get the objectlist of only these keys. + itemVal := item.Val + if len(item.Keys) > 1 { + itemVal = n.Filter(keyStr) + done[keyStr] = struct{}{} + } + + // Make the field name + fieldName := fmt.Sprintf("%s.%s", name, keyStr) + + // Get the key/value as reflection values + key := reflect.ValueOf(keyStr) + val := reflect.Indirect(reflect.New(resultElemType)) + + // If we have a pre-existing value in the map, use that + oldVal := resultMap.MapIndex(key) + if oldVal.IsValid() { + val.Set(oldVal) + } + + // Decode! + if err := d.decode(fieldName, itemVal, val); err != nil { + return err + } + + // Set the value on the map + resultMap.SetMapIndex(key, val) + } + + // Set the final map if we can + set.Set(resultMap) + return nil +} + +func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + resultType := result.Type() + resultElemType := resultType.Elem() + val := reflect.New(resultElemType) + if err := d.decode(name, node, reflect.Indirect(val)); err != nil { + return err + } + + result.Set(val) + return nil +} + +func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { + // If we have an interface, then we can address the interface, + // but not the slice itself, so get the element but set the interface + set := result + if result.Kind() == reflect.Interface { + result = result.Elem() + } + // Create the slice if it isn't nil + resultType := result.Type() + resultElemType := resultType.Elem() + if result.IsNil() { + resultSliceType := reflect.SliceOf(resultElemType) + result = reflect.MakeSlice( + resultSliceType, 0, 0) + } + + // Figure out the items we'll be copying into the slice + var items []ast.Node + switch n := node.(type) { + case *ast.ObjectList: + items = make([]ast.Node, len(n.Items)) + for i, item := range n.Items { + items[i] = item + } + case *ast.ObjectType: + items = []ast.Node{n} + case *ast.ListType: + items = n.List + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("unknown slice type: %T", node), + } + } + + for i, item := range items { + fieldName := fmt.Sprintf("%s[%d]", name, i) + + // Decode + val := reflect.Indirect(reflect.New(resultElemType)) + + // if item is an object that was decoded from ambiguous JSON and + // flattened, make sure it's expanded if it needs to decode into a + // defined structure. + item := expandObject(item, val) + + if err := d.decode(fieldName, item, val); err != nil { + return err + } + + // Append it onto the slice + result = reflect.Append(result, val) + } + + set.Set(result) + return nil +} + +// expandObject detects if an ambiguous JSON object was flattened to a List which +// should be decoded into a struct, and expands the ast to properly deocode. +func expandObject(node ast.Node, result reflect.Value) ast.Node { + item, ok := node.(*ast.ObjectItem) + if !ok { + return node + } + + elemType := result.Type() + + // our target type must be a struct + switch elemType.Kind() { + case reflect.Ptr: + switch elemType.Elem().Kind() { + case reflect.Struct: + //OK + default: + return node + } + case reflect.Struct: + //OK + default: + return node + } + + // A list value will have a key and field name. If it had more fields, + // it wouldn't have been flattened. + if len(item.Keys) != 2 { + return node + } + + keyToken := item.Keys[0].Token + item.Keys = item.Keys[1:] + + // we need to un-flatten the ast enough to decode + newNode := &ast.ObjectItem{ + Keys: []*ast.ObjectKey{ + &ast.ObjectKey{ + Token: keyToken, + }, + }, + Val: &ast.ObjectType{ + List: &ast.ObjectList{ + Items: []*ast.ObjectItem{item}, + }, + }, + } + + return newNode +} + +func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + switch n.Token.Type { + case token.NUMBER: + result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) + return nil + case token.STRING, token.HEREDOC: + result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type for string %T", name, node), + } +} + +func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { + var item *ast.ObjectItem + if it, ok := node.(*ast.ObjectItem); ok { + item = it + node = it.Val + } + + if ot, ok := node.(*ast.ObjectType); ok { + node = ot.List + } + + // Handle the special case where the object itself is a literal. Previously + // the yacc parser would always ensure top-level elements were arrays. The new + // parser does not make the same guarantees, thus we need to convert any + // top-level literal elements into a list. + if _, ok := node.(*ast.LiteralType); ok && item != nil { + node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} + } + + list, ok := node.(*ast.ObjectList) + if !ok { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), + } + } + + // This slice will keep track of all the structs we'll be decoding. + // There can be more than one struct if there are embedded structs + // that are squashed. + structs := make([]reflect.Value, 1, 5) + structs[0] = result + + // Compile the list of all the fields that we're going to be decoding + // from all the structs. + type field struct { + field reflect.StructField + val reflect.Value + } + fields := []field{} + for len(structs) > 0 { + structVal := structs[0] + structs = structs[1:] + + structType := structVal.Type() + for i := 0; i < structType.NumField(); i++ { + fieldType := structType.Field(i) + tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") + + // Ignore fields with tag name "-" + if tagParts[0] == "-" { + continue + } + + if fieldType.Anonymous { + fieldKind := fieldType.Type.Kind() + if fieldKind != reflect.Struct { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unsupported type to struct: %s", + fieldType.Name, fieldKind), + } + } + + // We have an embedded field. We "squash" the fields down + // if specified in the tag. + squash := false + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + } + + if squash { + structs = append( + structs, result.FieldByName(fieldType.Name)) + continue + } + } + + // Normal struct field, store it away + fields = append(fields, field{fieldType, structVal.Field(i)}) + } + } + + usedKeys := make(map[string]struct{}) + decodedFields := make([]string, 0, len(fields)) + decodedFieldsVal := make([]reflect.Value, 0) + unusedKeysVal := make([]reflect.Value, 0) + for _, f := range fields { + field, fieldValue := f.field, f.val + if !fieldValue.IsValid() { + // This should never happen + panic("field is not valid") + } + + // If we can't set the field, then it is unexported or something, + // and we just continue onwards. + if !fieldValue.CanSet() { + continue + } + + fieldName := field.Name + + tagValue := field.Tag.Get(tagName) + tagParts := strings.SplitN(tagValue, ",", 2) + if len(tagParts) >= 2 { + switch tagParts[1] { + case "decodedFields": + decodedFieldsVal = append(decodedFieldsVal, fieldValue) + continue + case "key": + if item == nil { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: %s asked for 'key', impossible", + name, fieldName), + } + } + + fieldValue.SetString(item.Keys[0].Token.Value().(string)) + continue + case "unusedKeys": + unusedKeysVal = append(unusedKeysVal, fieldValue) + continue + } + } + + if tagParts[0] != "" { + fieldName = tagParts[0] + } + + // Determine the element we'll use to decode. If it is a single + // match (only object with the field), then we decode it exactly. + // If it is a prefix match, then we decode the matches. + filter := list.Filter(fieldName) + + prefixMatches := filter.Children() + matches := filter.Elem() + if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { + continue + } + + // Track the used key + usedKeys[fieldName] = struct{}{} + + // Create the field name and decode. We range over the elements + // because we actually want the value. + fieldName = fmt.Sprintf("%s.%s", name, fieldName) + if len(prefixMatches.Items) > 0 { + if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil { + return err + } + } + for _, match := range matches.Items { + var decodeNode ast.Node = match.Val + if ot, ok := decodeNode.(*ast.ObjectType); ok { + decodeNode = &ast.ObjectList{Items: ot.List.Items} + } + + if err := d.decode(fieldName, decodeNode, fieldValue); err != nil { + return err + } + } + + decodedFields = append(decodedFields, field.Name) + } + + if len(decodedFieldsVal) > 0 { + // Sort it so that it is deterministic + sort.Strings(decodedFields) + + for _, v := range decodedFieldsVal { + v.Set(reflect.ValueOf(decodedFields)) + } + } + + return nil +} + +// findNodeType returns the type of ast.Node +func findNodeType() reflect.Type { + var nodeContainer struct { + Node ast.Node + } + value := reflect.ValueOf(nodeContainer).FieldByName("Node") + return value.Type() +} diff --git a/vendor/github.com/hashicorp/hcl/hcl.go b/vendor/github.com/hashicorp/hcl/hcl.go new file mode 100644 index 0000000..575a20b --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl.go @@ -0,0 +1,11 @@ +// Package hcl decodes HCL into usable Go structures. +// +// hcl input can come in either pure HCL format or JSON format. +// It can be parsed into an AST, and then decoded into a structure, +// or it can be decoded directly from a string into a structure. +// +// If you choose to parse HCL into a raw AST, the benefit is that you +// can write custom visitor implementations to implement custom +// semantic checks. By default, HCL does not perform any semantic +// checks. +package hcl diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go new file mode 100644 index 0000000..6e5ef65 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go @@ -0,0 +1,219 @@ +// Package ast declares the types used to represent syntax trees for HCL +// (HashiCorp Configuration Language) +package ast + +import ( + "fmt" + "strings" + + "github.com/hashicorp/hcl/hcl/token" +) + +// Node is an element in the abstract syntax tree. +type Node interface { + node() + Pos() token.Pos +} + +func (File) node() {} +func (ObjectList) node() {} +func (ObjectKey) node() {} +func (ObjectItem) node() {} +func (Comment) node() {} +func (CommentGroup) node() {} +func (ObjectType) node() {} +func (LiteralType) node() {} +func (ListType) node() {} + +// File represents a single HCL file +type File struct { + Node Node // usually a *ObjectList + Comments []*CommentGroup // list of all comments in the source +} + +func (f *File) Pos() token.Pos { + return f.Node.Pos() +} + +// ObjectList represents a list of ObjectItems. An HCL file itself is an +// ObjectList. +type ObjectList struct { + Items []*ObjectItem +} + +func (o *ObjectList) Add(item *ObjectItem) { + o.Items = append(o.Items, item) +} + +// Filter filters out the objects with the given key list as a prefix. +// +// The returned list of objects contain ObjectItems where the keys have +// this prefix already stripped off. This might result in objects with +// zero-length key lists if they have no children. +// +// If no matches are found, an empty ObjectList (non-nil) is returned. +func (o *ObjectList) Filter(keys ...string) *ObjectList { + var result ObjectList + for _, item := range o.Items { + // If there aren't enough keys, then ignore this + if len(item.Keys) < len(keys) { + continue + } + + match := true + for i, key := range item.Keys[:len(keys)] { + key := key.Token.Value().(string) + if key != keys[i] && !strings.EqualFold(key, keys[i]) { + match = false + break + } + } + if !match { + continue + } + + // Strip off the prefix from the children + newItem := *item + newItem.Keys = newItem.Keys[len(keys):] + result.Add(&newItem) + } + + return &result +} + +// Children returns further nested objects (key length > 0) within this +// ObjectList. This should be used with Filter to get at child items. +func (o *ObjectList) Children() *ObjectList { + var result ObjectList + for _, item := range o.Items { + if len(item.Keys) > 0 { + result.Add(item) + } + } + + return &result +} + +// Elem returns items in the list that are direct element assignments +// (key length == 0). This should be used with Filter to get at elements. +func (o *ObjectList) Elem() *ObjectList { + var result ObjectList + for _, item := range o.Items { + if len(item.Keys) == 0 { + result.Add(item) + } + } + + return &result +} + +func (o *ObjectList) Pos() token.Pos { + // always returns the uninitiliazed position + return o.Items[0].Pos() +} + +// ObjectItem represents a HCL Object Item. An item is represented with a key +// (or keys). It can be an assignment or an object (both normal and nested) +type ObjectItem struct { + // keys is only one length long if it's of type assignment. If it's a + // nested object it can be larger than one. In that case "assign" is + // invalid as there is no assignments for a nested object. + Keys []*ObjectKey + + // assign contains the position of "=", if any + Assign token.Pos + + // val is the item itself. It can be an object,list, number, bool or a + // string. If key length is larger than one, val can be only of type + // Object. + Val Node + + LeadComment *CommentGroup // associated lead comment + LineComment *CommentGroup // associated line comment +} + +func (o *ObjectItem) Pos() token.Pos { + // I'm not entirely sure what causes this, but removing this causes + // a test failure. We should investigate at some point. + if len(o.Keys) == 0 { + return token.Pos{} + } + + return o.Keys[0].Pos() +} + +// ObjectKeys are either an identifier or of type string. +type ObjectKey struct { + Token token.Token +} + +func (o *ObjectKey) Pos() token.Pos { + return o.Token.Pos +} + +// LiteralType represents a literal of basic type. Valid types are: +// token.NUMBER, token.FLOAT, token.BOOL and token.STRING +type LiteralType struct { + Token token.Token + + // comment types, only used when in a list + LeadComment *CommentGroup + LineComment *CommentGroup +} + +func (l *LiteralType) Pos() token.Pos { + return l.Token.Pos +} + +// ListStatement represents a HCL List type +type ListType struct { + Lbrack token.Pos // position of "[" + Rbrack token.Pos // position of "]" + List []Node // the elements in lexical order +} + +func (l *ListType) Pos() token.Pos { + return l.Lbrack +} + +func (l *ListType) Add(node Node) { + l.List = append(l.List, node) +} + +// ObjectType represents a HCL Object Type +type ObjectType struct { + Lbrace token.Pos // position of "{" + Rbrace token.Pos // position of "}" + List *ObjectList // the nodes in lexical order +} + +func (o *ObjectType) Pos() token.Pos { + return o.Lbrace +} + +// Comment node represents a single //, # style or /*- style commment +type Comment struct { + Start token.Pos // position of / or # + Text string +} + +func (c *Comment) Pos() token.Pos { + return c.Start +} + +// CommentGroup node represents a sequence of comments with no other tokens and +// no empty lines between. +type CommentGroup struct { + List []*Comment // len(List) > 0 +} + +func (c *CommentGroup) Pos() token.Pos { + return c.List[0].Pos() +} + +//------------------------------------------------------------------- +// GoStringer +//------------------------------------------------------------------- + +func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } +func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go new file mode 100644 index 0000000..ba07ad4 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go @@ -0,0 +1,52 @@ +package ast + +import "fmt" + +// WalkFunc describes a function to be called for each node during a Walk. The +// returned node can be used to rewrite the AST. Walking stops the returned +// bool is false. +type WalkFunc func(Node) (Node, bool) + +// Walk traverses an AST in depth-first order: It starts by calling fn(node); +// node must not be nil. If fn returns true, Walk invokes fn recursively for +// each of the non-nil children of node, followed by a call of fn(nil). The +// returned node of fn can be used to rewrite the passed node to fn. +func Walk(node Node, fn WalkFunc) Node { + rewritten, ok := fn(node) + if !ok { + return rewritten + } + + switch n := node.(type) { + case *File: + n.Node = Walk(n.Node, fn) + case *ObjectList: + for i, item := range n.Items { + n.Items[i] = Walk(item, fn).(*ObjectItem) + } + case *ObjectKey: + // nothing to do + case *ObjectItem: + for i, k := range n.Keys { + n.Keys[i] = Walk(k, fn).(*ObjectKey) + } + + if n.Val != nil { + n.Val = Walk(n.Val, fn) + } + case *LiteralType: + // nothing to do + case *ListType: + for i, l := range n.List { + n.List[i] = Walk(l, fn) + } + case *ObjectType: + n.List = Walk(n.List, fn).(*ObjectList) + default: + // should we panic here? + fmt.Printf("unknown type: %T\n", n) + } + + fn(nil) + return rewritten +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go new file mode 100644 index 0000000..5c99381 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go @@ -0,0 +1,17 @@ +package parser + +import ( + "fmt" + + "github.com/hashicorp/hcl/hcl/token" +) + +// PosError is a parse error that contains a position. +type PosError struct { + Pos token.Pos + Err error +} + +func (e *PosError) Error() string { + return fmt.Sprintf("At %s: %s", e.Pos, e.Err) +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go new file mode 100644 index 0000000..64c83bc --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go @@ -0,0 +1,532 @@ +// Package parser implements a parser for HCL (HashiCorp Configuration +// Language) +package parser + +import ( + "bytes" + "errors" + "fmt" + "strings" + + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/hcl/hcl/scanner" + "github.com/hashicorp/hcl/hcl/token" +) + +type Parser struct { + sc *scanner.Scanner + + // Last read token + tok token.Token + commaPrev token.Token + + comments []*ast.CommentGroup + leadComment *ast.CommentGroup // last lead comment + lineComment *ast.CommentGroup // last line comment + + enableTrace bool + indent int + n int // buffer size (max = 1) +} + +func newParser(src []byte) *Parser { + return &Parser{ + sc: scanner.New(src), + } +} + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func Parse(src []byte) (*ast.File, error) { + // normalize all line endings + // since the scanner and output only work with "\n" line endings, we may + // end up with dangling "\r" characters in the parsed data. + src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1) + + p := newParser(src) + return p.Parse() +} + +var errEofToken = errors.New("EOF token found") + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func (p *Parser) Parse() (*ast.File, error) { + f := &ast.File{} + var err, scerr error + p.sc.Error = func(pos token.Pos, msg string) { + scerr = &PosError{Pos: pos, Err: errors.New(msg)} + } + + f.Node, err = p.objectList(false) + if scerr != nil { + return nil, scerr + } + if err != nil { + return nil, err + } + + f.Comments = p.comments + return f, nil +} + +// objectList parses a list of items within an object (generally k/v pairs). +// The parameter" obj" tells this whether to we are within an object (braces: +// '{', '}') or just at the top level. If we're within an object, we end +// at an RBRACE. +func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) { + defer un(trace(p, "ParseObjectList")) + node := &ast.ObjectList{} + + for { + if obj { + tok := p.scan() + p.unscan() + if tok.Type == token.RBRACE { + break + } + } + + n, err := p.objectItem() + if err == errEofToken { + break // we are finished + } + + // we don't return a nil node, because might want to use already + // collected items. + if err != nil { + return node, err + } + + node.Add(n) + + // object lists can be optionally comma-delimited e.g. when a list of maps + // is being expressed, so a comma is allowed here - it's simply consumed + tok := p.scan() + if tok.Type != token.COMMA { + p.unscan() + } + } + return node, nil +} + +func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { + endline = p.tok.Pos.Line + + // count the endline if it's multiline comment, ie starting with /* + if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { + // don't use range here - no need to decode Unicode code points + for i := 0; i < len(p.tok.Text); i++ { + if p.tok.Text[i] == '\n' { + endline++ + } + } + } + + comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} + p.tok = p.sc.Scan() + return +} + +func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { + var list []*ast.Comment + endline = p.tok.Pos.Line + + for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { + var comment *ast.Comment + comment, endline = p.consumeComment() + list = append(list, comment) + } + + // add comment group to the comments list + comments = &ast.CommentGroup{List: list} + p.comments = append(p.comments, comments) + + return +} + +// objectItem parses a single object item +func (p *Parser) objectItem() (*ast.ObjectItem, error) { + defer un(trace(p, "ParseObjectItem")) + + keys, err := p.objectKey() + if len(keys) > 0 && err == errEofToken { + // We ignore eof token here since it is an error if we didn't + // receive a value (but we did receive a key) for the item. + err = nil + } + if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { + // This is a strange boolean statement, but what it means is: + // We have keys with no value, and we're likely in an object + // (since RBrace ends an object). For this, we set err to nil so + // we continue and get the error below of having the wrong value + // type. + err = nil + + // Reset the token type so we don't think it completed fine. See + // objectType which uses p.tok.Type to check if we're done with + // the object. + p.tok.Type = token.EOF + } + if err != nil { + return nil, err + } + + o := &ast.ObjectItem{ + Keys: keys, + } + + if p.leadComment != nil { + o.LeadComment = p.leadComment + p.leadComment = nil + } + + switch p.tok.Type { + case token.ASSIGN: + o.Assign = p.tok.Pos + o.Val, err = p.object() + if err != nil { + return nil, err + } + case token.LBRACE: + o.Val, err = p.objectType() + if err != nil { + return nil, err + } + default: + keyStr := make([]string, 0, len(keys)) + for _, k := range keys { + keyStr = append(keyStr, k.Token.Text) + } + + return nil, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf( + "key '%s' expected start of object ('{') or assignment ('=')", + strings.Join(keyStr, " ")), + } + } + + // key=#comment + // val + if p.lineComment != nil { + o.LineComment, p.lineComment = p.lineComment, nil + } + + // do a look-ahead for line comment + p.scan() + if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { + o.LineComment = p.lineComment + p.lineComment = nil + } + p.unscan() + return o, nil +} + +// objectKey parses an object key and returns a ObjectKey AST +func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { + keyCount := 0 + keys := make([]*ast.ObjectKey, 0) + + for { + tok := p.scan() + switch tok.Type { + case token.EOF: + // It is very important to also return the keys here as well as + // the error. This is because we need to be able to tell if we + // did parse keys prior to finding the EOF, or if we just found + // a bare EOF. + return keys, errEofToken + case token.ASSIGN: + // assignment or object only, but not nested objects. this is not + // allowed: `foo bar = {}` + if keyCount > 1 { + return nil, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), + } + } + + if keyCount == 0 { + return nil, &PosError{ + Pos: p.tok.Pos, + Err: errors.New("no object keys found!"), + } + } + + return keys, nil + case token.LBRACE: + var err error + + // If we have no keys, then it is a syntax error. i.e. {{}} is not + // allowed. + if len(keys) == 0 { + err = &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), + } + } + + // object + return keys, err + case token.IDENT, token.STRING: + keyCount++ + keys = append(keys, &ast.ObjectKey{Token: p.tok}) + case token.ILLEGAL: + return keys, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("illegal character"), + } + default: + return keys, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), + } + } + } +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) object() (ast.Node, error) { + defer un(trace(p, "ParseType")) + tok := p.scan() + + switch tok.Type { + case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: + return p.literalType() + case token.LBRACE: + return p.objectType() + case token.LBRACK: + return p.listType() + case token.COMMENT: + // implement comment + case token.EOF: + return nil, errEofToken + } + + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("Unknown token: %+v", tok), + } +} + +// objectType parses an object type and returns a ObjectType AST +func (p *Parser) objectType() (*ast.ObjectType, error) { + defer un(trace(p, "ParseObjectType")) + + // we assume that the currently scanned token is a LBRACE + o := &ast.ObjectType{ + Lbrace: p.tok.Pos, + } + + l, err := p.objectList(true) + + // if we hit RBRACE, we are good to go (means we parsed all Items), if it's + // not a RBRACE, it's an syntax error and we just return it. + if err != nil && p.tok.Type != token.RBRACE { + return nil, err + } + + // No error, scan and expect the ending to be a brace + if tok := p.scan(); tok.Type != token.RBRACE { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type), + } + } + + o.List = l + o.Rbrace = p.tok.Pos // advanced via parseObjectList + return o, nil +} + +// listType parses a list type and returns a ListType AST +func (p *Parser) listType() (*ast.ListType, error) { + defer un(trace(p, "ParseListType")) + + // we assume that the currently scanned token is a LBRACK + l := &ast.ListType{ + Lbrack: p.tok.Pos, + } + + needComma := false + for { + tok := p.scan() + if needComma { + switch tok.Type { + case token.COMMA, token.RBRACK: + default: + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error parsing list, expected comma or list end, got: %s", + tok.Type), + } + } + } + switch tok.Type { + case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: + node, err := p.literalType() + if err != nil { + return nil, err + } + + // If there is a lead comment, apply it + if p.leadComment != nil { + node.LeadComment = p.leadComment + p.leadComment = nil + } + + l.Add(node) + needComma = true + case token.COMMA: + // get next list item or we are at the end + // do a look-ahead for line comment + p.scan() + if p.lineComment != nil && len(l.List) > 0 { + lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) + if ok { + lit.LineComment = p.lineComment + l.List[len(l.List)-1] = lit + p.lineComment = nil + } + } + p.unscan() + + needComma = false + continue + case token.LBRACE: + // Looks like a nested object, so parse it out + node, err := p.objectType() + if err != nil { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error while trying to parse object within list: %s", err), + } + } + l.Add(node) + needComma = true + case token.LBRACK: + node, err := p.listType() + if err != nil { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error while trying to parse list within list: %s", err), + } + } + l.Add(node) + case token.RBRACK: + // finished + l.Rbrack = p.tok.Pos + return l, nil + default: + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), + } + } + } +} + +// literalType parses a literal type and returns a LiteralType AST +func (p *Parser) literalType() (*ast.LiteralType, error) { + defer un(trace(p, "ParseLiteral")) + + return &ast.LiteralType{ + Token: p.tok, + }, nil +} + +// scan returns the next token from the underlying scanner. If a token has +// been unscanned then read that instead. In the process, it collects any +// comment groups encountered, and remembers the last lead and line comments. +func (p *Parser) scan() token.Token { + // If we have a token on the buffer, then return it. + if p.n != 0 { + p.n = 0 + return p.tok + } + + // Otherwise read the next token from the scanner and Save it to the buffer + // in case we unscan later. + prev := p.tok + p.tok = p.sc.Scan() + + if p.tok.Type == token.COMMENT { + var comment *ast.CommentGroup + var endline int + + // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", + // p.tok.Pos.Line, prev.Pos.Line, endline) + if p.tok.Pos.Line == prev.Pos.Line { + // The comment is on same line as the previous token; it + // cannot be a lead comment but may be a line comment. + comment, endline = p.consumeCommentGroup(0) + if p.tok.Pos.Line != endline { + // The next token is on a different line, thus + // the last comment group is a line comment. + p.lineComment = comment + } + } + + // consume successor comments, if any + endline = -1 + for p.tok.Type == token.COMMENT { + comment, endline = p.consumeCommentGroup(1) + } + + if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { + switch p.tok.Type { + case token.RBRACE, token.RBRACK: + // Do not count for these cases + default: + // The next token is following on the line immediately after the + // comment group, thus the last comment group is a lead comment. + p.leadComment = comment + } + } + + } + + return p.tok +} + +// unscan pushes the previously read token back onto the buffer. +func (p *Parser) unscan() { + p.n = 1 +} + +// ---------------------------------------------------------------------------- +// Parsing support + +func (p *Parser) printTrace(a ...interface{}) { + if !p.enableTrace { + return + } + + const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + const n = len(dots) + fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) + + i := 2 * p.indent + for i > n { + fmt.Print(dots) + i -= n + } + // i <= n + fmt.Print(dots[0:i]) + fmt.Println(a...) +} + +func trace(p *Parser, msg string) *Parser { + p.printTrace(msg, "(") + p.indent++ + return p +} + +// Usage pattern: defer un(trace(p, "...")) +func un(p *Parser) { + p.indent-- + p.printTrace(")") +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go new file mode 100644 index 0000000..624a18f --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go @@ -0,0 +1,652 @@ +// Package scanner implements a scanner for HCL (HashiCorp Configuration +// Language) source text. +package scanner + +import ( + "bytes" + "fmt" + "os" + "regexp" + "unicode" + "unicode/utf8" + + "github.com/hashicorp/hcl/hcl/token" +) + +// eof represents a marker rune for the end of the reader. +const eof = rune(0) + +// Scanner defines a lexical scanner +type Scanner struct { + buf *bytes.Buffer // Source buffer for advancing and scanning + src []byte // Source buffer for immutable access + + // Source Position + srcPos token.Pos // current position + prevPos token.Pos // previous position, used for peek() method + + lastCharLen int // length of last character in bytes + lastLineLen int // length of last line in characters (for correct column reporting) + + tokStart int // token text start position + tokEnd int // token text end position + + // Error is called for each error encountered. If no Error + // function is set, the error is reported to os.Stderr. + Error func(pos token.Pos, msg string) + + // ErrorCount is incremented by one for each error encountered. + ErrorCount int + + // tokPos is the start position of most recently scanned token; set by + // Scan. The Filename field is always left untouched by the Scanner. If + // an error is reported (via Error) and Position is invalid, the scanner is + // not inside a token. + tokPos token.Pos +} + +// New creates and initializes a new instance of Scanner using src as +// its source content. +func New(src []byte) *Scanner { + // even though we accept a src, we read from a io.Reader compatible type + // (*bytes.Buffer). So in the future we might easily change it to streaming + // read. + b := bytes.NewBuffer(src) + s := &Scanner{ + buf: b, + src: src, + } + + // srcPosition always starts with 1 + s.srcPos.Line = 1 + return s +} + +// next reads the next rune from the bufferred reader. Returns the rune(0) if +// an error occurs (or io.EOF is returned). +func (s *Scanner) next() rune { + ch, size, err := s.buf.ReadRune() + if err != nil { + // advance for error reporting + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + return eof + } + + // remember last position + s.prevPos = s.srcPos + + s.srcPos.Column++ + s.lastCharLen = size + s.srcPos.Offset += size + + if ch == utf8.RuneError && size == 1 { + s.err("illegal UTF-8 encoding") + return ch + } + + if ch == '\n' { + s.srcPos.Line++ + s.lastLineLen = s.srcPos.Column + s.srcPos.Column = 0 + } + + if ch == '\x00' { + s.err("unexpected null character (0x00)") + return eof + } + + if ch == '\uE123' { + s.err("unicode code point U+E123 reserved for internal use") + return utf8.RuneError + } + + // debug + // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) + return ch +} + +// unread unreads the previous read Rune and updates the source position +func (s *Scanner) unread() { + if err := s.buf.UnreadRune(); err != nil { + panic(err) // this is user fault, we should catch it + } + s.srcPos = s.prevPos // put back last position +} + +// peek returns the next rune without advancing the reader. +func (s *Scanner) peek() rune { + peek, _, err := s.buf.ReadRune() + if err != nil { + return eof + } + + s.buf.UnreadRune() + return peek +} + +// Scan scans the next token and returns the token. +func (s *Scanner) Scan() token.Token { + ch := s.next() + + // skip white space + for isWhitespace(ch) { + ch = s.next() + } + + var tok token.Type + + // token text markings + s.tokStart = s.srcPos.Offset - s.lastCharLen + + // token position, initial next() is moving the offset by one(size of rune + // actually), though we are interested with the starting point + s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen + if s.srcPos.Column > 0 { + // common case: last character was not a '\n' + s.tokPos.Line = s.srcPos.Line + s.tokPos.Column = s.srcPos.Column + } else { + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + s.tokPos.Line = s.srcPos.Line - 1 + s.tokPos.Column = s.lastLineLen + } + + switch { + case isLetter(ch): + tok = token.IDENT + lit := s.scanIdentifier() + if lit == "true" || lit == "false" { + tok = token.BOOL + } + case isDecimal(ch): + tok = s.scanNumber(ch) + default: + switch ch { + case eof: + tok = token.EOF + case '"': + tok = token.STRING + s.scanString() + case '#', '/': + tok = token.COMMENT + s.scanComment(ch) + case '.': + tok = token.PERIOD + ch = s.peek() + if isDecimal(ch) { + tok = token.FLOAT + ch = s.scanMantissa(ch) + ch = s.scanExponent(ch) + } + case '<': + tok = token.HEREDOC + s.scanHeredoc() + case '[': + tok = token.LBRACK + case ']': + tok = token.RBRACK + case '{': + tok = token.LBRACE + case '}': + tok = token.RBRACE + case ',': + tok = token.COMMA + case '=': + tok = token.ASSIGN + case '+': + tok = token.ADD + case '-': + if isDecimal(s.peek()) { + ch := s.next() + tok = s.scanNumber(ch) + } else { + tok = token.SUB + } + default: + s.err("illegal char") + } + } + + // finish token ending + s.tokEnd = s.srcPos.Offset + + // create token literal + var tokenText string + if s.tokStart >= 0 { + tokenText = string(s.src[s.tokStart:s.tokEnd]) + } + s.tokStart = s.tokEnd // ensure idempotency of tokenText() call + + return token.Token{ + Type: tok, + Pos: s.tokPos, + Text: tokenText, + } +} + +func (s *Scanner) scanComment(ch rune) { + // single line comments + if ch == '#' || (ch == '/' && s.peek() != '*') { + if ch == '/' && s.peek() != '/' { + s.err("expected '/' for comment") + return + } + + ch = s.next() + for ch != '\n' && ch >= 0 && ch != eof { + ch = s.next() + } + if ch != eof && ch >= 0 { + s.unread() + } + return + } + + // be sure we get the character after /* This allows us to find comment's + // that are not erminated + if ch == '/' { + s.next() + ch = s.next() // read character after "/*" + } + + // look for /* - style comments + for { + if ch < 0 || ch == eof { + s.err("comment not terminated") + break + } + + ch0 := ch + ch = s.next() + if ch0 == '*' && ch == '/' { + break + } + } +} + +// scanNumber scans a HCL number definition starting with the given rune +func (s *Scanner) scanNumber(ch rune) token.Type { + if ch == '0' { + // check for hexadecimal, octal or float + ch = s.next() + if ch == 'x' || ch == 'X' { + // hexadecimal + ch = s.next() + found := false + for isHexadecimal(ch) { + ch = s.next() + found = true + } + + if !found { + s.err("illegal hexadecimal number") + } + + if ch != eof { + s.unread() + } + + return token.NUMBER + } + + // now it's either something like: 0421(octal) or 0.1231(float) + illegalOctal := false + for isDecimal(ch) { + ch = s.next() + if ch == '8' || ch == '9' { + // this is just a possibility. For example 0159 is illegal, but + // 0159.23 is valid. So we mark a possible illegal octal. If + // the next character is not a period, we'll print the error. + illegalOctal = true + } + } + + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if illegalOctal { + s.err("illegal octal number") + } + + if ch != eof { + s.unread() + } + return token.NUMBER + } + + s.scanMantissa(ch) + ch = s.next() // seek forward + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if ch != eof { + s.unread() + } + return token.NUMBER +} + +// scanMantissa scans the mantissa beginning from the rune. It returns the next +// non decimal rune. It's used to determine wheter it's a fraction or exponent. +func (s *Scanner) scanMantissa(ch rune) rune { + scanned := false + for isDecimal(ch) { + ch = s.next() + scanned = true + } + + if scanned && ch != eof { + s.unread() + } + return ch +} + +// scanFraction scans the fraction after the '.' rune +func (s *Scanner) scanFraction(ch rune) rune { + if ch == '.' { + ch = s.peek() // we peek just to see if we can move forward + ch = s.scanMantissa(ch) + } + return ch +} + +// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' +// rune. +func (s *Scanner) scanExponent(ch rune) rune { + if ch == 'e' || ch == 'E' { + ch = s.next() + if ch == '-' || ch == '+' { + ch = s.next() + } + ch = s.scanMantissa(ch) + } + return ch +} + +// scanHeredoc scans a heredoc string +func (s *Scanner) scanHeredoc() { + // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { + break + } + + // Not an anchor match, record the start of a new line + lineStart = s.srcPos.Offset + } + + if ch == eof { + s.err("heredoc not terminated") + return + } + } + + return +} + +// scanString scans a quoted string +func (s *Scanner) scanString() { + braces := 0 + for { + // '"' opening already consumed + // read character after quote + ch := s.next() + + if (ch == '\n' && braces == 0) || ch < 0 || ch == eof { + s.err("literal not terminated") + return + } + + if ch == '"' && braces == 0 { + break + } + + // If we're going into a ${} then we can ignore quotes for awhile + if braces == 0 && ch == '$' && s.peek() == '{' { + braces++ + s.next() + } else if braces > 0 && ch == '{' { + braces++ + } + if braces > 0 && ch == '}' { + braces-- + } + + if ch == '\\' { + s.scanEscape() + } + } + + return +} + +// scanEscape scans an escape sequence +func (s *Scanner) scanEscape() rune { + // http://en.cppreference.com/w/cpp/language/escape + ch := s.next() // read character after '/' + switch ch { + case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': + // nothing to do + case '0', '1', '2', '3', '4', '5', '6', '7': + // octal notation + ch = s.scanDigits(ch, 8, 3) + case 'x': + // hexademical notation + ch = s.scanDigits(s.next(), 16, 2) + case 'u': + // universal character name + ch = s.scanDigits(s.next(), 16, 4) + case 'U': + // universal character name + ch = s.scanDigits(s.next(), 16, 8) + default: + s.err("illegal char escape") + } + return ch +} + +// scanDigits scans a rune with the given base for n times. For example an +// octal notation \184 would yield in scanDigits(ch, 8, 3) +func (s *Scanner) scanDigits(ch rune, base, n int) rune { + start := n + for n > 0 && digitVal(ch) < base { + ch = s.next() + if ch == eof { + // If we see an EOF, we halt any more scanning of digits + // immediately. + break + } + + n-- + } + if n > 0 { + s.err("illegal char escape") + } + + if n != start && ch != eof { + // we scanned all digits, put the last non digit char back, + // only if we read anything at all + s.unread() + } + + return ch +} + +// scanIdentifier scans an identifier and returns the literal string +func (s *Scanner) scanIdentifier() string { + offs := s.srcPos.Offset - s.lastCharLen + ch := s.next() + for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { + ch = s.next() + } + + if ch != eof { + s.unread() // we got identifier, put back latest char + } + + return string(s.src[offs:s.srcPos.Offset]) +} + +// recentPosition returns the position of the character immediately after the +// character or token returned by the last call to Scan. +func (s *Scanner) recentPosition() (pos token.Pos) { + pos.Offset = s.srcPos.Offset - s.lastCharLen + switch { + case s.srcPos.Column > 0: + // common case: last character was not a '\n' + pos.Line = s.srcPos.Line + pos.Column = s.srcPos.Column + case s.lastLineLen > 0: + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + pos.Line = s.srcPos.Line - 1 + pos.Column = s.lastLineLen + default: + // at the beginning of the source + pos.Line = 1 + pos.Column = 1 + } + return +} + +// err prints the error of any scanning to s.Error function. If the function is +// not defined, by default it prints them to os.Stderr +func (s *Scanner) err(msg string) { + s.ErrorCount++ + pos := s.recentPosition() + + if s.Error != nil { + s.Error(pos, msg) + return + } + + fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) +} + +// isHexadecimal returns true if the given rune is a letter +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) +} + +// isDigit returns true if the given rune is a decimal digit +func isDigit(ch rune) bool { + return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) +} + +// isDecimal returns true if the given rune is a decimal number +func isDecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +// isHexadecimal returns true if the given rune is an hexadecimal number +func isHexadecimal(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' +} + +// isWhitespace returns true if the rune is a space, tab, newline or carriage return +func isWhitespace(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' +} + +// digitVal returns the integer value of a given octal,decimal or hexadecimal rune +func digitVal(ch rune) int { + switch { + case '0' <= ch && ch <= '9': + return int(ch - '0') + case 'a' <= ch && ch <= 'f': + return int(ch - 'a' + 10) + case 'A' <= ch && ch <= 'F': + return int(ch - 'A' + 10) + } + return 16 // larger than any legal digit val +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go new file mode 100644 index 0000000..5f981ea --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go @@ -0,0 +1,241 @@ +package strconv + +import ( + "errors" + "unicode/utf8" +) + +// ErrSyntax indicates that a value does not have the right syntax for the target type. +var ErrSyntax = errors.New("invalid syntax") + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (t string, err error) { + n := len(s) + if n < 2 { + return "", ErrSyntax + } + quote := s[0] + if quote != s[n-1] { + return "", ErrSyntax + } + s = s[1 : n-1] + + if quote != '"' { + return "", ErrSyntax + } + if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') { + return "", ErrSyntax + } + + // Is it trivial? Avoid allocation. + if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { + switch quote { + case '"': + return s, nil + case '\'': + r, size := utf8.DecodeRuneInString(s) + if size == len(s) && (r != utf8.RuneError || size != 1) { + return s, nil + } + } + } + + var runeTmp [utf8.UTFMax]byte + buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. + for len(s) > 0 { + // If we're starting a '${}' then let it through un-unquoted. + // Specifically: we don't unquote any characters within the `${}` + // section. + if s[0] == '$' && len(s) > 1 && s[1] == '{' { + buf = append(buf, '$', '{') + s = s[2:] + + // Continue reading until we find the closing brace, copying as-is + braces := 1 + for len(s) > 0 && braces > 0 { + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError { + return "", ErrSyntax + } + + s = s[size:] + + n := utf8.EncodeRune(runeTmp[:], r) + buf = append(buf, runeTmp[:n]...) + + switch r { + case '{': + braces++ + case '}': + braces-- + } + } + if braces != 0 { + return "", ErrSyntax + } + if len(s) == 0 { + // If there's no string left, we're done! + break + } else { + // If there's more left, we need to pop back up to the top of the loop + // in case there's another interpolation in this string. + continue + } + } + + if s[0] == '\n' { + return "", ErrSyntax + } + + c, multibyte, ss, err := unquoteChar(s, quote) + if err != nil { + return "", err + } + s = ss + if c < utf8.RuneSelf || !multibyte { + buf = append(buf, byte(c)) + } else { + n := utf8.EncodeRune(runeTmp[:], c) + buf = append(buf, runeTmp[:n]...) + } + if quote == '\'' && len(s) != 0 { + // single-quoted must be single character + return "", ErrSyntax + } + } + return string(buf), nil +} + +// contains reports whether the string contains the byte c. +func contains(s string, c byte) bool { + for i := 0; i < len(s); i++ { + if s[i] == c { + return true + } + } + return false +} + +func unhex(b byte) (v rune, ok bool) { + c := rune(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { + // easy cases + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = ErrSyntax + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return rune(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = ErrSyntax + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + var v rune + if len(s) < n { + err = ErrSyntax + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = ErrSyntax + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if v > utf8.MaxRune { + err = ErrSyntax + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := rune(c) - '0' + if len(s) < 2 { + err = ErrSyntax + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := rune(s[j]) - '0' + if x < 0 || x > 7 { + err = ErrSyntax + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = ErrSyntax + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = ErrSyntax + return + } + value = rune(c) + default: + err = ErrSyntax + return + } + tail = s + return +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/position.go b/vendor/github.com/hashicorp/hcl/hcl/token/position.go new file mode 100644 index 0000000..59c1bb7 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/token/position.go @@ -0,0 +1,46 @@ +package token + +import "fmt" + +// Pos describes an arbitrary source position +// including the file, line, and column location. +// A Position is valid if the line number is > 0. +type Pos struct { + Filename string // filename, if any + Offset int // offset, starting at 0 + Line int // line number, starting at 1 + Column int // column number, starting at 1 (character count) +} + +// IsValid returns true if the position is valid. +func (p *Pos) IsValid() bool { return p.Line > 0 } + +// String returns a string in one of several forms: +// +// file:line:column valid position with file name +// line:column valid position without file name +// file invalid position with file name +// - invalid position without file name +func (p Pos) String() string { + s := p.Filename + if p.IsValid() { + if s != "" { + s += ":" + } + s += fmt.Sprintf("%d:%d", p.Line, p.Column) + } + if s == "" { + s = "-" + } + return s +} + +// Before reports whether the position p is before u. +func (p Pos) Before(u Pos) bool { + return u.Offset > p.Offset || u.Line > p.Line +} + +// After reports whether the position p is after u. +func (p Pos) After(u Pos) bool { + return u.Offset < p.Offset || u.Line < p.Line +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/token.go b/vendor/github.com/hashicorp/hcl/hcl/token/token.go new file mode 100644 index 0000000..e37c066 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/token/token.go @@ -0,0 +1,219 @@ +// Package token defines constants representing the lexical tokens for HCL +// (HashiCorp Configuration Language) +package token + +import ( + "fmt" + "strconv" + "strings" + + hclstrconv "github.com/hashicorp/hcl/hcl/strconv" +) + +// Token defines a single HCL token which can be obtained via the Scanner +type Token struct { + Type Type + Pos Pos + Text string + JSON bool +} + +// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) +type Type int + +const ( + // Special tokens + ILLEGAL Type = iota + EOF + COMMENT + + identifier_beg + IDENT // literals + literal_beg + NUMBER // 12345 + FLOAT // 123.45 + BOOL // true,false + STRING // "abc" + HEREDOC // < 0 { + // Pop the current item + n := len(frontier) + item := frontier[n-1] + frontier = frontier[:n-1] + + switch v := item.Val.(type) { + case *ast.ObjectType: + items, frontier = flattenObjectType(v, item, items, frontier) + case *ast.ListType: + items, frontier = flattenListType(v, item, items, frontier) + default: + items = append(items, item) + } + } + + // Reverse the list since the frontier model runs things backwards + for i := len(items)/2 - 1; i >= 0; i-- { + opp := len(items) - 1 - i + items[i], items[opp] = items[opp], items[i] + } + + // Done! Set the original items + list.Items = items + return n, true + }) +} + +func flattenListType( + ot *ast.ListType, + item *ast.ObjectItem, + items []*ast.ObjectItem, + frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { + // If the list is empty, keep the original list + if len(ot.List) == 0 { + items = append(items, item) + return items, frontier + } + + // All the elements of this object must also be objects! + for _, subitem := range ot.List { + if _, ok := subitem.(*ast.ObjectType); !ok { + items = append(items, item) + return items, frontier + } + } + + // Great! We have a match go through all the items and flatten + for _, elem := range ot.List { + // Add it to the frontier so that we can recurse + frontier = append(frontier, &ast.ObjectItem{ + Keys: item.Keys, + Assign: item.Assign, + Val: elem, + LeadComment: item.LeadComment, + LineComment: item.LineComment, + }) + } + + return items, frontier +} + +func flattenObjectType( + ot *ast.ObjectType, + item *ast.ObjectItem, + items []*ast.ObjectItem, + frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { + // If the list has no items we do not have to flatten anything + if ot.List.Items == nil { + items = append(items, item) + return items, frontier + } + + // All the elements of this object must also be objects! + for _, subitem := range ot.List.Items { + if _, ok := subitem.Val.(*ast.ObjectType); !ok { + items = append(items, item) + return items, frontier + } + } + + // Great! We have a match go through all the items and flatten + for _, subitem := range ot.List.Items { + // Copy the new key + keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) + copy(keys, item.Keys) + copy(keys[len(item.Keys):], subitem.Keys) + + // Add it to the frontier so that we can recurse + frontier = append(frontier, &ast.ObjectItem{ + Keys: keys, + Assign: item.Assign, + Val: subitem.Val, + LeadComment: item.LeadComment, + LineComment: item.LineComment, + }) + } + + return items, frontier +} diff --git a/vendor/github.com/hashicorp/hcl/json/parser/parser.go b/vendor/github.com/hashicorp/hcl/json/parser/parser.go new file mode 100644 index 0000000..125a5f0 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/parser/parser.go @@ -0,0 +1,313 @@ +package parser + +import ( + "errors" + "fmt" + + "github.com/hashicorp/hcl/hcl/ast" + hcltoken "github.com/hashicorp/hcl/hcl/token" + "github.com/hashicorp/hcl/json/scanner" + "github.com/hashicorp/hcl/json/token" +) + +type Parser struct { + sc *scanner.Scanner + + // Last read token + tok token.Token + commaPrev token.Token + + enableTrace bool + indent int + n int // buffer size (max = 1) +} + +func newParser(src []byte) *Parser { + return &Parser{ + sc: scanner.New(src), + } +} + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func Parse(src []byte) (*ast.File, error) { + p := newParser(src) + return p.Parse() +} + +var errEofToken = errors.New("EOF token found") + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func (p *Parser) Parse() (*ast.File, error) { + f := &ast.File{} + var err, scerr error + p.sc.Error = func(pos token.Pos, msg string) { + scerr = fmt.Errorf("%s: %s", pos, msg) + } + + // The root must be an object in JSON + object, err := p.object() + if scerr != nil { + return nil, scerr + } + if err != nil { + return nil, err + } + + // We make our final node an object list so it is more HCL compatible + f.Node = object.List + + // Flatten it, which finds patterns and turns them into more HCL-like + // AST trees. + flattenObjects(f.Node) + + return f, nil +} + +func (p *Parser) objectList() (*ast.ObjectList, error) { + defer un(trace(p, "ParseObjectList")) + node := &ast.ObjectList{} + + for { + n, err := p.objectItem() + if err == errEofToken { + break // we are finished + } + + // we don't return a nil node, because might want to use already + // collected items. + if err != nil { + return node, err + } + + node.Add(n) + + // Check for a followup comma. If it isn't a comma, then we're done + if tok := p.scan(); tok.Type != token.COMMA { + break + } + } + + return node, nil +} + +// objectItem parses a single object item +func (p *Parser) objectItem() (*ast.ObjectItem, error) { + defer un(trace(p, "ParseObjectItem")) + + keys, err := p.objectKey() + if err != nil { + return nil, err + } + + o := &ast.ObjectItem{ + Keys: keys, + } + + switch p.tok.Type { + case token.COLON: + pos := p.tok.Pos + o.Assign = hcltoken.Pos{ + Filename: pos.Filename, + Offset: pos.Offset, + Line: pos.Line, + Column: pos.Column, + } + + o.Val, err = p.objectValue() + if err != nil { + return nil, err + } + } + + return o, nil +} + +// objectKey parses an object key and returns a ObjectKey AST +func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { + keyCount := 0 + keys := make([]*ast.ObjectKey, 0) + + for { + tok := p.scan() + switch tok.Type { + case token.EOF: + return nil, errEofToken + case token.STRING: + keyCount++ + keys = append(keys, &ast.ObjectKey{ + Token: p.tok.HCLToken(), + }) + case token.COLON: + // If we have a zero keycount it means that we never got + // an object key, i.e. `{ :`. This is a syntax error. + if keyCount == 0 { + return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) + } + + // Done + return keys, nil + case token.ILLEGAL: + return nil, errors.New("illegal") + default: + return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) + } + } +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) objectValue() (ast.Node, error) { + defer un(trace(p, "ParseObjectValue")) + tok := p.scan() + + switch tok.Type { + case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: + return p.literalType() + case token.LBRACE: + return p.objectType() + case token.LBRACK: + return p.listType() + case token.EOF: + return nil, errEofToken + } + + return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) object() (*ast.ObjectType, error) { + defer un(trace(p, "ParseType")) + tok := p.scan() + + switch tok.Type { + case token.LBRACE: + return p.objectType() + case token.EOF: + return nil, errEofToken + } + + return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) +} + +// objectType parses an object type and returns a ObjectType AST +func (p *Parser) objectType() (*ast.ObjectType, error) { + defer un(trace(p, "ParseObjectType")) + + // we assume that the currently scanned token is a LBRACE + o := &ast.ObjectType{} + + l, err := p.objectList() + + // if we hit RBRACE, we are good to go (means we parsed all Items), if it's + // not a RBRACE, it's an syntax error and we just return it. + if err != nil && p.tok.Type != token.RBRACE { + return nil, err + } + + o.List = l + return o, nil +} + +// listType parses a list type and returns a ListType AST +func (p *Parser) listType() (*ast.ListType, error) { + defer un(trace(p, "ParseListType")) + + // we assume that the currently scanned token is a LBRACK + l := &ast.ListType{} + + for { + tok := p.scan() + switch tok.Type { + case token.NUMBER, token.FLOAT, token.STRING: + node, err := p.literalType() + if err != nil { + return nil, err + } + + l.Add(node) + case token.COMMA: + continue + case token.LBRACE: + node, err := p.objectType() + if err != nil { + return nil, err + } + + l.Add(node) + case token.BOOL: + // TODO(arslan) should we support? not supported by HCL yet + case token.LBRACK: + // TODO(arslan) should we support nested lists? Even though it's + // written in README of HCL, it's not a part of the grammar + // (not defined in parse.y) + case token.RBRACK: + // finished + return l, nil + default: + return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) + } + + } +} + +// literalType parses a literal type and returns a LiteralType AST +func (p *Parser) literalType() (*ast.LiteralType, error) { + defer un(trace(p, "ParseLiteral")) + + return &ast.LiteralType{ + Token: p.tok.HCLToken(), + }, nil +} + +// scan returns the next token from the underlying scanner. If a token has +// been unscanned then read that instead. +func (p *Parser) scan() token.Token { + // If we have a token on the buffer, then return it. + if p.n != 0 { + p.n = 0 + return p.tok + } + + p.tok = p.sc.Scan() + return p.tok +} + +// unscan pushes the previously read token back onto the buffer. +func (p *Parser) unscan() { + p.n = 1 +} + +// ---------------------------------------------------------------------------- +// Parsing support + +func (p *Parser) printTrace(a ...interface{}) { + if !p.enableTrace { + return + } + + const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + const n = len(dots) + fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) + + i := 2 * p.indent + for i > n { + fmt.Print(dots) + i -= n + } + // i <= n + fmt.Print(dots[0:i]) + fmt.Println(a...) +} + +func trace(p *Parser, msg string) *Parser { + p.printTrace(msg, "(") + p.indent++ + return p +} + +// Usage pattern: defer un(trace(p, "...")) +func un(p *Parser) { + p.indent-- + p.printTrace(")") +} diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go new file mode 100644 index 0000000..fe3f0f0 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go @@ -0,0 +1,451 @@ +package scanner + +import ( + "bytes" + "fmt" + "os" + "unicode" + "unicode/utf8" + + "github.com/hashicorp/hcl/json/token" +) + +// eof represents a marker rune for the end of the reader. +const eof = rune(0) + +// Scanner defines a lexical scanner +type Scanner struct { + buf *bytes.Buffer // Source buffer for advancing and scanning + src []byte // Source buffer for immutable access + + // Source Position + srcPos token.Pos // current position + prevPos token.Pos // previous position, used for peek() method + + lastCharLen int // length of last character in bytes + lastLineLen int // length of last line in characters (for correct column reporting) + + tokStart int // token text start position + tokEnd int // token text end position + + // Error is called for each error encountered. If no Error + // function is set, the error is reported to os.Stderr. + Error func(pos token.Pos, msg string) + + // ErrorCount is incremented by one for each error encountered. + ErrorCount int + + // tokPos is the start position of most recently scanned token; set by + // Scan. The Filename field is always left untouched by the Scanner. If + // an error is reported (via Error) and Position is invalid, the scanner is + // not inside a token. + tokPos token.Pos +} + +// New creates and initializes a new instance of Scanner using src as +// its source content. +func New(src []byte) *Scanner { + // even though we accept a src, we read from a io.Reader compatible type + // (*bytes.Buffer). So in the future we might easily change it to streaming + // read. + b := bytes.NewBuffer(src) + s := &Scanner{ + buf: b, + src: src, + } + + // srcPosition always starts with 1 + s.srcPos.Line = 1 + return s +} + +// next reads the next rune from the bufferred reader. Returns the rune(0) if +// an error occurs (or io.EOF is returned). +func (s *Scanner) next() rune { + ch, size, err := s.buf.ReadRune() + if err != nil { + // advance for error reporting + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + return eof + } + + if ch == utf8.RuneError && size == 1 { + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + s.err("illegal UTF-8 encoding") + return ch + } + + // remember last position + s.prevPos = s.srcPos + + s.srcPos.Column++ + s.lastCharLen = size + s.srcPos.Offset += size + + if ch == '\n' { + s.srcPos.Line++ + s.lastLineLen = s.srcPos.Column + s.srcPos.Column = 0 + } + + // debug + // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) + return ch +} + +// unread unreads the previous read Rune and updates the source position +func (s *Scanner) unread() { + if err := s.buf.UnreadRune(); err != nil { + panic(err) // this is user fault, we should catch it + } + s.srcPos = s.prevPos // put back last position +} + +// peek returns the next rune without advancing the reader. +func (s *Scanner) peek() rune { + peek, _, err := s.buf.ReadRune() + if err != nil { + return eof + } + + s.buf.UnreadRune() + return peek +} + +// Scan scans the next token and returns the token. +func (s *Scanner) Scan() token.Token { + ch := s.next() + + // skip white space + for isWhitespace(ch) { + ch = s.next() + } + + var tok token.Type + + // token text markings + s.tokStart = s.srcPos.Offset - s.lastCharLen + + // token position, initial next() is moving the offset by one(size of rune + // actually), though we are interested with the starting point + s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen + if s.srcPos.Column > 0 { + // common case: last character was not a '\n' + s.tokPos.Line = s.srcPos.Line + s.tokPos.Column = s.srcPos.Column + } else { + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + s.tokPos.Line = s.srcPos.Line - 1 + s.tokPos.Column = s.lastLineLen + } + + switch { + case isLetter(ch): + lit := s.scanIdentifier() + if lit == "true" || lit == "false" { + tok = token.BOOL + } else if lit == "null" { + tok = token.NULL + } else { + s.err("illegal char") + } + case isDecimal(ch): + tok = s.scanNumber(ch) + default: + switch ch { + case eof: + tok = token.EOF + case '"': + tok = token.STRING + s.scanString() + case '.': + tok = token.PERIOD + ch = s.peek() + if isDecimal(ch) { + tok = token.FLOAT + ch = s.scanMantissa(ch) + ch = s.scanExponent(ch) + } + case '[': + tok = token.LBRACK + case ']': + tok = token.RBRACK + case '{': + tok = token.LBRACE + case '}': + tok = token.RBRACE + case ',': + tok = token.COMMA + case ':': + tok = token.COLON + case '-': + if isDecimal(s.peek()) { + ch := s.next() + tok = s.scanNumber(ch) + } else { + s.err("illegal char") + } + default: + s.err("illegal char: " + string(ch)) + } + } + + // finish token ending + s.tokEnd = s.srcPos.Offset + + // create token literal + var tokenText string + if s.tokStart >= 0 { + tokenText = string(s.src[s.tokStart:s.tokEnd]) + } + s.tokStart = s.tokEnd // ensure idempotency of tokenText() call + + return token.Token{ + Type: tok, + Pos: s.tokPos, + Text: tokenText, + } +} + +// scanNumber scans a HCL number definition starting with the given rune +func (s *Scanner) scanNumber(ch rune) token.Type { + zero := ch == '0' + pos := s.srcPos + + s.scanMantissa(ch) + ch = s.next() // seek forward + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if ch != eof { + s.unread() + } + + // If we have a larger number and this is zero, error + if zero && pos != s.srcPos { + s.err("numbers cannot start with 0") + } + + return token.NUMBER +} + +// scanMantissa scans the mantissa beginning from the rune. It returns the next +// non decimal rune. It's used to determine wheter it's a fraction or exponent. +func (s *Scanner) scanMantissa(ch rune) rune { + scanned := false + for isDecimal(ch) { + ch = s.next() + scanned = true + } + + if scanned && ch != eof { + s.unread() + } + return ch +} + +// scanFraction scans the fraction after the '.' rune +func (s *Scanner) scanFraction(ch rune) rune { + if ch == '.' { + ch = s.peek() // we peek just to see if we can move forward + ch = s.scanMantissa(ch) + } + return ch +} + +// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' +// rune. +func (s *Scanner) scanExponent(ch rune) rune { + if ch == 'e' || ch == 'E' { + ch = s.next() + if ch == '-' || ch == '+' { + ch = s.next() + } + ch = s.scanMantissa(ch) + } + return ch +} + +// scanString scans a quoted string +func (s *Scanner) scanString() { + braces := 0 + for { + // '"' opening already consumed + // read character after quote + ch := s.next() + + if ch == '\n' || ch < 0 || ch == eof { + s.err("literal not terminated") + return + } + + if ch == '"' { + break + } + + // If we're going into a ${} then we can ignore quotes for awhile + if braces == 0 && ch == '$' && s.peek() == '{' { + braces++ + s.next() + } else if braces > 0 && ch == '{' { + braces++ + } + if braces > 0 && ch == '}' { + braces-- + } + + if ch == '\\' { + s.scanEscape() + } + } + + return +} + +// scanEscape scans an escape sequence +func (s *Scanner) scanEscape() rune { + // http://en.cppreference.com/w/cpp/language/escape + ch := s.next() // read character after '/' + switch ch { + case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': + // nothing to do + case '0', '1', '2', '3', '4', '5', '6', '7': + // octal notation + ch = s.scanDigits(ch, 8, 3) + case 'x': + // hexademical notation + ch = s.scanDigits(s.next(), 16, 2) + case 'u': + // universal character name + ch = s.scanDigits(s.next(), 16, 4) + case 'U': + // universal character name + ch = s.scanDigits(s.next(), 16, 8) + default: + s.err("illegal char escape") + } + return ch +} + +// scanDigits scans a rune with the given base for n times. For example an +// octal notation \184 would yield in scanDigits(ch, 8, 3) +func (s *Scanner) scanDigits(ch rune, base, n int) rune { + for n > 0 && digitVal(ch) < base { + ch = s.next() + n-- + } + if n > 0 { + s.err("illegal char escape") + } + + // we scanned all digits, put the last non digit char back + s.unread() + return ch +} + +// scanIdentifier scans an identifier and returns the literal string +func (s *Scanner) scanIdentifier() string { + offs := s.srcPos.Offset - s.lastCharLen + ch := s.next() + for isLetter(ch) || isDigit(ch) || ch == '-' { + ch = s.next() + } + + if ch != eof { + s.unread() // we got identifier, put back latest char + } + + return string(s.src[offs:s.srcPos.Offset]) +} + +// recentPosition returns the position of the character immediately after the +// character or token returned by the last call to Scan. +func (s *Scanner) recentPosition() (pos token.Pos) { + pos.Offset = s.srcPos.Offset - s.lastCharLen + switch { + case s.srcPos.Column > 0: + // common case: last character was not a '\n' + pos.Line = s.srcPos.Line + pos.Column = s.srcPos.Column + case s.lastLineLen > 0: + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + pos.Line = s.srcPos.Line - 1 + pos.Column = s.lastLineLen + default: + // at the beginning of the source + pos.Line = 1 + pos.Column = 1 + } + return +} + +// err prints the error of any scanning to s.Error function. If the function is +// not defined, by default it prints them to os.Stderr +func (s *Scanner) err(msg string) { + s.ErrorCount++ + pos := s.recentPosition() + + if s.Error != nil { + s.Error(pos, msg) + return + } + + fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) +} + +// isHexadecimal returns true if the given rune is a letter +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) +} + +// isHexadecimal returns true if the given rune is a decimal digit +func isDigit(ch rune) bool { + return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) +} + +// isHexadecimal returns true if the given rune is a decimal number +func isDecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +// isHexadecimal returns true if the given rune is an hexadecimal number +func isHexadecimal(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' +} + +// isWhitespace returns true if the rune is a space, tab, newline or carriage return +func isWhitespace(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' +} + +// digitVal returns the integer value of a given octal,decimal or hexadecimal rune +func digitVal(ch rune) int { + switch { + case '0' <= ch && ch <= '9': + return int(ch - '0') + case 'a' <= ch && ch <= 'f': + return int(ch - 'a' + 10) + case 'A' <= ch && ch <= 'F': + return int(ch - 'A' + 10) + } + return 16 // larger than any legal digit val +} diff --git a/vendor/github.com/hashicorp/hcl/json/token/position.go b/vendor/github.com/hashicorp/hcl/json/token/position.go new file mode 100644 index 0000000..59c1bb7 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/token/position.go @@ -0,0 +1,46 @@ +package token + +import "fmt" + +// Pos describes an arbitrary source position +// including the file, line, and column location. +// A Position is valid if the line number is > 0. +type Pos struct { + Filename string // filename, if any + Offset int // offset, starting at 0 + Line int // line number, starting at 1 + Column int // column number, starting at 1 (character count) +} + +// IsValid returns true if the position is valid. +func (p *Pos) IsValid() bool { return p.Line > 0 } + +// String returns a string in one of several forms: +// +// file:line:column valid position with file name +// line:column valid position without file name +// file invalid position with file name +// - invalid position without file name +func (p Pos) String() string { + s := p.Filename + if p.IsValid() { + if s != "" { + s += ":" + } + s += fmt.Sprintf("%d:%d", p.Line, p.Column) + } + if s == "" { + s = "-" + } + return s +} + +// Before reports whether the position p is before u. +func (p Pos) Before(u Pos) bool { + return u.Offset > p.Offset || u.Line > p.Line +} + +// After reports whether the position p is after u. +func (p Pos) After(u Pos) bool { + return u.Offset < p.Offset || u.Line < p.Line +} diff --git a/vendor/github.com/hashicorp/hcl/json/token/token.go b/vendor/github.com/hashicorp/hcl/json/token/token.go new file mode 100644 index 0000000..95a0c3e --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/token/token.go @@ -0,0 +1,118 @@ +package token + +import ( + "fmt" + "strconv" + + hcltoken "github.com/hashicorp/hcl/hcl/token" +) + +// Token defines a single HCL token which can be obtained via the Scanner +type Token struct { + Type Type + Pos Pos + Text string +} + +// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) +type Type int + +const ( + // Special tokens + ILLEGAL Type = iota + EOF + + identifier_beg + literal_beg + NUMBER // 12345 + FLOAT // 123.45 + BOOL // true,false + STRING // "abc" + NULL // null + literal_end + identifier_end + + operator_beg + LBRACK // [ + LBRACE // { + COMMA // , + PERIOD // . + COLON // : + + RBRACK // ] + RBRACE // } + + operator_end +) + +var tokens = [...]string{ + ILLEGAL: "ILLEGAL", + + EOF: "EOF", + + NUMBER: "NUMBER", + FLOAT: "FLOAT", + BOOL: "BOOL", + STRING: "STRING", + NULL: "NULL", + + LBRACK: "LBRACK", + LBRACE: "LBRACE", + COMMA: "COMMA", + PERIOD: "PERIOD", + COLON: "COLON", + + RBRACK: "RBRACK", + RBRACE: "RBRACE", +} + +// String returns the string corresponding to the token tok. +func (t Type) String() string { + s := "" + if 0 <= t && t < Type(len(tokens)) { + s = tokens[t] + } + if s == "" { + s = "token(" + strconv.Itoa(int(t)) + ")" + } + return s +} + +// IsIdentifier returns true for tokens corresponding to identifiers and basic +// type literals; it returns false otherwise. +func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } + +// IsLiteral returns true for tokens corresponding to basic type literals; it +// returns false otherwise. +func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } + +// IsOperator returns true for tokens corresponding to operators and +// delimiters; it returns false otherwise. +func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } + +// String returns the token's literal text. Note that this is only +// applicable for certain token types, such as token.IDENT, +// token.STRING, etc.. +func (t Token) String() string { + return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) +} + +// HCLToken converts this token to an HCL token. +// +// The token type must be a literal type or this will panic. +func (t Token) HCLToken() hcltoken.Token { + switch t.Type { + case BOOL: + return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} + case FLOAT: + return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} + case NULL: + return hcltoken.Token{Type: hcltoken.STRING, Text: ""} + case NUMBER: + return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} + case STRING: + return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} + default: + panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) + } +} diff --git a/vendor/github.com/hashicorp/hcl/lex.go b/vendor/github.com/hashicorp/hcl/lex.go new file mode 100644 index 0000000..d9993c2 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/lex.go @@ -0,0 +1,38 @@ +package hcl + +import ( + "unicode" + "unicode/utf8" +) + +type lexModeValue byte + +const ( + lexModeUnknown lexModeValue = iota + lexModeHcl + lexModeJson +) + +// lexMode returns whether we're going to be parsing in JSON +// mode or HCL mode. +func lexMode(v []byte) lexModeValue { + var ( + r rune + w int + offset int + ) + + for { + r, w = utf8.DecodeRune(v[offset:]) + offset += w + if unicode.IsSpace(r) { + continue + } + if r == '{' { + return lexModeJson + } + break + } + + return lexModeHcl +} diff --git a/vendor/github.com/hashicorp/hcl/parse.go b/vendor/github.com/hashicorp/hcl/parse.go new file mode 100644 index 0000000..1fca53c --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/parse.go @@ -0,0 +1,39 @@ +package hcl + +import ( + "fmt" + + "github.com/hashicorp/hcl/hcl/ast" + hclParser "github.com/hashicorp/hcl/hcl/parser" + jsonParser "github.com/hashicorp/hcl/json/parser" +) + +// ParseBytes accepts as input byte slice and returns ast tree. +// +// Input can be either JSON or HCL +func ParseBytes(in []byte) (*ast.File, error) { + return parse(in) +} + +// ParseString accepts input as a string and returns ast tree. +func ParseString(input string) (*ast.File, error) { + return parse([]byte(input)) +} + +func parse(in []byte) (*ast.File, error) { + switch lexMode(in) { + case lexModeHcl: + return hclParser.Parse(in) + case lexModeJson: + return jsonParser.Parse(in) + } + + return nil, fmt.Errorf("unknown config format") +} + +// Parse parses the given input and returns the root object. +// +// The input format can be either HCL or JSON. +func Parse(input string) (*ast.File, error) { + return parse([]byte(input)) +} diff --git a/vendor/github.com/hashicorp/vault/LICENSE b/vendor/github.com/hashicorp/vault/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/vault/api/auth.go b/vendor/github.com/hashicorp/vault/api/auth.go new file mode 100644 index 0000000..da870c1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/auth.go @@ -0,0 +1,11 @@ +package api + +// Auth is used to perform credential backend related operations. +type Auth struct { + c *Client +} + +// Auth is used to return the client for credential-backend API calls. +func (c *Client) Auth() *Auth { + return &Auth{c: c} +} diff --git a/vendor/github.com/hashicorp/vault/api/auth_token.go b/vendor/github.com/hashicorp/vault/api/auth_token.go new file mode 100644 index 0000000..4f74f61 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/auth_token.go @@ -0,0 +1,243 @@ +package api + +// TokenAuth is used to perform token backend operations on Vault +type TokenAuth struct { + c *Client +} + +// Token is used to return the client for token-backend API calls +func (a *Auth) Token() *TokenAuth { + return &TokenAuth{c: a.c} +} + +func (c *TokenAuth) Create(opts *TokenCreateRequest) (*Secret, error) { + r := c.c.NewRequest("POST", "/v1/auth/token/create") + if err := r.SetJSONBody(opts); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) CreateOrphan(opts *TokenCreateRequest) (*Secret, error) { + r := c.c.NewRequest("POST", "/v1/auth/token/create-orphan") + if err := r.SetJSONBody(opts); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) CreateWithRole(opts *TokenCreateRequest, roleName string) (*Secret, error) { + r := c.c.NewRequest("POST", "/v1/auth/token/create/"+roleName) + if err := r.SetJSONBody(opts); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) Lookup(token string) (*Secret, error) { + r := c.c.NewRequest("POST", "/v1/auth/token/lookup") + if err := r.SetJSONBody(map[string]interface{}{ + "token": token, + }); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) LookupAccessor(accessor string) (*Secret, error) { + r := c.c.NewRequest("POST", "/v1/auth/token/lookup-accessor") + if err := r.SetJSONBody(map[string]interface{}{ + "accessor": accessor, + }); err != nil { + return nil, err + } + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) LookupSelf() (*Secret, error) { + r := c.c.NewRequest("GET", "/v1/auth/token/lookup-self") + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) { + r := c.c.NewRequest("PUT", "/v1/auth/token/renew") + if err := r.SetJSONBody(map[string]interface{}{ + "token": token, + "increment": increment, + }); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *TokenAuth) RenewSelf(increment int) (*Secret, error) { + r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self") + + body := map[string]interface{}{"increment": increment} + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +// RenewTokenAsSelf behaves like renew-self, but authenticates using a provided +// token instead of the token attached to the client. +func (c *TokenAuth) RenewTokenAsSelf(token string, increment int) (*Secret, error) { + r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self") + r.ClientToken = token + + body := map[string]interface{}{"increment": increment} + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +// RevokeAccessor revokes a token associated with the given accessor +// along with all the child tokens. +func (c *TokenAuth) RevokeAccessor(accessor string) error { + r := c.c.NewRequest("POST", "/v1/auth/token/revoke-accessor") + if err := r.SetJSONBody(map[string]interface{}{ + "accessor": accessor, + }); err != nil { + return err + } + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +// RevokeOrphan revokes a token without revoking the tree underneath it (so +// child tokens are orphaned rather than revoked) +func (c *TokenAuth) RevokeOrphan(token string) error { + r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-orphan") + if err := r.SetJSONBody(map[string]interface{}{ + "token": token, + }); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +// RevokeSelf revokes the token making the call. The `token` parameter is kept +// for backwards compatibility but is ignored; only the client's set token has +// an effect. +func (c *TokenAuth) RevokeSelf(token string) error { + r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-self") + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +// RevokeTree is the "normal" revoke operation that revokes the given token and +// the entire tree underneath -- all of its child tokens, their child tokens, +// etc. +func (c *TokenAuth) RevokeTree(token string) error { + r := c.c.NewRequest("PUT", "/v1/auth/token/revoke") + if err := r.SetJSONBody(map[string]interface{}{ + "token": token, + }); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +// TokenCreateRequest is the options structure for creating a token. +type TokenCreateRequest struct { + ID string `json:"id,omitempty"` + Policies []string `json:"policies,omitempty"` + Metadata map[string]string `json:"meta,omitempty"` + Lease string `json:"lease,omitempty"` + TTL string `json:"ttl,omitempty"` + ExplicitMaxTTL string `json:"explicit_max_ttl,omitempty"` + Period string `json:"period,omitempty"` + NoParent bool `json:"no_parent,omitempty"` + NoDefaultPolicy bool `json:"no_default_policy,omitempty"` + DisplayName string `json:"display_name"` + NumUses int `json:"num_uses"` + Renewable *bool `json:"renewable,omitempty"` +} diff --git a/vendor/github.com/hashicorp/vault/api/client.go b/vendor/github.com/hashicorp/vault/api/client.go new file mode 100644 index 0000000..8f0d3f8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/client.go @@ -0,0 +1,724 @@ +package api + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "net/url" + "os" + "path" + "strconv" + "strings" + "sync" + "time" + "unicode" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-cleanhttp" + retryablehttp "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/go-rootcerts" + "github.com/hashicorp/vault/helper/parseutil" + "golang.org/x/net/http2" + "golang.org/x/time/rate" +) + +const EnvVaultAddress = "VAULT_ADDR" +const EnvVaultCACert = "VAULT_CACERT" +const EnvVaultCAPath = "VAULT_CAPATH" +const EnvVaultClientCert = "VAULT_CLIENT_CERT" +const EnvVaultClientKey = "VAULT_CLIENT_KEY" +const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT" +const EnvVaultInsecure = "VAULT_SKIP_VERIFY" +const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME" +const EnvVaultWrapTTL = "VAULT_WRAP_TTL" +const EnvVaultMaxRetries = "VAULT_MAX_RETRIES" +const EnvVaultToken = "VAULT_TOKEN" +const EnvVaultMFA = "VAULT_MFA" +const EnvRateLimit = "VAULT_RATE_LIMIT" + +// WrappingLookupFunc is a function that, given an HTTP verb and a path, +// returns an optional string duration to be used for response wrapping (e.g. +// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/", +// however, end-of-path forward slashes are not trimmed, so must match your +// called path precisely. +type WrappingLookupFunc func(operation, path string) string + +// Config is used to configure the creation of the client. +type Config struct { + modifyLock sync.RWMutex + + // Address is the address of the Vault server. This should be a complete + // URL such as "http://vault.example.com". If you need a custom SSL + // cert or want to enable insecure mode, you need to specify a custom + // HttpClient. + Address string + + // HttpClient is the HTTP client to use. Vault sets sane defaults for the + // http.Client and its associated http.Transport created in DefaultConfig. + // If you must modify Vault's defaults, it is suggested that you start with + // that client and modify as needed rather than start with an empty client + // (or http.DefaultClient). + HttpClient *http.Client + + // MaxRetries controls the maximum number of times to retry when a 5xx + // error occurs. Set to 0 to disable retrying. Defaults to 2 (for a total + // of three tries). + MaxRetries int + + // Timeout is for setting custom timeout parameter in the HttpClient + Timeout time.Duration + + // If there is an error when creating the configuration, this will be the + // error + Error error + + // The Backoff function to use; a default is used if not provided + Backoff retryablehttp.Backoff + + // Limiter is the rate limiter used by the client. + // If this pointer is nil, then there will be no limit set. + // In contrast, if this pointer is set, even to an empty struct, + // then that limiter will be used. Note that an empty Limiter + // is equivalent blocking all events. + Limiter *rate.Limiter +} + +// TLSConfig contains the parameters needed to configure TLS on the HTTP client +// used to communicate with Vault. +type TLSConfig struct { + // CACert is the path to a PEM-encoded CA cert file to use to verify the + // Vault server SSL certificate. + CACert string + + // CAPath is the path to a directory of PEM-encoded CA cert files to verify + // the Vault server SSL certificate. + CAPath string + + // ClientCert is the path to the certificate for Vault communication + ClientCert string + + // ClientKey is the path to the private key for Vault communication + ClientKey string + + // TLSServerName, if set, is used to set the SNI host when connecting via + // TLS. + TLSServerName string + + // Insecure enables or disables SSL verification + Insecure bool +} + +// DefaultConfig returns a default configuration for the client. It is +// safe to modify the return value of this function. +// +// The default Address is https://127.0.0.1:8200, but this can be overridden by +// setting the `VAULT_ADDR` environment variable. +// +// If an error is encountered, this will return nil. +func DefaultConfig() *Config { + config := &Config{ + Address: "https://127.0.0.1:8200", + HttpClient: cleanhttp.DefaultClient(), + } + config.HttpClient.Timeout = time.Second * 60 + + transport := config.HttpClient.Transport.(*http.Transport) + transport.TLSHandshakeTimeout = 10 * time.Second + transport.TLSClientConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + } + if err := http2.ConfigureTransport(transport); err != nil { + config.Error = err + return config + } + + if err := config.ReadEnvironment(); err != nil { + config.Error = err + return config + } + + // Ensure redirects are not automatically followed + // Note that this is sane for the API client as it has its own + // redirect handling logic (and thus also for command/meta), + // but in e.g. http_test actual redirect handling is necessary + config.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + // Returning this value causes the Go net library to not close the + // response body and to nil out the error. Otherwise retry clients may + // try three times on every redirect because it sees an error from this + // function (to prevent redirects) passing through to it. + return http.ErrUseLastResponse + } + + config.Backoff = retryablehttp.LinearJitterBackoff + config.MaxRetries = 2 + + return config +} + +// ConfigureTLS takes a set of TLS configurations and applies those to the the +// HTTP client. +func (c *Config) ConfigureTLS(t *TLSConfig) error { + if c.HttpClient == nil { + c.HttpClient = DefaultConfig().HttpClient + } + clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig + + var clientCert tls.Certificate + foundClientCert := false + + switch { + case t.ClientCert != "" && t.ClientKey != "": + var err error + clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey) + if err != nil { + return err + } + foundClientCert = true + case t.ClientCert != "" || t.ClientKey != "": + return fmt.Errorf("both client cert and client key must be provided") + } + + if t.CACert != "" || t.CAPath != "" { + rootConfig := &rootcerts.Config{ + CAFile: t.CACert, + CAPath: t.CAPath, + } + if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil { + return err + } + } + + if t.Insecure { + clientTLSConfig.InsecureSkipVerify = true + } + + if foundClientCert { + // We use this function to ignore the server's preferential list of + // CAs, otherwise any CA used for the cert auth backend must be in the + // server's CA pool + clientTLSConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { + return &clientCert, nil + } + } + + if t.TLSServerName != "" { + clientTLSConfig.ServerName = t.TLSServerName + } + + return nil +} + +// ReadEnvironment reads configuration information from the environment. If +// there is an error, no configuration value is updated. +func (c *Config) ReadEnvironment() error { + var envAddress string + var envCACert string + var envCAPath string + var envClientCert string + var envClientKey string + var envClientTimeout time.Duration + var envInsecure bool + var envTLSServerName string + var envMaxRetries *uint64 + var limit *rate.Limiter + + // Parse the environment variables + if v := os.Getenv(EnvVaultAddress); v != "" { + envAddress = v + } + if v := os.Getenv(EnvVaultMaxRetries); v != "" { + maxRetries, err := strconv.ParseUint(v, 10, 32) + if err != nil { + return err + } + envMaxRetries = &maxRetries + } + if v := os.Getenv(EnvVaultCACert); v != "" { + envCACert = v + } + if v := os.Getenv(EnvVaultCAPath); v != "" { + envCAPath = v + } + if v := os.Getenv(EnvVaultClientCert); v != "" { + envClientCert = v + } + if v := os.Getenv(EnvVaultClientKey); v != "" { + envClientKey = v + } + if v := os.Getenv(EnvRateLimit); v != "" { + rateLimit, burstLimit, err := parseRateLimit(v) + if err != nil { + return err + } + limit = rate.NewLimiter(rate.Limit(rateLimit), burstLimit) + } + if t := os.Getenv(EnvVaultClientTimeout); t != "" { + clientTimeout, err := parseutil.ParseDurationSecond(t) + if err != nil { + return fmt.Errorf("could not parse %q", EnvVaultClientTimeout) + } + envClientTimeout = clientTimeout + } + if v := os.Getenv(EnvVaultInsecure); v != "" { + var err error + envInsecure, err = strconv.ParseBool(v) + if err != nil { + return fmt.Errorf("could not parse VAULT_SKIP_VERIFY") + } + } + if v := os.Getenv(EnvVaultTLSServerName); v != "" { + envTLSServerName = v + } + + // Configure the HTTP clients TLS configuration. + t := &TLSConfig{ + CACert: envCACert, + CAPath: envCAPath, + ClientCert: envClientCert, + ClientKey: envClientKey, + TLSServerName: envTLSServerName, + Insecure: envInsecure, + } + + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.Limiter = limit + + if err := c.ConfigureTLS(t); err != nil { + return err + } + + if envAddress != "" { + c.Address = envAddress + } + + if envMaxRetries != nil { + c.MaxRetries = int(*envMaxRetries) + } + + if envClientTimeout != 0 { + c.Timeout = envClientTimeout + } + + return nil +} + +func parseRateLimit(val string) (rate float64, burst int, err error) { + + _, err = fmt.Sscanf(val, "%f:%d", &rate, &burst) + if err != nil { + rate, err = strconv.ParseFloat(val, 64) + if err != nil { + err = fmt.Errorf("%v was provided but incorrectly formatted", EnvRateLimit) + } + burst = int(rate) + } + + return rate, burst, err + +} + +// Client is the client to the Vault API. Create a client with NewClient. +type Client struct { + modifyLock sync.RWMutex + addr *url.URL + config *Config + token string + headers http.Header + wrappingLookupFunc WrappingLookupFunc + mfaCreds []string + policyOverride bool +} + +// NewClient returns a new client for the given configuration. +// +// If the configuration is nil, Vault will use configuration from +// DefaultConfig(), which is the recommended starting configuration. +// +// If the environment variable `VAULT_TOKEN` is present, the token will be +// automatically added to the client. Otherwise, you must manually call +// `SetToken()`. +func NewClient(c *Config) (*Client, error) { + def := DefaultConfig() + if def == nil { + return nil, fmt.Errorf("could not create/read default configuration") + } + if def.Error != nil { + return nil, errwrap.Wrapf("error encountered setting up default configuration: {{err}}", def.Error) + } + + if c == nil { + c = def + } + + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + u, err := url.Parse(c.Address) + if err != nil { + return nil, err + } + + if c.HttpClient == nil { + c.HttpClient = def.HttpClient + } + if c.HttpClient.Transport == nil { + c.HttpClient.Transport = def.HttpClient.Transport + } + + client := &Client{ + addr: u, + config: c, + } + + if token := os.Getenv(EnvVaultToken); token != "" { + client.token = token + } + + return client, nil +} + +// Sets the address of Vault in the client. The format of address should be +// "://:". Setting this on a client will override the +// value of VAULT_ADDR environment variable. +func (c *Client) SetAddress(addr string) error { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + parsedAddr, err := url.Parse(addr) + if err != nil { + return errwrap.Wrapf("failed to set address: {{err}}", err) + } + + c.addr = parsedAddr + return nil +} + +// Address returns the Vault URL the client is configured to connect to +func (c *Client) Address() string { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + + return c.addr.String() +} + +// SetLimiter will set the rate limiter for this client. +// This method is thread-safe. +// rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter +func (c *Client) SetLimiter(rateLimit float64, burst int) { + c.modifyLock.RLock() + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + c.modifyLock.RUnlock() + + c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst) +} + +// SetMaxRetries sets the number of retries that will be used in the case of certain errors +func (c *Client) SetMaxRetries(retries int) { + c.modifyLock.RLock() + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + c.modifyLock.RUnlock() + + c.config.MaxRetries = retries +} + +// SetClientTimeout sets the client request timeout +func (c *Client) SetClientTimeout(timeout time.Duration) { + c.modifyLock.RLock() + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + c.modifyLock.RUnlock() + + c.config.Timeout = timeout +} + +// CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs +// for a given operation and path +func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + + return c.wrappingLookupFunc +} + +// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs +// for a given operation and path +func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.wrappingLookupFunc = lookupFunc +} + +// SetMFACreds sets the MFA credentials supplied either via the environment +// variable or via the command line. +func (c *Client) SetMFACreds(creds []string) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.mfaCreds = creds +} + +// Token returns the access token being used by this client. It will +// return the empty string if there is no token set. +func (c *Client) Token() string { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + + return c.token +} + +// SetToken sets the token directly. This won't perform any auth +// verification, it simply sets the token properly for future requests. +func (c *Client) SetToken(v string) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.token = v +} + +// ClearToken deletes the token if it is set or does nothing otherwise. +func (c *Client) ClearToken() { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.token = "" +} + +// SetHeaders sets the headers to be used for future requests. +func (c *Client) SetHeaders(headers http.Header) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.headers = headers +} + +// SetBackoff sets the backoff function to be used for future requests. +func (c *Client) SetBackoff(backoff retryablehttp.Backoff) { + c.modifyLock.RLock() + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + c.modifyLock.RUnlock() + + c.config.Backoff = backoff +} + +// Clone creates a new client with the same configuration. Note that the same +// underlying http.Client is used; modifying the client from more than one +// goroutine at once may not be safe, so modify the client as needed and then +// clone. +func (c *Client) Clone() (*Client, error) { + c.modifyLock.RLock() + c.config.modifyLock.RLock() + config := c.config + c.modifyLock.RUnlock() + + newConfig := &Config{ + Address: config.Address, + HttpClient: config.HttpClient, + MaxRetries: config.MaxRetries, + Timeout: config.Timeout, + Backoff: config.Backoff, + Limiter: config.Limiter, + } + config.modifyLock.RUnlock() + + return NewClient(newConfig) +} + +// SetPolicyOverride sets whether requests should be sent with the policy +// override flag to request overriding soft-mandatory Sentinel policies (both +// RGPs and EGPs) +func (c *Client) SetPolicyOverride(override bool) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.policyOverride = override +} + +// NewRequest creates a new raw request object to query the Vault server +// configured for this client. This is an advanced method and generally +// doesn't need to be called externally. +func (c *Client) NewRequest(method, requestPath string) *Request { + c.modifyLock.RLock() + addr := c.addr + token := c.token + mfaCreds := c.mfaCreds + wrappingLookupFunc := c.wrappingLookupFunc + headers := c.headers + policyOverride := c.policyOverride + c.modifyLock.RUnlock() + + // if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV + // record and take the highest match; this is not designed for high-availability, just discovery + var host string = addr.Host + if addr.Port() == "" { + // Internet Draft specifies that the SRV record is ignored if a port is given + _, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname()) + if err == nil && len(addrs) > 0 { + host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port) + } + } + + req := &Request{ + Method: method, + URL: &url.URL{ + User: addr.User, + Scheme: addr.Scheme, + Host: host, + Path: path.Join(addr.Path, requestPath), + }, + ClientToken: token, + Params: make(map[string][]string), + } + + var lookupPath string + switch { + case strings.HasPrefix(requestPath, "/v1/"): + lookupPath = strings.TrimPrefix(requestPath, "/v1/") + case strings.HasPrefix(requestPath, "v1/"): + lookupPath = strings.TrimPrefix(requestPath, "v1/") + default: + lookupPath = requestPath + } + + req.MFAHeaderVals = mfaCreds + + if wrappingLookupFunc != nil { + req.WrapTTL = wrappingLookupFunc(method, lookupPath) + } else { + req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath) + } + + if headers != nil { + req.Headers = headers + } + + req.PolicyOverride = policyOverride + + return req +} + +// RawRequest performs the raw request given. This request may be against +// a Vault server not configured with this client. This is an advanced operation +// that generally won't need to be called externally. +func (c *Client) RawRequest(r *Request) (*Response, error) { + c.modifyLock.RLock() + token := c.token + + c.config.modifyLock.RLock() + limiter := c.config.Limiter + maxRetries := c.config.MaxRetries + backoff := c.config.Backoff + httpClient := c.config.HttpClient + timeout := c.config.Timeout + c.config.modifyLock.RUnlock() + + c.modifyLock.RUnlock() + + if limiter != nil { + limiter.Wait(context.Background()) + } + + // Sanity check the token before potentially erroring from the API + idx := strings.IndexFunc(token, func(c rune) bool { + return !unicode.IsPrint(c) + }) + if idx != -1 { + return nil, fmt.Errorf("configured Vault token contains non-printable characters and cannot be used") + } + + redirectCount := 0 +START: + req, err := r.toRetryableHTTP() + if err != nil { + return nil, err + } + if req == nil { + return nil, fmt.Errorf("nil request created") + } + + // Set the timeout, if any + var cancelFunc context.CancelFunc + if timeout != 0 { + var ctx context.Context + ctx, cancelFunc = context.WithTimeout(context.Background(), timeout) + req.Request = req.Request.WithContext(ctx) + } + + if backoff == nil { + backoff = retryablehttp.LinearJitterBackoff + } + + client := &retryablehttp.Client{ + HTTPClient: httpClient, + RetryWaitMin: 1000 * time.Millisecond, + RetryWaitMax: 1500 * time.Millisecond, + RetryMax: maxRetries, + CheckRetry: retryablehttp.DefaultRetryPolicy, + Backoff: backoff, + ErrorHandler: retryablehttp.PassthroughErrorHandler, + } + + var result *Response + resp, err := client.Do(req) + if cancelFunc != nil { + cancelFunc() + } + if resp != nil { + result = &Response{Response: resp} + } + if err != nil { + if strings.Contains(err.Error(), "tls: oversized") { + err = errwrap.Wrapf( + "{{err}}\n\n"+ + "This error usually means that the server is running with TLS disabled\n"+ + "but the client is configured to use TLS. Please either enable TLS\n"+ + "on the server or run the client with -address set to an address\n"+ + "that uses the http protocol:\n\n"+ + " vault -address http://
\n\n"+ + "You can also set the VAULT_ADDR environment variable:\n\n\n"+ + " VAULT_ADDR=http://
vault \n\n"+ + "where
is replaced by the actual address to the server.", + err) + } + return result, err + } + + // Check for a redirect, only allowing for a single redirect + if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && redirectCount == 0 { + // Parse the updated location + respLoc, err := resp.Location() + if err != nil { + return result, err + } + + // Ensure a protocol downgrade doesn't happen + if req.URL.Scheme == "https" && respLoc.Scheme != "https" { + return result, fmt.Errorf("redirect would cause protocol downgrade") + } + + // Update the request + r.URL = respLoc + + // Reset the request body if any + if err := r.ResetJSONBody(); err != nil { + return result, err + } + + // Retry the request + redirectCount++ + goto START + } + + if err := result.Error(); err != nil { + return result, err + } + + return result, nil +} diff --git a/vendor/github.com/hashicorp/vault/api/help.go b/vendor/github.com/hashicorp/vault/api/help.go new file mode 100644 index 0000000..b9ae100 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/help.go @@ -0,0 +1,25 @@ +package api + +import ( + "fmt" +) + +// Help reads the help information for the given path. +func (c *Client) Help(path string) (*Help, error) { + r := c.NewRequest("GET", fmt.Sprintf("/v1/%s", path)) + r.Params.Add("help", "1") + resp, err := c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result Help + err = resp.DecodeJSON(&result) + return &result, err +} + +type Help struct { + Help string `json:"help"` + SeeAlso []string `json:"see_also"` +} diff --git a/vendor/github.com/hashicorp/vault/api/logical.go b/vendor/github.com/hashicorp/vault/api/logical.go new file mode 100644 index 0000000..346a711 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/logical.go @@ -0,0 +1,242 @@ +package api + +import ( + "bytes" + "fmt" + "io" + "os" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" +) + +const ( + wrappedResponseLocation = "cubbyhole/response" +) + +var ( + // The default TTL that will be used with `sys/wrapping/wrap`, can be + // changed + DefaultWrappingTTL = "5m" + + // The default function used if no other function is set, which honors the + // env var and wraps `sys/wrapping/wrap` + DefaultWrappingLookupFunc = func(operation, path string) string { + if os.Getenv(EnvVaultWrapTTL) != "" { + return os.Getenv(EnvVaultWrapTTL) + } + + if (operation == "PUT" || operation == "POST") && path == "sys/wrapping/wrap" { + return DefaultWrappingTTL + } + + return "" + } +) + +// Logical is used to perform logical backend operations on Vault. +type Logical struct { + c *Client +} + +// Logical is used to return the client for logical-backend API calls. +func (c *Client) Logical() *Logical { + return &Logical{c: c} +} + +func (c *Logical) Read(path string) (*Secret, error) { + r := c.c.NewRequest("GET", "/v1/"+path) + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + } + if resp != nil && resp.StatusCode == 404 { + secret, parseErr := ParseSecret(resp.Body) + switch parseErr { + case nil: + case io.EOF: + return nil, nil + default: + return nil, err + } + if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { + return secret, nil + } + return nil, nil + } + if err != nil { + return nil, err + } + + return ParseSecret(resp.Body) +} + +func (c *Logical) List(path string) (*Secret, error) { + r := c.c.NewRequest("LIST", "/v1/"+path) + // Set this for broader compatibility, but we use LIST above to be able to + // handle the wrapping lookup function + r.Method = "GET" + r.Params.Set("list", "true") + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + } + if resp != nil && resp.StatusCode == 404 { + secret, parseErr := ParseSecret(resp.Body) + switch parseErr { + case nil: + case io.EOF: + return nil, nil + default: + return nil, err + } + if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { + return secret, nil + } + return nil, nil + } + if err != nil { + return nil, err + } + + return ParseSecret(resp.Body) +} + +func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) { + r := c.c.NewRequest("PUT", "/v1/"+path) + if err := r.SetJSONBody(data); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + } + if resp != nil && resp.StatusCode == 404 { + secret, parseErr := ParseSecret(resp.Body) + switch parseErr { + case nil: + case io.EOF: + return nil, nil + default: + return nil, err + } + if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { + return secret, err + } + } + if err != nil { + return nil, err + } + + if resp.StatusCode == 200 { + return ParseSecret(resp.Body) + } + + return nil, nil +} + +func (c *Logical) Delete(path string) (*Secret, error) { + r := c.c.NewRequest("DELETE", "/v1/"+path) + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + } + if resp != nil && resp.StatusCode == 404 { + secret, parseErr := ParseSecret(resp.Body) + switch parseErr { + case nil: + case io.EOF: + return nil, nil + default: + return nil, err + } + if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { + return secret, err + } + } + if err != nil { + return nil, err + } + + if resp.StatusCode == 200 { + return ParseSecret(resp.Body) + } + + return nil, nil +} + +func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) { + var data map[string]interface{} + if wrappingToken != "" { + if c.c.Token() == "" { + c.c.SetToken(wrappingToken) + } else if wrappingToken != c.c.Token() { + data = map[string]interface{}{ + "token": wrappingToken, + } + } + } + + r := c.c.NewRequest("PUT", "/v1/sys/wrapping/unwrap") + if err := r.SetJSONBody(data); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + } + if resp == nil || resp.StatusCode != 404 { + if err != nil { + return nil, err + } + if resp == nil { + return nil, nil + } + return ParseSecret(resp.Body) + } + + // In the 404 case this may actually be a wrapped 404 error + secret, parseErr := ParseSecret(resp.Body) + switch parseErr { + case nil: + case io.EOF: + return nil, nil + default: + return nil, err + } + if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { + return secret, nil + } + + // Otherwise this might be an old-style wrapping token so attempt the old + // method + if wrappingToken != "" { + origToken := c.c.Token() + defer c.c.SetToken(origToken) + c.c.SetToken(wrappingToken) + } + + secret, err = c.Read(wrappedResponseLocation) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err) + } + if secret == nil { + return nil, fmt.Errorf("no value found at %q", wrappedResponseLocation) + } + if secret.Data == nil { + return nil, fmt.Errorf("\"data\" not found in wrapping response") + } + if _, ok := secret.Data["response"]; !ok { + return nil, fmt.Errorf("\"response\" not found in wrapping response \"data\" map") + } + + wrappedSecret := new(Secret) + buf := bytes.NewBufferString(secret.Data["response"].(string)) + if err := jsonutil.DecodeJSONFromReader(buf, wrappedSecret); err != nil { + return nil, errwrap.Wrapf("error unmarshalling wrapped secret: {{err}}", err) + } + + return wrappedSecret, nil +} diff --git a/vendor/github.com/hashicorp/vault/api/renewer.go b/vendor/github.com/hashicorp/vault/api/renewer.go new file mode 100644 index 0000000..1d37a19 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/renewer.go @@ -0,0 +1,349 @@ +package api + +import ( + "errors" + "math/rand" + "sync" + "time" +) + +var ( + ErrRenewerMissingInput = errors.New("missing input to renewer") + ErrRenewerMissingSecret = errors.New("missing secret to renew") + ErrRenewerNotRenewable = errors.New("secret is not renewable") + ErrRenewerNoSecretData = errors.New("returned empty secret data") + + // DefaultRenewerRenewBuffer is the default size of the buffer for renew + // messages on the channel. + DefaultRenewerRenewBuffer = 5 +) + +// Renewer is a process for renewing a secret. +// +// renewer, err := client.NewRenewer(&RenewerInput{ +// Secret: mySecret, +// }) +// go renewer.Renew() +// defer renewer.Stop() +// +// for { +// select { +// case err := <-renewer.DoneCh(): +// if err != nil { +// log.Fatal(err) +// } +// +// // Renewal is now over +// case renewal := <-renewer.RenewCh(): +// log.Printf("Successfully renewed: %#v", renewal) +// } +// } +// +// +// The `DoneCh` will return if renewal fails or if the remaining lease duration +// after a renewal is less than or equal to the grace (in number of seconds). In +// both cases, the caller should attempt a re-read of the secret. Clients should +// check the return value of the channel to see if renewal was successful. +type Renewer struct { + l sync.Mutex + + client *Client + secret *Secret + grace time.Duration + random *rand.Rand + increment int + doneCh chan error + renewCh chan *RenewOutput + + stopped bool + stopCh chan struct{} +} + +// RenewerInput is used as input to the renew function. +type RenewerInput struct { + // Secret is the secret to renew + Secret *Secret + + // DEPRECATED: this does not do anything. + Grace time.Duration + + // Rand is the randomizer to use for underlying randomization. If not + // provided, one will be generated and seeded automatically. If provided, it + // is assumed to have already been seeded. + Rand *rand.Rand + + // RenewBuffer is the size of the buffered channel where renew messages are + // dispatched. + RenewBuffer int + + // The new TTL, in seconds, that should be set on the lease. The TTL set + // here may or may not be honored by the vault server, based on Vault + // configuration or any associated max TTL values. + Increment int +} + +// RenewOutput is the metadata returned to the client (if it's listening) to +// renew messages. +type RenewOutput struct { + // RenewedAt is the timestamp when the renewal took place (UTC). + RenewedAt time.Time + + // Secret is the underlying renewal data. It's the same struct as all data + // that is returned from Vault, but since this is renewal data, it will not + // usually include the secret itself. + Secret *Secret +} + +// NewRenewer creates a new renewer from the given input. +func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) { + if i == nil { + return nil, ErrRenewerMissingInput + } + + secret := i.Secret + if secret == nil { + return nil, ErrRenewerMissingSecret + } + + random := i.Rand + if random == nil { + random = rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + } + + renewBuffer := i.RenewBuffer + if renewBuffer == 0 { + renewBuffer = DefaultRenewerRenewBuffer + } + + return &Renewer{ + client: c, + secret: secret, + increment: i.Increment, + random: random, + doneCh: make(chan error, 1), + renewCh: make(chan *RenewOutput, renewBuffer), + + stopped: false, + stopCh: make(chan struct{}), + }, nil +} + +// DoneCh returns the channel where the renewer will publish when renewal stops. +// If there is an error, this will be an error. +func (r *Renewer) DoneCh() <-chan error { + return r.doneCh +} + +// RenewCh is a channel that receives a message when a successful renewal takes +// place and includes metadata about the renewal. +func (r *Renewer) RenewCh() <-chan *RenewOutput { + return r.renewCh +} + +// Stop stops the renewer. +func (r *Renewer) Stop() { + r.l.Lock() + if !r.stopped { + close(r.stopCh) + r.stopped = true + } + r.l.Unlock() +} + +// Renew starts a background process for renewing this secret. When the secret +// has auth data, this attempts to renew the auth (token). When the secret has +// a lease, this attempts to renew the lease. +func (r *Renewer) Renew() { + var result error + if r.secret.Auth != nil { + result = r.renewAuth() + } else { + result = r.renewLease() + } + + r.doneCh <- result +} + +// renewAuth is a helper for renewing authentication. +func (r *Renewer) renewAuth() error { + if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" { + return ErrRenewerNotRenewable + } + + priorDuration := time.Duration(r.secret.Auth.LeaseDuration) * time.Second + r.calculateGrace(priorDuration) + + client, token := r.client, r.secret.Auth.ClientToken + + for { + // Check if we are stopped. + select { + case <-r.stopCh: + return nil + default: + } + + // Renew the auth. + renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment) + if err != nil { + return err + } + + // Push a message that a renewal took place. + select { + case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}: + default: + } + + // Somehow, sometimes, this happens. + if renewal == nil || renewal.Auth == nil { + return ErrRenewerNoSecretData + } + + // Do nothing if we are not renewable + if !renewal.Auth.Renewable { + return ErrRenewerNotRenewable + } + + // Grab the lease duration + leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second + + // We keep evaluating a new grace period so long as the lease is + // extending. Once it stops extending, we've hit the max and need to + // rely on the grace duration. + if leaseDuration > priorDuration { + r.calculateGrace(leaseDuration) + } + priorDuration = leaseDuration + + // The sleep duration is set to 2/3 of the current lease duration plus + // 1/3 of the current grace period, which adds jitter. + sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3) + + // If we are within grace, return now; or, if the amount of time we + // would sleep would land us in the grace period. This helps with short + // tokens; for example, you don't want a current lease duration of 4 + // seconds, a grace period of 3 seconds, and end up sleeping for more + // than three of those seconds and having a very small budget of time + // to renew. + if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace { + return nil + } + + select { + case <-r.stopCh: + return nil + case <-time.After(sleepDuration): + continue + } + } +} + +// renewLease is a helper for renewing a lease. +func (r *Renewer) renewLease() error { + if !r.secret.Renewable || r.secret.LeaseID == "" { + return ErrRenewerNotRenewable + } + + priorDuration := time.Duration(r.secret.LeaseDuration) * time.Second + r.calculateGrace(priorDuration) + + client, leaseID := r.client, r.secret.LeaseID + + for { + // Check if we are stopped. + select { + case <-r.stopCh: + return nil + default: + } + + // Renew the lease. + renewal, err := client.Sys().Renew(leaseID, r.increment) + if err != nil { + return err + } + + // Push a message that a renewal took place. + select { + case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}: + default: + } + + // Somehow, sometimes, this happens. + if renewal == nil { + return ErrRenewerNoSecretData + } + + // Do nothing if we are not renewable + if !renewal.Renewable { + return ErrRenewerNotRenewable + } + + // Grab the lease duration + leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second + + // We keep evaluating a new grace period so long as the lease is + // extending. Once it stops extending, we've hit the max and need to + // rely on the grace duration. + if leaseDuration > priorDuration { + r.calculateGrace(leaseDuration) + } + priorDuration = leaseDuration + + // The sleep duration is set to 2/3 of the current lease duration plus + // 1/3 of the current grace period, which adds jitter. + sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3) + + // If we are within grace, return now; or, if the amount of time we + // would sleep would land us in the grace period. This helps with short + // tokens; for example, you don't want a current lease duration of 4 + // seconds, a grace period of 3 seconds, and end up sleeping for more + // than three of those seconds and having a very small budget of time + // to renew. + if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace { + return nil + } + + select { + case <-r.stopCh: + return nil + case <-time.After(sleepDuration): + continue + } + } +} + +// sleepDuration calculates the time to sleep given the base lease duration. The +// base is the resulting lease duration. It will be reduced to 1/3 and +// multiplied by a random float between 0.0 and 1.0. This extra randomness +// prevents multiple clients from all trying to renew simultaneously. +func (r *Renewer) sleepDuration(base time.Duration) time.Duration { + sleep := float64(base) + + // Renew at 1/3 the remaining lease. This will give us an opportunity to retry + // at least one more time should the first renewal fail. + sleep = sleep / 3.0 + + // Use a randomness so many clients do not hit Vault simultaneously. + sleep = sleep * (r.random.Float64() + 1) / 2.0 + + return time.Duration(sleep) +} + +// calculateGrace calculates the grace period based on a reasonable set of +// assumptions given the total lease time; it also adds some jitter to not have +// clients be in sync. +func (r *Renewer) calculateGrace(leaseDuration time.Duration) { + if leaseDuration == 0 { + r.grace = 0 + return + } + + leaseNanos := float64(leaseDuration.Nanoseconds()) + jitterMax := 0.1 * leaseNanos + + // For a given lease duration, we want to allow 80-90% of that to elapse, + // so the remaining amount is the grace period + r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax)) +} diff --git a/vendor/github.com/hashicorp/vault/api/request.go b/vendor/github.com/hashicorp/vault/api/request.go new file mode 100644 index 0000000..5bcff8c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/request.go @@ -0,0 +1,145 @@ +package api + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/url" + + retryablehttp "github.com/hashicorp/go-retryablehttp" +) + +// Request is a raw request configuration structure used to initiate +// API requests to the Vault server. +type Request struct { + Method string + URL *url.URL + Params url.Values + Headers http.Header + ClientToken string + MFAHeaderVals []string + WrapTTL string + Obj interface{} + + // When possible, use BodyBytes as it is more efficient due to how the + // retry logic works + BodyBytes []byte + + // Fallback + Body io.Reader + BodySize int64 + + // Whether to request overriding soft-mandatory Sentinel policies (RGPs and + // EGPs). If set, the override flag will take effect for all policies + // evaluated during the request. + PolicyOverride bool +} + +// SetJSONBody is used to set a request body that is a JSON-encoded value. +func (r *Request) SetJSONBody(val interface{}) error { + buf, err := json.Marshal(val) + if err != nil { + return err + } + + r.Obj = val + r.BodyBytes = buf + return nil +} + +// ResetJSONBody is used to reset the body for a redirect +func (r *Request) ResetJSONBody() error { + if r.BodyBytes == nil { + return nil + } + return r.SetJSONBody(r.Obj) +} + +// DEPRECATED: ToHTTP turns this request into a valid *http.Request for use +// with the net/http package. +func (r *Request) ToHTTP() (*http.Request, error) { + req, err := r.toRetryableHTTP() + if err != nil { + return nil, err + } + + switch { + case r.BodyBytes == nil && r.Body == nil: + // No body + + case r.BodyBytes != nil: + req.Request.Body = ioutil.NopCloser(bytes.NewReader(r.BodyBytes)) + + default: + if c, ok := r.Body.(io.ReadCloser); ok { + req.Request.Body = c + } else { + req.Request.Body = ioutil.NopCloser(r.Body) + } + } + + return req.Request, nil +} + +func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) { + // Encode the query parameters + r.URL.RawQuery = r.Params.Encode() + + // Create the HTTP request, defaulting to retryable + var req *retryablehttp.Request + + var err error + var body interface{} + + switch { + case r.BodyBytes == nil && r.Body == nil: + // No body + + case r.BodyBytes != nil: + // Use bytes, it's more efficient + body = r.BodyBytes + + default: + body = r.Body + } + + req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), body) + if err != nil { + return nil, err + } + + req.URL.User = r.URL.User + req.URL.Scheme = r.URL.Scheme + req.URL.Host = r.URL.Host + req.Host = r.URL.Host + + if r.Headers != nil { + for header, vals := range r.Headers { + for _, val := range vals { + req.Header.Add(header, val) + } + } + } + + if len(r.ClientToken) != 0 { + req.Header.Set("X-Vault-Token", r.ClientToken) + } + + if len(r.WrapTTL) != 0 { + req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL) + } + + if len(r.MFAHeaderVals) != 0 { + for _, mfaHeaderVal := range r.MFAHeaderVals { + req.Header.Add("X-Vault-MFA", mfaHeaderVal) + } + } + + if r.PolicyOverride { + req.Header.Set("X-Vault-Policy-Override", "true") + } + + return req, nil +} diff --git a/vendor/github.com/hashicorp/vault/api/response.go b/vendor/github.com/hashicorp/vault/api/response.go new file mode 100644 index 0000000..053a277 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/response.go @@ -0,0 +1,77 @@ +package api + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + + "github.com/hashicorp/vault/helper/jsonutil" +) + +// Response is a raw response that wraps an HTTP response. +type Response struct { + *http.Response +} + +// DecodeJSON will decode the response body to a JSON structure. This +// will consume the response body, but will not close it. Close must +// still be called. +func (r *Response) DecodeJSON(out interface{}) error { + return jsonutil.DecodeJSONFromReader(r.Body, out) +} + +// Error returns an error response if there is one. If there is an error, +// this will fully consume the response body, but will not close it. The +// body must still be closed manually. +func (r *Response) Error() error { + // 200 to 399 are okay status codes. 429 is the code for health status of + // standby nodes. + if (r.StatusCode >= 200 && r.StatusCode < 400) || r.StatusCode == 429 { + return nil + } + + // We have an error. Let's copy the body into our own buffer first, + // so that if we can't decode JSON, we can at least copy it raw. + bodyBuf := &bytes.Buffer{} + if _, err := io.Copy(bodyBuf, r.Body); err != nil { + return err + } + + r.Body.Close() + r.Body = ioutil.NopCloser(bodyBuf) + + // Decode the error response if we can. Note that we wrap the bodyBuf + // in a bytes.Reader here so that the JSON decoder doesn't move the + // read pointer for the original buffer. + var resp ErrorResponse + if err := jsonutil.DecodeJSON(bodyBuf.Bytes(), &resp); err != nil { + // Ignore the decoding error and just drop the raw response + return fmt.Errorf( + "Error making API request.\n\n"+ + "URL: %s %s\n"+ + "Code: %d. Raw Message:\n\n%s", + r.Request.Method, r.Request.URL.String(), + r.StatusCode, bodyBuf.String()) + } + + var errBody bytes.Buffer + errBody.WriteString(fmt.Sprintf( + "Error making API request.\n\n"+ + "URL: %s %s\n"+ + "Code: %d. Errors:\n\n", + r.Request.Method, r.Request.URL.String(), + r.StatusCode)) + for _, err := range resp.Errors { + errBody.WriteString(fmt.Sprintf("* %s", err)) + } + + return fmt.Errorf(errBody.String()) +} + +// ErrorResponse is the raw structure of errors when they're returned by the +// HTTP API. +type ErrorResponse struct { + Errors []string +} diff --git a/vendor/github.com/hashicorp/vault/api/secret.go b/vendor/github.com/hashicorp/vault/api/secret.go new file mode 100644 index 0000000..4675f4a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/secret.go @@ -0,0 +1,255 @@ +package api + +import ( + "fmt" + "io" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/parseutil" +) + +// Secret is the structure returned for every secret within Vault. +type Secret struct { + // The request ID that generated this response + RequestID string `json:"request_id"` + + LeaseID string `json:"lease_id"` + LeaseDuration int `json:"lease_duration"` + Renewable bool `json:"renewable"` + + // Data is the actual contents of the secret. The format of the data + // is arbitrary and up to the secret backend. + Data map[string]interface{} `json:"data"` + + // Warnings contains any warnings related to the operation. These + // are not issues that caused the command to fail, but that the + // client should be aware of. + Warnings []string `json:"warnings"` + + // Auth, if non-nil, means that there was authentication information + // attached to this response. + Auth *SecretAuth `json:"auth,omitempty"` + + // WrapInfo, if non-nil, means that the initial response was wrapped in the + // cubbyhole of the given token (which has a TTL of the given number of + // seconds) + WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"` +} + +// TokenID returns the standardized token ID (token) for the given secret. +func (s *Secret) TokenID() (string, error) { + if s == nil { + return "", nil + } + + if s.Auth != nil && len(s.Auth.ClientToken) > 0 { + return s.Auth.ClientToken, nil + } + + if s.Data == nil || s.Data["id"] == nil { + return "", nil + } + + id, ok := s.Data["id"].(string) + if !ok { + return "", fmt.Errorf("token found but in the wrong format") + } + + return id, nil +} + +// TokenAccessor returns the standardized token accessor for the given secret. +// If the secret is nil or does not contain an accessor, this returns the empty +// string. +func (s *Secret) TokenAccessor() (string, error) { + if s == nil { + return "", nil + } + + if s.Auth != nil && len(s.Auth.Accessor) > 0 { + return s.Auth.Accessor, nil + } + + if s.Data == nil || s.Data["accessor"] == nil { + return "", nil + } + + accessor, ok := s.Data["accessor"].(string) + if !ok { + return "", fmt.Errorf("token found but in the wrong format") + } + + return accessor, nil +} + +// TokenRemainingUses returns the standardized remaining uses for the given +// secret. If the secret is nil or does not contain the "num_uses", this +// returns -1. On error, this will return -1 and a non-nil error. +func (s *Secret) TokenRemainingUses() (int, error) { + if s == nil || s.Data == nil || s.Data["num_uses"] == nil { + return -1, nil + } + + uses, err := parseutil.ParseInt(s.Data["num_uses"]) + if err != nil { + return 0, err + } + + return int(uses), nil +} + +// TokenPolicies returns the standardized list of policies for the given secret. +// If the secret is nil or does not contain any policies, this returns nil. +func (s *Secret) TokenPolicies() ([]string, error) { + if s == nil { + return nil, nil + } + + if s.Auth != nil && len(s.Auth.Policies) > 0 { + return s.Auth.Policies, nil + } + + if s.Data == nil || s.Data["policies"] == nil { + return nil, nil + } + + sList, ok := s.Data["policies"].([]string) + if ok { + return sList, nil + } + + list, ok := s.Data["policies"].([]interface{}) + if !ok { + return nil, fmt.Errorf("unable to convert token policies to expected format") + } + + policies := make([]string, len(list)) + for i := range list { + p, ok := list[i].(string) + if !ok { + return nil, fmt.Errorf("unable to convert policy %v to string", list[i]) + } + policies[i] = p + } + + return policies, nil +} + +// TokenMetadata returns the map of metadata associated with this token, if any +// exists. If the secret is nil or does not contain the "metadata" key, this +// returns nil. +func (s *Secret) TokenMetadata() (map[string]string, error) { + if s == nil { + return nil, nil + } + + if s.Auth != nil && len(s.Auth.Metadata) > 0 { + return s.Auth.Metadata, nil + } + + if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) { + return nil, nil + } + + data, ok := s.Data["metadata"].(map[string]interface{}) + if !ok { + data, ok = s.Data["meta"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("unable to convert metadata field to expected format") + } + } + + metadata := make(map[string]string, len(data)) + for k, v := range data { + typed, ok := v.(string) + if !ok { + return nil, fmt.Errorf("unable to convert metadata value %v to string", v) + } + metadata[k] = typed + } + + return metadata, nil +} + +// TokenIsRenewable returns the standardized token renewability for the given +// secret. If the secret is nil or does not contain the "renewable" key, this +// returns false. +func (s *Secret) TokenIsRenewable() (bool, error) { + if s == nil { + return false, nil + } + + if s.Auth != nil && s.Auth.Renewable { + return s.Auth.Renewable, nil + } + + if s.Data == nil || s.Data["renewable"] == nil { + return false, nil + } + + renewable, err := parseutil.ParseBool(s.Data["renewable"]) + if err != nil { + return false, errwrap.Wrapf("could not convert renewable value to a boolean: {{err}}", err) + } + + return renewable, nil +} + +// TokenTTL returns the standardized remaining token TTL for the given secret. +// If the secret is nil or does not contain a TTL, this returns 0. +func (s *Secret) TokenTTL() (time.Duration, error) { + if s == nil { + return 0, nil + } + + if s.Auth != nil && s.Auth.LeaseDuration > 0 { + return time.Duration(s.Auth.LeaseDuration) * time.Second, nil + } + + if s.Data == nil || s.Data["ttl"] == nil { + return 0, nil + } + + ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"]) + if err != nil { + return 0, err + } + + return ttl, nil +} + +// SecretWrapInfo contains wrapping information if we have it. If what is +// contained is an authentication token, the accessor for the token will be +// available in WrappedAccessor. +type SecretWrapInfo struct { + Token string `json:"token"` + Accessor string `json:"accessor"` + TTL int `json:"ttl"` + CreationTime time.Time `json:"creation_time"` + CreationPath string `json:"creation_path"` + WrappedAccessor string `json:"wrapped_accessor"` +} + +// SecretAuth is the structure containing auth information if we have it. +type SecretAuth struct { + ClientToken string `json:"client_token"` + Accessor string `json:"accessor"` + Policies []string `json:"policies"` + Metadata map[string]string `json:"metadata"` + + LeaseDuration int `json:"lease_duration"` + Renewable bool `json:"renewable"` +} + +// ParseSecret is used to parse a secret value from JSON from an io.Reader. +func ParseSecret(r io.Reader) (*Secret, error) { + // First decode the JSON into a map[string]interface{} + var secret Secret + if err := jsonutil.DecodeJSONFromReader(r, &secret); err != nil { + return nil, err + } + + return &secret, nil +} diff --git a/vendor/github.com/hashicorp/vault/api/ssh.go b/vendor/github.com/hashicorp/vault/api/ssh.go new file mode 100644 index 0000000..a17b0eb --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/ssh.go @@ -0,0 +1,55 @@ +package api + +import "fmt" + +// SSH is used to return a client to invoke operations on SSH backend. +type SSH struct { + c *Client + MountPoint string +} + +// SSH returns the client for logical-backend API calls. +func (c *Client) SSH() *SSH { + return c.SSHWithMountPoint(SSHHelperDefaultMountPoint) +} + +// SSHWithMountPoint returns the client with specific SSH mount point. +func (c *Client) SSHWithMountPoint(mountPoint string) *SSH { + return &SSH{ + c: c, + MountPoint: mountPoint, + } +} + +// Credential invokes the SSH backend API to create a credential to establish an SSH session. +func (c *SSH) Credential(role string, data map[string]interface{}) (*Secret, error) { + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/creds/%s", c.MountPoint, role)) + if err := r.SetJSONBody(data); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +// SignKey signs the given public key and returns a signed public key to pass +// along with the SSH request. +func (c *SSH) SignKey(role string, data map[string]interface{}) (*Secret, error) { + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/sign/%s", c.MountPoint, role)) + if err := r.SetJSONBody(data); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} diff --git a/vendor/github.com/hashicorp/vault/api/ssh_agent.go b/vendor/github.com/hashicorp/vault/api/ssh_agent.go new file mode 100644 index 0000000..8027001 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/ssh_agent.go @@ -0,0 +1,257 @@ +package api + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "os" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-rootcerts" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/mitchellh/mapstructure" +) + +const ( + // SSHHelperDefaultMountPoint is the default path at which SSH backend will be + // mounted in the Vault server. + SSHHelperDefaultMountPoint = "ssh" + + // VerifyEchoRequest is the echo request message sent as OTP by the helper. + VerifyEchoRequest = "verify-echo-request" + + // VerifyEchoResponse is the echo response message sent as a response to OTP + // matching echo request. + VerifyEchoResponse = "verify-echo-response" +) + +// SSHHelper is a structure representing a vault-ssh-helper which can talk to vault server +// in order to verify the OTP entered by the user. It contains the path at which +// SSH backend is mounted at the server. +type SSHHelper struct { + c *Client + MountPoint string +} + +// SSHVerifyResponse is a structure representing the fields in Vault server's +// response. +type SSHVerifyResponse struct { + // Usually empty. If the request OTP is echo request message, this will + // be set to the corresponding echo response message. + Message string `json:"message" mapstructure:"message"` + + // Username associated with the OTP + Username string `json:"username" mapstructure:"username"` + + // IP associated with the OTP + IP string `json:"ip" mapstructure:"ip"` + + // Name of the role against which the OTP was issued + RoleName string `json:"role_name" mapstructure:"role_name"` +} + +// SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file. +type SSHHelperConfig struct { + VaultAddr string `hcl:"vault_addr"` + SSHMountPoint string `hcl:"ssh_mount_point"` + CACert string `hcl:"ca_cert"` + CAPath string `hcl:"ca_path"` + AllowedCidrList string `hcl:"allowed_cidr_list"` + AllowedRoles string `hcl:"allowed_roles"` + TLSSkipVerify bool `hcl:"tls_skip_verify"` + TLSServerName string `hcl:"tls_server_name"` +} + +// SetTLSParameters sets the TLS parameters for this SSH agent. +func (c *SSHHelperConfig) SetTLSParameters(clientConfig *Config, certPool *x509.CertPool) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: c.TLSSkipVerify, + MinVersion: tls.VersionTLS12, + RootCAs: certPool, + ServerName: c.TLSServerName, + } + + transport := cleanhttp.DefaultTransport() + transport.TLSClientConfig = tlsConfig + clientConfig.HttpClient.Transport = transport +} + +// Returns true if any of the following conditions are true: +// * CA cert is configured +// * CA path is configured +// * configured to skip certificate verification +// * TLS server name is configured +// +func (c *SSHHelperConfig) shouldSetTLSParameters() bool { + return c.CACert != "" || c.CAPath != "" || c.TLSServerName != "" || c.TLSSkipVerify +} + +// NewClient returns a new client for the configuration. This client will be used by the +// vault-ssh-helper to communicate with Vault server and verify the OTP entered by user. +// If the configuration supplies Vault SSL certificates, then the client will +// have TLS configured in its transport. +func (c *SSHHelperConfig) NewClient() (*Client, error) { + // Creating a default client configuration for communicating with vault server. + clientConfig := DefaultConfig() + + // Pointing the client to the actual address of vault server. + clientConfig.Address = c.VaultAddr + + // Check if certificates are provided via config file. + if c.shouldSetTLSParameters() { + rootConfig := &rootcerts.Config{ + CAFile: c.CACert, + CAPath: c.CAPath, + } + certPool, err := rootcerts.LoadCACerts(rootConfig) + if err != nil { + return nil, err + } + // Enable TLS on the HTTP client information + c.SetTLSParameters(clientConfig, certPool) + } + + // Creating the client object for the given configuration + client, err := NewClient(clientConfig) + if err != nil { + return nil, err + } + + return client, nil +} + +// LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding +// in-memory structure. +// +// Vault address is a required parameter. +// Mount point defaults to "ssh". +func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) { + contents, err := ioutil.ReadFile(path) + if err != nil && !os.IsNotExist(err) { + return nil, multierror.Prefix(err, "ssh_helper:") + } + return ParseSSHHelperConfig(string(contents)) +} + +// ParseSSHHelperConfig parses the given contents as a string for the SSHHelper +// configuration. +func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) { + root, err := hcl.Parse(string(contents)) + if err != nil { + return nil, errwrap.Wrapf("error parsing config: {{err}}", err) + } + + list, ok := root.Node.(*ast.ObjectList) + if !ok { + return nil, fmt.Errorf("error parsing config: file doesn't contain a root object") + } + + valid := []string{ + "vault_addr", + "ssh_mount_point", + "ca_cert", + "ca_path", + "allowed_cidr_list", + "allowed_roles", + "tls_skip_verify", + "tls_server_name", + } + if err := checkHCLKeys(list, valid); err != nil { + return nil, multierror.Prefix(err, "ssh_helper:") + } + + var c SSHHelperConfig + c.SSHMountPoint = SSHHelperDefaultMountPoint + if err := hcl.DecodeObject(&c, list); err != nil { + return nil, multierror.Prefix(err, "ssh_helper:") + } + + if c.VaultAddr == "" { + return nil, fmt.Errorf(`missing config "vault_addr"`) + } + return &c, nil +} + +// SSHHelper creates an SSHHelper object which can talk to Vault server with SSH backend +// mounted at default path ("ssh"). +func (c *Client) SSHHelper() *SSHHelper { + return c.SSHHelperWithMountPoint(SSHHelperDefaultMountPoint) +} + +// SSHHelperWithMountPoint creates an SSHHelper object which can talk to Vault server with SSH backend +// mounted at a specific mount point. +func (c *Client) SSHHelperWithMountPoint(mountPoint string) *SSHHelper { + return &SSHHelper{ + c: c, + MountPoint: mountPoint, + } +} + +// Verify verifies if the key provided by user is present in Vault server. The response +// will contain the IP address and username associated with the OTP. In case the +// OTP matches the echo request message, instead of searching an entry for the OTP, +// an echo response message is returned. This feature is used by ssh-helper to verify if +// its configured correctly. +func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) { + data := map[string]interface{}{ + "otp": otp, + } + verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint) + r := c.c.NewRequest("PUT", verifyPath) + if err := r.SetJSONBody(data); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + secret, err := ParseSecret(resp.Body) + if err != nil { + return nil, err + } + + if secret.Data == nil { + return nil, nil + } + + var verifyResp SSHVerifyResponse + err = mapstructure.Decode(secret.Data, &verifyResp) + if err != nil { + return nil, err + } + return &verifyResp, nil +} + +func checkHCLKeys(node ast.Node, valid []string) error { + var list *ast.ObjectList + switch n := node.(type) { + case *ast.ObjectList: + list = n + case *ast.ObjectType: + list = n.List + default: + return fmt.Errorf("cannot check HCL keys of type %T", n) + } + + validMap := make(map[string]struct{}, len(valid)) + for _, v := range valid { + validMap[v] = struct{}{} + } + + var result error + for _, item := range list.Items { + key := item.Keys[0].Token.Value().(string) + if _, ok := validMap[key]; !ok { + result = multierror.Append(result, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line)) + } + } + + return result +} diff --git a/vendor/github.com/hashicorp/vault/api/sys.go b/vendor/github.com/hashicorp/vault/api/sys.go new file mode 100644 index 0000000..5fb1118 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys.go @@ -0,0 +1,11 @@ +package api + +// Sys is used to perform system-related operations on Vault. +type Sys struct { + c *Client +} + +// Sys is used to return the client for sys-related API calls. +func (c *Client) Sys() *Sys { + return &Sys{c: c} +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_audit.go b/vendor/github.com/hashicorp/vault/api/sys_audit.go new file mode 100644 index 0000000..05cd756 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_audit.go @@ -0,0 +1,125 @@ +package api + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" +) + +func (c *Sys) AuditHash(path string, input string) (string, error) { + body := map[string]interface{}{ + "input": input, + } + + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit-hash/%s", path)) + if err := r.SetJSONBody(body); err != nil { + return "", err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return "", err + } + defer resp.Body.Close() + + type d struct { + Hash string `json:"hash"` + } + + var result d + err = resp.DecodeJSON(&result) + if err != nil { + return "", err + } + + return result.Hash, err +} + +func (c *Sys) ListAudit() (map[string]*Audit, error) { + r := c.c.NewRequest("GET", "/v1/sys/audit") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + mounts := map[string]*Audit{} + for k, v := range result { + switch v.(type) { + case map[string]interface{}: + default: + continue + } + var res Audit + err = mapstructure.Decode(v, &res) + if err != nil { + return nil, err + } + // Not a mount, some other api.Secret data + if res.Type == "" { + continue + } + mounts[k] = &res + } + + return mounts, nil +} + +// DEPRECATED: Use EnableAuditWithOptions instead +func (c *Sys) EnableAudit( + path string, auditType string, desc string, opts map[string]string) error { + return c.EnableAuditWithOptions(path, &EnableAuditOptions{ + Type: auditType, + Description: desc, + Options: opts, + }) +} + +func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error { + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path)) + if err := r.SetJSONBody(options); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +func (c *Sys) DisableAudit(path string) error { + r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/audit/%s", path)) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +// Structures for the requests/resposne are all down here. They aren't +// individually documented because the map almost directly to the raw HTTP API +// documentation. Please refer to that documentation for more details. + +type EnableAuditOptions struct { + Type string `json:"type"` + Description string `json:"description"` + Options map[string]string `json:"options"` + Local bool `json:"local"` +} + +type Audit struct { + Path string + Type string + Description string + Options map[string]string + Local bool +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_auth.go b/vendor/github.com/hashicorp/vault/api/sys_auth.go new file mode 100644 index 0000000..0b1a319 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_auth.go @@ -0,0 +1,119 @@ +package api + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" +) + +func (c *Sys) ListAuth() (map[string]*AuthMount, error) { + r := c.c.NewRequest("GET", "/v1/sys/auth") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + mounts := map[string]*AuthMount{} + for k, v := range result { + switch v.(type) { + case map[string]interface{}: + default: + continue + } + var res AuthMount + err = mapstructure.Decode(v, &res) + if err != nil { + return nil, err + } + // Not a mount, some other api.Secret data + if res.Type == "" { + continue + } + mounts[k] = &res + } + + return mounts, nil +} + +// DEPRECATED: Use EnableAuthWithOptions instead +func (c *Sys) EnableAuth(path, authType, desc string) error { + return c.EnableAuthWithOptions(path, &EnableAuthOptions{ + Type: authType, + Description: desc, + }) +} + +func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error { + r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path)) + if err := r.SetJSONBody(options); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +func (c *Sys) DisableAuth(path string) error { + r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/auth/%s", path)) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +// Structures for the requests/resposne are all down here. They aren't +// individually documented because the map almost directly to the raw HTTP API +// documentation. Please refer to that documentation for more details. + +type EnableAuthOptions struct { + Type string `json:"type"` + Description string `json:"description"` + Config AuthConfigInput `json:"config"` + Local bool `json:"local"` + PluginName string `json:"plugin_name,omitempty"` + SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` + Options map[string]string `json:"options" mapstructure:"options"` +} + +type AuthConfigInput struct { + DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` +} + +type AuthMount struct { + Type string `json:"type" mapstructure:"type"` + Description string `json:"description" mapstructure:"description"` + Accessor string `json:"accessor" mapstructure:"accessor"` + Config AuthConfigOutput `json:"config" mapstructure:"config"` + Local bool `json:"local" mapstructure:"local"` + SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` + Options map[string]string `json:"options" mapstructure:"options"` +} + +type AuthConfigOutput struct { + DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go new file mode 100644 index 0000000..cbb3a72 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go @@ -0,0 +1,49 @@ +package api + +import "fmt" + +func (c *Sys) CapabilitiesSelf(path string) ([]string, error) { + return c.Capabilities(c.c.Token(), path) +} + +func (c *Sys) Capabilities(token, path string) ([]string, error) { + body := map[string]string{ + "token": token, + "path": path, + } + + reqPath := "/v1/sys/capabilities" + if token == c.c.Token() { + reqPath = fmt.Sprintf("%s-self", reqPath) + } + + r := c.c.NewRequest("POST", reqPath) + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + if result["capabilities"] == nil { + return nil, nil + } + var capabilities []string + capabilitiesRaw, ok := result["capabilities"].([]interface{}) + if !ok { + return nil, fmt.Errorf("error interpreting returned capabilities") + } + for _, capability := range capabilitiesRaw { + capabilities = append(capabilities, capability.(string)) + } + return capabilities, nil +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_config_cors.go b/vendor/github.com/hashicorp/vault/api/sys_config_cors.go new file mode 100644 index 0000000..e7f2a59 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_config_cors.go @@ -0,0 +1,56 @@ +package api + +func (c *Sys) CORSStatus() (*CORSResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/config/cors") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result CORSResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) ConfigureCORS(req *CORSRequest) (*CORSResponse, error) { + r := c.c.NewRequest("PUT", "/v1/sys/config/cors") + if err := r.SetJSONBody(req); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result CORSResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) DisableCORS() (*CORSResponse, error) { + r := c.c.NewRequest("DELETE", "/v1/sys/config/cors") + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result CORSResponse + err = resp.DecodeJSON(&result) + return &result, err + +} + +type CORSRequest struct { + AllowedOrigins string `json:"allowed_origins"` + Enabled bool `json:"enabled"` +} + +type CORSResponse struct { + AllowedOrigins string `json:"allowed_origins"` + Enabled bool `json:"enabled"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go new file mode 100644 index 0000000..adb5496 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go @@ -0,0 +1,110 @@ +package api + +func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) { + return c.generateRootStatusCommon("/v1/sys/generate-root/attempt") +} + +func (c *Sys) GenerateDROperationTokenStatus() (*GenerateRootStatusResponse, error) { + return c.generateRootStatusCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt") +} + +func (c *Sys) generateRootStatusCommon(path string) (*GenerateRootStatusResponse, error) { + r := c.c.NewRequest("GET", path) + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result GenerateRootStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) { + return c.generateRootInitCommon("/v1/sys/generate-root/attempt", otp, pgpKey) +} + +func (c *Sys) GenerateDROperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) { + return c.generateRootInitCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey) +} + +func (c *Sys) generateRootInitCommon(path, otp, pgpKey string) (*GenerateRootStatusResponse, error) { + body := map[string]interface{}{ + "otp": otp, + "pgp_key": pgpKey, + } + + r := c.c.NewRequest("PUT", path) + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result GenerateRootStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) GenerateRootCancel() error { + return c.generateRootCancelCommon("/v1/sys/generate-root/attempt") +} + +func (c *Sys) GenerateDROperationTokenCancel() error { + return c.generateRootCancelCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt") +} + +func (c *Sys) generateRootCancelCommon(path string) error { + r := c.c.NewRequest("DELETE", path) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) { + return c.generateRootUpdateCommon("/v1/sys/generate-root/update", shard, nonce) +} + +func (c *Sys) GenerateDROperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) { + return c.generateRootUpdateCommon("/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce) +} + +func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRootStatusResponse, error) { + body := map[string]interface{}{ + "key": shard, + "nonce": nonce, + } + + r := c.c.NewRequest("PUT", path) + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result GenerateRootStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type GenerateRootStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + Progress int `json:"progress"` + Required int `json:"required"` + Complete bool `json:"complete"` + EncodedToken string `json:"encoded_token"` + EncodedRootToken string `json:"encoded_root_token"` + PGPFingerprint string `json:"pgp_fingerprint"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_health.go b/vendor/github.com/hashicorp/vault/api/sys_health.go new file mode 100644 index 0000000..82fd1f6 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_health.go @@ -0,0 +1,33 @@ +package api + +func (c *Sys) Health() (*HealthResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/health") + // If the code is 400 or above it will automatically turn into an error, + // but the sys/health API defaults to returning 5xx when not sealed or + // inited, so we force this code to be something else so we parse correctly + r.Params.Add("uninitcode", "299") + r.Params.Add("sealedcode", "299") + r.Params.Add("standbycode", "299") + r.Params.Add("drsecondarycode", "299") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result HealthResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type HealthResponse struct { + Initialized bool `json:"initialized"` + Sealed bool `json:"sealed"` + Standby bool `json:"standby"` + ReplicationPerformanceMode string `json:"replication_performance_mode"` + ReplicationDRMode string `json:"replication_dr_mode"` + ServerTimeUTC int64 `json:"server_time_utc"` + Version string `json:"version"` + ClusterName string `json:"cluster_name,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_init.go b/vendor/github.com/hashicorp/vault/api/sys_init.go new file mode 100644 index 0000000..f824ab7 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_init.go @@ -0,0 +1,54 @@ +package api + +func (c *Sys) InitStatus() (bool, error) { + r := c.c.NewRequest("GET", "/v1/sys/init") + resp, err := c.c.RawRequest(r) + if err != nil { + return false, err + } + defer resp.Body.Close() + + var result InitStatusResponse + err = resp.DecodeJSON(&result) + return result.Initialized, err +} + +func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) { + r := c.c.NewRequest("PUT", "/v1/sys/init") + if err := r.SetJSONBody(opts); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result InitResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type InitRequest struct { + SecretShares int `json:"secret_shares"` + SecretThreshold int `json:"secret_threshold"` + StoredShares int `json:"stored_shares"` + PGPKeys []string `json:"pgp_keys"` + RecoveryShares int `json:"recovery_shares"` + RecoveryThreshold int `json:"recovery_threshold"` + RecoveryPGPKeys []string `json:"recovery_pgp_keys"` + RootTokenPGPKey string `json:"root_token_pgp_key"` +} + +type InitStatusResponse struct { + Initialized bool +} + +type InitResponse struct { + Keys []string `json:"keys"` + KeysB64 []string `json:"keys_base64"` + RecoveryKeys []string `json:"recovery_keys"` + RecoveryKeysB64 []string `json:"recovery_keys_base64"` + RootToken string `json:"root_token"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_leader.go b/vendor/github.com/hashicorp/vault/api/sys_leader.go new file mode 100644 index 0000000..4951c46 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_leader.go @@ -0,0 +1,21 @@ +package api + +func (c *Sys) Leader() (*LeaderResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/leader") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result LeaderResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type LeaderResponse struct { + HAEnabled bool `json:"ha_enabled"` + IsSelf bool `json:"is_self"` + LeaderAddress string `json:"leader_address"` + LeaderClusterAddress string `json:"leader_cluster_address"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_leases.go b/vendor/github.com/hashicorp/vault/api/sys_leases.go new file mode 100644 index 0000000..34bd99e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_leases.go @@ -0,0 +1,48 @@ +package api + +func (c *Sys) Renew(id string, increment int) (*Secret, error) { + r := c.c.NewRequest("PUT", "/v1/sys/leases/renew") + + body := map[string]interface{}{ + "increment": increment, + "lease_id": id, + } + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ParseSecret(resp.Body) +} + +func (c *Sys) Revoke(id string) error { + r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke/"+id) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RevokePrefix(id string) error { + r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-prefix/"+id) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RevokeForce(id string) error { + r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-force/"+id) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_mounts.go b/vendor/github.com/hashicorp/vault/api/sys_mounts.go new file mode 100644 index 0000000..8ac5b45 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_mounts.go @@ -0,0 +1,159 @@ +package api + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" +) + +func (c *Sys) ListMounts() (map[string]*MountOutput, error) { + r := c.c.NewRequest("GET", "/v1/sys/mounts") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + mounts := map[string]*MountOutput{} + for k, v := range result { + switch v.(type) { + case map[string]interface{}: + default: + continue + } + var res MountOutput + err = mapstructure.Decode(v, &res) + if err != nil { + return nil, err + } + // Not a mount, some other api.Secret data + if res.Type == "" { + continue + } + mounts[k] = &res + } + + return mounts, nil +} + +func (c *Sys) Mount(path string, mountInfo *MountInput) error { + r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s", path)) + if err := r.SetJSONBody(mountInfo); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +func (c *Sys) Unmount(path string) error { + r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/mounts/%s", path)) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) Remount(from, to string) error { + body := map[string]interface{}{ + "from": from, + "to": to, + } + + r := c.c.NewRequest("POST", "/v1/sys/remount") + if err := r.SetJSONBody(body); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) TuneMount(path string, config MountConfigInput) error { + r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s/tune", path)) + if err := r.SetJSONBody(config); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) { + r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/mounts/%s/tune", path)) + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result MountConfigOutput + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + return &result, err +} + +type MountInput struct { + Type string `json:"type"` + Description string `json:"description"` + Config MountConfigInput `json:"config"` + Options map[string]string `json:"options"` + Local bool `json:"local"` + PluginName string `json:"plugin_name,omitempty"` + SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` +} + +type MountConfigInput struct { + Options map[string]string `json:"options" mapstructure:"options"` + DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` + ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` +} + +type MountOutput struct { + Type string `json:"type"` + Description string `json:"description"` + Accessor string `json:"accessor"` + Config MountConfigOutput `json:"config"` + Options map[string]string `json:"options"` + Local bool `json:"local"` + SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` +} + +type MountConfigOutput struct { + DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` + ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_plugins.go b/vendor/github.com/hashicorp/vault/api/sys_plugins.go new file mode 100644 index 0000000..8183b10 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_plugins.go @@ -0,0 +1,117 @@ +package api + +import ( + "fmt" + "net/http" +) + +// ListPluginsInput is used as input to the ListPlugins function. +type ListPluginsInput struct{} + +// ListPluginsResponse is the response from the ListPlugins call. +type ListPluginsResponse struct { + // Names is the list of names of the plugins. + Names []string +} + +// ListPlugins lists all plugins in the catalog and returns their names as a +// list of strings. +func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) { + path := "/v1/sys/plugins/catalog" + req := c.c.NewRequest("LIST", path) + resp, err := c.c.RawRequest(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result struct { + Data struct { + Keys []string `json:"keys"` + } `json:"data"` + } + if err := resp.DecodeJSON(&result); err != nil { + return nil, err + } + + return &ListPluginsResponse{Names: result.Data.Keys}, nil +} + +// GetPluginInput is used as input to the GetPlugin function. +type GetPluginInput struct { + Name string `json:"-"` +} + +// GetPluginResponse is the response from the GetPlugin call. +type GetPluginResponse struct { + Args []string `json:"args"` + Builtin bool `json:"builtin"` + Command string `json:"command"` + Name string `json:"name"` + SHA256 string `json:"sha256"` +} + +func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) { + path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + req := c.c.NewRequest(http.MethodGet, path) + resp, err := c.c.RawRequest(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result GetPluginResponse + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + return &result, err +} + +// RegisterPluginInput is used as input to the RegisterPlugin function. +type RegisterPluginInput struct { + // Name is the name of the plugin. Required. + Name string `json:"-"` + + // Args is the list of args to spawn the process with. + Args []string `json:"args,omitempty"` + + // Command is the command to run. + Command string `json:"command,omitempty"` + + // SHA256 is the shasum of the plugin. + SHA256 string `json:"sha256,omitempty"` +} + +// RegisterPlugin registers the plugin with the given information. +func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error { + path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + req := c.c.NewRequest(http.MethodPut, path) + if err := req.SetJSONBody(i); err != nil { + return err + } + + resp, err := c.c.RawRequest(req) + if err == nil { + defer resp.Body.Close() + } + return err +} + +// DeregisterPluginInput is used as input to the DeregisterPlugin function. +type DeregisterPluginInput struct { + // Name is the name of the plugin. Required. + Name string `json:"-"` +} + +// DeregisterPlugin removes the plugin with the given name from the plugin +// catalog. +func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error { + path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + req := c.c.NewRequest(http.MethodDelete, path) + resp, err := c.c.RawRequest(req) + if err == nil { + defer resp.Body.Close() + } + return err +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_policy.go b/vendor/github.com/hashicorp/vault/api/sys_policy.go new file mode 100644 index 0000000..9c9d9c0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_policy.go @@ -0,0 +1,97 @@ +package api + +import "fmt" + +func (c *Sys) ListPolicies() ([]string, error) { + r := c.c.NewRequest("GET", "/v1/sys/policy") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return nil, err + } + + var ok bool + if _, ok = result["policies"]; !ok { + return nil, fmt.Errorf("policies not found in response") + } + + listRaw := result["policies"].([]interface{}) + var policies []string + + for _, val := range listRaw { + policies = append(policies, val.(string)) + } + + return policies, err +} + +func (c *Sys) GetPolicy(name string) (string, error) { + r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policy/%s", name)) + resp, err := c.c.RawRequest(r) + if resp != nil { + defer resp.Body.Close() + if resp.StatusCode == 404 { + return "", nil + } + } + if err != nil { + return "", err + } + + var result map[string]interface{} + err = resp.DecodeJSON(&result) + if err != nil { + return "", err + } + + if rulesRaw, ok := result["rules"]; ok { + return rulesRaw.(string), nil + } + if policyRaw, ok := result["policy"]; ok { + return policyRaw.(string), nil + } + + return "", fmt.Errorf("no policy found in response") +} + +func (c *Sys) PutPolicy(name, rules string) error { + body := map[string]string{ + "rules": rules, + } + + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/policy/%s", name)) + if err := r.SetJSONBody(body); err != nil { + return err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +func (c *Sys) DeletePolicy(name string) error { + r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policy/%s", name)) + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +type getPoliciesResp struct { + Rules string `json:"rules"` +} + +type listPoliciesResp struct { + Policies []string `json:"policies"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_rekey.go b/vendor/github.com/hashicorp/vault/api/sys_rekey.go new file mode 100644 index 0000000..ddeac01 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_rekey.go @@ -0,0 +1,309 @@ +package api + +func (c *Sys) RekeyStatus() (*RekeyStatusResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey/init") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRecoveryKeyStatus() (*RekeyStatusResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/init") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyVerificationStatus() (*RekeyVerificationStatusResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey/verify") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyVerificationStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRecoveryKeyVerificationStatus() (*RekeyVerificationStatusResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/verify") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyVerificationStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) { + r := c.c.NewRequest("PUT", "/v1/sys/rekey/init") + if err := r.SetJSONBody(config); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRecoveryKeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) { + r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/init") + if err := r.SetJSONBody(config); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyCancel() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey/init") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RekeyRecoveryKeyCancel() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/init") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RekeyVerificationCancel() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey/verify") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RekeyRecoveryKeyVerificationCancel() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/verify") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) RekeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) { + body := map[string]interface{}{ + "key": shard, + "nonce": nonce, + } + + r := c.c.NewRequest("PUT", "/v1/sys/rekey/update") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyUpdateResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRecoveryKeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) { + body := map[string]interface{}{ + "key": shard, + "nonce": nonce, + } + + r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/update") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyUpdateResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey/backup") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyRetrieveResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-backup") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyRetrieveResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyDeleteBackup() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey/backup") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + + return err +} + +func (c *Sys) RekeyDeleteRecoveryBackup() error { + r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-backup") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + + return err +} + +func (c *Sys) RekeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) { + body := map[string]interface{}{ + "key": shard, + "nonce": nonce, + } + + r := c.c.NewRequest("PUT", "/v1/sys/rekey/verify") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyVerificationUpdateResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +func (c *Sys) RekeyRecoveryKeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) { + body := map[string]interface{}{ + "key": shard, + "nonce": nonce, + } + + r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/verify") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result RekeyVerificationUpdateResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type RekeyInitRequest struct { + SecretShares int `json:"secret_shares"` + SecretThreshold int `json:"secret_threshold"` + StoredShares int `json:"stored_shares"` + PGPKeys []string `json:"pgp_keys"` + Backup bool + RequireVerification bool `json:"require_verification"` +} + +type RekeyStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` + Required int `json:"required"` + PGPFingerprints []string `json:"pgp_fingerprints"` + Backup bool `json:"backup"` + VerificationRequired bool `json:"verification_required"` + VerificationNonce string `json:"verification_nonce"` +} + +type RekeyUpdateResponse struct { + Nonce string `json:"nonce"` + Complete bool `json:"complete"` + Keys []string `json:"keys"` + KeysB64 []string `json:"keys_base64"` + PGPFingerprints []string `json:"pgp_fingerprints"` + Backup bool `json:"backup"` + VerificationRequired bool `json:"verification_required"` + VerificationNonce string `json:"verification_nonce,omitempty"` +} + +type RekeyRetrieveResponse struct { + Nonce string `json:"nonce"` + Keys map[string][]string `json:"keys"` + KeysB64 map[string][]string `json:"keys_base64"` +} + +type RekeyVerificationStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` +} + +type RekeyVerificationUpdateResponse struct { + Nonce string `json:"nonce"` + Complete bool `json:"complete"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_rotate.go b/vendor/github.com/hashicorp/vault/api/sys_rotate.go new file mode 100644 index 0000000..8108dce --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_rotate.go @@ -0,0 +1,30 @@ +package api + +import "time" + +func (c *Sys) Rotate() error { + r := c.c.NewRequest("POST", "/v1/sys/rotate") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) KeyStatus() (*KeyStatus, error) { + r := c.c.NewRequest("GET", "/v1/sys/key-status") + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + result := new(KeyStatus) + err = resp.DecodeJSON(result) + return result, err +} + +type KeyStatus struct { + Term int `json:"term"` + InstallTime time.Time `json:"install_time"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_seal.go b/vendor/github.com/hashicorp/vault/api/sys_seal.go new file mode 100644 index 0000000..3d594ba --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_seal.go @@ -0,0 +1,62 @@ +package api + +func (c *Sys) SealStatus() (*SealStatusResponse, error) { + r := c.c.NewRequest("GET", "/v1/sys/seal-status") + return sealStatusRequest(c, r) +} + +func (c *Sys) Seal() error { + r := c.c.NewRequest("PUT", "/v1/sys/seal") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} + +func (c *Sys) ResetUnsealProcess() (*SealStatusResponse, error) { + body := map[string]interface{}{"reset": true} + + r := c.c.NewRequest("PUT", "/v1/sys/unseal") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + return sealStatusRequest(c, r) +} + +func (c *Sys) Unseal(shard string) (*SealStatusResponse, error) { + body := map[string]interface{}{"key": shard} + + r := c.c.NewRequest("PUT", "/v1/sys/unseal") + if err := r.SetJSONBody(body); err != nil { + return nil, err + } + + return sealStatusRequest(c, r) +} + +func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) { + resp, err := c.c.RawRequest(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result SealStatusResponse + err = resp.DecodeJSON(&result) + return &result, err +} + +type SealStatusResponse struct { + Type string `json:"type"` + Sealed bool `json:"sealed"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` + Nonce string `json:"nonce"` + Version string `json:"version"` + ClusterName string `json:"cluster_name,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` + RecoverySeal bool `json:"recovery_seal"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_stepdown.go b/vendor/github.com/hashicorp/vault/api/sys_stepdown.go new file mode 100644 index 0000000..421e5f1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/sys_stepdown.go @@ -0,0 +1,10 @@ +package api + +func (c *Sys) StepDown() error { + r := c.c.NewRequest("PUT", "/v1/sys/step-down") + resp, err := c.c.RawRequest(r) + if err == nil { + defer resp.Body.Close() + } + return err +} diff --git a/vendor/github.com/hashicorp/vault/audit/audit.go b/vendor/github.com/hashicorp/vault/audit/audit.go new file mode 100644 index 0000000..fed7033 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/audit.go @@ -0,0 +1,63 @@ +package audit + +import ( + "context" + + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" +) + +// Backend interface must be implemented for an audit +// mechanism to be made available. Audit backends can be enabled to +// sink information to different backends such as logs, file, databases, +// or other external services. +type Backend interface { + // LogRequest is used to synchronously log a request. This is done after the + // request is authorized but before the request is executed. The arguments + // MUST not be modified in anyway. They should be deep copied if this is + // a possibility. + LogRequest(context.Context, *LogInput) error + + // LogResponse is used to synchronously log a response. This is done after + // the request is processed but before the response is sent. The arguments + // MUST not be modified in anyway. They should be deep copied if this is + // a possibility. + LogResponse(context.Context, *LogInput) error + + // GetHash is used to return the given data with the backend's hash, + // so that a caller can determine if a value in the audit log matches + // an expected plaintext value + GetHash(context.Context, string) (string, error) + + // Reload is called on SIGHUP for supporting backends. + Reload(context.Context) error + + // Invalidate is called for path invalidation + Invalidate(context.Context) +} + +// LogInput contains the input parameters passed into LogRequest and LogResponse +type LogInput struct { + Auth *logical.Auth + Request *logical.Request + Response *logical.Response + OuterErr error + NonHMACReqDataKeys []string + NonHMACRespDataKeys []string +} + +// BackendConfig contains configuration parameters used in the factory func to +// instantiate audit backends +type BackendConfig struct { + // The view to store the salt + SaltView logical.Storage + + // The salt config that should be used for any secret obfuscation + SaltConfig *salt.Config + + // Config is the opaque user configuration provided when mounting + Config map[string]string +} + +// Factory is the factory function to create an audit backend. +type Factory func(context.Context, *BackendConfig) (Backend, error) diff --git a/vendor/github.com/hashicorp/vault/audit/format.go b/vendor/github.com/hashicorp/vault/audit/format.go new file mode 100644 index 0000000..93d0dd5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/format.go @@ -0,0 +1,446 @@ +package audit + +import ( + "context" + "fmt" + "io" + "strings" + "time" + + "github.com/SermoDigital/jose/jws" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" + "github.com/mitchellh/copystructure" +) + +type AuditFormatWriter interface { + WriteRequest(io.Writer, *AuditRequestEntry) error + WriteResponse(io.Writer, *AuditResponseEntry) error + Salt(context.Context) (*salt.Salt, error) +} + +// AuditFormatter implements the Formatter interface, and allows the underlying +// marshaller to be swapped out +type AuditFormatter struct { + AuditFormatWriter +} + +var _ Formatter = (*AuditFormatter)(nil) + +func (f *AuditFormatter) FormatRequest(ctx context.Context, w io.Writer, config FormatterConfig, in *LogInput) error { + if in == nil || in.Request == nil { + return fmt.Errorf("request to request-audit a nil request") + } + + if w == nil { + return fmt.Errorf("writer for audit request is nil") + } + + if f.AuditFormatWriter == nil { + return fmt.Errorf("no format writer specified") + } + + salt, err := f.Salt(ctx) + if err != nil { + return errwrap.Wrapf("error fetching salt: {{err}}", err) + } + + // Set these to the input values at first + auth := in.Auth + req := in.Request + + if !config.Raw { + // Before we copy the structure we must nil out some data + // otherwise we will cause reflection to panic and die + if in.Request.Connection != nil && in.Request.Connection.ConnState != nil { + origState := in.Request.Connection.ConnState + in.Request.Connection.ConnState = nil + defer func() { + in.Request.Connection.ConnState = origState + }() + } + + // Copy the auth structure + if in.Auth != nil { + cp, err := copystructure.Copy(in.Auth) + if err != nil { + return err + } + auth = cp.(*logical.Auth) + } + + cp, err := copystructure.Copy(in.Request) + if err != nil { + return err + } + req = cp.(*logical.Request) + + // Hash any sensitive information + if auth != nil { + // Cache and restore accessor in the auth + var authAccessor string + if !config.HMACAccessor && auth.Accessor != "" { + authAccessor = auth.Accessor + } + if err := Hash(salt, auth, nil); err != nil { + return err + } + if authAccessor != "" { + auth.Accessor = authAccessor + } + } + + // Cache and restore accessor in the request + var clientTokenAccessor string + if !config.HMACAccessor && req != nil && req.ClientTokenAccessor != "" { + clientTokenAccessor = req.ClientTokenAccessor + } + if err := Hash(salt, req, in.NonHMACReqDataKeys); err != nil { + return err + } + if clientTokenAccessor != "" { + req.ClientTokenAccessor = clientTokenAccessor + } + } + + // If auth is nil, make an empty one + if auth == nil { + auth = new(logical.Auth) + } + var errString string + if in.OuterErr != nil { + errString = in.OuterErr.Error() + } + + reqEntry := &AuditRequestEntry{ + Type: "request", + Error: errString, + + Auth: AuditAuth{ + ClientToken: auth.ClientToken, + Accessor: auth.Accessor, + DisplayName: auth.DisplayName, + Policies: auth.Policies, + Metadata: auth.Metadata, + EntityID: auth.EntityID, + RemainingUses: req.ClientTokenRemainingUses, + }, + + Request: AuditRequest{ + ID: req.ID, + ClientToken: req.ClientToken, + ClientTokenAccessor: req.ClientTokenAccessor, + Operation: req.Operation, + Path: req.Path, + Data: req.Data, + PolicyOverride: req.PolicyOverride, + RemoteAddr: getRemoteAddr(req), + ReplicationCluster: req.ReplicationCluster, + Headers: req.Headers, + }, + } + + if req.WrapInfo != nil { + reqEntry.Request.WrapTTL = int(req.WrapInfo.TTL / time.Second) + } + + if !config.OmitTime { + reqEntry.Time = time.Now().UTC().Format(time.RFC3339Nano) + } + + return f.AuditFormatWriter.WriteRequest(w, reqEntry) +} + +func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config FormatterConfig, in *LogInput) error { + if in == nil || in.Request == nil { + return fmt.Errorf("request to response-audit a nil request") + } + + if w == nil { + return fmt.Errorf("writer for audit request is nil") + } + + if f.AuditFormatWriter == nil { + return fmt.Errorf("no format writer specified") + } + + salt, err := f.Salt(ctx) + if err != nil { + return errwrap.Wrapf("error fetching salt: {{err}}", err) + } + + // Set these to the input values at first + auth := in.Auth + req := in.Request + resp := in.Response + + if !config.Raw { + // Before we copy the structure we must nil out some data + // otherwise we will cause reflection to panic and die + if in.Request.Connection != nil && in.Request.Connection.ConnState != nil { + origState := in.Request.Connection.ConnState + in.Request.Connection.ConnState = nil + defer func() { + in.Request.Connection.ConnState = origState + }() + } + + // Copy the auth structure + if in.Auth != nil { + cp, err := copystructure.Copy(in.Auth) + if err != nil { + return err + } + auth = cp.(*logical.Auth) + } + + cp, err := copystructure.Copy(in.Request) + if err != nil { + return err + } + req = cp.(*logical.Request) + + if in.Response != nil { + cp, err := copystructure.Copy(in.Response) + if err != nil { + return err + } + resp = cp.(*logical.Response) + } + + // Hash any sensitive information + + // Cache and restore accessor in the auth + if auth != nil { + var accessor string + if !config.HMACAccessor && auth.Accessor != "" { + accessor = auth.Accessor + } + if err := Hash(salt, auth, nil); err != nil { + return err + } + if accessor != "" { + auth.Accessor = accessor + } + } + + // Cache and restore accessor in the request + var clientTokenAccessor string + if !config.HMACAccessor && req != nil && req.ClientTokenAccessor != "" { + clientTokenAccessor = req.ClientTokenAccessor + } + if err := Hash(salt, req, in.NonHMACReqDataKeys); err != nil { + return err + } + if clientTokenAccessor != "" { + req.ClientTokenAccessor = clientTokenAccessor + } + + // Cache and restore accessor in the response + if resp != nil { + var accessor, wrappedAccessor, wrappingAccessor string + if !config.HMACAccessor && resp != nil && resp.Auth != nil && resp.Auth.Accessor != "" { + accessor = resp.Auth.Accessor + } + if !config.HMACAccessor && resp != nil && resp.WrapInfo != nil && resp.WrapInfo.WrappedAccessor != "" { + wrappedAccessor = resp.WrapInfo.WrappedAccessor + wrappingAccessor = resp.WrapInfo.Accessor + } + if err := Hash(salt, resp, in.NonHMACRespDataKeys); err != nil { + return err + } + if accessor != "" { + resp.Auth.Accessor = accessor + } + if wrappedAccessor != "" { + resp.WrapInfo.WrappedAccessor = wrappedAccessor + } + if wrappingAccessor != "" { + resp.WrapInfo.Accessor = wrappingAccessor + } + } + } + + // If things are nil, make empty to avoid panics + if auth == nil { + auth = new(logical.Auth) + } + if resp == nil { + resp = new(logical.Response) + } + var errString string + if in.OuterErr != nil { + errString = in.OuterErr.Error() + } + + var respAuth *AuditAuth + if resp.Auth != nil { + respAuth = &AuditAuth{ + ClientToken: resp.Auth.ClientToken, + Accessor: resp.Auth.Accessor, + DisplayName: resp.Auth.DisplayName, + Policies: resp.Auth.Policies, + Metadata: resp.Auth.Metadata, + NumUses: resp.Auth.NumUses, + } + } + + var respSecret *AuditSecret + if resp.Secret != nil { + respSecret = &AuditSecret{ + LeaseID: resp.Secret.LeaseID, + } + } + + var respWrapInfo *AuditResponseWrapInfo + if resp.WrapInfo != nil { + token := resp.WrapInfo.Token + if jwtToken := parseVaultTokenFromJWT(token); jwtToken != nil { + token = *jwtToken + } + respWrapInfo = &AuditResponseWrapInfo{ + TTL: int(resp.WrapInfo.TTL / time.Second), + Token: token, + Accessor: resp.WrapInfo.Accessor, + CreationTime: resp.WrapInfo.CreationTime.UTC().Format(time.RFC3339Nano), + CreationPath: resp.WrapInfo.CreationPath, + WrappedAccessor: resp.WrapInfo.WrappedAccessor, + } + } + + respEntry := &AuditResponseEntry{ + Type: "response", + Error: errString, + Auth: AuditAuth{ + DisplayName: auth.DisplayName, + Policies: auth.Policies, + Metadata: auth.Metadata, + ClientToken: auth.ClientToken, + Accessor: auth.Accessor, + RemainingUses: req.ClientTokenRemainingUses, + EntityID: auth.EntityID, + }, + + Request: AuditRequest{ + ID: req.ID, + ClientToken: req.ClientToken, + ClientTokenAccessor: req.ClientTokenAccessor, + Operation: req.Operation, + Path: req.Path, + Data: req.Data, + PolicyOverride: req.PolicyOverride, + RemoteAddr: getRemoteAddr(req), + ReplicationCluster: req.ReplicationCluster, + Headers: req.Headers, + }, + + Response: AuditResponse{ + Auth: respAuth, + Secret: respSecret, + Data: resp.Data, + Redirect: resp.Redirect, + WrapInfo: respWrapInfo, + }, + } + + if req.WrapInfo != nil { + respEntry.Request.WrapTTL = int(req.WrapInfo.TTL / time.Second) + } + + if !config.OmitTime { + respEntry.Time = time.Now().UTC().Format(time.RFC3339Nano) + } + + return f.AuditFormatWriter.WriteResponse(w, respEntry) +} + +// AuditRequestEntry is the structure of a request audit log entry in Audit. +type AuditRequestEntry struct { + Time string `json:"time,omitempty"` + Type string `json:"type"` + Auth AuditAuth `json:"auth"` + Request AuditRequest `json:"request"` + Error string `json:"error"` +} + +// AuditResponseEntry is the structure of a response audit log entry in Audit. +type AuditResponseEntry struct { + Time string `json:"time,omitempty"` + Type string `json:"type"` + Auth AuditAuth `json:"auth"` + Request AuditRequest `json:"request"` + Response AuditResponse `json:"response"` + Error string `json:"error"` +} + +type AuditRequest struct { + ID string `json:"id"` + ReplicationCluster string `json:"replication_cluster,omitempty"` + Operation logical.Operation `json:"operation"` + ClientToken string `json:"client_token"` + ClientTokenAccessor string `json:"client_token_accessor"` + Path string `json:"path"` + Data map[string]interface{} `json:"data"` + PolicyOverride bool `json:"policy_override"` + RemoteAddr string `json:"remote_address"` + WrapTTL int `json:"wrap_ttl"` + Headers map[string][]string `json:"headers"` +} + +type AuditResponse struct { + Auth *AuditAuth `json:"auth,omitempty"` + Secret *AuditSecret `json:"secret,omitempty"` + Data map[string]interface{} `json:"data,omitempty"` + Redirect string `json:"redirect,omitempty"` + WrapInfo *AuditResponseWrapInfo `json:"wrap_info,omitempty"` +} + +type AuditAuth struct { + ClientToken string `json:"client_token"` + Accessor string `json:"accessor"` + DisplayName string `json:"display_name"` + Policies []string `json:"policies"` + Metadata map[string]string `json:"metadata"` + NumUses int `json:"num_uses,omitempty"` + RemainingUses int `json:"remaining_uses,omitempty"` + EntityID string `json:"entity_id"` +} + +type AuditSecret struct { + LeaseID string `json:"lease_id"` +} + +type AuditResponseWrapInfo struct { + TTL int `json:"ttl"` + Token string `json:"token"` + Accessor string `json:"accessor"` + CreationTime string `json:"creation_time"` + CreationPath string `json:"creation_path"` + WrappedAccessor string `json:"wrapped_accessor,omitempty"` +} + +// getRemoteAddr safely gets the remote address avoiding a nil pointer +func getRemoteAddr(req *logical.Request) string { + if req != nil && req.Connection != nil { + return req.Connection.RemoteAddr + } + return "" +} + +// parseVaultTokenFromJWT returns a string iff the token was a JWT and we could +// extract the original token ID from inside +func parseVaultTokenFromJWT(token string) *string { + if strings.Count(token, ".") != 2 { + return nil + } + + wt, err := jws.ParseJWT([]byte(token)) + if err != nil || wt == nil { + return nil + } + + result, _ := wt.Claims().JWTID() + + return &result +} diff --git a/vendor/github.com/hashicorp/vault/audit/format_json.go b/vendor/github.com/hashicorp/vault/audit/format_json.go new file mode 100644 index 0000000..f42ab20 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/format_json.go @@ -0,0 +1,53 @@ +package audit + +import ( + "context" + "encoding/json" + "fmt" + "io" + + "github.com/hashicorp/vault/helper/salt" +) + +// JSONFormatWriter is an AuditFormatWriter implementation that structures data into +// a JSON format. +type JSONFormatWriter struct { + Prefix string + SaltFunc func(context.Context) (*salt.Salt, error) +} + +func (f *JSONFormatWriter) WriteRequest(w io.Writer, req *AuditRequestEntry) error { + if req == nil { + return fmt.Errorf("request entry was nil, cannot encode") + } + + if len(f.Prefix) > 0 { + _, err := w.Write([]byte(f.Prefix)) + if err != nil { + return err + } + } + + enc := json.NewEncoder(w) + return enc.Encode(req) +} + +func (f *JSONFormatWriter) WriteResponse(w io.Writer, resp *AuditResponseEntry) error { + if resp == nil { + return fmt.Errorf("response entry was nil, cannot encode") + } + + if len(f.Prefix) > 0 { + _, err := w.Write([]byte(f.Prefix)) + if err != nil { + return err + } + } + + enc := json.NewEncoder(w) + return enc.Encode(resp) +} + +func (f *JSONFormatWriter) Salt(ctx context.Context) (*salt.Salt, error) { + return f.SaltFunc(ctx) +} diff --git a/vendor/github.com/hashicorp/vault/audit/format_jsonx.go b/vendor/github.com/hashicorp/vault/audit/format_jsonx.go new file mode 100644 index 0000000..3093746 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/format_jsonx.go @@ -0,0 +1,74 @@ +package audit + +import ( + "context" + "encoding/json" + "fmt" + "io" + + "github.com/hashicorp/vault/helper/salt" + "github.com/jefferai/jsonx" +) + +// JSONxFormatWriter is an AuditFormatWriter implementation that structures data into +// a XML format. +type JSONxFormatWriter struct { + Prefix string + SaltFunc func(context.Context) (*salt.Salt, error) +} + +func (f *JSONxFormatWriter) WriteRequest(w io.Writer, req *AuditRequestEntry) error { + if req == nil { + return fmt.Errorf("request entry was nil, cannot encode") + } + + if len(f.Prefix) > 0 { + _, err := w.Write([]byte(f.Prefix)) + if err != nil { + return err + } + } + + jsonBytes, err := json.Marshal(req) + if err != nil { + return err + } + + xmlBytes, err := jsonx.EncodeJSONBytes(jsonBytes) + if err != nil { + return err + } + + _, err = w.Write(xmlBytes) + return err +} + +func (f *JSONxFormatWriter) WriteResponse(w io.Writer, resp *AuditResponseEntry) error { + if resp == nil { + return fmt.Errorf("response entry was nil, cannot encode") + } + + if len(f.Prefix) > 0 { + _, err := w.Write([]byte(f.Prefix)) + if err != nil { + return err + } + } + + jsonBytes, err := json.Marshal(resp) + if err != nil { + return err + } + + xmlBytes, err := jsonx.EncodeJSONBytes(jsonBytes) + if err != nil { + return err + } + + _, err = w.Write(xmlBytes) + return err +} + +func (f *JSONxFormatWriter) Salt(ctx context.Context) (*salt.Salt, error) { + return f.SaltFunc(ctx) +} diff --git a/vendor/github.com/hashicorp/vault/audit/formatter.go b/vendor/github.com/hashicorp/vault/audit/formatter.go new file mode 100644 index 0000000..7702a1e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/formatter.go @@ -0,0 +1,24 @@ +package audit + +import ( + "context" + "io" +) + +// Formatter is an interface that is responsible for formating a +// request/response into some format. Formatters write their output +// to an io.Writer. +// +// It is recommended that you pass data through Hash prior to formatting it. +type Formatter interface { + FormatRequest(context.Context, io.Writer, FormatterConfig, *LogInput) error + FormatResponse(context.Context, io.Writer, FormatterConfig, *LogInput) error +} + +type FormatterConfig struct { + Raw bool + HMACAccessor bool + + // This should only ever be used in a testing context + OmitTime bool +} diff --git a/vendor/github.com/hashicorp/vault/audit/hashstructure.go b/vendor/github.com/hashicorp/vault/audit/hashstructure.go new file mode 100644 index 0000000..be1aad9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/hashstructure.go @@ -0,0 +1,319 @@ +package audit + +import ( + "errors" + "reflect" + "strings" + "time" + + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" + "github.com/mitchellh/copystructure" + "github.com/mitchellh/reflectwalk" +) + +// HashString hashes the given opaque string and returns it +func HashString(salter *salt.Salt, data string) string { + return salter.GetIdentifiedHMAC(data) +} + +// Hash will hash the given type. This has built-in support for auth, +// requests, and responses. If it is a type that isn't recognized, then +// it will be passed through. +// +// The structure is modified in-place. +func Hash(salter *salt.Salt, raw interface{}, nonHMACDataKeys []string) error { + fn := salter.GetIdentifiedHMAC + + switch s := raw.(type) { + case *logical.Auth: + if s == nil { + return nil + } + if s.ClientToken != "" { + s.ClientToken = fn(s.ClientToken) + } + if s.Accessor != "" { + s.Accessor = fn(s.Accessor) + } + + case *logical.Request: + if s == nil { + return nil + } + if s.Auth != nil { + if err := Hash(salter, s.Auth, nil); err != nil { + return err + } + } + + if s.ClientToken != "" { + s.ClientToken = fn(s.ClientToken) + } + + if s.ClientTokenAccessor != "" { + s.ClientTokenAccessor = fn(s.ClientTokenAccessor) + } + + data, err := HashStructure(s.Data, fn, nonHMACDataKeys) + if err != nil { + return err + } + + s.Data = data.(map[string]interface{}) + + case *logical.Response: + if s == nil { + return nil + } + + if s.Auth != nil { + if err := Hash(salter, s.Auth, nil); err != nil { + return err + } + } + + if s.WrapInfo != nil { + if err := Hash(salter, s.WrapInfo, nil); err != nil { + return err + } + } + + data, err := HashStructure(s.Data, fn, nonHMACDataKeys) + if err != nil { + return err + } + + s.Data = data.(map[string]interface{}) + + case *wrapping.ResponseWrapInfo: + if s == nil { + return nil + } + + s.Token = fn(s.Token) + s.Accessor = fn(s.Accessor) + + if s.WrappedAccessor != "" { + s.WrappedAccessor = fn(s.WrappedAccessor) + } + } + + return nil +} + +// HashStructure takes an interface and hashes all the values within +// the structure. Only _values_ are hashed: keys of objects are not. +// +// For the HashCallback, see the built-in HashCallbacks below. +func HashStructure(s interface{}, cb HashCallback, ignoredKeys []string) (interface{}, error) { + s, err := copystructure.Copy(s) + if err != nil { + return nil, err + } + + walker := &hashWalker{Callback: cb, IgnoredKeys: ignoredKeys} + if err := reflectwalk.Walk(s, walker); err != nil { + return nil, err + } + + return s, nil +} + +// HashCallback is the callback called for HashStructure to hash +// a value. +type HashCallback func(string) string + +// hashWalker implements interfaces for the reflectwalk package +// (github.com/mitchellh/reflectwalk) that can be used to automatically +// replace primitives with a hashed value. +type hashWalker struct { + // Callback is the function to call with the primitive that is + // to be hashed. If there is an error, walking will be halted + // immediately and the error returned. + Callback HashCallback + + // IgnoreKeys are the keys that wont have the HashCallback applied + IgnoredKeys []string + + key []string + lastValue reflect.Value + loc reflectwalk.Location + cs []reflect.Value + csKey []reflect.Value + csData interface{} + sliceIndex int + unknownKeys []string +} + +// hashTimeType stores a pre-computed reflect.Type for a time.Time so +// we can quickly compare in hashWalker.Struct. We create an empty/invalid +// time.Time{} so we don't need to incur any additional startup cost vs. +// Now() or Unix(). +var hashTimeType = reflect.TypeOf(time.Time{}) + +func (w *hashWalker) Enter(loc reflectwalk.Location) error { + w.loc = loc + return nil +} + +func (w *hashWalker) Exit(loc reflectwalk.Location) error { + w.loc = reflectwalk.None + + switch loc { + case reflectwalk.Map: + w.cs = w.cs[:len(w.cs)-1] + case reflectwalk.MapValue: + w.key = w.key[:len(w.key)-1] + w.csKey = w.csKey[:len(w.csKey)-1] + case reflectwalk.Slice: + w.cs = w.cs[:len(w.cs)-1] + case reflectwalk.SliceElem: + w.csKey = w.csKey[:len(w.csKey)-1] + } + + return nil +} + +func (w *hashWalker) Map(m reflect.Value) error { + w.cs = append(w.cs, m) + return nil +} + +func (w *hashWalker) MapElem(m, k, v reflect.Value) error { + w.csData = k + w.csKey = append(w.csKey, k) + w.key = append(w.key, k.String()) + w.lastValue = v + return nil +} + +func (w *hashWalker) Slice(s reflect.Value) error { + w.cs = append(w.cs, s) + return nil +} + +func (w *hashWalker) SliceElem(i int, elem reflect.Value) error { + w.csKey = append(w.csKey, reflect.ValueOf(i)) + w.sliceIndex = i + return nil +} + +func (w *hashWalker) Struct(v reflect.Value) error { + // We are looking for time values. If it isn't one, ignore it. + if v.Type() != hashTimeType { + return nil + } + + // If we aren't in a map value, return an error to prevent a panic + if v.Interface() != w.lastValue.Interface() { + return errors.New("time.Time value in a non map key cannot be hashed for audits") + } + + // Create a string value of the time. IMPORTANT: this must never change + // across Vault versions or the hash value of equivalent time.Time will + // change. + strVal := v.Interface().(time.Time).Format(time.RFC3339Nano) + + // Set the map value to the string instead of the time.Time object + m := w.cs[len(w.cs)-1] + mk := w.csData.(reflect.Value) + m.SetMapIndex(mk, reflect.ValueOf(strVal)) + + // Skip this entry so that we don't walk the struct. + return reflectwalk.SkipEntry +} + +func (w *hashWalker) StructField(reflect.StructField, reflect.Value) error { + return nil +} + +func (w *hashWalker) Primitive(v reflect.Value) error { + if w.Callback == nil { + return nil + } + + // We don't touch map keys + if w.loc == reflectwalk.MapKey { + return nil + } + + setV := v + + // We only care about strings + if v.Kind() == reflect.Interface { + setV = v + v = v.Elem() + } + if v.Kind() != reflect.String { + return nil + } + + // See if the current key is part of the ignored keys + currentKey := w.key[len(w.key)-1] + if strutil.StrListContains(w.IgnoredKeys, currentKey) { + return nil + } + + replaceVal := w.Callback(v.String()) + + resultVal := reflect.ValueOf(replaceVal) + switch w.loc { + case reflectwalk.MapKey: + m := w.cs[len(w.cs)-1] + + // Delete the old value + var zero reflect.Value + m.SetMapIndex(w.csData.(reflect.Value), zero) + + // Set the new key with the existing value + m.SetMapIndex(resultVal, w.lastValue) + + // Set the key to be the new key + w.csData = resultVal + case reflectwalk.MapValue: + // If we're in a map, then the only way to set a map value is + // to set it directly. + m := w.cs[len(w.cs)-1] + mk := w.csData.(reflect.Value) + m.SetMapIndex(mk, resultVal) + default: + // Otherwise, we should be addressable + setV.Set(resultVal) + } + + return nil +} + +func (w *hashWalker) removeCurrent() { + // Append the key to the unknown keys + w.unknownKeys = append(w.unknownKeys, strings.Join(w.key, ".")) + + for i := 1; i <= len(w.cs); i++ { + c := w.cs[len(w.cs)-i] + switch c.Kind() { + case reflect.Map: + // Zero value so that we delete the map key + var val reflect.Value + + // Get the key and delete it + k := w.csData.(reflect.Value) + c.SetMapIndex(k, val) + return + } + } + + panic("No container found for removeCurrent") +} + +func (w *hashWalker) replaceCurrent(v reflect.Value) { + c := w.cs[len(w.cs)-2] + switch c.Kind() { + case reflect.Map: + // Get the key and delete it + k := w.csKey[len(w.csKey)-1] + c.SetMapIndex(k, v) + } +} diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/backend.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/backend.go new file mode 100644 index 0000000..19e62cf --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/backend.go @@ -0,0 +1,60 @@ +package userpass + +import ( + "context" + + "github.com/hashicorp/vault/helper/mfa" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +func Backend() *backend { + var b backend + b.Backend = &framework.Backend{ + Help: backendHelp, + + PathsSpecial: &logical.Paths{ + Root: mfa.MFARootPaths(), + + Unauthenticated: []string{ + "login/*", + }, + }, + + Paths: append([]*framework.Path{ + pathUsers(&b), + pathUsersList(&b), + pathUserPolicies(&b), + pathUserPassword(&b), + }, + mfa.MFAPaths(b.Backend, pathLogin(&b))..., + ), + + AuthRenew: b.pathLoginRenew, + BackendType: logical.TypeCredential, + } + + return &b +} + +type backend struct { + *framework.Backend +} + +const backendHelp = ` +The "userpass" credential provider allows authentication using +a combination of a username and password. No additional factors +are supported. + +The username/password combination is configured using the "users/" +endpoints by a user with root access. Authentication is then done +by supplying the two fields for "login". +` diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/cli.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/cli.go new file mode 100644 index 0000000..8531af3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/cli.go @@ -0,0 +1,105 @@ +package userpass + +import ( + "fmt" + "os" + "strings" + + "github.com/hashicorp/vault/api" + pwd "github.com/hashicorp/vault/helper/password" + "github.com/mitchellh/mapstructure" +) + +type CLIHandler struct { + DefaultMount string +} + +func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) { + var data struct { + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + Mount string `mapstructure:"mount"` + Method string `mapstructure:"method"` + Passcode string `mapstructure:"passcode"` + } + if err := mapstructure.WeakDecode(m, &data); err != nil { + return nil, err + } + + if data.Username == "" { + return nil, fmt.Errorf("'username' must be specified") + } + if data.Password == "" { + fmt.Fprintf(os.Stderr, "Password (will be hidden): ") + password, err := pwd.Read(os.Stdin) + fmt.Fprintf(os.Stderr, "\n") + if err != nil { + return nil, err + } + data.Password = password + } + if data.Mount == "" { + data.Mount = h.DefaultMount + } + + options := map[string]interface{}{ + "password": data.Password, + } + if data.Method != "" { + options["method"] = data.Method + } + if data.Passcode != "" { + options["passcode"] = data.Passcode + } + + path := fmt.Sprintf("auth/%s/login/%s", data.Mount, data.Username) + secret, err := c.Logical().Write(path, options) + if err != nil { + return nil, err + } + if secret == nil { + return nil, fmt.Errorf("empty response from credential provider") + } + + return secret, nil +} + +func (h *CLIHandler) Help() string { + help := ` +Usage: vault login -method=userpass [CONFIG K=V...] + + The userpass auth method allows users to authenticate using Vault's + internal user database. + + If MFA is enabled, a "method" and/or "passcode" may be required depending on + the MFA method. To check which MFA is in use, run: + + $ vault read auth//mfa_config + + Authenticate as "sally": + + $ vault login -method=userpass username=sally + Password (will be hidden): + + Authenticate as "bob": + + $ vault login -method=userpass username=bob password=password + +Configuration: + + method= + MFA method. + + passcode= + MFA OTP/passcode. + + password= + Password to use for authentication. If not provided, the CLI will prompt + for this on stdin. + + username= + Username to use for authentication. +` + + return strings.TrimSpace(help) +} diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_login.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_login.go new file mode 100644 index 0000000..89ee1d9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_login.go @@ -0,0 +1,138 @@ +package userpass + +import ( + "context" + "crypto/subtle" + "fmt" + "strings" + + "github.com/hashicorp/vault/helper/cidrutil" + "github.com/hashicorp/vault/helper/policyutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "golang.org/x/crypto/bcrypt" +) + +func pathLogin(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "login/" + framework.GenericNameRegex("username"), + Fields: map[string]*framework.FieldSchema{ + "username": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Username of the user.", + }, + + "password": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Password for this user.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathLogin, + logical.AliasLookaheadOperation: b.pathLoginAliasLookahead, + }, + + HelpSynopsis: pathLoginSyn, + HelpDescription: pathLoginDesc, + } +} + +func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username := strings.ToLower(d.Get("username").(string)) + if username == "" { + return nil, fmt.Errorf("missing username") + } + + return &logical.Response{ + Auth: &logical.Auth{ + Alias: &logical.Alias{ + Name: username, + }, + }, + }, nil +} + +func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username := strings.ToLower(d.Get("username").(string)) + + password := d.Get("password").(string) + if password == "" { + return nil, fmt.Errorf("missing password") + } + + // Get the user and validate auth + user, err := b.user(ctx, req.Storage, username) + if err != nil { + return nil, err + } + if user == nil { + return logical.ErrorResponse("invalid username or password"), nil + } + + // Check for a CIDR match. + if !cidrutil.RemoteAddrIsOk(req.Connection.RemoteAddr, user.BoundCIDRs) { + return logical.ErrorResponse("login request originated from invalid CIDR"), nil + } + + // Check for a password match. Check for a hash collision for Vault 0.2+, + // but handle the older legacy passwords with a constant time comparison. + passwordBytes := []byte(password) + if user.PasswordHash != nil { + if err := bcrypt.CompareHashAndPassword(user.PasswordHash, passwordBytes); err != nil { + return logical.ErrorResponse("invalid username or password"), nil + } + } else { + if subtle.ConstantTimeCompare([]byte(user.Password), passwordBytes) != 1 { + return logical.ErrorResponse("invalid username or password"), nil + } + } + + return &logical.Response{ + Auth: &logical.Auth{ + Policies: user.Policies, + Metadata: map[string]string{ + "username": username, + }, + DisplayName: username, + LeaseOptions: logical.LeaseOptions{ + TTL: user.TTL, + MaxTTL: user.MaxTTL, + Renewable: true, + }, + Alias: &logical.Alias{ + Name: username, + }, + BoundCIDRs: user.BoundCIDRs, + }, + }, nil +} + +func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // Get the user + user, err := b.user(ctx, req.Storage, req.Auth.Metadata["username"]) + if err != nil { + return nil, err + } + if user == nil { + // User no longer exists, do not renew + return nil, nil + } + + if !policyutil.EquivalentPolicies(user.Policies, req.Auth.Policies) { + return nil, fmt.Errorf("policies have changed, not renewing") + } + + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = user.TTL + resp.Auth.MaxTTL = user.MaxTTL + return resp, nil +} + +const pathLoginSyn = ` +Log in with a username and password. +` + +const pathLoginDesc = ` +This endpoint authenticates using a username and password. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_password.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_password.go new file mode 100644 index 0000000..0d47db3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_password.go @@ -0,0 +1,79 @@ +package userpass + +import ( + "context" + "fmt" + + "golang.org/x/crypto/bcrypt" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathUserPassword(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "users/" + framework.GenericNameRegex("username") + "/password$", + Fields: map[string]*framework.FieldSchema{ + "username": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Username for this user.", + }, + + "password": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Password for this user.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathUserPasswordUpdate, + }, + + HelpSynopsis: pathUserPasswordHelpSyn, + HelpDescription: pathUserPasswordHelpDesc, + } +} + +func (b *backend) pathUserPasswordUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username := d.Get("username").(string) + + userEntry, err := b.user(ctx, req.Storage, username) + if err != nil { + return nil, err + } + if userEntry == nil { + return nil, fmt.Errorf("username does not exist") + } + + userErr, intErr := b.updateUserPassword(req, d, userEntry) + if intErr != nil { + return nil, err + } + if userErr != nil { + return logical.ErrorResponse(userErr.Error()), logical.ErrInvalidRequest + } + + return nil, b.setUser(ctx, req.Storage, username, userEntry) +} + +func (b *backend) updateUserPassword(req *logical.Request, d *framework.FieldData, userEntry *UserEntry) (error, error) { + password := d.Get("password").(string) + if password == "" { + return fmt.Errorf("missing password"), nil + } + // Generate a hash of the password + hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return nil, err + } + userEntry.PasswordHash = hash + return nil, nil +} + +const pathUserPasswordHelpSyn = ` +Reset user's password. +` + +const pathUserPasswordHelpDesc = ` +This endpoint allows resetting the user's password. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_policies.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_policies.go new file mode 100644 index 0000000..f23e35d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_user_policies.go @@ -0,0 +1,57 @@ +package userpass + +import ( + "context" + "fmt" + + "github.com/hashicorp/vault/helper/policyutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathUserPolicies(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "users/" + framework.GenericNameRegex("username") + "/policies$", + Fields: map[string]*framework.FieldSchema{ + "username": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Username for this user.", + }, + "policies": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "Comma-separated list of policies", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathUserPoliciesUpdate, + }, + + HelpSynopsis: pathUserPoliciesHelpSyn, + HelpDescription: pathUserPoliciesHelpDesc, + } +} + +func (b *backend) pathUserPoliciesUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username := d.Get("username").(string) + + userEntry, err := b.user(ctx, req.Storage, username) + if err != nil { + return nil, err + } + if userEntry == nil { + return nil, fmt.Errorf("username does not exist") + } + + userEntry.Policies = policyutil.ParsePolicies(d.Get("policies")) + + return nil, b.setUser(ctx, req.Storage, username, userEntry) +} + +const pathUserPoliciesHelpSyn = ` +Update the policies associated with the username. +` + +const pathUserPoliciesHelpDesc = ` +This endpoint allows updating the policies associated with the username. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_users.go b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_users.go new file mode 100644 index 0000000..0e8eee8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/credential/userpass/path_users.go @@ -0,0 +1,238 @@ +package userpass + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/policyutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathUsersList(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "users/?", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.pathUserList, + }, + + HelpSynopsis: pathUserHelpSyn, + HelpDescription: pathUserHelpDesc, + } +} + +func pathUsers(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "users/" + framework.GenericNameRegex("username"), + Fields: map[string]*framework.FieldSchema{ + "username": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Username for this user.", + }, + + "password": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Password for this user.", + }, + + "policies": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "Comma-separated list of policies", + }, + + "ttl": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: "Duration after which authentication will be expired", + }, + + "max_ttl": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: "Maximum duration after which authentication will be expired", + }, + + "bound_cidrs": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of +IP addresses which can perform the login operation.`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.DeleteOperation: b.pathUserDelete, + logical.ReadOperation: b.pathUserRead, + logical.UpdateOperation: b.pathUserWrite, + logical.CreateOperation: b.pathUserWrite, + }, + + ExistenceCheck: b.userExistenceCheck, + + HelpSynopsis: pathUserHelpSyn, + HelpDescription: pathUserHelpDesc, + } +} + +func (b *backend) userExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + userEntry, err := b.user(ctx, req.Storage, data.Get("username").(string)) + if err != nil { + return false, err + } + + return userEntry != nil, nil +} + +func (b *backend) user(ctx context.Context, s logical.Storage, username string) (*UserEntry, error) { + if username == "" { + return nil, fmt.Errorf("missing username") + } + + entry, err := s.Get(ctx, "user/"+strings.ToLower(username)) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var result UserEntry + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + + return &result, nil +} + +func (b *backend) setUser(ctx context.Context, s logical.Storage, username string, userEntry *UserEntry) error { + entry, err := logical.StorageEntryJSON("user/"+username, userEntry) + if err != nil { + return err + } + + return s.Put(ctx, entry) +} + +func (b *backend) pathUserList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + users, err := req.Storage.List(ctx, "user/") + if err != nil { + return nil, err + } + return logical.ListResponse(users), nil +} + +func (b *backend) pathUserDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "user/"+strings.ToLower(d.Get("username").(string))) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (b *backend) pathUserRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + user, err := b.user(ctx, req.Storage, strings.ToLower(d.Get("username").(string))) + if err != nil { + return nil, err + } + if user == nil { + return nil, nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "policies": user.Policies, + "ttl": user.TTL.Seconds(), + "max_ttl": user.MaxTTL.Seconds(), + "bound_cidrs": user.BoundCIDRs, + }, + }, nil +} + +func (b *backend) userCreateUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username := strings.ToLower(d.Get("username").(string)) + userEntry, err := b.user(ctx, req.Storage, username) + if err != nil { + return nil, err + } + // Due to existence check, user will only be nil if it's a create operation + if userEntry == nil { + userEntry = &UserEntry{} + } + + if _, ok := d.GetOk("password"); ok { + userErr, intErr := b.updateUserPassword(req, d, userEntry) + if intErr != nil { + return nil, err + } + if userErr != nil { + return logical.ErrorResponse(userErr.Error()), logical.ErrInvalidRequest + } + } + + if policiesRaw, ok := d.GetOk("policies"); ok { + userEntry.Policies = policyutil.ParsePolicies(policiesRaw) + } + + ttl, ok := d.GetOk("ttl") + if ok { + userEntry.TTL = time.Duration(ttl.(int)) * time.Second + } + + maxTTL, ok := d.GetOk("max_ttl") + if ok { + userEntry.MaxTTL = time.Duration(maxTTL.(int)) * time.Second + } + + boundCIDRs, err := parseutil.ParseAddrs(d.Get("bound_cidrs")) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + userEntry.BoundCIDRs = boundCIDRs + + return nil, b.setUser(ctx, req.Storage, username, userEntry) +} + +func (b *backend) pathUserWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + password := d.Get("password").(string) + if req.Operation == logical.CreateOperation && password == "" { + return logical.ErrorResponse("missing password"), logical.ErrInvalidRequest + } + return b.userCreateUpdate(ctx, req, d) +} + +type UserEntry struct { + // Password is deprecated in Vault 0.2 in favor of + // PasswordHash, but is retained for backwards compatibility. + Password string + + // PasswordHash is a bcrypt hash of the password. This is + // used instead of the actual password in Vault 0.2+. + PasswordHash []byte + + Policies []string + + // Duration after which the user will be revoked unless renewed + TTL time.Duration + + // Maximum duration for which user can be valid + MaxTTL time.Duration + + BoundCIDRs []*sockaddr.SockAddrMarshaler +} + +const pathUserHelpSyn = ` +Manage users allowed to authenticate. +` + +const pathUserHelpDesc = ` +This endpoint allows you to create, read, update, and delete users +that are allowed to authenticate. + +Deleting a user will not revoke auth for prior authenticated users +with that name. To do this, do a revoke on "login/" for +the username you want revoked. If you don't need to revoke login immediately, +then the next renew will cause the lease to expire. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/client.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/client.go new file mode 100644 index 0000000..37cb629 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/client.go @@ -0,0 +1,75 @@ +package dbplugin + +import ( + "context" + "errors" + "sync" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" +) + +// DatabasePluginClient embeds a databasePluginRPCClient and wraps it's Close +// method to also call Kill() on the plugin.Client. +type DatabasePluginClient struct { + client *plugin.Client + sync.Mutex + + Database +} + +// This wraps the Close call and ensures we both close the database connection +// and kill the plugin. +func (dc *DatabasePluginClient) Close() error { + err := dc.Database.Close() + dc.client.Kill() + + return err +} + +// newPluginClient returns a databaseRPCClient with a connection to a running +// plugin. The client is wrapped in a DatabasePluginClient object to ensure the +// plugin is killed on call of Close(). +func newPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger) (Database, error) { + // pluginMap is the map of plugins we can dispense. + var pluginMap = map[string]plugin.Plugin{ + "database": new(DatabasePlugin), + } + + client, err := pluginRunner.Run(ctx, sys, pluginMap, handshakeConfig, []string{}, logger) + if err != nil { + return nil, err + } + + // Connect via RPC + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + // Request the plugin + raw, err := rpcClient.Dispense("database") + if err != nil { + return nil, err + } + + // We should have a database type now. This feels like a normal interface + // implementation but is in fact over an RPC connection. + var db Database + switch raw.(type) { + case *gRPCClient: + db = raw.(*gRPCClient) + case *databasePluginRPCClient: + logger.Warn("plugin is using deprecated net RPC transport, recompile plugin to upgrade to gRPC", "plugin", pluginRunner.Name) + db = raw.(*databasePluginRPCClient) + default: + return nil, errors.New("unsupported client type") + } + + // Wrap RPC implementation in DatabasePluginClient + return &DatabasePluginClient{ + client: client, + Database: db, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.pb.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.pb.go new file mode 100644 index 0000000..3c5bb98 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.pb.go @@ -0,0 +1,1022 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: builtin/logical/database/dbplugin/database.proto + +package dbplugin // import "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// Deprecated: Do not use. +type InitializeRequest struct { + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection" json:"verify_connection,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InitializeRequest) Reset() { *m = InitializeRequest{} } +func (m *InitializeRequest) String() string { return proto.CompactTextString(m) } +func (*InitializeRequest) ProtoMessage() {} +func (*InitializeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{0} +} +func (m *InitializeRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InitializeRequest.Unmarshal(m, b) +} +func (m *InitializeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InitializeRequest.Marshal(b, m, deterministic) +} +func (dst *InitializeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_InitializeRequest.Merge(dst, src) +} +func (m *InitializeRequest) XXX_Size() int { + return xxx_messageInfo_InitializeRequest.Size(m) +} +func (m *InitializeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_InitializeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_InitializeRequest proto.InternalMessageInfo + +func (m *InitializeRequest) GetConfig() []byte { + if m != nil { + return m.Config + } + return nil +} + +func (m *InitializeRequest) GetVerifyConnection() bool { + if m != nil { + return m.VerifyConnection + } + return false +} + +type InitRequest struct { + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection" json:"verify_connection,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InitRequest) Reset() { *m = InitRequest{} } +func (m *InitRequest) String() string { return proto.CompactTextString(m) } +func (*InitRequest) ProtoMessage() {} +func (*InitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{1} +} +func (m *InitRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InitRequest.Unmarshal(m, b) +} +func (m *InitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InitRequest.Marshal(b, m, deterministic) +} +func (dst *InitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_InitRequest.Merge(dst, src) +} +func (m *InitRequest) XXX_Size() int { + return xxx_messageInfo_InitRequest.Size(m) +} +func (m *InitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_InitRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_InitRequest proto.InternalMessageInfo + +func (m *InitRequest) GetConfig() []byte { + if m != nil { + return m.Config + } + return nil +} + +func (m *InitRequest) GetVerifyConnection() bool { + if m != nil { + return m.VerifyConnection + } + return false +} + +type CreateUserRequest struct { + Statements *Statements `protobuf:"bytes,1,opt,name=statements" json:"statements,omitempty"` + UsernameConfig *UsernameConfig `protobuf:"bytes,2,opt,name=username_config,json=usernameConfig" json:"username_config,omitempty"` + Expiration *timestamp.Timestamp `protobuf:"bytes,3,opt,name=expiration" json:"expiration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateUserRequest) Reset() { *m = CreateUserRequest{} } +func (m *CreateUserRequest) String() string { return proto.CompactTextString(m) } +func (*CreateUserRequest) ProtoMessage() {} +func (*CreateUserRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{2} +} +func (m *CreateUserRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateUserRequest.Unmarshal(m, b) +} +func (m *CreateUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateUserRequest.Marshal(b, m, deterministic) +} +func (dst *CreateUserRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateUserRequest.Merge(dst, src) +} +func (m *CreateUserRequest) XXX_Size() int { + return xxx_messageInfo_CreateUserRequest.Size(m) +} +func (m *CreateUserRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateUserRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateUserRequest proto.InternalMessageInfo + +func (m *CreateUserRequest) GetStatements() *Statements { + if m != nil { + return m.Statements + } + return nil +} + +func (m *CreateUserRequest) GetUsernameConfig() *UsernameConfig { + if m != nil { + return m.UsernameConfig + } + return nil +} + +func (m *CreateUserRequest) GetExpiration() *timestamp.Timestamp { + if m != nil { + return m.Expiration + } + return nil +} + +type RenewUserRequest struct { + Statements *Statements `protobuf:"bytes,1,opt,name=statements" json:"statements,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username" json:"username,omitempty"` + Expiration *timestamp.Timestamp `protobuf:"bytes,3,opt,name=expiration" json:"expiration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RenewUserRequest) Reset() { *m = RenewUserRequest{} } +func (m *RenewUserRequest) String() string { return proto.CompactTextString(m) } +func (*RenewUserRequest) ProtoMessage() {} +func (*RenewUserRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{3} +} +func (m *RenewUserRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RenewUserRequest.Unmarshal(m, b) +} +func (m *RenewUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RenewUserRequest.Marshal(b, m, deterministic) +} +func (dst *RenewUserRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RenewUserRequest.Merge(dst, src) +} +func (m *RenewUserRequest) XXX_Size() int { + return xxx_messageInfo_RenewUserRequest.Size(m) +} +func (m *RenewUserRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RenewUserRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RenewUserRequest proto.InternalMessageInfo + +func (m *RenewUserRequest) GetStatements() *Statements { + if m != nil { + return m.Statements + } + return nil +} + +func (m *RenewUserRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *RenewUserRequest) GetExpiration() *timestamp.Timestamp { + if m != nil { + return m.Expiration + } + return nil +} + +type RevokeUserRequest struct { + Statements *Statements `protobuf:"bytes,1,opt,name=statements" json:"statements,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username" json:"username,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RevokeUserRequest) Reset() { *m = RevokeUserRequest{} } +func (m *RevokeUserRequest) String() string { return proto.CompactTextString(m) } +func (*RevokeUserRequest) ProtoMessage() {} +func (*RevokeUserRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{4} +} +func (m *RevokeUserRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RevokeUserRequest.Unmarshal(m, b) +} +func (m *RevokeUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RevokeUserRequest.Marshal(b, m, deterministic) +} +func (dst *RevokeUserRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RevokeUserRequest.Merge(dst, src) +} +func (m *RevokeUserRequest) XXX_Size() int { + return xxx_messageInfo_RevokeUserRequest.Size(m) +} +func (m *RevokeUserRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RevokeUserRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RevokeUserRequest proto.InternalMessageInfo + +func (m *RevokeUserRequest) GetStatements() *Statements { + if m != nil { + return m.Statements + } + return nil +} + +func (m *RevokeUserRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +type RotateRootCredentialsRequest struct { + Statements []string `protobuf:"bytes,1,rep,name=statements" json:"statements,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RotateRootCredentialsRequest) Reset() { *m = RotateRootCredentialsRequest{} } +func (m *RotateRootCredentialsRequest) String() string { return proto.CompactTextString(m) } +func (*RotateRootCredentialsRequest) ProtoMessage() {} +func (*RotateRootCredentialsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{5} +} +func (m *RotateRootCredentialsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RotateRootCredentialsRequest.Unmarshal(m, b) +} +func (m *RotateRootCredentialsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RotateRootCredentialsRequest.Marshal(b, m, deterministic) +} +func (dst *RotateRootCredentialsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RotateRootCredentialsRequest.Merge(dst, src) +} +func (m *RotateRootCredentialsRequest) XXX_Size() int { + return xxx_messageInfo_RotateRootCredentialsRequest.Size(m) +} +func (m *RotateRootCredentialsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RotateRootCredentialsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RotateRootCredentialsRequest proto.InternalMessageInfo + +func (m *RotateRootCredentialsRequest) GetStatements() []string { + if m != nil { + return m.Statements + } + return nil +} + +type Statements struct { + // DEPRECATED, will be removed in 0.12 + CreationStatements string `protobuf:"bytes,1,opt,name=creation_statements,json=creationStatements" json:"creation_statements,omitempty"` // Deprecated: Do not use. + // DEPRECATED, will be removed in 0.12 + RevocationStatements string `protobuf:"bytes,2,opt,name=revocation_statements,json=revocationStatements" json:"revocation_statements,omitempty"` // Deprecated: Do not use. + // DEPRECATED, will be removed in 0.12 + RollbackStatements string `protobuf:"bytes,3,opt,name=rollback_statements,json=rollbackStatements" json:"rollback_statements,omitempty"` // Deprecated: Do not use. + // DEPRECATED, will be removed in 0.12 + RenewStatements string `protobuf:"bytes,4,opt,name=renew_statements,json=renewStatements" json:"renew_statements,omitempty"` // Deprecated: Do not use. + Creation []string `protobuf:"bytes,5,rep,name=creation" json:"creation,omitempty"` + Revocation []string `protobuf:"bytes,6,rep,name=revocation" json:"revocation,omitempty"` + Rollback []string `protobuf:"bytes,7,rep,name=rollback" json:"rollback,omitempty"` + Renewal []string `protobuf:"bytes,8,rep,name=renewal" json:"renewal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Statements) Reset() { *m = Statements{} } +func (m *Statements) String() string { return proto.CompactTextString(m) } +func (*Statements) ProtoMessage() {} +func (*Statements) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{6} +} +func (m *Statements) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Statements.Unmarshal(m, b) +} +func (m *Statements) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Statements.Marshal(b, m, deterministic) +} +func (dst *Statements) XXX_Merge(src proto.Message) { + xxx_messageInfo_Statements.Merge(dst, src) +} +func (m *Statements) XXX_Size() int { + return xxx_messageInfo_Statements.Size(m) +} +func (m *Statements) XXX_DiscardUnknown() { + xxx_messageInfo_Statements.DiscardUnknown(m) +} + +var xxx_messageInfo_Statements proto.InternalMessageInfo + +// Deprecated: Do not use. +func (m *Statements) GetCreationStatements() string { + if m != nil { + return m.CreationStatements + } + return "" +} + +// Deprecated: Do not use. +func (m *Statements) GetRevocationStatements() string { + if m != nil { + return m.RevocationStatements + } + return "" +} + +// Deprecated: Do not use. +func (m *Statements) GetRollbackStatements() string { + if m != nil { + return m.RollbackStatements + } + return "" +} + +// Deprecated: Do not use. +func (m *Statements) GetRenewStatements() string { + if m != nil { + return m.RenewStatements + } + return "" +} + +func (m *Statements) GetCreation() []string { + if m != nil { + return m.Creation + } + return nil +} + +func (m *Statements) GetRevocation() []string { + if m != nil { + return m.Revocation + } + return nil +} + +func (m *Statements) GetRollback() []string { + if m != nil { + return m.Rollback + } + return nil +} + +func (m *Statements) GetRenewal() []string { + if m != nil { + return m.Renewal + } + return nil +} + +type UsernameConfig struct { + DisplayName string `protobuf:"bytes,1,opt,name=DisplayName" json:"DisplayName,omitempty"` + RoleName string `protobuf:"bytes,2,opt,name=RoleName" json:"RoleName,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UsernameConfig) Reset() { *m = UsernameConfig{} } +func (m *UsernameConfig) String() string { return proto.CompactTextString(m) } +func (*UsernameConfig) ProtoMessage() {} +func (*UsernameConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{7} +} +func (m *UsernameConfig) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UsernameConfig.Unmarshal(m, b) +} +func (m *UsernameConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UsernameConfig.Marshal(b, m, deterministic) +} +func (dst *UsernameConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_UsernameConfig.Merge(dst, src) +} +func (m *UsernameConfig) XXX_Size() int { + return xxx_messageInfo_UsernameConfig.Size(m) +} +func (m *UsernameConfig) XXX_DiscardUnknown() { + xxx_messageInfo_UsernameConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_UsernameConfig proto.InternalMessageInfo + +func (m *UsernameConfig) GetDisplayName() string { + if m != nil { + return m.DisplayName + } + return "" +} + +func (m *UsernameConfig) GetRoleName() string { + if m != nil { + return m.RoleName + } + return "" +} + +type InitResponse struct { + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InitResponse) Reset() { *m = InitResponse{} } +func (m *InitResponse) String() string { return proto.CompactTextString(m) } +func (*InitResponse) ProtoMessage() {} +func (*InitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{8} +} +func (m *InitResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InitResponse.Unmarshal(m, b) +} +func (m *InitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InitResponse.Marshal(b, m, deterministic) +} +func (dst *InitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_InitResponse.Merge(dst, src) +} +func (m *InitResponse) XXX_Size() int { + return xxx_messageInfo_InitResponse.Size(m) +} +func (m *InitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_InitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_InitResponse proto.InternalMessageInfo + +func (m *InitResponse) GetConfig() []byte { + if m != nil { + return m.Config + } + return nil +} + +type CreateUserResponse struct { + Username string `protobuf:"bytes,1,opt,name=username" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password" json:"password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateUserResponse) Reset() { *m = CreateUserResponse{} } +func (m *CreateUserResponse) String() string { return proto.CompactTextString(m) } +func (*CreateUserResponse) ProtoMessage() {} +func (*CreateUserResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{9} +} +func (m *CreateUserResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateUserResponse.Unmarshal(m, b) +} +func (m *CreateUserResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateUserResponse.Marshal(b, m, deterministic) +} +func (dst *CreateUserResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateUserResponse.Merge(dst, src) +} +func (m *CreateUserResponse) XXX_Size() int { + return xxx_messageInfo_CreateUserResponse.Size(m) +} +func (m *CreateUserResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateUserResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateUserResponse proto.InternalMessageInfo + +func (m *CreateUserResponse) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *CreateUserResponse) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +type TypeResponse struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TypeResponse) Reset() { *m = TypeResponse{} } +func (m *TypeResponse) String() string { return proto.CompactTextString(m) } +func (*TypeResponse) ProtoMessage() {} +func (*TypeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{10} +} +func (m *TypeResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TypeResponse.Unmarshal(m, b) +} +func (m *TypeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TypeResponse.Marshal(b, m, deterministic) +} +func (dst *TypeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TypeResponse.Merge(dst, src) +} +func (m *TypeResponse) XXX_Size() int { + return xxx_messageInfo_TypeResponse.Size(m) +} +func (m *TypeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TypeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TypeResponse proto.InternalMessageInfo + +func (m *TypeResponse) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +type RotateRootCredentialsResponse struct { + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RotateRootCredentialsResponse) Reset() { *m = RotateRootCredentialsResponse{} } +func (m *RotateRootCredentialsResponse) String() string { return proto.CompactTextString(m) } +func (*RotateRootCredentialsResponse) ProtoMessage() {} +func (*RotateRootCredentialsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{11} +} +func (m *RotateRootCredentialsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RotateRootCredentialsResponse.Unmarshal(m, b) +} +func (m *RotateRootCredentialsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RotateRootCredentialsResponse.Marshal(b, m, deterministic) +} +func (dst *RotateRootCredentialsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RotateRootCredentialsResponse.Merge(dst, src) +} +func (m *RotateRootCredentialsResponse) XXX_Size() int { + return xxx_messageInfo_RotateRootCredentialsResponse.Size(m) +} +func (m *RotateRootCredentialsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RotateRootCredentialsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RotateRootCredentialsResponse proto.InternalMessageInfo + +func (m *RotateRootCredentialsResponse) GetConfig() []byte { + if m != nil { + return m.Config + } + return nil +} + +type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_database_a524e050c674f25f, []int{12} +} +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (dst *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(dst, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo + +func init() { + proto.RegisterType((*InitializeRequest)(nil), "dbplugin.InitializeRequest") + proto.RegisterType((*InitRequest)(nil), "dbplugin.InitRequest") + proto.RegisterType((*CreateUserRequest)(nil), "dbplugin.CreateUserRequest") + proto.RegisterType((*RenewUserRequest)(nil), "dbplugin.RenewUserRequest") + proto.RegisterType((*RevokeUserRequest)(nil), "dbplugin.RevokeUserRequest") + proto.RegisterType((*RotateRootCredentialsRequest)(nil), "dbplugin.RotateRootCredentialsRequest") + proto.RegisterType((*Statements)(nil), "dbplugin.Statements") + proto.RegisterType((*UsernameConfig)(nil), "dbplugin.UsernameConfig") + proto.RegisterType((*InitResponse)(nil), "dbplugin.InitResponse") + proto.RegisterType((*CreateUserResponse)(nil), "dbplugin.CreateUserResponse") + proto.RegisterType((*TypeResponse)(nil), "dbplugin.TypeResponse") + proto.RegisterType((*RotateRootCredentialsResponse)(nil), "dbplugin.RotateRootCredentialsResponse") + proto.RegisterType((*Empty)(nil), "dbplugin.Empty") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DatabaseClient is the client API for Database service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DatabaseClient interface { + Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeResponse, error) + CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) + RenewUser(ctx context.Context, in *RenewUserRequest, opts ...grpc.CallOption) (*Empty, error) + RevokeUser(ctx context.Context, in *RevokeUserRequest, opts ...grpc.CallOption) (*Empty, error) + RotateRootCredentials(ctx context.Context, in *RotateRootCredentialsRequest, opts ...grpc.CallOption) (*RotateRootCredentialsResponse, error) + Init(ctx context.Context, in *InitRequest, opts ...grpc.CallOption) (*InitResponse, error) + Close(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + Initialize(ctx context.Context, in *InitializeRequest, opts ...grpc.CallOption) (*Empty, error) +} + +type databaseClient struct { + cc *grpc.ClientConn +} + +func NewDatabaseClient(cc *grpc.ClientConn) DatabaseClient { + return &databaseClient{cc} +} + +func (c *databaseClient) Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeResponse, error) { + out := new(TypeResponse) + err := c.cc.Invoke(ctx, "/dbplugin.Database/Type", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) { + out := new(CreateUserResponse) + err := c.cc.Invoke(ctx, "/dbplugin.Database/CreateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) RenewUser(ctx context.Context, in *RenewUserRequest, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/dbplugin.Database/RenewUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) RevokeUser(ctx context.Context, in *RevokeUserRequest, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/dbplugin.Database/RevokeUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) RotateRootCredentials(ctx context.Context, in *RotateRootCredentialsRequest, opts ...grpc.CallOption) (*RotateRootCredentialsResponse, error) { + out := new(RotateRootCredentialsResponse) + err := c.cc.Invoke(ctx, "/dbplugin.Database/RotateRootCredentials", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) Init(ctx context.Context, in *InitRequest, opts ...grpc.CallOption) (*InitResponse, error) { + out := new(InitResponse) + err := c.cc.Invoke(ctx, "/dbplugin.Database/Init", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *databaseClient) Close(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/dbplugin.Database/Close", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Deprecated: Do not use. +func (c *databaseClient) Initialize(ctx context.Context, in *InitializeRequest, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/dbplugin.Database/Initialize", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DatabaseServer is the server API for Database service. +type DatabaseServer interface { + Type(context.Context, *Empty) (*TypeResponse, error) + CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) + RenewUser(context.Context, *RenewUserRequest) (*Empty, error) + RevokeUser(context.Context, *RevokeUserRequest) (*Empty, error) + RotateRootCredentials(context.Context, *RotateRootCredentialsRequest) (*RotateRootCredentialsResponse, error) + Init(context.Context, *InitRequest) (*InitResponse, error) + Close(context.Context, *Empty) (*Empty, error) + Initialize(context.Context, *InitializeRequest) (*Empty, error) +} + +func RegisterDatabaseServer(s *grpc.Server, srv DatabaseServer) { + s.RegisterService(&_Database_serviceDesc, srv) +} + +func _Database_Type_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).Type(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/Type", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).Type(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).CreateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/CreateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).CreateUser(ctx, req.(*CreateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_RenewUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RenewUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).RenewUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/RenewUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).RenewUser(ctx, req.(*RenewUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_RevokeUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevokeUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).RevokeUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/RevokeUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).RevokeUser(ctx, req.(*RevokeUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_RotateRootCredentials_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RotateRootCredentialsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).RotateRootCredentials(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/RotateRootCredentials", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).RotateRootCredentials(ctx, req.(*RotateRootCredentialsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_Init_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).Init(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/Init", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).Init(ctx, req.(*InitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_Close_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).Close(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/Close", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).Close(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Database_Initialize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InitializeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseServer).Initialize(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dbplugin.Database/Initialize", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseServer).Initialize(ctx, req.(*InitializeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Database_serviceDesc = grpc.ServiceDesc{ + ServiceName: "dbplugin.Database", + HandlerType: (*DatabaseServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Type", + Handler: _Database_Type_Handler, + }, + { + MethodName: "CreateUser", + Handler: _Database_CreateUser_Handler, + }, + { + MethodName: "RenewUser", + Handler: _Database_RenewUser_Handler, + }, + { + MethodName: "RevokeUser", + Handler: _Database_RevokeUser_Handler, + }, + { + MethodName: "RotateRootCredentials", + Handler: _Database_RotateRootCredentials_Handler, + }, + { + MethodName: "Init", + Handler: _Database_Init_Handler, + }, + { + MethodName: "Close", + Handler: _Database_Close_Handler, + }, + { + MethodName: "Initialize", + Handler: _Database_Initialize_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "builtin/logical/database/dbplugin/database.proto", +} + +func init() { + proto.RegisterFile("builtin/logical/database/dbplugin/database.proto", fileDescriptor_database_a524e050c674f25f) +} + +var fileDescriptor_database_a524e050c674f25f = []byte{ + // 724 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xd1, 0x4e, 0xdb, 0x4a, + 0x10, 0x95, 0x93, 0x00, 0xc9, 0x80, 0x80, 0xec, 0x05, 0x64, 0xf9, 0x72, 0x6f, 0x91, 0x1f, 0x28, + 0x55, 0xd5, 0xb8, 0x82, 0x56, 0x54, 0xa8, 0xa2, 0x2a, 0xa1, 0xaa, 0x2a, 0x55, 0x3c, 0x2c, 0xf0, + 0x52, 0x55, 0x42, 0x1b, 0x67, 0x49, 0x56, 0x38, 0x5e, 0xd7, 0xbb, 0x0e, 0x4d, 0x7f, 0xa0, 0xfd, + 0x8c, 0x7e, 0x4e, 0x1f, 0xfb, 0x49, 0x95, 0x37, 0x59, 0xef, 0x26, 0x86, 0xf2, 0x40, 0xfb, 0xe6, + 0xd9, 0x99, 0x33, 0x73, 0xe6, 0x78, 0x76, 0x16, 0x9e, 0x76, 0x32, 0x16, 0x49, 0x16, 0x07, 0x11, + 0xef, 0xb1, 0x90, 0x44, 0x41, 0x97, 0x48, 0xd2, 0x21, 0x82, 0x06, 0xdd, 0x4e, 0x12, 0x65, 0x3d, + 0x16, 0x17, 0x27, 0xad, 0x24, 0xe5, 0x92, 0xa3, 0xba, 0x76, 0x78, 0x0f, 0x7a, 0x9c, 0xf7, 0x22, + 0x1a, 0xa8, 0xf3, 0x4e, 0x76, 0x19, 0x48, 0x36, 0xa0, 0x42, 0x92, 0x41, 0x32, 0x0e, 0xf5, 0x3f, + 0x42, 0xf3, 0x5d, 0xcc, 0x24, 0x23, 0x11, 0xfb, 0x42, 0x31, 0xfd, 0x94, 0x51, 0x21, 0xd1, 0x06, + 0xcc, 0x87, 0x3c, 0xbe, 0x64, 0x3d, 0xd7, 0xd9, 0x72, 0x76, 0x96, 0xf0, 0xc4, 0x42, 0x8f, 0xa1, + 0x39, 0xa4, 0x29, 0xbb, 0x1c, 0x5d, 0x84, 0x3c, 0x8e, 0x69, 0x28, 0x19, 0x8f, 0xdd, 0xca, 0x96, + 0xb3, 0x53, 0xc7, 0xab, 0x63, 0x47, 0xbb, 0x38, 0x3f, 0xa8, 0xb8, 0x8e, 0x8f, 0x61, 0x31, 0xcf, + 0xfe, 0x27, 0xf3, 0xfa, 0x3f, 0x1c, 0x68, 0xb6, 0x53, 0x4a, 0x24, 0x3d, 0x17, 0x34, 0xd5, 0xa9, + 0x9f, 0x01, 0x08, 0x49, 0x24, 0x1d, 0xd0, 0x58, 0x0a, 0x95, 0x7e, 0x71, 0x77, 0xad, 0xa5, 0x75, + 0x68, 0x9d, 0x16, 0x3e, 0x6c, 0xc5, 0xa1, 0xd7, 0xb0, 0x92, 0x09, 0x9a, 0xc6, 0x64, 0x40, 0x2f, + 0x26, 0xcc, 0x2a, 0x0a, 0xea, 0x1a, 0xe8, 0xf9, 0x24, 0xa0, 0xad, 0xfc, 0x78, 0x39, 0x9b, 0xb2, + 0xd1, 0x01, 0x00, 0xfd, 0x9c, 0xb0, 0x94, 0x28, 0xd2, 0x55, 0x85, 0xf6, 0x5a, 0x63, 0xd9, 0x5b, + 0x5a, 0xf6, 0xd6, 0x99, 0x96, 0x1d, 0x5b, 0xd1, 0xfe, 0x77, 0x07, 0x56, 0x31, 0x8d, 0xe9, 0xf5, + 0xfd, 0x3b, 0xf1, 0xa0, 0xae, 0x89, 0xa9, 0x16, 0x1a, 0xb8, 0xb0, 0xef, 0x45, 0x91, 0x42, 0x13, + 0xd3, 0x21, 0xbf, 0xa2, 0x7f, 0x95, 0xa2, 0x7f, 0x08, 0x9b, 0x98, 0xe7, 0xa1, 0x98, 0x73, 0xd9, + 0x4e, 0x69, 0x97, 0xc6, 0xf9, 0x4c, 0x0a, 0x5d, 0xf1, 0xff, 0x99, 0x8a, 0xd5, 0x9d, 0x86, 0x9d, + 0xdb, 0xff, 0x59, 0x01, 0x30, 0x65, 0xd1, 0x1e, 0xfc, 0x13, 0xe6, 0x23, 0xc2, 0x78, 0x7c, 0x31, + 0xc3, 0xb4, 0x71, 0x54, 0x71, 0x1d, 0x8c, 0xb4, 0xdb, 0x02, 0xed, 0xc3, 0x7a, 0x4a, 0x87, 0x3c, + 0x2c, 0xc1, 0x2a, 0x05, 0x6c, 0xcd, 0x04, 0x4c, 0x57, 0x4b, 0x79, 0x14, 0x75, 0x48, 0x78, 0x65, + 0xc3, 0xaa, 0xa6, 0x9a, 0x76, 0x5b, 0xa0, 0x27, 0xb0, 0x9a, 0xe6, 0xbf, 0xde, 0x46, 0xd4, 0x0a, + 0xc4, 0x8a, 0xf2, 0x9d, 0x4e, 0x89, 0xa7, 0x29, 0xbb, 0x73, 0xaa, 0xfd, 0xc2, 0xce, 0xc5, 0x31, + 0xbc, 0xdc, 0xf9, 0xb1, 0x38, 0xe6, 0x24, 0xc7, 0x6a, 0x02, 0xee, 0xc2, 0x18, 0xab, 0x6d, 0xe4, + 0xc2, 0x82, 0x2a, 0x45, 0x22, 0xb7, 0xae, 0x5c, 0xda, 0xf4, 0x4f, 0x60, 0x79, 0x7a, 0xf4, 0xd1, + 0x16, 0x2c, 0x1e, 0x33, 0x91, 0x44, 0x64, 0x74, 0x92, 0xff, 0x43, 0xa5, 0x26, 0xb6, 0x8f, 0xf2, + 0x4a, 0x98, 0x47, 0xf4, 0xc4, 0xfa, 0xc5, 0xda, 0xf6, 0xb7, 0x61, 0x69, 0xbc, 0x0b, 0x44, 0xc2, + 0x63, 0x41, 0x6f, 0x5b, 0x06, 0xfe, 0x7b, 0x40, 0xf6, 0xf5, 0x9e, 0x44, 0xdb, 0xc3, 0xe3, 0xcc, + 0xcc, 0xb7, 0x07, 0xf5, 0x84, 0x08, 0x71, 0xcd, 0xd3, 0xae, 0xae, 0xaa, 0x6d, 0xdf, 0x87, 0xa5, + 0xb3, 0x51, 0x42, 0x8b, 0x3c, 0x08, 0x6a, 0x72, 0x94, 0xe8, 0x1c, 0xea, 0xdb, 0xdf, 0x87, 0xff, + 0x6e, 0x19, 0xbe, 0x3b, 0xa8, 0x2e, 0xc0, 0xdc, 0x9b, 0x41, 0x22, 0x47, 0xbb, 0x5f, 0x6b, 0x50, + 0x3f, 0x9e, 0xec, 0x60, 0x14, 0x40, 0x2d, 0x2f, 0x89, 0x56, 0xcc, 0x8d, 0x50, 0x51, 0xde, 0x86, + 0x39, 0x98, 0xe2, 0xf4, 0x16, 0xc0, 0x74, 0x8c, 0xfe, 0x35, 0x51, 0xa5, 0x35, 0xe7, 0x6d, 0xde, + 0xec, 0x9c, 0x24, 0x7a, 0x01, 0x8d, 0x62, 0x9d, 0x20, 0xcf, 0x84, 0xce, 0xee, 0x18, 0x6f, 0x96, + 0x5a, 0xbe, 0x22, 0xcc, 0x35, 0xb7, 0x29, 0x94, 0x2e, 0x7f, 0x19, 0xdb, 0x87, 0xf5, 0x1b, 0xe5, + 0x43, 0xdb, 0x56, 0x9a, 0xdf, 0x5c, 0x6e, 0xef, 0xe1, 0x9d, 0x71, 0x93, 0xfe, 0x9e, 0x43, 0x2d, + 0x1f, 0x21, 0xb4, 0x6e, 0x00, 0xd6, 0xf3, 0x62, 0xeb, 0x3b, 0x35, 0x69, 0x8f, 0x60, 0xae, 0x1d, + 0x71, 0x71, 0xc3, 0x1f, 0x29, 0xf5, 0xf2, 0x0a, 0xc0, 0x3c, 0x87, 0xb6, 0x0e, 0xa5, 0x47, 0xb2, + 0x84, 0xf5, 0xab, 0xdf, 0x2a, 0xce, 0xd1, 0xe1, 0x87, 0x97, 0x3d, 0x26, 0xfb, 0x59, 0xa7, 0x15, + 0xf2, 0x41, 0xd0, 0x27, 0xa2, 0xcf, 0x42, 0x9e, 0x26, 0xc1, 0x90, 0x64, 0x91, 0x0c, 0xee, 0x7c, + 0xc9, 0x3b, 0xf3, 0x6a, 0x1f, 0xef, 0xfd, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x9c, 0x49, 0x0b, 0x5b, + 0xf5, 0x07, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.proto b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.proto new file mode 100644 index 0000000..7873792 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.proto @@ -0,0 +1,93 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/builtin/logical/database/dbplugin"; + +package dbplugin; + +import "google/protobuf/timestamp.proto"; + +message InitializeRequest { + option deprecated = true; + bytes config = 1; + bool verify_connection = 2; +} + +message InitRequest { + bytes config = 1; + bool verify_connection = 2; +} + +message CreateUserRequest { + Statements statements = 1; + UsernameConfig username_config = 2; + google.protobuf.Timestamp expiration = 3; +} + +message RenewUserRequest { + Statements statements = 1; + string username = 2; + google.protobuf.Timestamp expiration = 3; +} + +message RevokeUserRequest { + Statements statements = 1; + string username = 2; +} + +message RotateRootCredentialsRequest { + repeated string statements = 1; +} + +message Statements { + // DEPRECATED, will be removed in 0.12 + string creation_statements = 1 [deprecated=true]; + // DEPRECATED, will be removed in 0.12 + string revocation_statements = 2 [deprecated=true]; + // DEPRECATED, will be removed in 0.12 + string rollback_statements = 3 [deprecated=true]; + // DEPRECATED, will be removed in 0.12 + string renew_statements = 4 [deprecated=true]; + + repeated string creation = 5; + repeated string revocation = 6; + repeated string rollback = 7; + repeated string renewal = 8; +} + +message UsernameConfig { + string DisplayName = 1; + string RoleName = 2; +} + +message InitResponse { + bytes config = 1; +} + +message CreateUserResponse { + string username = 1; + string password = 2; +} + +message TypeResponse { + string type = 1; +} + +message RotateRootCredentialsResponse { + bytes config = 1; +} + +message Empty {} + +service Database { + rpc Type(Empty) returns (TypeResponse); + rpc CreateUser(CreateUserRequest) returns (CreateUserResponse); + rpc RenewUser(RenewUserRequest) returns (Empty); + rpc RevokeUser(RevokeUserRequest) returns (Empty); + rpc RotateRootCredentials(RotateRootCredentialsRequest) returns (RotateRootCredentialsResponse); + rpc Init(InitRequest) returns (InitResponse); + rpc Close(Empty) returns (Empty); + + rpc Initialize(InitializeRequest) returns (Empty) { + option deprecated = true; + }; +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/databasemiddleware.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/databasemiddleware.go new file mode 100644 index 0000000..ba2dd4e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/databasemiddleware.go @@ -0,0 +1,275 @@ +package dbplugin + +import ( + "context" + "errors" + "net/url" + "strings" + "sync" + "time" + + "github.com/hashicorp/errwrap" + + metrics "github.com/armon/go-metrics" + log "github.com/hashicorp/go-hclog" +) + +// ---- Tracing Middleware Domain ---- + +// databaseTracingMiddleware wraps a implementation of Database and executes +// trace logging on function call. +type databaseTracingMiddleware struct { + next Database + logger log.Logger +} + +func (mw *databaseTracingMiddleware) Type() (string, error) { + return mw.next.Type() +} + +func (mw *databaseTracingMiddleware) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { + defer func(then time.Time) { + mw.logger.Trace("create user", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("create user", "status", "started") + return mw.next.CreateUser(ctx, statements, usernameConfig, expiration) +} + +func (mw *databaseTracingMiddleware) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) (err error) { + defer func(then time.Time) { + mw.logger.Trace("renew user", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("renew user", "status", "started") + return mw.next.RenewUser(ctx, statements, username, expiration) +} + +func (mw *databaseTracingMiddleware) RevokeUser(ctx context.Context, statements Statements, username string) (err error) { + defer func(then time.Time) { + mw.logger.Trace("revoke user", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("revoke user", "status", "started") + return mw.next.RevokeUser(ctx, statements, username) +} + +func (mw *databaseTracingMiddleware) RotateRootCredentials(ctx context.Context, statements []string) (conf map[string]interface{}, err error) { + defer func(then time.Time) { + mw.logger.Trace("rotate root credentials", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("rotate root credentials", "status", "started") + return mw.next.RotateRootCredentials(ctx, statements) +} + +func (mw *databaseTracingMiddleware) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := mw.Init(ctx, conf, verifyConnection) + return err +} + +func (mw *databaseTracingMiddleware) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (saveConf map[string]interface{}, err error) { + defer func(then time.Time) { + mw.logger.Trace("initialize", "status", "finished", "verify", verifyConnection, "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("initialize", "status", "started") + return mw.next.Init(ctx, conf, verifyConnection) +} + +func (mw *databaseTracingMiddleware) Close() (err error) { + defer func(then time.Time) { + mw.logger.Trace("close", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + mw.logger.Trace("close", "status", "started") + return mw.next.Close() +} + +// ---- Metrics Middleware Domain ---- + +// databaseMetricsMiddleware wraps an implementation of Databases and on +// function call logs metrics about this instance. +type databaseMetricsMiddleware struct { + next Database + + typeStr string +} + +func (mw *databaseMetricsMiddleware) Type() (string, error) { + return mw.next.Type() +} + +func (mw *databaseMetricsMiddleware) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "CreateUser"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "CreateUser"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "CreateUser", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "CreateUser", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "CreateUser"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "CreateUser"}, 1) + return mw.next.CreateUser(ctx, statements, usernameConfig, expiration) +} + +func (mw *databaseMetricsMiddleware) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) (err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "RenewUser"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "RenewUser"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "RenewUser", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RenewUser", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "RenewUser"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RenewUser"}, 1) + return mw.next.RenewUser(ctx, statements, username, expiration) +} + +func (mw *databaseMetricsMiddleware) RevokeUser(ctx context.Context, statements Statements, username string) (err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "RevokeUser"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "RevokeUser"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "RevokeUser", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RevokeUser", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "RevokeUser"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RevokeUser"}, 1) + return mw.next.RevokeUser(ctx, statements, username) +} + +func (mw *databaseMetricsMiddleware) RotateRootCredentials(ctx context.Context, statements []string) (conf map[string]interface{}, err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "RotateRootCredentials"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "RotateRootCredentials"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "RotateRootCredentials", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RotateRootCredentials", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "RotateRootCredentials"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "RotateRootCredentials"}, 1) + return mw.next.RotateRootCredentials(ctx, statements) +} + +func (mw *databaseMetricsMiddleware) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := mw.Init(ctx, conf, verifyConnection) + return err +} + +func (mw *databaseMetricsMiddleware) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (saveConf map[string]interface{}, err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "Initialize"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "Initialize"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "Initialize", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "Initialize", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "Initialize"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "Initialize"}, 1) + return mw.next.Init(ctx, conf, verifyConnection) +} + +func (mw *databaseMetricsMiddleware) Close() (err error) { + defer func(now time.Time) { + metrics.MeasureSince([]string{"database", "Close"}, now) + metrics.MeasureSince([]string{"database", mw.typeStr, "Close"}, now) + + if err != nil { + metrics.IncrCounter([]string{"database", "Close", "error"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "Close", "error"}, 1) + } + }(time.Now()) + + metrics.IncrCounter([]string{"database", "Close"}, 1) + metrics.IncrCounter([]string{"database", mw.typeStr, "Close"}, 1) + return mw.next.Close() +} + +// ---- Error Sanitizer Middleware Domain ---- + +// DatabaseErrorSanitizerMiddleware wraps an implementation of Databases and +// sanitizes returned error messages +type DatabaseErrorSanitizerMiddleware struct { + l sync.RWMutex + next Database + secretsFn func() map[string]interface{} +} + +func NewDatabaseErrorSanitizerMiddleware(next Database, secretsFn func() map[string]interface{}) *DatabaseErrorSanitizerMiddleware { + return &DatabaseErrorSanitizerMiddleware{ + next: next, + secretsFn: secretsFn, + } +} + +func (mw *DatabaseErrorSanitizerMiddleware) Type() (string, error) { + dbType, err := mw.next.Type() + return dbType, mw.sanitize(err) +} + +func (mw *DatabaseErrorSanitizerMiddleware) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { + username, password, err = mw.next.CreateUser(ctx, statements, usernameConfig, expiration) + return username, password, mw.sanitize(err) +} + +func (mw *DatabaseErrorSanitizerMiddleware) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) (err error) { + return mw.sanitize(mw.next.RenewUser(ctx, statements, username, expiration)) +} + +func (mw *DatabaseErrorSanitizerMiddleware) RevokeUser(ctx context.Context, statements Statements, username string) (err error) { + return mw.sanitize(mw.next.RevokeUser(ctx, statements, username)) +} + +func (mw *DatabaseErrorSanitizerMiddleware) RotateRootCredentials(ctx context.Context, statements []string) (conf map[string]interface{}, err error) { + conf, err = mw.next.RotateRootCredentials(ctx, statements) + return conf, mw.sanitize(err) +} + +func (mw *DatabaseErrorSanitizerMiddleware) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := mw.Init(ctx, conf, verifyConnection) + return err +} + +func (mw *DatabaseErrorSanitizerMiddleware) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (saveConf map[string]interface{}, err error) { + saveConf, err = mw.next.Init(ctx, conf, verifyConnection) + return saveConf, mw.sanitize(err) +} + +func (mw *DatabaseErrorSanitizerMiddleware) Close() (err error) { + return mw.sanitize(mw.next.Close()) +} + +// sanitize +func (mw *DatabaseErrorSanitizerMiddleware) sanitize(err error) error { + if err == nil { + return nil + } + if errwrap.ContainsType(err, new(url.Error)) { + return errors.New("unable to parse connection url") + } + if mw.secretsFn != nil { + for k, v := range mw.secretsFn() { + if k == "" { + continue + } + err = errors.New(strings.Replace(err.Error(), k, v.(string), -1)) + } + } + return err +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/grpc_transport.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/grpc_transport.go new file mode 100644 index 0000000..1b5267e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/grpc_transport.go @@ -0,0 +1,285 @@ +package dbplugin + +import ( + "context" + "encoding/json" + "errors" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/vault/helper/pluginutil" +) + +var ( + ErrPluginShutdown = errors.New("plugin shutdown") +) + +// ---- gRPC Server domain ---- + +type gRPCServer struct { + impl Database +} + +func (s *gRPCServer) Type(context.Context, *Empty) (*TypeResponse, error) { + t, err := s.impl.Type() + if err != nil { + return nil, err + } + + return &TypeResponse{ + Type: t, + }, nil +} + +func (s *gRPCServer) CreateUser(ctx context.Context, req *CreateUserRequest) (*CreateUserResponse, error) { + e, err := ptypes.Timestamp(req.Expiration) + if err != nil { + return nil, err + } + + u, p, err := s.impl.CreateUser(ctx, *req.Statements, *req.UsernameConfig, e) + + return &CreateUserResponse{ + Username: u, + Password: p, + }, err +} + +func (s *gRPCServer) RenewUser(ctx context.Context, req *RenewUserRequest) (*Empty, error) { + e, err := ptypes.Timestamp(req.Expiration) + if err != nil { + return nil, err + } + err = s.impl.RenewUser(ctx, *req.Statements, req.Username, e) + return &Empty{}, err +} + +func (s *gRPCServer) RevokeUser(ctx context.Context, req *RevokeUserRequest) (*Empty, error) { + err := s.impl.RevokeUser(ctx, *req.Statements, req.Username) + return &Empty{}, err +} + +func (s *gRPCServer) RotateRootCredentials(ctx context.Context, req *RotateRootCredentialsRequest) (*RotateRootCredentialsResponse, error) { + + resp, err := s.impl.RotateRootCredentials(ctx, req.Statements) + if err != nil { + return nil, err + } + + respConfig, err := json.Marshal(resp) + if err != nil { + return nil, err + } + + return &RotateRootCredentialsResponse{ + Config: respConfig, + }, err +} + +func (s *gRPCServer) Initialize(ctx context.Context, req *InitializeRequest) (*Empty, error) { + _, err := s.Init(ctx, &InitRequest{ + Config: req.Config, + VerifyConnection: req.VerifyConnection, + }) + return &Empty{}, err +} + +func (s *gRPCServer) Init(ctx context.Context, req *InitRequest) (*InitResponse, error) { + config := map[string]interface{}{} + err := json.Unmarshal(req.Config, &config) + if err != nil { + return nil, err + } + + resp, err := s.impl.Init(ctx, config, req.VerifyConnection) + if err != nil { + return nil, err + } + + respConfig, err := json.Marshal(resp) + if err != nil { + return nil, err + } + + return &InitResponse{ + Config: respConfig, + }, err +} + +func (s *gRPCServer) Close(_ context.Context, _ *Empty) (*Empty, error) { + s.impl.Close() + return &Empty{}, nil +} + +// ---- gRPC client domain ---- + +type gRPCClient struct { + client DatabaseClient + clientConn *grpc.ClientConn + + doneCtx context.Context +} + +func (c *gRPCClient) Type() (string, error) { + resp, err := c.client.Type(c.doneCtx, &Empty{}) + if err != nil { + return "", err + } + + return resp.Type, err +} + +func (c *gRPCClient) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { + t, err := ptypes.TimestampProto(expiration) + if err != nil { + return "", "", err + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) + defer close(quitCh) + defer cancel() + + resp, err := c.client.CreateUser(ctx, &CreateUserRequest{ + Statements: &statements, + UsernameConfig: &usernameConfig, + Expiration: t, + }) + if err != nil { + if c.doneCtx.Err() != nil { + return "", "", ErrPluginShutdown + } + + return "", "", err + } + + return resp.Username, resp.Password, err +} + +func (c *gRPCClient) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) error { + t, err := ptypes.TimestampProto(expiration) + if err != nil { + return err + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) + defer close(quitCh) + defer cancel() + + _, err = c.client.RenewUser(ctx, &RenewUserRequest{ + Statements: &statements, + Username: username, + Expiration: t, + }) + if err != nil { + if c.doneCtx.Err() != nil { + return ErrPluginShutdown + } + + return err + } + + return nil +} + +func (c *gRPCClient) RevokeUser(ctx context.Context, statements Statements, username string) error { + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) + defer close(quitCh) + defer cancel() + + _, err := c.client.RevokeUser(ctx, &RevokeUserRequest{ + Statements: &statements, + Username: username, + }) + + if err != nil { + if c.doneCtx.Err() != nil { + return ErrPluginShutdown + } + + return err + } + + return nil +} + +func (c *gRPCClient) RotateRootCredentials(ctx context.Context, statements []string) (conf map[string]interface{}, err error) { + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) + defer close(quitCh) + defer cancel() + + resp, err := c.client.RotateRootCredentials(ctx, &RotateRootCredentialsRequest{ + Statements: statements, + }) + + if err != nil { + if c.doneCtx.Err() != nil { + return nil, ErrPluginShutdown + } + + return nil, err + } + + if err := json.Unmarshal(resp.Config, &conf); err != nil { + return nil, err + } + + return conf, nil +} + +func (c *gRPCClient) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := c.Init(ctx, conf, verifyConnection) + return err +} + +func (c *gRPCClient) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (map[string]interface{}, error) { + configRaw, err := json.Marshal(conf) + if err != nil { + return nil, err + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) + defer close(quitCh) + defer cancel() + + resp, err := c.client.Init(ctx, &InitRequest{ + Config: configRaw, + VerifyConnection: verifyConnection, + }) + if err != nil { + // Fall back to old call if not implemented + grpcStatus, ok := status.FromError(err) + if ok && grpcStatus.Code() == codes.Unimplemented { + _, err = c.client.Initialize(ctx, &InitializeRequest{ + Config: configRaw, + VerifyConnection: verifyConnection, + }) + if err == nil { + return conf, nil + } + } + + if c.doneCtx.Err() != nil { + return nil, ErrPluginShutdown + } + return nil, err + } + + if err := json.Unmarshal(resp.Config, &conf); err != nil { + return nil, err + } + return conf, nil +} + +func (c *gRPCClient) Close() error { + _, err := c.client.Close(c.doneCtx, &Empty{}) + return err +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/netrpc_transport.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/netrpc_transport.go new file mode 100644 index 0000000..25cbc97 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/netrpc_transport.go @@ -0,0 +1,197 @@ +package dbplugin + +import ( + "context" + "encoding/json" + "fmt" + "net/rpc" + "strings" + "time" +) + +// ---- RPC server domain ---- + +// databasePluginRPCServer implements an RPC version of Database and is run +// inside a plugin. It wraps an underlying implementation of Database. +type databasePluginRPCServer struct { + impl Database +} + +func (ds *databasePluginRPCServer) Type(_ struct{}, resp *string) error { + var err error + *resp, err = ds.impl.Type() + return err +} + +func (ds *databasePluginRPCServer) CreateUser(args *CreateUserRequestRPC, resp *CreateUserResponse) error { + var err error + resp.Username, resp.Password, err = ds.impl.CreateUser(context.Background(), args.Statements, args.UsernameConfig, args.Expiration) + return err +} + +func (ds *databasePluginRPCServer) RenewUser(args *RenewUserRequestRPC, _ *struct{}) error { + err := ds.impl.RenewUser(context.Background(), args.Statements, args.Username, args.Expiration) + return err +} + +func (ds *databasePluginRPCServer) RevokeUser(args *RevokeUserRequestRPC, _ *struct{}) error { + err := ds.impl.RevokeUser(context.Background(), args.Statements, args.Username) + return err +} + +func (ds *databasePluginRPCServer) RotateRootCredentials(args *RotateRootCredentialsRequestRPC, resp *RotateRootCredentialsResponse) error { + config, err := ds.impl.RotateRootCredentials(context.Background(), args.Statements) + if err != nil { + return err + } + resp.Config, err = json.Marshal(config) + return err +} + +func (ds *databasePluginRPCServer) Initialize(args *InitializeRequestRPC, _ *struct{}) error { + return ds.Init(&InitRequestRPC{ + Config: args.Config, + VerifyConnection: args.VerifyConnection, + }, &InitResponse{}) +} + +func (ds *databasePluginRPCServer) Init(args *InitRequestRPC, resp *InitResponse) error { + config, err := ds.impl.Init(context.Background(), args.Config, args.VerifyConnection) + if err != nil { + return err + } + resp.Config, err = json.Marshal(config) + return err +} + +func (ds *databasePluginRPCServer) Close(_ struct{}, _ *struct{}) error { + ds.impl.Close() + return nil +} + +// ---- RPC client domain ---- +// databasePluginRPCClient implements Database and is used on the client to +// make RPC calls to a plugin. +type databasePluginRPCClient struct { + client *rpc.Client +} + +func (dr *databasePluginRPCClient) Type() (string, error) { + var dbType string + err := dr.client.Call("Plugin.Type", struct{}{}, &dbType) + + return fmt.Sprintf("plugin-%s", dbType), err +} + +func (dr *databasePluginRPCClient) CreateUser(_ context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { + req := CreateUserRequestRPC{ + Statements: statements, + UsernameConfig: usernameConfig, + Expiration: expiration, + } + + var resp CreateUserResponse + err = dr.client.Call("Plugin.CreateUser", req, &resp) + + return resp.Username, resp.Password, err +} + +func (dr *databasePluginRPCClient) RenewUser(_ context.Context, statements Statements, username string, expiration time.Time) error { + req := RenewUserRequestRPC{ + Statements: statements, + Username: username, + Expiration: expiration, + } + + return dr.client.Call("Plugin.RenewUser", req, &struct{}{}) +} + +func (dr *databasePluginRPCClient) RevokeUser(_ context.Context, statements Statements, username string) error { + req := RevokeUserRequestRPC{ + Statements: statements, + Username: username, + } + + return dr.client.Call("Plugin.RevokeUser", req, &struct{}{}) +} + +func (dr *databasePluginRPCClient) RotateRootCredentials(_ context.Context, statements []string) (saveConf map[string]interface{}, err error) { + req := RotateRootCredentialsRequestRPC{ + Statements: statements, + } + + var resp RotateRootCredentialsResponse + err = dr.client.Call("Plugin.RotateRootCredentials", req, &resp) + + err = json.Unmarshal(resp.Config, &saveConf) + return saveConf, err +} + +func (dr *databasePluginRPCClient) Initialize(_ context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := dr.Init(nil, conf, verifyConnection) + return err +} + +func (dr *databasePluginRPCClient) Init(_ context.Context, conf map[string]interface{}, verifyConnection bool) (saveConf map[string]interface{}, err error) { + req := InitRequestRPC{ + Config: conf, + VerifyConnection: verifyConnection, + } + + var resp InitResponse + err = dr.client.Call("Plugin.Init", req, &resp) + if err != nil { + if strings.Contains(err.Error(), "can't find method Plugin.Init") { + req := InitializeRequestRPC{ + Config: conf, + VerifyConnection: verifyConnection, + } + + err = dr.client.Call("Plugin.Initialize", req, &struct{}{}) + if err == nil { + return conf, nil + } + } + return nil, err + } + + err = json.Unmarshal(resp.Config, &saveConf) + return saveConf, err +} + +func (dr *databasePluginRPCClient) Close() error { + return dr.client.Call("Plugin.Close", struct{}{}, &struct{}{}) +} + +// ---- RPC Request Args Domain ---- + +type InitializeRequestRPC struct { + Config map[string]interface{} + VerifyConnection bool +} + +type InitRequestRPC struct { + Config map[string]interface{} + VerifyConnection bool +} + +type CreateUserRequestRPC struct { + Statements Statements + UsernameConfig UsernameConfig + Expiration time.Time +} + +type RenewUserRequestRPC struct { + Statements Statements + Username string + Expiration time.Time +} + +type RevokeUserRequestRPC struct { + Statements Statements + Username string +} + +type RotateRootCredentialsRequestRPC struct { + Statements []string +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/plugin.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/plugin.go new file mode 100644 index 0000000..502f97e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/plugin.go @@ -0,0 +1,148 @@ +package dbplugin + +import ( + "context" + "fmt" + "net/rpc" + "time" + + "google.golang.org/grpc" + + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" +) + +// Database is the interface that all database objects must implement. +type Database interface { + Type() (string, error) + CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) + RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) error + RevokeUser(ctx context.Context, statements Statements, username string) error + + RotateRootCredentials(ctx context.Context, statements []string) (config map[string]interface{}, err error) + + Init(ctx context.Context, config map[string]interface{}, verifyConnection bool) (saveConfig map[string]interface{}, err error) + Close() error + + // DEPRECATED, will be removed in 0.12 + Initialize(ctx context.Context, config map[string]interface{}, verifyConnection bool) (err error) +} + +// PluginFactory is used to build plugin database types. It wraps the database +// object in a logging and metrics middleware. +func PluginFactory(ctx context.Context, pluginName string, sys pluginutil.LookRunnerUtil, logger log.Logger) (Database, error) { + // Look for plugin in the plugin catalog + pluginRunner, err := sys.LookupPlugin(ctx, pluginName) + if err != nil { + return nil, err + } + + namedLogger := logger.Named(pluginName) + + var transport string + var db Database + if pluginRunner.Builtin { + // Plugin is builtin so we can retrieve an instance of the interface + // from the pluginRunner. Then cast it to a Database. + dbRaw, err := pluginRunner.BuiltinFactory() + if err != nil { + return nil, errwrap.Wrapf("error initializing plugin: {{err}}", err) + } + + var ok bool + db, ok = dbRaw.(Database) + if !ok { + return nil, fmt.Errorf("unsupported database type: %q", pluginName) + } + + transport = "builtin" + + } else { + // create a DatabasePluginClient instance + db, err = newPluginClient(ctx, sys, pluginRunner, namedLogger) + if err != nil { + return nil, err + } + + // Switch on the underlying database client type to get the transport + // method. + switch db.(*DatabasePluginClient).Database.(type) { + case *gRPCClient: + transport = "gRPC" + case *databasePluginRPCClient: + transport = "netRPC" + } + + } + + typeStr, err := db.Type() + if err != nil { + return nil, errwrap.Wrapf("error getting plugin type: {{err}}", err) + } + + // Wrap with metrics middleware + db = &databaseMetricsMiddleware{ + next: db, + typeStr: typeStr, + } + + // Wrap with tracing middleware + if namedLogger.IsTrace() { + db = &databaseTracingMiddleware{ + next: db, + logger: namedLogger.With("transport", transport), + } + } + + return db, nil +} + +// handshakeConfigs are used to just do a basic handshake between +// a plugin and host. If the handshake fails, a user friendly error is shown. +// This prevents users from executing bad plugins or executing a plugin +// directory. It is a UX feature, not a security feature. +var handshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 3, + MagicCookieKey: "VAULT_DATABASE_PLUGIN", + MagicCookieValue: "926a0820-aea2-be28-51d6-83cdf00e8edb", +} + +var _ plugin.Plugin = &DatabasePlugin{} +var _ plugin.GRPCPlugin = &DatabasePlugin{} + +// DatabasePlugin implements go-plugin's Plugin interface. It has methods for +// retrieving a server and a client instance of the plugin. +type DatabasePlugin struct { + impl Database +} + +func (d DatabasePlugin) Server(*plugin.MuxBroker) (interface{}, error) { + impl := &DatabaseErrorSanitizerMiddleware{ + next: d.impl, + } + + return &databasePluginRPCServer{impl: impl}, nil +} + +func (DatabasePlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &databasePluginRPCClient{client: c}, nil +} + +func (d DatabasePlugin) GRPCServer(_ *plugin.GRPCBroker, s *grpc.Server) error { + impl := &DatabaseErrorSanitizerMiddleware{ + next: d.impl, + } + + RegisterDatabaseServer(s, &gRPCServer{impl: impl}) + return nil +} + +func (DatabasePlugin) GRPCClient(doneCtx context.Context, _ *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { + return &gRPCClient{ + client: NewDatabaseClient(c), + clientConn: c, + doneCtx: doneCtx, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/server.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/server.go new file mode 100644 index 0000000..656c44b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/server.go @@ -0,0 +1,39 @@ +package dbplugin + +import ( + "crypto/tls" + + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" +) + +// Serve is called from within a plugin and wraps the provided +// Database implementation in a databasePluginRPCServer object and starts a +// RPC server. +func Serve(db Database, tlsProvider func() (*tls.Config, error)) { + plugin.Serve(ServeConfig(db, tlsProvider)) +} + +func ServeConfig(db Database, tlsProvider func() (*tls.Config, error)) *plugin.ServeConfig { + dbPlugin := &DatabasePlugin{ + impl: db, + } + + // pluginMap is the map of plugins we can dispense. + var pluginMap = map[string]plugin.Plugin{ + "database": dbPlugin, + } + + conf := &plugin.ServeConfig{ + HandshakeConfig: handshakeConfig, + Plugins: pluginMap, + TLSProvider: tlsProvider, + GRPCServer: plugin.DefaultGRPCServer, + } + + if !pluginutil.GRPCSupport() { + conf.GRPCServer = nil + } + + return conf +} diff --git a/vendor/github.com/hashicorp/vault/command/config/config.go b/vendor/github.com/hashicorp/vault/command/config/config.go new file mode 100644 index 0000000..ebee11e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/config/config.go @@ -0,0 +1,128 @@ +package config + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/mitchellh/go-homedir" +) + +const ( + // DefaultConfigPath is the default path to the configuration file + DefaultConfigPath = "~/.vault" + + // ConfigPathEnv is the environment variable that can be used to + // override where the Vault configuration is. + ConfigPathEnv = "VAULT_CONFIG_PATH" +) + +// Config is the CLI configuration for Vault that can be specified via +// a `$HOME/.vault` file which is HCL-formatted (therefore HCL or JSON). +type DefaultConfig struct { + // TokenHelper is the executable/command that is executed for storing + // and retrieving the authentication token for the Vault CLI. If this + // is not specified, then vault's internal token store will be used, which + // stores the token on disk unencrypted. + TokenHelper string `hcl:"token_helper"` +} + +// Config loads the configuration and returns it. If the configuration +// is already loaded, it is returned. +func Config() (*DefaultConfig, error) { + var err error + config, err := LoadConfig("") + if err != nil { + return nil, err + } + + return config, nil +} + +// LoadConfig reads the configuration from the given path. If path is +// empty, then the default path will be used, or the environment variable +// if set. +func LoadConfig(path string) (*DefaultConfig, error) { + if path == "" { + path = DefaultConfigPath + } + if v := os.Getenv(ConfigPathEnv); v != "" { + path = v + } + + // NOTE: requires HOME env var to be set + path, err := homedir.Expand(path) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error expanding config path %q: {{err}}", path), err) + } + + contents, err := ioutil.ReadFile(path) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + + conf, err := ParseConfig(string(contents)) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error parsing config file at %q: {{err}}; ensure that the file is valid; Ansible Vault is known to conflict with it.", path), err) + } + + return conf, nil +} + +// ParseConfig parses the given configuration as a string. +func ParseConfig(contents string) (*DefaultConfig, error) { + root, err := hcl.Parse(contents) + if err != nil { + return nil, err + } + + // Top-level item should be the object list + list, ok := root.Node.(*ast.ObjectList) + if !ok { + return nil, fmt.Errorf("failed to parse config; does not contain a root object") + } + + valid := []string{ + "token_helper", + } + if err := checkHCLKeys(list, valid); err != nil { + return nil, err + } + + var c DefaultConfig + if err := hcl.DecodeObject(&c, list); err != nil { + return nil, err + } + return &c, nil +} + +func checkHCLKeys(node ast.Node, valid []string) error { + var list *ast.ObjectList + switch n := node.(type) { + case *ast.ObjectList: + list = n + case *ast.ObjectType: + list = n.List + default: + return fmt.Errorf("cannot check HCL keys of type %T", n) + } + + validMap := make(map[string]struct{}, len(valid)) + for _, v := range valid { + validMap[v] = struct{}{} + } + + var result error + for _, item := range list.Items { + key := item.Keys[0].Token.Value().(string) + if _, ok := validMap[key]; !ok { + result = multierror.Append(result, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line)) + } + } + + return result +} diff --git a/vendor/github.com/hashicorp/vault/command/config/util.go b/vendor/github.com/hashicorp/vault/command/config/util.go new file mode 100644 index 0000000..a9d5951 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/config/util.go @@ -0,0 +1,24 @@ +package config + +import ( + "github.com/hashicorp/vault/command/token" +) + +// DefaultTokenHelper returns the token helper that is configured for Vault. +func DefaultTokenHelper() (token.TokenHelper, error) { + config, err := LoadConfig("") + if err != nil { + return nil, err + } + + path := config.TokenHelper + if path == "" { + return &token.InternalTokenHelper{}, nil + } + + path, err = token.ExternalTokenHelperPath(path) + if err != nil { + return nil, err + } + return &token.ExternalTokenHelper{BinaryPath: path}, nil +} diff --git a/vendor/github.com/hashicorp/vault/command/token/helper.go b/vendor/github.com/hashicorp/vault/command/token/helper.go new file mode 100644 index 0000000..cac7948 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/token/helper.go @@ -0,0 +1,14 @@ +package token + +// TokenHelper is an interface that contains basic operations that must be +// implemented by a token helper +type TokenHelper interface { + // Path displays a method-specific path; for the internal helper this + // is the location of the token stored on disk; for the external helper + // this is the location of the binary being invoked + Path() string + + Erase() error + Get() (string, error) + Store(string) error +} diff --git a/vendor/github.com/hashicorp/vault/command/token/helper_external.go b/vendor/github.com/hashicorp/vault/command/token/helper_external.go new file mode 100644 index 0000000..edd95d5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/token/helper_external.go @@ -0,0 +1,132 @@ +package token + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + + "github.com/hashicorp/errwrap" +) + +// ExternalTokenHelperPath takes the configured path to a helper and expands it to +// a full absolute path that can be executed. As of 0.5, the default token +// helper is internal, to avoid problems running in dev mode (see GH-850 and +// GH-783), so special assumptions of prepending "vault token-" no longer +// apply. +// +// As an additional result, only absolute paths are now allowed. Looking in the +// path or a current directory for an arbitrary executable could allow someone +// to switch the expected binary for one further up the path (or in the current +// directory), potentially opening up execution of an arbitrary binary. +func ExternalTokenHelperPath(path string) (string, error) { + if !filepath.IsAbs(path) { + var err error + path, err = filepath.Abs(path) + if err != nil { + return "", err + } + } + + if _, err := os.Stat(path); err != nil { + return "", fmt.Errorf("unknown error getting the external helper path") + } + + return path, nil +} + +var _ TokenHelper = (*ExternalTokenHelper)(nil) + +// ExternalTokenHelper is the struct that has all the logic for storing and retrieving +// tokens from the token helper. The API for the helpers is simple: the +// BinaryPath is executed within a shell with environment Env. The last argument +// appended will be the operation, which is: +// +// * "get" - Read the value of the token and write it to stdout. +// * "store" - Store the value of the token which is on stdin. Output +// nothing. +// * "erase" - Erase the contents stored. Output nothing. +// +// Any errors can be written on stdout. If the helper exits with a non-zero +// exit code then the stderr will be made part of the error value. +type ExternalTokenHelper struct { + BinaryPath string + Env []string +} + +// Erase deletes the contents from the helper. +func (h *ExternalTokenHelper) Erase() error { + cmd, err := h.cmd("erase") + if err != nil { + return err + } + if output, err := cmd.CombinedOutput(); err != nil { + return errwrap.Wrapf(fmt.Sprintf("%q: {{err}}", string(output)), err) + } + return nil +} + +// Get gets the token value from the helper. +func (h *ExternalTokenHelper) Get() (string, error) { + var buf, stderr bytes.Buffer + cmd, err := h.cmd("get") + if err != nil { + return "", err + } + cmd.Stdout = &buf + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return "", errwrap.Wrapf(fmt.Sprintf("%q: {{err}}", stderr.String()), err) + } + + return buf.String(), nil +} + +// Store stores the token value into the helper. +func (h *ExternalTokenHelper) Store(v string) error { + buf := bytes.NewBufferString(v) + cmd, err := h.cmd("store") + if err != nil { + return err + } + cmd.Stdin = buf + if output, err := cmd.CombinedOutput(); err != nil { + return errwrap.Wrapf(fmt.Sprintf("%q: {{err}}", string(output)), err) + } + + return nil +} + +func (h *ExternalTokenHelper) Path() string { + return h.BinaryPath +} + +func (h *ExternalTokenHelper) cmd(op string) (*exec.Cmd, error) { + script := strings.Replace(h.BinaryPath, "\\", "\\\\", -1) + " " + op + cmd, err := ExecScript(script) + if err != nil { + return nil, err + } + cmd.Env = h.Env + return cmd, nil +} + +// ExecScript returns a command to execute a script +func ExecScript(script string) (*exec.Cmd, error) { + var shell, flag string + if runtime.GOOS == "windows" { + shell = "cmd" + flag = "/C" + } else { + shell = "/bin/sh" + flag = "-c" + } + if other := os.Getenv("SHELL"); other != "" { + shell = other + } + cmd := exec.Command(shell, flag, script) + return cmd, nil +} diff --git a/vendor/github.com/hashicorp/vault/command/token/helper_internal.go b/vendor/github.com/hashicorp/vault/command/token/helper_internal.go new file mode 100644 index 0000000..f3f527b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/token/helper_internal.go @@ -0,0 +1,80 @@ +package token + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + + "github.com/mitchellh/go-homedir" +) + +var _ TokenHelper = (*InternalTokenHelper)(nil) + +// InternalTokenHelper fulfills the TokenHelper interface when no external +// token-helper is configured, and avoids shelling out +type InternalTokenHelper struct { + tokenPath string +} + +// populateTokenPath figures out the token path using homedir to get the user's +// home directory +func (i *InternalTokenHelper) populateTokenPath() { + homePath, err := homedir.Dir() + if err != nil { + panic(fmt.Sprintf("error getting user's home directory: %v", err)) + } + i.tokenPath = homePath + "/.vault-token" +} + +func (i *InternalTokenHelper) Path() string { + return i.tokenPath +} + +// Get gets the value of the stored token, if any +func (i *InternalTokenHelper) Get() (string, error) { + i.populateTokenPath() + f, err := os.Open(i.tokenPath) + if os.IsNotExist(err) { + return "", nil + } + if err != nil { + return "", err + } + defer f.Close() + + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, f); err != nil { + return "", err + } + + return strings.TrimSpace(buf.String()), nil +} + +// Store stores the value of the token to the file +func (i *InternalTokenHelper) Store(input string) error { + i.populateTokenPath() + f, err := os.OpenFile(i.tokenPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) + if err != nil { + return err + } + defer f.Close() + + buf := bytes.NewBufferString(input) + if _, err := io.Copy(f, buf); err != nil { + return err + } + + return nil +} + +// Erase erases the value of the token +func (i *InternalTokenHelper) Erase() error { + i.populateTokenPath() + if err := os.Remove(i.tokenPath); err != nil && !os.IsNotExist(err) { + return err + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/command/token/helper_testing.go b/vendor/github.com/hashicorp/vault/command/token/helper_testing.go new file mode 100644 index 0000000..9346593 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/token/helper_testing.go @@ -0,0 +1,42 @@ +package token + +import ( + "sync" +) + +var _ TokenHelper = (*TestingTokenHelper)(nil) + +// TestingTokenHelper implements token.TokenHelper which runs entirely +// in-memory. This should not be used outside of testing. +type TestingTokenHelper struct { + lock sync.RWMutex + token string +} + +func NewTestingTokenHelper() *TestingTokenHelper { + return &TestingTokenHelper{} +} + +func (t *TestingTokenHelper) Erase() error { + t.lock.Lock() + defer t.lock.Unlock() + t.token = "" + return nil +} + +func (t *TestingTokenHelper) Get() (string, error) { + t.lock.RLock() + defer t.lock.RUnlock() + return t.token, nil +} + +func (t *TestingTokenHelper) Path() string { + return "" +} + +func (t *TestingTokenHelper) Store(token string) error { + t.lock.Lock() + defer t.lock.Unlock() + t.token = token + return nil +} diff --git a/vendor/github.com/hashicorp/vault/command/token/testing.go b/vendor/github.com/hashicorp/vault/command/token/testing.go new file mode 100644 index 0000000..725f127 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/command/token/testing.go @@ -0,0 +1,78 @@ +package token + +import ( + "fmt" + "os" + "strings" + "testing" + + "github.com/mitchellh/cli" +) + +// Test is a public function that can be used in other tests to +// test that a helper is functioning properly. +func Test(t *testing.T, h TokenHelper) { + if err := h.Store("foo"); err != nil { + t.Fatalf("err: %s", err) + } + + v, err := h.Get() + if err != nil { + t.Fatalf("err: %s", err) + } + + if v != "foo" { + t.Fatalf("bad: %#v", v) + } + + if err := h.Erase(); err != nil { + t.Fatalf("err: %s", err) + } + + v, err = h.Get() + if err != nil { + t.Fatalf("err: %s", err) + } + + if v != "" { + t.Fatalf("bad: %#v", v) + } +} + +// TestProcess is used to re-execute this test in order to use it as the +// helper process. For this to work, the TestExternalTokenHelperProcess function must +// exist. +func TestProcess(t *testing.T, s ...string) { + h := &ExternalTokenHelper{BinaryPath: TestProcessPath(t, s...)} + Test(t, h) +} + +// TestProcessPath returns the path to the test process. +func TestProcessPath(t *testing.T, s ...string) string { + cs := []string{"-test.run=TestExternalTokenHelperProcess", "--", "GO_WANT_HELPER_PROCESS"} + cs = append(cs, s...) + return fmt.Sprintf( + "%s %s", + os.Args[0], + strings.Join(cs, " ")) +} + +// TestExternalTokenHelperProcessCLI can be called to implement TestExternalTokenHelperProcess +// for TestProcess that just executes a CLI command. +func TestExternalTokenHelperProcessCLI(t *testing.T, cmd cli.Command) { + args := os.Args + for len(args) > 0 { + if args[0] == "--" { + args = args[1:] + break + } + + args = args[1:] + } + if len(args) == 0 || args[0] != "GO_WANT_HELPER_PROCESS" { + return + } + args = args[1:] + + os.Exit(cmd.Run(args)) +} diff --git a/vendor/github.com/hashicorp/vault/helper/builtinplugins/builtin.go b/vendor/github.com/hashicorp/vault/helper/builtinplugins/builtin.go new file mode 100644 index 0000000..df424ce --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/builtinplugins/builtin.go @@ -0,0 +1,50 @@ +package builtinplugins + +import ( + "github.com/hashicorp/vault/plugins/database/cassandra" + "github.com/hashicorp/vault/plugins/database/hana" + "github.com/hashicorp/vault/plugins/database/mongodb" + "github.com/hashicorp/vault/plugins/database/mssql" + "github.com/hashicorp/vault/plugins/database/mysql" + "github.com/hashicorp/vault/plugins/database/postgresql" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" +) + +// BuiltinFactory is the func signature that should be returned by +// the plugin's New() func. +type BuiltinFactory func() (interface{}, error) + +var plugins = map[string]BuiltinFactory{ + // These four plugins all use the same mysql implementation but with + // different username settings passed by the constructor. + "mysql-database-plugin": mysql.New(mysql.MetadataLen, mysql.MetadataLen, mysql.UsernameLen), + "mysql-aurora-database-plugin": mysql.New(credsutil.NoneLength, mysql.LegacyMetadataLen, mysql.LegacyUsernameLen), + "mysql-rds-database-plugin": mysql.New(credsutil.NoneLength, mysql.LegacyMetadataLen, mysql.LegacyUsernameLen), + "mysql-legacy-database-plugin": mysql.New(credsutil.NoneLength, mysql.LegacyMetadataLen, mysql.LegacyUsernameLen), + + "postgresql-database-plugin": postgresql.New, + "mssql-database-plugin": mssql.New, + "cassandra-database-plugin": cassandra.New, + "mongodb-database-plugin": mongodb.New, + "hana-database-plugin": hana.New, +} + +// Get returns the BuiltinFactory func for a particular backend plugin +// from the plugins map. +func Get(name string) (BuiltinFactory, bool) { + f, ok := plugins[name] + return f, ok +} + +// Keys returns the list of plugin names that are considered builtin plugins. +func Keys() []string { + keys := make([]string, len(plugins)) + + i := 0 + for k := range plugins { + keys[i] = k + i++ + } + + return keys +} diff --git a/vendor/github.com/hashicorp/vault/helper/certutil/helpers.go b/vendor/github.com/hashicorp/vault/helper/certutil/helpers.go new file mode 100644 index 0000000..3c072ce --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/certutil/helpers.go @@ -0,0 +1,275 @@ +package certutil + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "encoding/pem" + "fmt" + "math/big" + "strconv" + "strings" + + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/mitchellh/mapstructure" +) + +// GetHexFormatted returns the byte buffer formatted in hex with +// the specified separator between bytes. +func GetHexFormatted(buf []byte, sep string) string { + var ret bytes.Buffer + for _, cur := range buf { + if ret.Len() > 0 { + fmt.Fprintf(&ret, sep) + } + fmt.Fprintf(&ret, "%02x", cur) + } + return ret.String() +} + +// ParseHexFormatted returns the raw bytes from a formatted hex string +func ParseHexFormatted(in, sep string) []byte { + var ret bytes.Buffer + var err error + var inBits int64 + inBytes := strings.Split(in, sep) + for _, inByte := range inBytes { + if inBits, err = strconv.ParseInt(inByte, 16, 8); err != nil { + return nil + } + ret.WriteByte(byte(inBits)) + } + return ret.Bytes() +} + +// GetSubjKeyID returns the subject key ID, e.g. the SHA1 sum +// of the marshaled public key +func GetSubjKeyID(privateKey crypto.Signer) ([]byte, error) { + if privateKey == nil { + return nil, errutil.InternalError{Err: "passed-in private key is nil"} + } + + marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public()) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error marshalling public key: %s", err)} + } + + subjKeyID := sha1.Sum(marshaledKey) + + return subjKeyID[:], nil +} + +// ParsePKIMap takes a map (for instance, the Secret.Data +// returned from the PKI backend) and returns a ParsedCertBundle. +func ParsePKIMap(data map[string]interface{}) (*ParsedCertBundle, error) { + result := &CertBundle{} + err := mapstructure.Decode(data, result) + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + + return result.ToParsedCertBundle() +} + +// ParsePKIJSON takes a JSON-encoded string and returns a ParsedCertBundle. +// +// This can be either the output of an +// issue call from the PKI backend or just its data member; or, +// JSON not coming from the PKI backend. +func ParsePKIJSON(input []byte) (*ParsedCertBundle, error) { + result := &CertBundle{} + err := jsonutil.DecodeJSON(input, &result) + + if err == nil { + return result.ToParsedCertBundle() + } + + var secret Secret + err = jsonutil.DecodeJSON(input, &secret) + + if err == nil { + return ParsePKIMap(secret.Data) + } + + return nil, errutil.UserError{Err: "unable to parse out of either secret data or a secret object"} +} + +// ParsePEMBundle takes a string of concatenated PEM-format certificate +// and private key values and decodes/parses them, checking validity along +// the way. The first certificate must be the subject certificate and issuing +// certificates may follow. There must be at most one private key. +func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) { + if len(pemBundle) == 0 { + return nil, errutil.UserError{Err: "empty pem bundle"} + } + + pemBytes := []byte(pemBundle) + var pemBlock *pem.Block + parsedBundle := &ParsedCertBundle{} + var certPath []*CertBlock + + for len(pemBytes) > 0 { + pemBlock, pemBytes = pem.Decode(pemBytes) + if pemBlock == nil { + return nil, errutil.UserError{Err: "no data found in PEM block"} + } + + if signer, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil { + if parsedBundle.PrivateKeyType != UnknownPrivateKey { + return nil, errutil.UserError{Err: "more than one private key given; provide only one private key in the bundle"} + } + parsedBundle.PrivateKeyFormat = ECBlock + parsedBundle.PrivateKeyType = ECPrivateKey + parsedBundle.PrivateKeyBytes = pemBlock.Bytes + parsedBundle.PrivateKey = signer + + } else if signer, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil { + if parsedBundle.PrivateKeyType != UnknownPrivateKey { + return nil, errutil.UserError{Err: "more than one private key given; provide only one private key in the bundle"} + } + parsedBundle.PrivateKeyType = RSAPrivateKey + parsedBundle.PrivateKeyFormat = PKCS1Block + parsedBundle.PrivateKeyBytes = pemBlock.Bytes + parsedBundle.PrivateKey = signer + } else if signer, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes); err == nil { + parsedBundle.PrivateKeyFormat = PKCS8Block + + if parsedBundle.PrivateKeyType != UnknownPrivateKey { + return nil, errutil.UserError{Err: "More than one private key given; provide only one private key in the bundle"} + } + switch signer := signer.(type) { + case *rsa.PrivateKey: + parsedBundle.PrivateKey = signer + parsedBundle.PrivateKeyType = RSAPrivateKey + parsedBundle.PrivateKeyBytes = pemBlock.Bytes + case *ecdsa.PrivateKey: + parsedBundle.PrivateKey = signer + parsedBundle.PrivateKeyType = ECPrivateKey + parsedBundle.PrivateKeyBytes = pemBlock.Bytes + } + } else if certificates, err := x509.ParseCertificates(pemBlock.Bytes); err == nil { + certPath = append(certPath, &CertBlock{ + Certificate: certificates[0], + Bytes: pemBlock.Bytes, + }) + } + } + + for i, certBlock := range certPath { + if i == 0 { + parsedBundle.Certificate = certBlock.Certificate + parsedBundle.CertificateBytes = certBlock.Bytes + } else { + parsedBundle.CAChain = append(parsedBundle.CAChain, certBlock) + } + } + + if err := parsedBundle.Verify(); err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("verification of parsed bundle failed: %s", err)} + } + + return parsedBundle, nil +} + +// GeneratePrivateKey generates a private key with the specified type and key bits +func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error { + var err error + var privateKeyType PrivateKeyType + var privateKeyBytes []byte + var privateKey crypto.Signer + + switch keyType { + case "rsa": + privateKeyType = RSAPrivateKey + privateKey, err = rsa.GenerateKey(rand.Reader, keyBits) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)} + } + privateKeyBytes = x509.MarshalPKCS1PrivateKey(privateKey.(*rsa.PrivateKey)) + case "ec": + privateKeyType = ECPrivateKey + var curve elliptic.Curve + switch keyBits { + case 224: + curve = elliptic.P224() + case 256: + curve = elliptic.P256() + case 384: + curve = elliptic.P384() + case 521: + curve = elliptic.P521() + default: + return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)} + } + privateKey, err = ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)} + } + privateKeyBytes, err = x509.MarshalECPrivateKey(privateKey.(*ecdsa.PrivateKey)) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error marshalling EC private key: %v", err)} + } + default: + return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)} + } + + container.SetParsedPrivateKey(privateKey, privateKeyType, privateKeyBytes) + return nil +} + +// GenerateSerialNumber generates a serial number suitable for a certificate +func GenerateSerialNumber() (*big.Int, error) { + serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil)) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)} + } + return serial, nil +} + +// ComparePublicKeys compares two public keys and returns true if they match +func ComparePublicKeys(key1Iface, key2Iface crypto.PublicKey) (bool, error) { + switch key1Iface.(type) { + case *rsa.PublicKey: + key1 := key1Iface.(*rsa.PublicKey) + key2, ok := key2Iface.(*rsa.PublicKey) + if !ok { + return false, fmt.Errorf("key types do not match: %T and %T", key1Iface, key2Iface) + } + if key1.N.Cmp(key2.N) != 0 || + key1.E != key2.E { + return false, nil + } + return true, nil + + case *ecdsa.PublicKey: + key1 := key1Iface.(*ecdsa.PublicKey) + key2, ok := key2Iface.(*ecdsa.PublicKey) + if !ok { + return false, fmt.Errorf("key types do not match: %T and %T", key1Iface, key2Iface) + } + if key1.X.Cmp(key2.X) != 0 || + key1.Y.Cmp(key2.Y) != 0 { + return false, nil + } + key1Params := key1.Params() + key2Params := key2.Params() + if key1Params.P.Cmp(key2Params.P) != 0 || + key1Params.N.Cmp(key2Params.N) != 0 || + key1Params.B.Cmp(key2Params.B) != 0 || + key1Params.Gx.Cmp(key2Params.Gx) != 0 || + key1Params.Gy.Cmp(key2Params.Gy) != 0 || + key1Params.BitSize != key2Params.BitSize { + return false, nil + } + return true, nil + + default: + return false, fmt.Errorf("cannot compare key with type %T", key1Iface) + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/certutil/types.go b/vendor/github.com/hashicorp/vault/helper/certutil/types.go new file mode 100644 index 0000000..fb30bef --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/certutil/types.go @@ -0,0 +1,595 @@ +// Package certutil contains helper functions that are mostly used +// with the PKI backend but can be generally useful. Functionality +// includes helpers for converting a certificate/private key bundle +// between DER and PEM, printing certificate serial numbers, and more. +// +// Functionality specific to the PKI backend includes some types +// and helper methods to make requesting certificates from the +// backend easy. +package certutil + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "math/big" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/errutil" +) + +// Secret is used to attempt to unmarshal a Vault secret +// JSON response, as a convenience +type Secret struct { + Data map[string]interface{} `json:"data"` +} + +// PrivateKeyType holds a string representation of the type of private key (ec +// or rsa) referenced in CertBundle and ParsedCertBundle. This uses colloquial +// names rather than official names, to eliminate confusion +type PrivateKeyType string + +//Well-known PrivateKeyTypes +const ( + UnknownPrivateKey PrivateKeyType = "" + RSAPrivateKey PrivateKeyType = "rsa" + ECPrivateKey PrivateKeyType = "ec" +) + +// TLSUsage controls whether the intended usage of a *tls.Config +// returned from ParsedCertBundle.getTLSConfig is for server use, +// client use, or both, which affects which values are set +type TLSUsage int + +//Well-known TLSUsage types +const ( + TLSUnknown TLSUsage = 0 + TLSServer TLSUsage = 1 << iota + TLSClient +) + +//BlockType indicates the serialization format of the key +type BlockType string + +//Well-known formats +const ( + PKCS1Block BlockType = "RSA PRIVATE KEY" + PKCS8Block BlockType = "PRIVATE KEY" + ECBlock BlockType = "EC PRIVATE KEY" +) + +//ParsedPrivateKeyContainer allows common key setting for certs and CSRs +type ParsedPrivateKeyContainer interface { + SetParsedPrivateKey(crypto.Signer, PrivateKeyType, []byte) +} + +// CertBlock contains the DER-encoded certificate and the PEM +// block's byte array +type CertBlock struct { + Certificate *x509.Certificate + Bytes []byte +} + +// CertBundle contains a key type, a PEM-encoded private key, +// a PEM-encoded certificate, and a string-encoded serial number, +// returned from a successful Issue request +type CertBundle struct { + PrivateKeyType PrivateKeyType `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` + Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` + IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"` + CAChain []string `json:"ca_chain" structs:"ca_chain" mapstructure:"ca_chain"` + PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` + SerialNumber string `json:"serial_number" structs:"serial_number" mapstructure:"serial_number"` +} + +// ParsedCertBundle contains a key type, a DER-encoded private key, +// and a DER-encoded certificate +type ParsedCertBundle struct { + PrivateKeyType PrivateKeyType + PrivateKeyFormat BlockType + PrivateKeyBytes []byte + PrivateKey crypto.Signer + CertificateBytes []byte + Certificate *x509.Certificate + CAChain []*CertBlock + SerialNumber *big.Int +} + +// CSRBundle contains a key type, a PEM-encoded private key, +// and a PEM-encoded CSR +type CSRBundle struct { + PrivateKeyType PrivateKeyType `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` + CSR string `json:"csr" structs:"csr" mapstructure:"csr"` + PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` +} + +// ParsedCSRBundle contains a key type, a DER-encoded private key, +// and a DER-encoded certificate request +type ParsedCSRBundle struct { + PrivateKeyType PrivateKeyType + PrivateKeyBytes []byte + PrivateKey crypto.Signer + CSRBytes []byte + CSR *x509.CertificateRequest +} + +// ToPEMBundle converts a string-based certificate bundle +// to a PEM-based string certificate bundle in trust path +// order, leaf certificate first +func (c *CertBundle) ToPEMBundle() string { + var result []string + + if len(c.PrivateKey) > 0 { + result = append(result, c.PrivateKey) + } + if len(c.Certificate) > 0 { + result = append(result, c.Certificate) + } + if len(c.CAChain) > 0 { + result = append(result, c.CAChain...) + } + + return strings.Join(result, "\n") +} + +// ToParsedCertBundle converts a string-based certificate bundle +// to a byte-based raw certificate bundle +func (c *CertBundle) ToParsedCertBundle() (*ParsedCertBundle, error) { + result := &ParsedCertBundle{} + var err error + var pemBlock *pem.Block + + if len(c.PrivateKey) > 0 { + pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding private key from cert bundle"} + } + + result.PrivateKeyBytes = pemBlock.Bytes + result.PrivateKeyFormat = BlockType(strings.TrimSpace(pemBlock.Type)) + + switch result.PrivateKeyFormat { + case ECBlock: + result.PrivateKeyType, c.PrivateKeyType = ECPrivateKey, ECPrivateKey + case PKCS1Block: + c.PrivateKeyType, result.PrivateKeyType = RSAPrivateKey, RSAPrivateKey + case PKCS8Block: + t, err := getPKCS8Type(pemBlock.Bytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error getting key type from pkcs#8: %v", err)} + } + result.PrivateKeyType = t + switch t { + case ECPrivateKey: + c.PrivateKeyType = ECPrivateKey + case RSAPrivateKey: + c.PrivateKeyType = RSAPrivateKey + } + default: + return nil, errutil.UserError{Err: fmt.Sprintf("Unsupported key block type: %s", pemBlock.Type)} + } + + result.PrivateKey, err = result.getSigner() + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error getting signer: %s", err)} + } + } + + if len(c.Certificate) > 0 { + pemBlock, _ = pem.Decode([]byte(c.Certificate)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} + } + result.CertificateBytes = pemBlock.Bytes + result.Certificate, err = x509.ParseCertificate(result.CertificateBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle: %v", err)} + } + } + switch { + case len(c.CAChain) > 0: + for _, cert := range c.CAChain { + pemBlock, _ := pem.Decode([]byte(cert)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} + } + + parsedCert, err := x509.ParseCertificate(pemBlock.Bytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via CA chain: %v", err)} + } + + certBlock := &CertBlock{ + Bytes: pemBlock.Bytes, + Certificate: parsedCert, + } + result.CAChain = append(result.CAChain, certBlock) + } + + // For backwards compatibility + case len(c.IssuingCA) > 0: + pemBlock, _ = pem.Decode([]byte(c.IssuingCA)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding ca certificate from cert bundle"} + } + + parsedCert, err := x509.ParseCertificate(pemBlock.Bytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via issuing CA: %v", err)} + } + + result.SerialNumber = result.Certificate.SerialNumber + + certBlock := &CertBlock{ + Bytes: pemBlock.Bytes, + Certificate: parsedCert, + } + result.CAChain = append(result.CAChain, certBlock) + } + + // Populate if it isn't there already + if len(c.SerialNumber) == 0 && len(c.Certificate) > 0 { + c.SerialNumber = GetHexFormatted(result.Certificate.SerialNumber.Bytes(), ":") + } + + return result, nil +} + +// ToCertBundle converts a byte-based raw DER certificate bundle +// to a PEM-based string certificate bundle +func (p *ParsedCertBundle) ToCertBundle() (*CertBundle, error) { + result := &CertBundle{} + block := pem.Block{ + Type: "CERTIFICATE", + } + + if p.Certificate != nil { + result.SerialNumber = strings.TrimSpace(GetHexFormatted(p.Certificate.SerialNumber.Bytes(), ":")) + } + + if p.CertificateBytes != nil && len(p.CertificateBytes) > 0 { + block.Bytes = p.CertificateBytes + result.Certificate = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + for _, caCert := range p.CAChain { + block.Bytes = caCert.Bytes + certificate := strings.TrimSpace(string(pem.EncodeToMemory(&block))) + + result.CAChain = append(result.CAChain, certificate) + } + + if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { + block.Type = string(p.PrivateKeyFormat) + block.Bytes = p.PrivateKeyBytes + result.PrivateKeyType = p.PrivateKeyType + + //Handle bundle not parsed by us + if block.Type == "" { + switch p.PrivateKeyType { + case ECPrivateKey: + block.Type = string(ECBlock) + case RSAPrivateKey: + block.Type = string(PKCS1Block) + } + } + + result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + return result, nil +} + +// Verify checks if the parsed bundle is valid. It validates the public +// key of the certificate to the private key and checks the certificate trust +// chain for path issues. +func (p *ParsedCertBundle) Verify() error { + // If private key exists, check if it matches the public key of cert + if p.PrivateKey != nil && p.Certificate != nil { + equal, err := ComparePublicKeys(p.Certificate.PublicKey, p.PrivateKey.Public()) + if err != nil { + return errwrap.Wrapf("could not compare public and private keys: {{err}}", err) + } + if !equal { + return fmt.Errorf("public key of certificate does not match private key") + } + } + + certPath := p.GetCertificatePath() + if len(certPath) > 1 { + for i, caCert := range certPath[1:] { + if !caCert.Certificate.IsCA { + return fmt.Errorf("certificate %d of certificate chain is not a certificate authority", i+1) + } + if !bytes.Equal(certPath[i].Certificate.AuthorityKeyId, caCert.Certificate.SubjectKeyId) { + return fmt.Errorf("certificate %d of certificate chain ca trust path is incorrect (%q/%q)", + i+1, certPath[i].Certificate.Subject.CommonName, caCert.Certificate.Subject.CommonName) + } + } + } + + return nil +} + +// GetCertificatePath returns a slice of certificates making up a path, pulled +// from the parsed cert bundle +func (p *ParsedCertBundle) GetCertificatePath() []*CertBlock { + var certPath []*CertBlock + + certPath = append(certPath, &CertBlock{ + Certificate: p.Certificate, + Bytes: p.CertificateBytes, + }) + + if len(p.CAChain) > 0 { + // Root CA puts itself in the chain + if p.CAChain[0].Certificate.SerialNumber != p.Certificate.SerialNumber { + certPath = append(certPath, p.CAChain...) + } + } + + return certPath +} + +// GetSigner returns a crypto.Signer corresponding to the private key +// contained in this ParsedCertBundle. The Signer contains a Public() function +// for getting the corresponding public. The Signer can also be +// type-converted to private keys +func (p *ParsedCertBundle) getSigner() (crypto.Signer, error) { + var signer crypto.Signer + var err error + + if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { + return nil, errutil.UserError{Err: "Given parsed cert bundle does not have private key information"} + } + + switch p.PrivateKeyFormat { + case ECBlock: + signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} + } + + case PKCS1Block: + signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} + } + + case PKCS8Block: + if k, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes); err == nil { + switch k := k.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey: + return k.(crypto.Signer), nil + default: + return nil, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"} + } + } + return nil, errutil.UserError{Err: fmt.Sprintf("Failed to parse pkcs#8 key: %v", err)} + default: + return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA and EC are supported"} + } + return signer, nil +} + +// SetParsedPrivateKey sets the private key parameters on the bundle +func (p *ParsedCertBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType PrivateKeyType, privateKeyBytes []byte) { + p.PrivateKey = privateKey + p.PrivateKeyType = privateKeyType + p.PrivateKeyBytes = privateKeyBytes +} + +func getPKCS8Type(bs []byte) (PrivateKeyType, error) { + k, err := x509.ParsePKCS8PrivateKey(bs) + if err != nil { + return UnknownPrivateKey, errutil.UserError{Err: fmt.Sprintf("Failed to parse pkcs#8 key: %v", err)} + } + + switch k.(type) { + case *ecdsa.PrivateKey: + return ECPrivateKey, nil + case *rsa.PrivateKey: + return RSAPrivateKey, nil + default: + return UnknownPrivateKey, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"} + } +} + +// ToParsedCSRBundle converts a string-based CSR bundle +// to a byte-based raw CSR bundle +func (c *CSRBundle) ToParsedCSRBundle() (*ParsedCSRBundle, error) { + result := &ParsedCSRBundle{} + var err error + var pemBlock *pem.Block + + if len(c.PrivateKey) > 0 { + pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding private key from cert bundle"} + } + result.PrivateKeyBytes = pemBlock.Bytes + + switch BlockType(pemBlock.Type) { + case ECBlock: + result.PrivateKeyType = ECPrivateKey + case PKCS1Block: + result.PrivateKeyType = RSAPrivateKey + default: + // Try to figure it out and correct + if _, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil { + result.PrivateKeyType = ECPrivateKey + c.PrivateKeyType = "ec" + } else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil { + result.PrivateKeyType = RSAPrivateKey + c.PrivateKeyType = "rsa" + } else { + return nil, errutil.UserError{Err: fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)} + } + } + + result.PrivateKey, err = result.getSigner() + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error getting signer: %s", err)} + } + } + + if len(c.CSR) > 0 { + pemBlock, _ = pem.Decode([]byte(c.CSR)) + if pemBlock == nil { + return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} + } + result.CSRBytes = pemBlock.Bytes + result.CSR, err = x509.ParseCertificateRequest(result.CSRBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via CSR: %v", err)} + } + } + + return result, nil +} + +// ToCSRBundle converts a byte-based raw DER certificate bundle +// to a PEM-based string certificate bundle +func (p *ParsedCSRBundle) ToCSRBundle() (*CSRBundle, error) { + result := &CSRBundle{} + block := pem.Block{ + Type: "CERTIFICATE REQUEST", + } + + if p.CSRBytes != nil && len(p.CSRBytes) > 0 { + block.Bytes = p.CSRBytes + result.CSR = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { + block.Bytes = p.PrivateKeyBytes + switch p.PrivateKeyType { + case RSAPrivateKey: + result.PrivateKeyType = "rsa" + block.Type = "RSA PRIVATE KEY" + case ECPrivateKey: + result.PrivateKeyType = "ec" + block.Type = "EC PRIVATE KEY" + default: + return nil, errutil.InternalError{Err: "Could not determine private key type when creating block"} + } + result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + return result, nil +} + +// GetSigner returns a crypto.Signer corresponding to the private key +// contained in this ParsedCSRBundle. The Signer contains a Public() function +// for getting the corresponding public. The Signer can also be +// type-converted to private keys +func (p *ParsedCSRBundle) getSigner() (crypto.Signer, error) { + var signer crypto.Signer + var err error + + if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { + return nil, errutil.UserError{Err: "Given parsed cert bundle does not have private key information"} + } + + switch p.PrivateKeyType { + case ECPrivateKey: + signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} + } + + case RSAPrivateKey: + signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} + } + + default: + return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA and EC are supported"} + } + return signer, nil +} + +// SetParsedPrivateKey sets the private key parameters on the bundle +func (p *ParsedCSRBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType PrivateKeyType, privateKeyBytes []byte) { + p.PrivateKey = privateKey + p.PrivateKeyType = privateKeyType + p.PrivateKeyBytes = privateKeyBytes +} + +// getTLSConfig returns a TLS config generally suitable for client +// authentication. The returned TLS config can be modified slightly +// to be made suitable for a server requiring client authentication; +// specifically, you should set the value of ClientAuth in the returned +// config to match your needs. +func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) { + tlsCert := tls.Certificate{ + Certificate: [][]byte{}, + } + + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, + } + + if p.Certificate != nil { + tlsCert.Leaf = p.Certificate + } + + if p.PrivateKey != nil { + tlsCert.PrivateKey = p.PrivateKey + } + + if p.CertificateBytes != nil && len(p.CertificateBytes) > 0 { + tlsCert.Certificate = append(tlsCert.Certificate, p.CertificateBytes) + } + + if len(p.CAChain) > 0 { + for _, cert := range p.CAChain { + tlsCert.Certificate = append(tlsCert.Certificate, cert.Bytes) + } + + // Technically we only need one cert, but this doesn't duplicate code + certBundle, err := p.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting parsed bundle to string bundle when getting TLS config: {{err}}", err) + } + + caPool := x509.NewCertPool() + ok := caPool.AppendCertsFromPEM([]byte(certBundle.CAChain[0])) + if !ok { + return nil, fmt.Errorf("could not append CA certificate") + } + + if usage&TLSServer > 0 { + tlsConfig.ClientCAs = caPool + tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven + } + if usage&TLSClient > 0 { + tlsConfig.RootCAs = caPool + } + } + + if tlsCert.Certificate != nil && len(tlsCert.Certificate) > 0 { + tlsConfig.Certificates = []tls.Certificate{tlsCert} + tlsConfig.BuildNameToCertificate() + } + + return tlsConfig, nil +} + +// IssueData is a structure that is suitable for marshaling into a request; +// either via JSON, or into a map[string]interface{} via the structs package +type IssueData struct { + TTL string `json:"ttl" structs:"ttl" mapstructure:"ttl"` + CommonName string `json:"common_name" structs:"common_name" mapstructure:"common_name"` + OU string `json:"ou" structs:"ou" mapstructure:"ou"` + AltNames string `json:"alt_names" structs:"alt_names" mapstructure:"alt_names"` + IPSANs string `json:"ip_sans" structs:"ip_sans" mapstructure:"ip_sans"` + CSR string `json:"csr" structs:"csr" mapstructure:"csr"` +} diff --git a/vendor/github.com/hashicorp/vault/helper/cidrutil/cidr.go b/vendor/github.com/hashicorp/vault/helper/cidrutil/cidr.go new file mode 100644 index 0000000..6ecdba7 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/cidrutil/cidr.go @@ -0,0 +1,217 @@ +package cidrutil + +import ( + "fmt" + "net" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/helper/strutil" +) + +// RemoteAddrIsOk checks if the given remote address is either: +// - OK because there's no CIDR whitelist +// - OK because it's in the CIDR whitelist +func RemoteAddrIsOk(remoteAddr string, boundCIDRs []*sockaddr.SockAddrMarshaler) bool { + if len(boundCIDRs) == 0 { + // There's no CIDR whitelist. + return true + } + remoteSockAddr, err := sockaddr.NewSockAddr(remoteAddr) + if err != nil { + // Can't tell, err on the side of less access. + return false + } + for _, cidr := range boundCIDRs { + if cidr.Contains(remoteSockAddr) { + // Whitelisted. + return true + } + } + // Not whitelisted. + return false +} + +// IPBelongsToCIDR checks if the given IP is encompassed by the given CIDR block +func IPBelongsToCIDR(ipAddr string, cidr string) (bool, error) { + if ipAddr == "" { + return false, fmt.Errorf("missing IP address") + } + + ip := net.ParseIP(ipAddr) + if ip == nil { + return false, fmt.Errorf("invalid IP address") + } + + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return false, err + } + + if !ipnet.Contains(ip) { + return false, nil + } + + return true, nil +} + +// IPBelongsToCIDRBlocksSlice checks if the given IP is encompassed by any of the given +// CIDR blocks +func IPBelongsToCIDRBlocksSlice(ipAddr string, cidrs []string) (bool, error) { + if ipAddr == "" { + return false, fmt.Errorf("missing IP address") + } + + if len(cidrs) == 0 { + return false, fmt.Errorf("missing CIDR blocks to be checked against") + } + + if ip := net.ParseIP(ipAddr); ip == nil { + return false, fmt.Errorf("invalid IP address") + } + + for _, cidr := range cidrs { + belongs, err := IPBelongsToCIDR(ipAddr, cidr) + if err != nil { + return false, err + } + if belongs { + return true, nil + } + } + + return false, nil +} + +// ValidateCIDRListString checks if the list of CIDR blocks are valid, given +// that the input is a string composed by joining all the CIDR blocks using a +// separator. The input is separated based on the given separator and validity +// of each is checked. +func ValidateCIDRListString(cidrList string, separator string) (bool, error) { + if cidrList == "" { + return false, fmt.Errorf("missing CIDR list that needs validation") + } + if separator == "" { + return false, fmt.Errorf("missing separator") + } + + return ValidateCIDRListSlice(strutil.ParseDedupLowercaseAndSortStrings(cidrList, separator)) +} + +// ValidateCIDRListSlice checks if the given list of CIDR blocks are valid +func ValidateCIDRListSlice(cidrBlocks []string) (bool, error) { + if len(cidrBlocks) == 0 { + return false, fmt.Errorf("missing CIDR blocks that needs validation") + } + + for _, block := range cidrBlocks { + if _, _, err := net.ParseCIDR(strings.TrimSpace(block)); err != nil { + return false, err + } + } + + return true, nil +} + +// Subset checks if the IPs belonging to a given CIDR block is a subset of IPs +// belonging to another CIDR block. +func Subset(cidr1, cidr2 string) (bool, error) { + if cidr1 == "" { + return false, fmt.Errorf("missing CIDR to be checked against") + } + + if cidr2 == "" { + return false, fmt.Errorf("missing CIDR that needs to be checked") + } + + ip1, net1, err := net.ParseCIDR(cidr1) + if err != nil { + return false, errwrap.Wrapf("failed to parse the CIDR to be checked against: {{err}}", err) + } + + zeroAddr := false + if ip := ip1.To4(); ip != nil && ip.Equal(net.IPv4zero) { + zeroAddr = true + } + if ip := ip1.To16(); ip != nil && ip.Equal(net.IPv6zero) { + zeroAddr = true + } + + maskLen1, _ := net1.Mask.Size() + if !zeroAddr && maskLen1 == 0 { + return false, fmt.Errorf("CIDR to be checked against is not in its canonical form") + } + + ip2, net2, err := net.ParseCIDR(cidr2) + if err != nil { + return false, errwrap.Wrapf("failed to parse the CIDR that needs to be checked: {{err}}", err) + } + + zeroAddr = false + if ip := ip2.To4(); ip != nil && ip.Equal(net.IPv4zero) { + zeroAddr = true + } + if ip := ip2.To16(); ip != nil && ip.Equal(net.IPv6zero) { + zeroAddr = true + } + + maskLen2, _ := net2.Mask.Size() + if !zeroAddr && maskLen2 == 0 { + return false, fmt.Errorf("CIDR that needs to be checked is not in its canonical form") + } + + // If the mask length of the CIDR that needs to be checked is smaller + // then the mask length of the CIDR to be checked against, then the + // former will encompass more IPs than the latter, and hence can't be a + // subset of the latter. + if maskLen2 < maskLen1 { + return false, nil + } + + belongs, err := IPBelongsToCIDR(net2.IP.String(), cidr1) + if err != nil { + return false, err + } + + return belongs, nil +} + +// SubsetBlocks checks if each CIDR block of a given set of CIDR blocks, is a +// subset of at least one CIDR block belonging to another set of CIDR blocks. +// First parameter is the set of CIDR blocks to check against and the second +// parameter is the set of CIDR blocks that needs to be checked. +func SubsetBlocks(cidrBlocks1, cidrBlocks2 []string) (bool, error) { + if len(cidrBlocks1) == 0 { + return false, fmt.Errorf("missing CIDR blocks to be checked against") + } + + if len(cidrBlocks2) == 0 { + return false, fmt.Errorf("missing CIDR blocks that needs to be checked") + } + + // Check if all the elements of cidrBlocks2 is a subset of at least one + // element of cidrBlocks1 + for _, cidrBlock2 := range cidrBlocks2 { + isSubset := false + for _, cidrBlock1 := range cidrBlocks1 { + subset, err := Subset(cidrBlock1, cidrBlock2) + if err != nil { + return false, err + } + // If CIDR is a subset of any of the CIDR block, its + // good enough. Break out. + if subset { + isSubset = true + break + } + } + // CIDR block was not a subset of any of the CIDR blocks in the + // set of blocks to check against + if !isSubset { + return false, nil + } + } + + return true, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/compressutil/compress.go b/vendor/github.com/hashicorp/vault/helper/compressutil/compress.go new file mode 100644 index 0000000..a7fb87b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/compressutil/compress.go @@ -0,0 +1,192 @@ +package compressutil + +import ( + "bytes" + "compress/gzip" + "compress/lzw" + "fmt" + "io" + + "github.com/golang/snappy" + "github.com/hashicorp/errwrap" +) + +const ( + // A byte value used as a canary prefix for the compressed information + // which is used to distinguish if a JSON input is compressed or not. + // The value of this constant should not be a first character of any + // valid JSON string. + + // Byte value used as canary when using Gzip format + CompressionCanaryGzip byte = 'G' + + // Byte value used as canary when using Lzw format + CompressionCanaryLzw byte = 'L' + + // Byte value used as canary when using Snappy format + CompressionCanarySnappy byte = 'S' + + CompressionTypeLzw = "lzw" + + CompressionTypeGzip = "gzip" + + CompressionTypeSnappy = "snappy" +) + +// SnappyReadCloser embeds the snappy reader which implements the io.Reader +// interface. The decompress procedure in this utility expects an +// io.ReadCloser. This type implements the io.Closer interface to retain the +// generic way of decompression. +type SnappyReadCloser struct { + *snappy.Reader +} + +// Close is a noop method implemented only to satisfy the io.Closer interface +func (s *SnappyReadCloser) Close() error { + return nil +} + +// CompressionConfig is used to select a compression type to be performed by +// Compress and Decompress utilities. +// Supported types are: +// * CompressionTypeLzw +// * CompressionTypeGzip +// * CompressionTypeSnappy +// +// When using CompressionTypeGzip, the compression levels can also be chosen: +// * gzip.DefaultCompression +// * gzip.BestSpeed +// * gzip.BestCompression +type CompressionConfig struct { + // Type of the compression algorithm to be used + Type string + + // When using Gzip format, the compression level to employ + GzipCompressionLevel int +} + +// Compress places the canary byte in a buffer and uses the same buffer to fill +// in the compressed information of the given input. The configuration supports +// two type of compression: LZW and Gzip. When using Gzip compression format, +// if GzipCompressionLevel is not specified, the 'gzip.DefaultCompression' will +// be assumed. +func Compress(data []byte, config *CompressionConfig) ([]byte, error) { + var buf bytes.Buffer + var writer io.WriteCloser + var err error + + if config == nil { + return nil, fmt.Errorf("config is nil") + } + + // Write the canary into the buffer and create writer to compress the + // input data based on the configured type + switch config.Type { + case CompressionTypeLzw: + buf.Write([]byte{CompressionCanaryLzw}) + + writer = lzw.NewWriter(&buf, lzw.LSB, 8) + case CompressionTypeGzip: + buf.Write([]byte{CompressionCanaryGzip}) + + switch { + case config.GzipCompressionLevel == gzip.BestCompression, + config.GzipCompressionLevel == gzip.BestSpeed, + config.GzipCompressionLevel == gzip.DefaultCompression: + // These are valid compression levels + default: + // If compression level is set to NoCompression or to + // any invalid value, fallback to Defaultcompression + config.GzipCompressionLevel = gzip.DefaultCompression + } + writer, err = gzip.NewWriterLevel(&buf, config.GzipCompressionLevel) + case CompressionTypeSnappy: + buf.Write([]byte{CompressionCanarySnappy}) + writer = snappy.NewBufferedWriter(&buf) + default: + return nil, fmt.Errorf("unsupported compression type") + } + + if err != nil { + return nil, errwrap.Wrapf("failed to create a compression writer: {{err}}", err) + } + + if writer == nil { + return nil, fmt.Errorf("failed to create a compression writer") + } + + // Compress the input and place it in the same buffer containing the + // canary byte. + if _, err = writer.Write(data); err != nil { + return nil, errwrap.Wrapf("failed to compress input data: err: {{err}}", err) + } + + // Close the io.WriteCloser + if err = writer.Close(); err != nil { + return nil, err + } + + // Return the compressed bytes with canary byte at the start + return buf.Bytes(), nil +} + +// Decompress checks if the first byte in the input matches the canary byte. +// If the first byte is a canary byte, then the input past the canary byte +// will be decompressed using the method specified in the given configuration. +// If the first byte isn't a canary byte, then the utility returns a boolean +// value indicating that the input was not compressed. +func Decompress(data []byte) ([]byte, bool, error) { + var err error + var reader io.ReadCloser + if data == nil || len(data) == 0 { + return nil, false, fmt.Errorf("'data' being decompressed is empty") + } + + switch { + // If the first byte matches the canary byte, remove the canary + // byte and try to decompress the data that is after the canary. + case data[0] == CompressionCanaryGzip: + if len(data) < 2 { + return nil, false, fmt.Errorf("invalid 'data' after the canary") + } + data = data[1:] + reader, err = gzip.NewReader(bytes.NewReader(data)) + case data[0] == CompressionCanaryLzw: + if len(data) < 2 { + return nil, false, fmt.Errorf("invalid 'data' after the canary") + } + data = data[1:] + reader = lzw.NewReader(bytes.NewReader(data), lzw.LSB, 8) + + case data[0] == CompressionCanarySnappy: + if len(data) < 2 { + return nil, false, fmt.Errorf("invalid 'data' after the canary") + } + data = data[1:] + reader = &SnappyReadCloser{ + Reader: snappy.NewReader(bytes.NewReader(data)), + } + default: + // If the first byte doesn't match the canary byte, it means + // that the content was not compressed at all. Indicate the + // caller that the input was not compressed. + return nil, true, nil + } + if err != nil { + return nil, false, errwrap.Wrapf("failed to create a compression reader: {{err}}", err) + } + if reader == nil { + return nil, false, fmt.Errorf("failed to create a compression reader") + } + + // Close the io.ReadCloser + defer reader.Close() + + // Read all the compressed data into a buffer + var buf bytes.Buffer + if _, err = io.Copy(&buf, reader); err != nil { + return nil, false, err + } + + return buf.Bytes(), false, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/consts/consts.go b/vendor/github.com/hashicorp/vault/helper/consts/consts.go new file mode 100644 index 0000000..eee59d9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/consts.go @@ -0,0 +1,7 @@ +package consts + +const ( + // ExpirationRestoreWorkerCount specifies the number of workers to use while + // restoring leases into the expiration manager + ExpirationRestoreWorkerCount = 64 +) diff --git a/vendor/github.com/hashicorp/vault/helper/consts/error.go b/vendor/github.com/hashicorp/vault/helper/consts/error.go new file mode 100644 index 0000000..06977d5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/error.go @@ -0,0 +1,16 @@ +package consts + +import "errors" + +var ( + // ErrSealed is returned if an operation is performed on a sealed barrier. + // No operation is expected to succeed before unsealing + ErrSealed = errors.New("Vault is sealed") + + // ErrStandby is returned if an operation is performed on a standby Vault. + // No operation is expected to succeed until active. + ErrStandby = errors.New("Vault is in standby mode") + + // Used when .. is used in a path + ErrPathContainsParentReferences = errors.New("path cannot contain parent references") +) diff --git a/vendor/github.com/hashicorp/vault/helper/consts/replication.go b/vendor/github.com/hashicorp/vault/helper/consts/replication.go new file mode 100644 index 0000000..c109977 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/replication.go @@ -0,0 +1,82 @@ +package consts + +type ReplicationState uint32 + +const ( + _ ReplicationState = iota + OldReplicationPrimary + OldReplicationSecondary + OldReplicationBootstrapping + // Don't add anything here. Adding anything to this Old block would cause + // the rest of the values to change below. This was done originally to + // ensure no overlap between old and new values. + + ReplicationUnknown ReplicationState = 0 + ReplicationPerformancePrimary ReplicationState = 1 << iota + ReplicationPerformanceSecondary + OldSplitReplicationBootstrapping + ReplicationDRPrimary + ReplicationDRSecondary + ReplicationPerformanceBootstrapping + ReplicationDRBootstrapping + ReplicationPerformanceDisabled + ReplicationDRDisabled +) + +func (r ReplicationState) string() string { + switch r { + case ReplicationPerformanceSecondary: + return "secondary" + case ReplicationPerformancePrimary: + return "primary" + case ReplicationPerformanceBootstrapping: + return "bootstrapping" + case ReplicationPerformanceDisabled: + return "disabled" + case ReplicationDRPrimary: + return "primary" + case ReplicationDRSecondary: + return "secondary" + case ReplicationDRBootstrapping: + return "bootstrapping" + case ReplicationDRDisabled: + return "disabled" + } + + return "unknown" +} + +func (r ReplicationState) GetDRString() string { + switch { + case r.HasState(ReplicationDRBootstrapping): + return ReplicationDRBootstrapping.string() + case r.HasState(ReplicationDRPrimary): + return ReplicationDRPrimary.string() + case r.HasState(ReplicationDRSecondary): + return ReplicationDRSecondary.string() + case r.HasState(ReplicationDRDisabled): + return ReplicationDRDisabled.string() + default: + return "unknown" + } +} + +func (r ReplicationState) GetPerformanceString() string { + switch { + case r.HasState(ReplicationPerformanceBootstrapping): + return ReplicationPerformanceBootstrapping.string() + case r.HasState(ReplicationPerformancePrimary): + return ReplicationPerformancePrimary.string() + case r.HasState(ReplicationPerformanceSecondary): + return ReplicationPerformanceSecondary.string() + case r.HasState(ReplicationPerformanceDisabled): + return ReplicationPerformanceDisabled.string() + default: + return "unknown" + } +} + +func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 } +func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag } +func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag } +func (r *ReplicationState) ToggleState(flag ReplicationState) { *r ^= flag } diff --git a/vendor/github.com/hashicorp/vault/helper/dbtxn/dbtxn.go b/vendor/github.com/hashicorp/vault/helper/dbtxn/dbtxn.go new file mode 100644 index 0000000..3337bd9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/dbtxn/dbtxn.go @@ -0,0 +1,63 @@ +package dbtxn + +import ( + "context" + "database/sql" + "fmt" + "strings" +) + +// ExecuteDBQuery handles executing one single statement, while properly releasing its resources. +// - ctx: Required +// - db: Required +// - config: Optional, may be nil +// - query: Required +func ExecuteDBQuery(ctx context.Context, db *sql.DB, params map[string]string, query string) error { + + parsedQuery := parseQuery(params, query) + + stmt, err := db.PrepareContext(ctx, parsedQuery) + if err != nil { + return err + } + defer stmt.Close() + + return execute(ctx, stmt) +} + +// ExecuteTxQuery handles executing one single statement, while properly releasing its resources. +// - ctx: Required +// - tx: Required +// - config: Optional, may be nil +// - query: Required +func ExecuteTxQuery(ctx context.Context, tx *sql.Tx, params map[string]string, query string) error { + + parsedQuery := parseQuery(params, query) + + stmt, err := tx.PrepareContext(ctx, parsedQuery) + if err != nil { + return err + } + defer stmt.Close() + + return execute(ctx, stmt) +} + +func execute(ctx context.Context, stmt *sql.Stmt) error { + if _, err := stmt.ExecContext(ctx); err != nil { + return err + } + return nil +} + +func parseQuery(m map[string]string, tpl string) string { + + if m == nil || len(m) <= 0 { + return tpl + } + + for k, v := range m { + tpl = strings.Replace(tpl, fmt.Sprintf("{{%s}}", k), v, -1) + } + return tpl +} diff --git a/vendor/github.com/hashicorp/vault/helper/errutil/error.go b/vendor/github.com/hashicorp/vault/helper/errutil/error.go new file mode 100644 index 0000000..0b95efb --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/errutil/error.go @@ -0,0 +1,20 @@ +package errutil + +// UserError represents an error generated due to invalid user input +type UserError struct { + Err string +} + +func (e UserError) Error() string { + return e.Err +} + +// InternalError represents an error generated internally, +// presumably not due to invalid user input +type InternalError struct { + Err string +} + +func (e InternalError) Error() string { + return e.Err +} diff --git a/vendor/github.com/hashicorp/vault/helper/forwarding/types.pb.go b/vendor/github.com/hashicorp/vault/helper/forwarding/types.pb.go new file mode 100644 index 0000000..0e5338c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/forwarding/types.pb.go @@ -0,0 +1,343 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: helper/forwarding/types.proto + +package forwarding // import "github.com/hashicorp/vault/helper/forwarding" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Request struct { + // Not used right now but reserving in case it turns out that streaming + // makes things more economical on the gRPC side + // uint64 id = 1; + Method string `protobuf:"bytes,2,opt,name=method" json:"method,omitempty"` + Url *URL `protobuf:"bytes,3,opt,name=url" json:"url,omitempty"` + HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` + Host string `protobuf:"bytes,6,opt,name=host" json:"host,omitempty"` + RemoteAddr string `protobuf:"bytes,7,opt,name=remote_addr,json=remoteAddr" json:"remote_addr,omitempty"` + PeerCertificates [][]byte `protobuf:"bytes,8,rep,name=peer_certificates,json=peerCertificates,proto3" json:"peer_certificates,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_types_6ebfa235129f89d8, []int{0} +} +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (dst *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(dst, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetMethod() string { + if m != nil { + return m.Method + } + return "" +} + +func (m *Request) GetUrl() *URL { + if m != nil { + return m.Url + } + return nil +} + +func (m *Request) GetHeaderEntries() map[string]*HeaderEntry { + if m != nil { + return m.HeaderEntries + } + return nil +} + +func (m *Request) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +func (m *Request) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *Request) GetRemoteAddr() string { + if m != nil { + return m.RemoteAddr + } + return "" +} + +func (m *Request) GetPeerCertificates() [][]byte { + if m != nil { + return m.PeerCertificates + } + return nil +} + +type URL struct { + Scheme string `protobuf:"bytes,1,opt,name=scheme" json:"scheme,omitempty"` + Opaque string `protobuf:"bytes,2,opt,name=opaque" json:"opaque,omitempty"` + // This isn't needed now but might be in the future, so we'll skip the + // number to keep the ordering in net/url + // UserInfo user = 3; + Host string `protobuf:"bytes,4,opt,name=host" json:"host,omitempty"` + Path string `protobuf:"bytes,5,opt,name=path" json:"path,omitempty"` + RawPath string `protobuf:"bytes,6,opt,name=raw_path,json=rawPath" json:"raw_path,omitempty"` + // This also isn't needed right now, but we'll reserve the number + // bool force_query = 7; + RawQuery string `protobuf:"bytes,8,opt,name=raw_query,json=rawQuery" json:"raw_query,omitempty"` + Fragment string `protobuf:"bytes,9,opt,name=fragment" json:"fragment,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *URL) Reset() { *m = URL{} } +func (m *URL) String() string { return proto.CompactTextString(m) } +func (*URL) ProtoMessage() {} +func (*URL) Descriptor() ([]byte, []int) { + return fileDescriptor_types_6ebfa235129f89d8, []int{1} +} +func (m *URL) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_URL.Unmarshal(m, b) +} +func (m *URL) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_URL.Marshal(b, m, deterministic) +} +func (dst *URL) XXX_Merge(src proto.Message) { + xxx_messageInfo_URL.Merge(dst, src) +} +func (m *URL) XXX_Size() int { + return xxx_messageInfo_URL.Size(m) +} +func (m *URL) XXX_DiscardUnknown() { + xxx_messageInfo_URL.DiscardUnknown(m) +} + +var xxx_messageInfo_URL proto.InternalMessageInfo + +func (m *URL) GetScheme() string { + if m != nil { + return m.Scheme + } + return "" +} + +func (m *URL) GetOpaque() string { + if m != nil { + return m.Opaque + } + return "" +} + +func (m *URL) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *URL) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *URL) GetRawPath() string { + if m != nil { + return m.RawPath + } + return "" +} + +func (m *URL) GetRawQuery() string { + if m != nil { + return m.RawQuery + } + return "" +} + +func (m *URL) GetFragment() string { + if m != nil { + return m.Fragment + } + return "" +} + +type HeaderEntry struct { + Values []string `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HeaderEntry) Reset() { *m = HeaderEntry{} } +func (m *HeaderEntry) String() string { return proto.CompactTextString(m) } +func (*HeaderEntry) ProtoMessage() {} +func (*HeaderEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_types_6ebfa235129f89d8, []int{2} +} +func (m *HeaderEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HeaderEntry.Unmarshal(m, b) +} +func (m *HeaderEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HeaderEntry.Marshal(b, m, deterministic) +} +func (dst *HeaderEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeaderEntry.Merge(dst, src) +} +func (m *HeaderEntry) XXX_Size() int { + return xxx_messageInfo_HeaderEntry.Size(m) +} +func (m *HeaderEntry) XXX_DiscardUnknown() { + xxx_messageInfo_HeaderEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_HeaderEntry proto.InternalMessageInfo + +func (m *HeaderEntry) GetValues() []string { + if m != nil { + return m.Values + } + return nil +} + +type Response struct { + // Not used right now but reserving in case it turns out that streaming + // makes things more economical on the gRPC side + // uint64 id = 1; + StatusCode uint32 `protobuf:"varint,2,opt,name=status_code,json=statusCode" json:"status_code,omitempty"` + Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` + // Added in 0.6.2 to ensure that the content-type is set appropriately, as + // well as any other information + HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { + return fileDescriptor_types_6ebfa235129f89d8, []int{3} +} +func (m *Response) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Response.Unmarshal(m, b) +} +func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Response.Marshal(b, m, deterministic) +} +func (dst *Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_Response.Merge(dst, src) +} +func (m *Response) XXX_Size() int { + return xxx_messageInfo_Response.Size(m) +} +func (m *Response) XXX_DiscardUnknown() { + xxx_messageInfo_Response.DiscardUnknown(m) +} + +var xxx_messageInfo_Response proto.InternalMessageInfo + +func (m *Response) GetStatusCode() uint32 { + if m != nil { + return m.StatusCode + } + return 0 +} + +func (m *Response) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +func (m *Response) GetHeaderEntries() map[string]*HeaderEntry { + if m != nil { + return m.HeaderEntries + } + return nil +} + +func init() { + proto.RegisterType((*Request)(nil), "forwarding.Request") + proto.RegisterMapType((map[string]*HeaderEntry)(nil), "forwarding.Request.HeaderEntriesEntry") + proto.RegisterType((*URL)(nil), "forwarding.URL") + proto.RegisterType((*HeaderEntry)(nil), "forwarding.HeaderEntry") + proto.RegisterType((*Response)(nil), "forwarding.Response") + proto.RegisterMapType((map[string]*HeaderEntry)(nil), "forwarding.Response.HeaderEntriesEntry") +} + +func init() { + proto.RegisterFile("helper/forwarding/types.proto", fileDescriptor_types_6ebfa235129f89d8) +} + +var fileDescriptor_types_6ebfa235129f89d8 = []byte{ + // 475 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x4f, 0x8f, 0xd3, 0x3e, + 0x10, 0x55, 0x9a, 0x6e, 0xff, 0x4c, 0x77, 0x7f, 0xbf, 0xc5, 0x07, 0x30, 0x8b, 0x10, 0xa1, 0x12, + 0x10, 0x09, 0x48, 0xa4, 0x72, 0x41, 0xdc, 0x60, 0x85, 0xc4, 0x61, 0x41, 0x60, 0x69, 0x0f, 0x70, + 0x89, 0xdc, 0x78, 0x5a, 0x47, 0x34, 0x75, 0x6a, 0x3b, 0x5b, 0xe5, 0x63, 0xf1, 0x9d, 0x38, 0xf1, + 0x29, 0x90, 0x9d, 0xb0, 0x0d, 0x5a, 0x21, 0x4e, 0x9c, 0x32, 0xef, 0xbd, 0xc9, 0x78, 0xde, 0x8c, + 0x0d, 0xf7, 0x25, 0x6e, 0x2a, 0xd4, 0xe9, 0x4a, 0xe9, 0x3d, 0xd7, 0xa2, 0xd8, 0xae, 0x53, 0xdb, + 0x54, 0x68, 0x92, 0x4a, 0x2b, 0xab, 0x08, 0x1c, 0xf8, 0xf9, 0xf7, 0x01, 0x8c, 0x19, 0xee, 0x6a, + 0x34, 0x96, 0xdc, 0x86, 0x51, 0x89, 0x56, 0x2a, 0x41, 0x07, 0x51, 0x10, 0x4f, 0x59, 0x87, 0xc8, + 0x43, 0x08, 0x6b, 0xbd, 0xa1, 0x61, 0x14, 0xc4, 0xb3, 0xc5, 0xff, 0xc9, 0xe1, 0xef, 0xe4, 0x92, + 0x5d, 0x30, 0xa7, 0x91, 0xf7, 0xf0, 0x9f, 0x44, 0x2e, 0x50, 0x67, 0xb8, 0xb5, 0xba, 0x40, 0x43, + 0x87, 0x51, 0x18, 0xcf, 0x16, 0x8f, 0xfb, 0xd9, 0xdd, 0x39, 0xc9, 0x3b, 0x9f, 0xf9, 0xb6, 0x4d, + 0x74, 0x9f, 0x86, 0x9d, 0xc8, 0x3e, 0x47, 0x08, 0x0c, 0x97, 0x4a, 0x34, 0xf4, 0x28, 0x0a, 0xe2, + 0x63, 0xe6, 0x63, 0xc7, 0x49, 0x65, 0x2c, 0x1d, 0xf9, 0xde, 0x7c, 0x4c, 0x1e, 0xc0, 0x4c, 0x63, + 0xa9, 0x2c, 0x66, 0x5c, 0x08, 0x4d, 0xc7, 0x5e, 0x82, 0x96, 0x7a, 0x2d, 0x84, 0x26, 0x4f, 0xe1, + 0x56, 0x85, 0xa8, 0xb3, 0x1c, 0xb5, 0x2d, 0x56, 0x45, 0xce, 0x2d, 0x1a, 0x3a, 0x89, 0xc2, 0xf8, + 0x98, 0x9d, 0x3a, 0xe1, 0xbc, 0xc7, 0x9f, 0x7d, 0x06, 0x72, 0xb3, 0x35, 0x72, 0x0a, 0xe1, 0x57, + 0x6c, 0x68, 0xe0, 0x6b, 0xbb, 0x90, 0x3c, 0x87, 0xa3, 0x2b, 0xbe, 0xa9, 0xd1, 0x8f, 0x69, 0xb6, + 0xb8, 0xd3, 0xf7, 0x78, 0x28, 0xd0, 0xb0, 0x36, 0xeb, 0xd5, 0xe0, 0x65, 0x30, 0xff, 0x16, 0x40, + 0x78, 0xc9, 0x2e, 0xdc, 0x88, 0x4d, 0x2e, 0xb1, 0xc4, 0xae, 0x5e, 0x87, 0x1c, 0xaf, 0x2a, 0xbe, + 0xeb, 0x6a, 0x4e, 0x59, 0x87, 0xae, 0x4d, 0x0f, 0x7b, 0xa6, 0x09, 0x0c, 0x2b, 0x6e, 0xa5, 0x1f, + 0xce, 0x94, 0xf9, 0x98, 0xdc, 0x85, 0x89, 0xe6, 0xfb, 0xcc, 0xf3, 0xed, 0x80, 0xc6, 0x9a, 0xef, + 0x3f, 0x3a, 0xe9, 0x1e, 0x4c, 0x9d, 0xb4, 0xab, 0x51, 0x37, 0x74, 0xe2, 0x35, 0x97, 0xfb, 0xc9, + 0x61, 0x72, 0x06, 0x93, 0x95, 0xe6, 0xeb, 0x12, 0xb7, 0x96, 0x4e, 0x5b, 0xed, 0x17, 0x9e, 0x3f, + 0x82, 0x59, 0xcf, 0x8d, 0x6b, 0xd1, 0xfb, 0x31, 0x34, 0x88, 0x42, 0xd7, 0x62, 0x8b, 0xe6, 0x3f, + 0x02, 0x98, 0x30, 0x34, 0x95, 0xda, 0x1a, 0x74, 0x0b, 0x31, 0x96, 0xdb, 0xda, 0x64, 0xb9, 0x12, + 0xad, 0x99, 0x13, 0x06, 0x2d, 0x75, 0xae, 0x04, 0x5e, 0x6f, 0x36, 0xec, 0x6d, 0xf6, 0xc3, 0x1f, + 0x2e, 0xcf, 0x93, 0xdf, 0x2f, 0x4f, 0x7b, 0xc4, 0xdf, 0x6f, 0xcf, 0x3f, 0xdc, 0xe3, 0x9b, 0xe4, + 0xcb, 0xb3, 0x75, 0x61, 0x65, 0xbd, 0x4c, 0x72, 0x55, 0xa6, 0x92, 0x1b, 0x59, 0xe4, 0x4a, 0x57, + 0xe9, 0x15, 0xaf, 0x37, 0x36, 0xbd, 0xf1, 0xec, 0x96, 0x23, 0xff, 0xe2, 0x5e, 0xfc, 0x0c, 0x00, + 0x00, 0xff, 0xff, 0x03, 0xfa, 0xd9, 0x51, 0x92, 0x03, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/helper/forwarding/types.proto b/vendor/github.com/hashicorp/vault/helper/forwarding/types.proto new file mode 100644 index 0000000..2189934 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/forwarding/types.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/helper/forwarding"; + +package forwarding; + +message Request { + // Not used right now but reserving in case it turns out that streaming + // makes things more economical on the gRPC side + //uint64 id = 1; + string method = 2; + URL url = 3; + map header_entries = 4; + bytes body = 5; + string host = 6; + string remote_addr = 7; + repeated bytes peer_certificates = 8; +} + +message URL { + string scheme = 1; + string opaque = 2; + // This isn't needed now but might be in the future, so we'll skip the + // number to keep the ordering in net/url + //UserInfo user = 3; + string host = 4; + string path = 5; + string raw_path = 6; + // This also isn't needed right now, but we'll reserve the number + //bool force_query = 7; + string raw_query = 8; + string fragment = 9; +} + +message HeaderEntry { + repeated string values = 1; +} + +message Response { + // Not used right now but reserving in case it turns out that streaming + // makes things more economical on the gRPC side + //uint64 id = 1; + uint32 status_code = 2; + bytes body = 3; + // Added in 0.6.2 to ensure that the content-type is set appropriately, as + // well as any other information + map header_entries = 4; +} diff --git a/vendor/github.com/hashicorp/vault/helper/forwarding/util.go b/vendor/github.com/hashicorp/vault/helper/forwarding/util.go new file mode 100644 index 0000000..92e6cb1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/forwarding/util.go @@ -0,0 +1,203 @@ +package forwarding + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "net/http" + "net/url" + "os" + + "github.com/golang/protobuf/proto" + "github.com/hashicorp/vault/helper/compressutil" + "github.com/hashicorp/vault/helper/jsonutil" +) + +type bufCloser struct { + *bytes.Buffer +} + +func (b bufCloser) Close() error { + b.Reset() + return nil +} + +// GenerateForwardedRequest generates a new http.Request that contains the +// original requests's information in the new request's body. +func GenerateForwardedHTTPRequest(req *http.Request, addr string) (*http.Request, error) { + fq, err := GenerateForwardedRequest(req) + if err != nil { + return nil, err + } + + var newBody []byte + switch os.Getenv("VAULT_MESSAGE_TYPE") { + case "json": + newBody, err = jsonutil.EncodeJSON(fq) + case "json_compress": + newBody, err = jsonutil.EncodeJSONAndCompress(fq, &compressutil.CompressionConfig{ + Type: compressutil.CompressionTypeLzw, + }) + case "proto3": + fallthrough + default: + newBody, err = proto.Marshal(fq) + } + if err != nil { + return nil, err + } + + ret, err := http.NewRequest("POST", addr, bytes.NewBuffer(newBody)) + if err != nil { + return nil, err + } + + return ret, nil +} + +func GenerateForwardedRequest(req *http.Request) (*Request, error) { + fq := Request{ + Method: req.Method, + HeaderEntries: make(map[string]*HeaderEntry, len(req.Header)), + Host: req.Host, + RemoteAddr: req.RemoteAddr, + } + + reqURL := req.URL + fq.Url = &URL{ + Scheme: reqURL.Scheme, + Opaque: reqURL.Opaque, + Host: reqURL.Host, + Path: reqURL.Path, + RawPath: reqURL.RawPath, + RawQuery: reqURL.RawQuery, + Fragment: reqURL.Fragment, + } + + for k, v := range req.Header { + fq.HeaderEntries[k] = &HeaderEntry{ + Values: v, + } + } + + buf := bytes.NewBuffer(nil) + _, err := buf.ReadFrom(req.Body) + if err != nil { + return nil, err + } + fq.Body = buf.Bytes() + + if req.TLS != nil && req.TLS.PeerCertificates != nil && len(req.TLS.PeerCertificates) > 0 { + fq.PeerCertificates = make([][]byte, len(req.TLS.PeerCertificates)) + for i, cert := range req.TLS.PeerCertificates { + fq.PeerCertificates[i] = cert.Raw + } + } + + return &fq, nil +} + +// ParseForwardedRequest generates a new http.Request that is comprised of the +// values in the given request's body, assuming it correctly parses into a +// ForwardedRequest. +func ParseForwardedHTTPRequest(req *http.Request) (*http.Request, error) { + buf := bytes.NewBuffer(nil) + _, err := buf.ReadFrom(req.Body) + if err != nil { + return nil, err + } + + fq := new(Request) + switch os.Getenv("VAULT_MESSAGE_TYPE") { + case "json", "json_compress": + err = jsonutil.DecodeJSON(buf.Bytes(), fq) + default: + err = proto.Unmarshal(buf.Bytes(), fq) + } + if err != nil { + return nil, err + } + + return ParseForwardedRequest(fq) +} + +func ParseForwardedRequest(fq *Request) (*http.Request, error) { + buf := bufCloser{ + Buffer: bytes.NewBuffer(fq.Body), + } + + ret := &http.Request{ + Method: fq.Method, + Header: make(map[string][]string, len(fq.HeaderEntries)), + Body: buf, + Host: fq.Host, + RemoteAddr: fq.RemoteAddr, + } + + ret.URL = &url.URL{ + Scheme: fq.Url.Scheme, + Opaque: fq.Url.Opaque, + Host: fq.Url.Host, + Path: fq.Url.Path, + RawPath: fq.Url.RawPath, + RawQuery: fq.Url.RawQuery, + Fragment: fq.Url.Fragment, + } + + for k, v := range fq.HeaderEntries { + ret.Header[k] = v.Values + } + + if fq.PeerCertificates != nil && len(fq.PeerCertificates) > 0 { + ret.TLS = &tls.ConnectionState{ + PeerCertificates: make([]*x509.Certificate, len(fq.PeerCertificates)), + } + for i, certBytes := range fq.PeerCertificates { + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, err + } + ret.TLS.PeerCertificates[i] = cert + } + } + + return ret, nil +} + +type RPCResponseWriter struct { + statusCode int + header http.Header + body *bytes.Buffer +} + +// NewRPCResponseWriter returns an initialized RPCResponseWriter +func NewRPCResponseWriter() *RPCResponseWriter { + w := &RPCResponseWriter{ + header: make(http.Header), + body: new(bytes.Buffer), + statusCode: 200, + } + //w.header.Set("Content-Type", "application/octet-stream") + return w +} + +func (w *RPCResponseWriter) Header() http.Header { + return w.header +} + +func (w *RPCResponseWriter) Write(buf []byte) (int, error) { + w.body.Write(buf) + return len(buf), nil +} + +func (w *RPCResponseWriter) WriteHeader(code int) { + w.statusCode = code +} + +func (w *RPCResponseWriter) StatusCode() int { + return w.statusCode +} + +func (w *RPCResponseWriter) Body() *bytes.Buffer { + return w.body +} diff --git a/vendor/github.com/hashicorp/vault/helper/identity/identity.go b/vendor/github.com/hashicorp/vault/helper/identity/identity.go new file mode 100644 index 0000000..b1eab23 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/identity/identity.go @@ -0,0 +1,65 @@ +package identity + +import ( + "fmt" + + "github.com/gogo/protobuf/proto" + "github.com/hashicorp/errwrap" +) + +func (g *Group) Clone() (*Group, error) { + if g == nil { + return nil, fmt.Errorf("nil group") + } + + marshaledGroup, err := proto.Marshal(g) + if err != nil { + return nil, errwrap.Wrapf("failed to marshal group: {{err}}", err) + } + + var clonedGroup Group + err = proto.Unmarshal(marshaledGroup, &clonedGroup) + if err != nil { + return nil, errwrap.Wrapf("failed to unmarshal group: {{err}}", err) + } + + return &clonedGroup, nil +} + +func (e *Entity) Clone() (*Entity, error) { + if e == nil { + return nil, fmt.Errorf("nil entity") + } + + marshaledEntity, err := proto.Marshal(e) + if err != nil { + return nil, errwrap.Wrapf("failed to marshal entity: {{err}}", err) + } + + var clonedEntity Entity + err = proto.Unmarshal(marshaledEntity, &clonedEntity) + if err != nil { + return nil, errwrap.Wrapf("failed to unmarshal entity: {{err}}", err) + } + + return &clonedEntity, nil +} + +func (p *Alias) Clone() (*Alias, error) { + if p == nil { + return nil, fmt.Errorf("nil alias") + } + + marshaledAlias, err := proto.Marshal(p) + if err != nil { + return nil, errwrap.Wrapf("failed to marshal alias: {{err}}", err) + } + + var clonedAlias Alias + err = proto.Unmarshal(marshaledAlias, &clonedAlias) + if err != nil { + return nil, errwrap.Wrapf("failed to unmarshal alias: {{err}}", err) + } + + return &clonedAlias, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/identity/sentinel.go b/vendor/github.com/hashicorp/vault/helper/identity/sentinel.go new file mode 100644 index 0000000..bf3cfff --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/identity/sentinel.go @@ -0,0 +1,125 @@ +package identity + +import "github.com/golang/protobuf/ptypes" + +func (e *Entity) SentinelGet(key string) (interface{}, error) { + if e == nil { + return nil, nil + } + switch key { + case "aliases": + return e.Aliases, nil + case "id": + return e.ID, nil + case "meta", "metadata": + return e.Metadata, nil + case "name": + return e.Name, nil + case "creation_time": + return ptypes.TimestampString(e.CreationTime), nil + case "last_update_time": + return ptypes.TimestampString(e.LastUpdateTime), nil + case "merged_entity_ids": + return e.MergedEntityIDs, nil + case "policies": + return e.Policies, nil + } + + return nil, nil +} + +func (e *Entity) SentinelKeys() []string { + return []string{ + "id", + "aliases", + "metadata", + "meta", + "name", + "creation_time", + "last_update_time", + "merged_entity_ids", + "policies", + } +} + +func (p *Alias) SentinelGet(key string) (interface{}, error) { + if p == nil { + return nil, nil + } + switch key { + case "id": + return p.ID, nil + case "mount_type": + return p.MountType, nil + case "mount_accessor": + return p.MountAccessor, nil + case "mount_path": + return p.MountPath, nil + case "meta", "metadata": + return p.Metadata, nil + case "name": + return p.Name, nil + case "creation_time": + return ptypes.TimestampString(p.CreationTime), nil + case "last_update_time": + return ptypes.TimestampString(p.LastUpdateTime), nil + case "merged_from_entity_ids": + return p.MergedFromCanonicalIDs, nil + } + + return nil, nil +} + +func (a *Alias) SentinelKeys() []string { + return []string{ + "id", + "mount_type", + "mount_path", + "meta", + "metadata", + "name", + "creation_time", + "last_update_time", + "merged_from_entity_ids", + } +} + +func (g *Group) SentinelGet(key string) (interface{}, error) { + if g == nil { + return nil, nil + } + switch key { + case "id": + return g.ID, nil + case "name": + return g.Name, nil + case "policies": + return g.Policies, nil + case "parent_group_ids": + return g.ParentGroupIDs, nil + case "member_entity_ids": + return g.MemberEntityIDs, nil + case "meta", "metadata": + return g.Metadata, nil + case "creation_time": + return ptypes.TimestampString(g.CreationTime), nil + case "last_update_time": + return ptypes.TimestampString(g.LastUpdateTime), nil + } + + return nil, nil +} + +func (g *Group) SentinelKeys() []string { + return []string{ + "id", + "name", + "policies", + "parent_group_ids", + "member_entity_ids", + "metadata", + "meta", + "creation_time", + "last_update_time", + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/identity/types.pb.go b/vendor/github.com/hashicorp/vault/helper/identity/types.pb.go new file mode 100644 index 0000000..e26dcea --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/identity/types.pb.go @@ -0,0 +1,505 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: helper/identity/types.proto + +package identity // import "github.com/hashicorp/vault/helper/identity" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// Group represents an identity group. +type Group struct { + // ID is the unique identifier for this group + ID string `sentinel:"" protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + // Name is the unique name for this group + Name string `sentinel:"" protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // Policies are the vault policies to be granted to members of this group + Policies []string `sentinel:"" protobuf:"bytes,3,rep,name=policies" json:"policies,omitempty"` + // ParentGroupIDs are the identifiers of those groups to which this group is a + // member of. These will serve as references to the parent group in the + // hierarchy. + ParentGroupIDs []string `sentinel:"" protobuf:"bytes,4,rep,name=parent_group_ids,json=parentGroupIds" json:"parent_group_ids,omitempty"` + // MemberEntityIDs are the identifiers of entities which are members of this + // group + MemberEntityIDs []string `sentinel:"" protobuf:"bytes,5,rep,name=member_entity_ids,json=memberEntityIDs" json:"member_entity_ids,omitempty"` + // Metadata represents the custom data tied with this group + Metadata map[string]string `sentinel:"" protobuf:"bytes,6,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // CreationTime is the time at which this group was created + CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,7,opt,name=creation_time,json=creationTime" json:"creation_time,omitempty"` + // LastUpdateTime is the time at which this group was last modified + LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,8,opt,name=last_update_time,json=lastUpdateTime" json:"last_update_time,omitempty"` + // ModifyIndex tracks the number of updates to the group. It is useful to detect + // updates to the groups. + ModifyIndex uint64 `sentinel:"" protobuf:"varint,9,opt,name=modify_index,json=modifyIndex" json:"modify_index,omitempty"` + // BucketKeyHash is the MD5 hash of the storage bucket key into which this + // group is stored in the underlying storage. This is useful to find all + // the groups belonging to a particular bucket during invalidation of the + // storage key. + BucketKeyHash string `sentinel:"" protobuf:"bytes,10,opt,name=bucket_key_hash,json=bucketKeyHash" json:"bucket_key_hash,omitempty"` + // Alias is used to mark this group as an internal mapping of a group that + // is external to the identity store. Alias can only be set if the 'type' + // is set to 'external'. + Alias *Alias `sentinel:"" protobuf:"bytes,11,opt,name=alias" json:"alias,omitempty"` + // Type indicates if this group is an internal group or an external group. + // Memberships of the internal groups can be managed over the API whereas + // the memberships on the external group --for which a corresponding alias + // will be set-- will be managed automatically. + Type string `sentinel:"" protobuf:"bytes,12,opt,name=type" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Group) Reset() { *m = Group{} } +func (m *Group) String() string { return proto.CompactTextString(m) } +func (*Group) ProtoMessage() {} +func (*Group) Descriptor() ([]byte, []int) { + return fileDescriptor_types_d1c3c8d60c8e2caa, []int{0} +} +func (m *Group) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Group.Unmarshal(m, b) +} +func (m *Group) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Group.Marshal(b, m, deterministic) +} +func (dst *Group) XXX_Merge(src proto.Message) { + xxx_messageInfo_Group.Merge(dst, src) +} +func (m *Group) XXX_Size() int { + return xxx_messageInfo_Group.Size(m) +} +func (m *Group) XXX_DiscardUnknown() { + xxx_messageInfo_Group.DiscardUnknown(m) +} + +var xxx_messageInfo_Group proto.InternalMessageInfo + +func (m *Group) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Group) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Group) GetPolicies() []string { + if m != nil { + return m.Policies + } + return nil +} + +func (m *Group) GetParentGroupIDs() []string { + if m != nil { + return m.ParentGroupIDs + } + return nil +} + +func (m *Group) GetMemberEntityIDs() []string { + if m != nil { + return m.MemberEntityIDs + } + return nil +} + +func (m *Group) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *Group) GetCreationTime() *timestamp.Timestamp { + if m != nil { + return m.CreationTime + } + return nil +} + +func (m *Group) GetLastUpdateTime() *timestamp.Timestamp { + if m != nil { + return m.LastUpdateTime + } + return nil +} + +func (m *Group) GetModifyIndex() uint64 { + if m != nil { + return m.ModifyIndex + } + return 0 +} + +func (m *Group) GetBucketKeyHash() string { + if m != nil { + return m.BucketKeyHash + } + return "" +} + +func (m *Group) GetAlias() *Alias { + if m != nil { + return m.Alias + } + return nil +} + +func (m *Group) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +// Entity represents an entity that gets persisted and indexed. +// Entity is fundamentally composed of zero or many aliases. +type Entity struct { + // Aliases are the identities that this entity is made of. This can be + // empty as well to favor being able to create the entity first and then + // incrementally adding aliases. + Aliases []*Alias `sentinel:"" protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"` + // ID is the unique identifier of the entity which always be a UUID. This + // should never be allowed to be updated. + ID string `sentinel:"" protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` + // Name is a unique identifier of the entity which is intended to be + // human-friendly. The default name might not be human friendly since it + // gets suffixed by a UUID, but it can optionally be updated, unlike the ID + // field. + Name string `sentinel:"" protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + // Metadata represents the explicit metadata which is set by the + // clients. This is useful to tie any information pertaining to the + // aliases. This is a non-unique field of entity, meaning multiple + // entities can have the same metadata set. Entities will be indexed based + // on this explicit metadata. This enables virtual groupings of entities + // based on its metadata. + Metadata map[string]string `sentinel:"" protobuf:"bytes,4,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // CreationTime is the time at which this entity is first created. + CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,5,opt,name=creation_time,json=creationTime" json:"creation_time,omitempty"` + // LastUpdateTime is the most recent time at which the properties of this + // entity got modified. This is helpful in filtering out entities based on + // its age and to take action on them, if desired. + LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,6,opt,name=last_update_time,json=lastUpdateTime" json:"last_update_time,omitempty"` + // MergedEntityIDs are the entities which got merged to this one. Entities + // will be indexed based on all the entities that got merged into it. This + // helps to apply the actions on this entity on the tokens that are merged + // to the merged entities. Merged entities will be deleted entirely and + // this is the only trackable trail of its earlier presence. + MergedEntityIDs []string `sentinel:"" protobuf:"bytes,7,rep,name=merged_entity_ids,json=mergedEntityIDs" json:"merged_entity_ids,omitempty"` + // Policies the entity is entitled to + Policies []string `sentinel:"" protobuf:"bytes,8,rep,name=policies" json:"policies,omitempty"` + // BucketKeyHash is the MD5 hash of the storage bucket key into which this + // entity is stored in the underlying storage. This is useful to find all + // the entities belonging to a particular bucket during invalidation of the + // storage key. + BucketKeyHash string `sentinel:"" protobuf:"bytes,9,opt,name=bucket_key_hash,json=bucketKeyHash" json:"bucket_key_hash,omitempty"` + // Disabled indicates whether tokens associated with the account should not + // be able to be used + Disabled bool `sentinel:"" protobuf:"varint,11,opt,name=disabled" json:"disabled,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Entity) Reset() { *m = Entity{} } +func (m *Entity) String() string { return proto.CompactTextString(m) } +func (*Entity) ProtoMessage() {} +func (*Entity) Descriptor() ([]byte, []int) { + return fileDescriptor_types_d1c3c8d60c8e2caa, []int{1} +} +func (m *Entity) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Entity.Unmarshal(m, b) +} +func (m *Entity) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Entity.Marshal(b, m, deterministic) +} +func (dst *Entity) XXX_Merge(src proto.Message) { + xxx_messageInfo_Entity.Merge(dst, src) +} +func (m *Entity) XXX_Size() int { + return xxx_messageInfo_Entity.Size(m) +} +func (m *Entity) XXX_DiscardUnknown() { + xxx_messageInfo_Entity.DiscardUnknown(m) +} + +var xxx_messageInfo_Entity proto.InternalMessageInfo + +func (m *Entity) GetAliases() []*Alias { + if m != nil { + return m.Aliases + } + return nil +} + +func (m *Entity) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Entity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Entity) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *Entity) GetCreationTime() *timestamp.Timestamp { + if m != nil { + return m.CreationTime + } + return nil +} + +func (m *Entity) GetLastUpdateTime() *timestamp.Timestamp { + if m != nil { + return m.LastUpdateTime + } + return nil +} + +func (m *Entity) GetMergedEntityIDs() []string { + if m != nil { + return m.MergedEntityIDs + } + return nil +} + +func (m *Entity) GetPolicies() []string { + if m != nil { + return m.Policies + } + return nil +} + +func (m *Entity) GetBucketKeyHash() string { + if m != nil { + return m.BucketKeyHash + } + return "" +} + +func (m *Entity) GetDisabled() bool { + if m != nil { + return m.Disabled + } + return false +} + +// Alias represents the alias that gets stored inside of the +// entity object in storage and also represents in an in-memory index of an +// alias object. +type Alias struct { + // ID is the unique identifier that represents this alias + ID string `sentinel:"" protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + // CanonicalID is the entity identifier to which this alias belongs to + CanonicalID string `sentinel:"" protobuf:"bytes,2,opt,name=canonical_id,json=canonicalId" json:"canonical_id,omitempty"` + // MountType is the backend mount's type to which this alias belongs to. + // This enables categorically querying aliases of specific backend types. + MountType string `sentinel:"" protobuf:"bytes,3,opt,name=mount_type,json=mountType" json:"mount_type,omitempty"` + // MountAccessor is the backend mount's accessor to which this alias + // belongs to. + MountAccessor string `sentinel:"" protobuf:"bytes,4,opt,name=mount_accessor,json=mountAccessor" json:"mount_accessor,omitempty"` + // MountPath is the backend mount's path to which the Maccessor belongs to. This + // field is not used for any operational purposes. This is only returned when + // alias is read, only as a nicety. + MountPath string `sentinel:"" protobuf:"bytes,5,opt,name=mount_path,json=mountPath" json:"mount_path,omitempty"` + // Metadata is the explicit metadata that clients set against an entity + // which enables virtual grouping of aliases. Aliases will be indexed + // against their metadata. + Metadata map[string]string `sentinel:"" protobuf:"bytes,6,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Name is the identifier of this alias in its authentication source. + // This does not uniquely identify an alias in Vault. This in conjunction + // with MountAccessor form to be the factors that represent an alias in a + // unique way. Aliases will be indexed based on this combined uniqueness + // factor. + Name string `sentinel:"" protobuf:"bytes,7,opt,name=name" json:"name,omitempty"` + // CreationTime is the time at which this alias was first created + CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,8,opt,name=creation_time,json=creationTime" json:"creation_time,omitempty"` + // LastUpdateTime is the most recent time at which the properties of this + // alias got modified. This is helpful in filtering out aliases based + // on its age and to take action on them, if desired. + LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,9,opt,name=last_update_time,json=lastUpdateTime" json:"last_update_time,omitempty"` + // MergedFromCanonicalIDs is the FIFO history of merging activity + MergedFromCanonicalIDs []string `sentinel:"" protobuf:"bytes,10,rep,name=merged_from_canonical_ids,json=mergedFromCanonicalIds" json:"merged_from_canonical_ids,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Alias) Reset() { *m = Alias{} } +func (m *Alias) String() string { return proto.CompactTextString(m) } +func (*Alias) ProtoMessage() {} +func (*Alias) Descriptor() ([]byte, []int) { + return fileDescriptor_types_d1c3c8d60c8e2caa, []int{2} +} +func (m *Alias) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Alias.Unmarshal(m, b) +} +func (m *Alias) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Alias.Marshal(b, m, deterministic) +} +func (dst *Alias) XXX_Merge(src proto.Message) { + xxx_messageInfo_Alias.Merge(dst, src) +} +func (m *Alias) XXX_Size() int { + return xxx_messageInfo_Alias.Size(m) +} +func (m *Alias) XXX_DiscardUnknown() { + xxx_messageInfo_Alias.DiscardUnknown(m) +} + +var xxx_messageInfo_Alias proto.InternalMessageInfo + +func (m *Alias) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Alias) GetCanonicalID() string { + if m != nil { + return m.CanonicalID + } + return "" +} + +func (m *Alias) GetMountType() string { + if m != nil { + return m.MountType + } + return "" +} + +func (m *Alias) GetMountAccessor() string { + if m != nil { + return m.MountAccessor + } + return "" +} + +func (m *Alias) GetMountPath() string { + if m != nil { + return m.MountPath + } + return "" +} + +func (m *Alias) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *Alias) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Alias) GetCreationTime() *timestamp.Timestamp { + if m != nil { + return m.CreationTime + } + return nil +} + +func (m *Alias) GetLastUpdateTime() *timestamp.Timestamp { + if m != nil { + return m.LastUpdateTime + } + return nil +} + +func (m *Alias) GetMergedFromCanonicalIDs() []string { + if m != nil { + return m.MergedFromCanonicalIDs + } + return nil +} + +func init() { + proto.RegisterType((*Group)(nil), "identity.Group") + proto.RegisterMapType((map[string]string)(nil), "identity.Group.MetadataEntry") + proto.RegisterType((*Entity)(nil), "identity.Entity") + proto.RegisterMapType((map[string]string)(nil), "identity.Entity.MetadataEntry") + proto.RegisterType((*Alias)(nil), "identity.Alias") + proto.RegisterMapType((map[string]string)(nil), "identity.Alias.MetadataEntry") +} + +func init() { proto.RegisterFile("helper/identity/types.proto", fileDescriptor_types_d1c3c8d60c8e2caa) } + +var fileDescriptor_types_d1c3c8d60c8e2caa = []byte{ + // 656 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0x5d, 0x6f, 0xd3, 0x3c, + 0x14, 0xc7, 0xd5, 0xa6, 0x2f, 0xe9, 0x69, 0xd7, 0xed, 0xb1, 0x1e, 0xa1, 0x50, 0x34, 0xe8, 0x26, + 0x0d, 0x95, 0x09, 0x25, 0xd2, 0xb8, 0x61, 0xe3, 0x02, 0x0d, 0x18, 0x30, 0x21, 0x24, 0x14, 0x8d, + 0x1b, 0x6e, 0x22, 0x37, 0xf1, 0x1a, 0x6b, 0x49, 0x1c, 0xc5, 0xce, 0x44, 0xbe, 0x0e, 0x5f, 0x8d, + 0x6b, 0xbe, 0x03, 0xf2, 0x71, 0xd3, 0x96, 0x75, 0xbc, 0x4c, 0xdb, 0x9d, 0xfd, 0x3f, 0xc7, 0xc7, + 0xf6, 0xf9, 0xff, 0xe2, 0xc0, 0x83, 0x98, 0x25, 0x39, 0x2b, 0x3c, 0x1e, 0xb1, 0x4c, 0x71, 0x55, + 0x79, 0xaa, 0xca, 0x99, 0x74, 0xf3, 0x42, 0x28, 0x41, 0xec, 0x5a, 0x1d, 0x3d, 0x9a, 0x09, 0x31, + 0x4b, 0x98, 0x87, 0xfa, 0xb4, 0x3c, 0xf7, 0x14, 0x4f, 0x99, 0x54, 0x34, 0xcd, 0x4d, 0xea, 0xee, + 0xb7, 0x16, 0xb4, 0xdf, 0x15, 0xa2, 0xcc, 0xc9, 0x10, 0x9a, 0x3c, 0x72, 0x1a, 0xe3, 0xc6, 0xa4, + 0xe7, 0x37, 0x79, 0x44, 0x08, 0xb4, 0x32, 0x9a, 0x32, 0xa7, 0x89, 0x0a, 0x8e, 0xc9, 0x08, 0xec, + 0x5c, 0x24, 0x3c, 0xe4, 0x4c, 0x3a, 0xd6, 0xd8, 0x9a, 0xf4, 0xfc, 0xc5, 0x9c, 0x4c, 0x60, 0x2b, + 0xa7, 0x05, 0xcb, 0x54, 0x30, 0xd3, 0xf5, 0x02, 0x1e, 0x49, 0xa7, 0x85, 0x39, 0x43, 0xa3, 0xe3, + 0x36, 0xa7, 0x91, 0x24, 0xfb, 0xf0, 0x5f, 0xca, 0xd2, 0x29, 0x2b, 0x02, 0x73, 0x4a, 0x4c, 0x6d, + 0x63, 0xea, 0xa6, 0x09, 0x9c, 0xa0, 0xae, 0x73, 0x0f, 0xc1, 0x4e, 0x99, 0xa2, 0x11, 0x55, 0xd4, + 0xe9, 0x8c, 0xad, 0x49, 0xff, 0x60, 0xdb, 0xad, 0x6f, 0xe7, 0x62, 0x45, 0xf7, 0xe3, 0x3c, 0x7e, + 0x92, 0xa9, 0xa2, 0xf2, 0x17, 0xe9, 0xe4, 0x25, 0x6c, 0x84, 0x05, 0xa3, 0x8a, 0x8b, 0x2c, 0xd0, + 0xd7, 0x76, 0xba, 0xe3, 0xc6, 0xa4, 0x7f, 0x30, 0x72, 0x4d, 0x4f, 0xdc, 0xba, 0x27, 0xee, 0x59, + 0xdd, 0x13, 0x7f, 0x50, 0x2f, 0xd0, 0x12, 0x79, 0x03, 0x5b, 0x09, 0x95, 0x2a, 0x28, 0xf3, 0x88, + 0x2a, 0x66, 0x6a, 0xd8, 0x7f, 0xad, 0x31, 0xd4, 0x6b, 0x3e, 0xe3, 0x12, 0xac, 0xb2, 0x03, 0x83, + 0x54, 0x44, 0xfc, 0xbc, 0x0a, 0x78, 0x16, 0xb1, 0xaf, 0x4e, 0x6f, 0xdc, 0x98, 0xb4, 0xfc, 0xbe, + 0xd1, 0x4e, 0xb5, 0x44, 0x1e, 0xc3, 0xe6, 0xb4, 0x0c, 0x2f, 0x98, 0x0a, 0x2e, 0x58, 0x15, 0xc4, + 0x54, 0xc6, 0x0e, 0x60, 0xd7, 0x37, 0x8c, 0xfc, 0x81, 0x55, 0xef, 0xa9, 0x8c, 0xc9, 0x1e, 0xb4, + 0x69, 0xc2, 0xa9, 0x74, 0xfa, 0x78, 0x8a, 0xcd, 0x65, 0x27, 0x8e, 0xb5, 0xec, 0x9b, 0xa8, 0x76, + 0x4e, 0xd3, 0xe0, 0x0c, 0x8c, 0x73, 0x7a, 0x3c, 0x7a, 0x01, 0x1b, 0xbf, 0xf4, 0x89, 0x6c, 0x81, + 0x75, 0xc1, 0xaa, 0xb9, 0xdf, 0x7a, 0x48, 0xfe, 0x87, 0xf6, 0x25, 0x4d, 0xca, 0xda, 0x71, 0x33, + 0x39, 0x6a, 0x3e, 0x6f, 0xec, 0x7e, 0xb7, 0xa0, 0x63, 0x2c, 0x21, 0x4f, 0xa0, 0x8b, 0x9b, 0x30, + 0xe9, 0x34, 0xd0, 0x8e, 0xb5, 0x43, 0xd4, 0xf1, 0x39, 0x50, 0xcd, 0x35, 0xa0, 0xac, 0x15, 0xa0, + 0x8e, 0x56, 0xec, 0x6d, 0x61, 0xbd, 0x87, 0xcb, 0x7a, 0x66, 0xcb, 0x7f, 0xf7, 0xb7, 0x7d, 0x07, + 0xfe, 0x76, 0x6e, 0xec, 0x2f, 0xd2, 0x5c, 0xcc, 0x58, 0xb4, 0x4a, 0x73, 0xb7, 0xa6, 0x59, 0x07, + 0x96, 0x34, 0xaf, 0x7e, 0x3f, 0xf6, 0x95, 0xef, 0xe7, 0x1a, 0x08, 0x7a, 0xd7, 0x41, 0x30, 0x02, + 0x3b, 0xe2, 0x92, 0x4e, 0x13, 0x16, 0x21, 0x07, 0xb6, 0xbf, 0x98, 0xdf, 0xce, 0xe5, 0x1f, 0x16, + 0xb4, 0xd1, 0xc2, 0xb5, 0xa7, 0x60, 0x07, 0x06, 0x21, 0xcd, 0x44, 0xc6, 0x43, 0x9a, 0x04, 0x0b, + 0x4f, 0xfb, 0x0b, 0xed, 0x34, 0x22, 0xdb, 0x00, 0xa9, 0x28, 0x33, 0x15, 0x20, 0x79, 0xc6, 0xe2, + 0x1e, 0x2a, 0x67, 0x55, 0xce, 0xc8, 0x1e, 0x0c, 0x4d, 0x98, 0x86, 0x21, 0x93, 0x52, 0x14, 0x4e, + 0xcb, 0xdc, 0x0d, 0xd5, 0xe3, 0xb9, 0xb8, 0xac, 0x92, 0x53, 0x15, 0xa3, 0x9f, 0x75, 0x95, 0x4f, + 0x54, 0xc5, 0x7f, 0x7e, 0x0c, 0xf0, 0xe8, 0xbf, 0x85, 0xa5, 0x86, 0xaf, 0xbb, 0x02, 0xdf, 0x1a, + 0x40, 0xf6, 0x1d, 0x00, 0xd4, 0xbb, 0x31, 0x40, 0x87, 0x70, 0x7f, 0x0e, 0xd0, 0x79, 0x21, 0xd2, + 0x60, 0xb5, 0xd3, 0xd2, 0x01, 0xa4, 0xe4, 0x9e, 0x49, 0x78, 0x5b, 0x88, 0xf4, 0xf5, 0xb2, 0xe9, + 0xf2, 0x56, 0x7e, 0xbf, 0x7a, 0xfa, 0x65, 0x7f, 0xc6, 0x55, 0x5c, 0x4e, 0xdd, 0x50, 0xa4, 0x9e, + 0x06, 0x8e, 0x87, 0xa2, 0xc8, 0xbd, 0x4b, 0x5a, 0x26, 0xca, 0xbb, 0xf2, 0x7f, 0x99, 0x76, 0xf0, + 0x26, 0xcf, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x89, 0x41, 0x55, 0x79, 0x06, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/helper/identity/types.proto b/vendor/github.com/hashicorp/vault/helper/identity/types.proto new file mode 100644 index 0000000..523f447 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/identity/types.proto @@ -0,0 +1,166 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/helper/identity"; + +package identity; + +import "google/protobuf/timestamp.proto"; + +// Group represents an identity group. +message Group { + // ID is the unique identifier for this group + string id = 1; + + // Name is the unique name for this group + string name = 2; + + // Policies are the vault policies to be granted to members of this group + repeated string policies = 3; + + // ParentGroupIDs are the identifiers of those groups to which this group is a + // member of. These will serve as references to the parent group in the + // hierarchy. + repeated string parent_group_ids = 4; + + // MemberEntityIDs are the identifiers of entities which are members of this + // group + repeated string member_entity_ids = 5; + + // Metadata represents the custom data tied with this group + map metadata = 6; + + // CreationTime is the time at which this group was created + google.protobuf.Timestamp creation_time = 7; + + // LastUpdateTime is the time at which this group was last modified + google.protobuf.Timestamp last_update_time= 8; + + // ModifyIndex tracks the number of updates to the group. It is useful to detect + // updates to the groups. + uint64 modify_index = 9; + + // BucketKeyHash is the MD5 hash of the storage bucket key into which this + // group is stored in the underlying storage. This is useful to find all + // the groups belonging to a particular bucket during invalidation of the + // storage key. + string bucket_key_hash = 10; + + // Alias is used to mark this group as an internal mapping of a group that + // is external to the identity store. Alias can only be set if the 'type' + // is set to 'external'. + Alias alias = 11; + + // Type indicates if this group is an internal group or an external group. + // Memberships of the internal groups can be managed over the API whereas + // the memberships on the external group --for which a corresponding alias + // will be set-- will be managed automatically. + string type = 12; +} + + +// Entity represents an entity that gets persisted and indexed. +// Entity is fundamentally composed of zero or many aliases. +message Entity { + // Aliases are the identities that this entity is made of. This can be + // empty as well to favor being able to create the entity first and then + // incrementally adding aliases. + repeated Alias aliases = 1; + + // ID is the unique identifier of the entity which always be a UUID. This + // should never be allowed to be updated. + string id = 2; + + // Name is a unique identifier of the entity which is intended to be + // human-friendly. The default name might not be human friendly since it + // gets suffixed by a UUID, but it can optionally be updated, unlike the ID + // field. + string name = 3; + + // Metadata represents the explicit metadata which is set by the + // clients. This is useful to tie any information pertaining to the + // aliases. This is a non-unique field of entity, meaning multiple + // entities can have the same metadata set. Entities will be indexed based + // on this explicit metadata. This enables virtual groupings of entities + // based on its metadata. + map metadata = 4; + + // CreationTime is the time at which this entity is first created. + google.protobuf.Timestamp creation_time = 5; + + // LastUpdateTime is the most recent time at which the properties of this + // entity got modified. This is helpful in filtering out entities based on + // its age and to take action on them, if desired. + google.protobuf.Timestamp last_update_time= 6; + + // MergedEntityIDs are the entities which got merged to this one. Entities + // will be indexed based on all the entities that got merged into it. This + // helps to apply the actions on this entity on the tokens that are merged + // to the merged entities. Merged entities will be deleted entirely and + // this is the only trackable trail of its earlier presence. + repeated string merged_entity_ids = 7; + + // Policies the entity is entitled to + repeated string policies = 8; + + // BucketKeyHash is the MD5 hash of the storage bucket key into which this + // entity is stored in the underlying storage. This is useful to find all + // the entities belonging to a particular bucket during invalidation of the + // storage key. + string bucket_key_hash = 9; + + // **Enterprise only** + // MFASecrets holds the MFA secrets indexed by the identifier of the MFA + // method configuration. + //map mfa_secrets = 10; + + // Disabled indicates whether tokens associated with the account should not + // be able to be used + bool disabled = 11; +} + +// Alias represents the alias that gets stored inside of the +// entity object in storage and also represents in an in-memory index of an +// alias object. +message Alias { + // ID is the unique identifier that represents this alias + string id = 1; + + // CanonicalID is the entity identifier to which this alias belongs to + string canonical_id = 2; + + // MountType is the backend mount's type to which this alias belongs to. + // This enables categorically querying aliases of specific backend types. + string mount_type = 3; + + // MountAccessor is the backend mount's accessor to which this alias + // belongs to. + string mount_accessor = 4; + + // MountPath is the backend mount's path to which the Maccessor belongs to. This + // field is not used for any operational purposes. This is only returned when + // alias is read, only as a nicety. + string mount_path = 5; + + // Metadata is the explicit metadata that clients set against an entity + // which enables virtual grouping of aliases. Aliases will be indexed + // against their metadata. + map metadata = 6; + + // Name is the identifier of this alias in its authentication source. + // This does not uniquely identify an alias in Vault. This in conjunction + // with MountAccessor form to be the factors that represent an alias in a + // unique way. Aliases will be indexed based on this combined uniqueness + // factor. + string name = 7; + + // CreationTime is the time at which this alias was first created + google.protobuf.Timestamp creation_time = 8; + + // LastUpdateTime is the most recent time at which the properties of this + // alias got modified. This is helpful in filtering out aliases based + // on its age and to take action on them, if desired. + google.protobuf.Timestamp last_update_time = 9; + + // MergedFromCanonicalIDs is the FIFO history of merging activity + repeated string merged_from_canonical_ids = 10; +} diff --git a/vendor/github.com/hashicorp/vault/helper/jsonutil/json.go b/vendor/github.com/hashicorp/vault/helper/jsonutil/json.go new file mode 100644 index 0000000..d03ddef --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/jsonutil/json.go @@ -0,0 +1,100 @@ +package jsonutil + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "fmt" + "io" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/compressutil" +) + +// Encodes/Marshals the given object into JSON +func EncodeJSON(in interface{}) ([]byte, error) { + if in == nil { + return nil, fmt.Errorf("input for encoding is nil") + } + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + if err := enc.Encode(in); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// EncodeJSONAndCompress encodes the given input into JSON and compresses the +// encoded value (using Gzip format BestCompression level, by default). A +// canary byte is placed at the beginning of the returned bytes for the logic +// in decompression method to identify compressed input. +func EncodeJSONAndCompress(in interface{}, config *compressutil.CompressionConfig) ([]byte, error) { + if in == nil { + return nil, fmt.Errorf("input for encoding is nil") + } + + // First JSON encode the given input + encodedBytes, err := EncodeJSON(in) + if err != nil { + return nil, err + } + + if config == nil { + config = &compressutil.CompressionConfig{ + Type: compressutil.CompressionTypeGzip, + GzipCompressionLevel: gzip.BestCompression, + } + } + + return compressutil.Compress(encodedBytes, config) +} + +// DecodeJSON tries to decompress the given data. The call to decompress, fails +// if the content was not compressed in the first place, which is identified by +// a canary byte before the compressed data. If the data is not compressed, it +// is JSON decoded directly. Otherwise the decompressed data will be JSON +// decoded. +func DecodeJSON(data []byte, out interface{}) error { + if data == nil || len(data) == 0 { + return fmt.Errorf("'data' being decoded is nil") + } + if out == nil { + return fmt.Errorf("output parameter 'out' is nil") + } + + // Decompress the data if it was compressed in the first place + decompressedBytes, uncompressed, err := compressutil.Decompress(data) + if err != nil { + return errwrap.Wrapf("failed to decompress JSON: {{err}}", err) + } + if !uncompressed && (decompressedBytes == nil || len(decompressedBytes) == 0) { + return fmt.Errorf("decompressed data being decoded is invalid") + } + + // If the input supplied failed to contain the compression canary, it + // will be notified by the compression utility. Decode the decompressed + // input. + if !uncompressed { + data = decompressedBytes + } + + return DecodeJSONFromReader(bytes.NewReader(data), out) +} + +// Decodes/Unmarshals the given io.Reader pointing to a JSON, into a desired object +func DecodeJSONFromReader(r io.Reader, out interface{}) error { + if r == nil { + return fmt.Errorf("'io.Reader' being decoded is nil") + } + if out == nil { + return fmt.Errorf("output parameter 'out' is nil") + } + + dec := json.NewDecoder(r) + + // While decoding JSON values, interpret the integer values as `json.Number`s instead of `float64`. + dec.UseNumber() + + // Since 'out' is an interface representing a pointer, pass it to the decoder without an '&' + return dec.Decode(out) +} diff --git a/vendor/github.com/hashicorp/vault/helper/kdf/kdf.go b/vendor/github.com/hashicorp/vault/helper/kdf/kdf.go new file mode 100644 index 0000000..5009074 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/kdf/kdf.go @@ -0,0 +1,77 @@ +// This package is used to implement Key Derivation Functions (KDF) +// based on the recommendations of NIST SP 800-108. These are useful +// for generating unique-per-transaction keys, or situations in which +// a key hierarchy may be useful. +package kdf + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/binary" + "fmt" +) + +// PRF is a pseudo-random function that takes a key or seed, +// as well as additional binary data and generates output that is +// indistinguishable from random. Examples are cryptographic hash +// functions or block ciphers. +type PRF func([]byte, []byte) ([]byte, error) + +// CounterMode implements the counter mode KDF that uses a psuedo-random-function (PRF) +// along with a counter to generate derived keys. The KDF takes a base key +// a derivation context, and the required number of output bits. +func CounterMode(prf PRF, prfLen uint32, key []byte, context []byte, bits uint32) ([]byte, error) { + // Ensure the PRF is byte aligned + if prfLen%8 != 0 { + return nil, fmt.Errorf("PRF must be byte aligned") + } + + // Ensure the bits required are byte aligned + if bits%8 != 0 { + return nil, fmt.Errorf("bits required must be byte aligned") + } + + // Determine the number of rounds required + rounds := bits / prfLen + if bits%prfLen != 0 { + rounds++ + } + + // Allocate and setup the input + input := make([]byte, 4+len(context)+4) + copy(input[4:], context) + binary.BigEndian.PutUint32(input[4+len(context):], bits) + + // Iteratively generate more key material + var out []byte + var i uint32 + for i = 0; i < rounds; i++ { + // Update the counter in the input string + binary.BigEndian.PutUint32(input[:4], i) + + // Compute more key material + part, err := prf(key, input) + if err != nil { + return nil, err + } + if uint32(len(part)*8) != prfLen { + return nil, fmt.Errorf("PRF length mis-match (%d vs %d)", len(part)*8, prfLen) + } + out = append(out, part...) + } + + // Return the desired number of output bytes + return out[:bits/8], nil +} + +const ( + // HMACSHA256PRFLen is the length of output from HMACSHA256PRF + HMACSHA256PRFLen uint32 = 256 +) + +// HMACSHA256PRF is a pseudo-random-function (PRF) that uses an HMAC-SHA256 +func HMACSHA256PRF(key []byte, data []byte) ([]byte, error) { + hash := hmac.New(sha256.New, key) + hash.Write(data) + return hash.Sum(nil), nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/keysutil/encrypted_key_storage.go b/vendor/github.com/hashicorp/vault/helper/keysutil/encrypted_key_storage.go new file mode 100644 index 0000000..e220f8f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/keysutil/encrypted_key_storage.go @@ -0,0 +1,288 @@ +package keysutil + +import ( + "context" + "encoding/base64" + "errors" + "math/big" + paths "path" + "strings" + + "github.com/hashicorp/golang-lru" + "github.com/hashicorp/vault/logical" +) + +const ( + // DefaultCacheSize is used if no cache size is specified for + // NewEncryptedKeyStorage. This value is the number of cache entries to + // store, not the size in bytes of the cache. + DefaultCacheSize = 16 * 1024 + + // DefaultPrefix is used if no prefix is specified for + // NewEncryptedKeyStorage. Prefix must be defined so we can provide context + // for the base folder. + DefaultPrefix = "encryptedkeys/" + + // EncryptedKeyPolicyVersionTpl is a template that can be used to minimize + // the amount of data that's stored with the ciphertext. + EncryptedKeyPolicyVersionTpl = "{{version}}:" +) + +var ( + // ErrPolicyDerivedKeys is returned if the provided policy does not use + // derived keys. This is a requirement for this storage implementation. + ErrPolicyDerivedKeys = errors.New("key policy must use derived keys") + + // ErrPolicyConvergentEncryption is returned if the provided policy does not use + // convergent encryption. This is a requirement for this storage implementation. + ErrPolicyConvergentEncryption = errors.New("key policy must use convergent encryption") + + // ErrPolicyConvergentVersion is returned if the provided policy does not use + // a new enough convergent version. This is a requirement for this storage + // implementation. + ErrPolicyConvergentVersion = errors.New("key policy must use convergent version > 2") + + // ErrNilStorage is returned if the provided storage is nil. + ErrNilStorage = errors.New("nil storage provided") + + // ErrNilPolicy is returned if the provided policy is nil. + ErrNilPolicy = errors.New("nil policy provided") +) + +// EncryptedKeyStorageConfig is used to configure an EncryptedKeyStorage object. +type EncryptedKeyStorageConfig struct { + // Policy is the key policy to use to encrypt the key paths. + Policy *Policy + + // Prefix is the storage prefix for this instance of the EncryptedKeyStorage + // object. This is stored in plaintext. If not set the DefaultPrefix will be + // used. + Prefix string + + // CacheSize is the number of elements to cache. If not set the + // DetaultCacheSize will be used. + CacheSize int +} + +// NewEncryptedKeyStorageWrapper takes an EncryptedKeyStorageConfig and returns a new +// EncryptedKeyStorage object. +func NewEncryptedKeyStorageWrapper(config EncryptedKeyStorageConfig) (*EncryptedKeyStorageWrapper, error) { + if config.Policy == nil { + return nil, ErrNilPolicy + } + + if !config.Policy.Derived { + return nil, ErrPolicyDerivedKeys + } + + if !config.Policy.ConvergentEncryption { + return nil, ErrPolicyConvergentEncryption + } + + if config.Prefix == "" { + config.Prefix = DefaultPrefix + } + + if !strings.HasSuffix(config.Prefix, "/") { + config.Prefix += "/" + } + + size := config.CacheSize + if size <= 0 { + size = DefaultCacheSize + } + + cache, err := lru.New2Q(size) + if err != nil { + return nil, err + } + + return &EncryptedKeyStorageWrapper{ + policy: config.Policy, + prefix: config.Prefix, + lru: cache, + }, nil +} + +type EncryptedKeyStorageWrapper struct { + policy *Policy + lru *lru.TwoQueueCache + prefix string +} + +func (f *EncryptedKeyStorageWrapper) Wrap(s logical.Storage) logical.Storage { + return &encryptedKeyStorage{ + policy: f.policy, + s: s, + prefix: f.prefix, + lru: f.lru, + } +} + +// EncryptedKeyStorage implements the logical.Storage interface and ensures the +// storage paths are encrypted in the underlying storage. +type encryptedKeyStorage struct { + policy *Policy + s logical.Storage + lru *lru.TwoQueueCache + + prefix string +} + +func ensureTailingSlash(path string) string { + if !strings.HasSuffix(path, "/") { + return path + "/" + } + return path +} + +// List implements the logical.Storage List method, and decrypts all the items +// in a path prefix. This can only operate on full folder structures so the +// prefix should end in a "/". +func (s *encryptedKeyStorage) List(ctx context.Context, prefix string) ([]string, error) { + encPrefix, err := s.encryptPath(prefix) + if err != nil { + return nil, err + } + + keys, err := s.s.List(ctx, ensureTailingSlash(encPrefix)) + if err != nil { + return keys, err + } + + decryptedKeys := make([]string, len(keys)) + + // The context for the decryption operations will be the object's prefix + // joined with the provided prefix. Join cleans the path ensuring there + // isn't a trailing "/". + context := []byte(paths.Join(s.prefix, prefix)) + + for i, k := range keys { + raw, ok := s.lru.Get(k) + if ok { + // cache HIT, we can bail early and skip the decode & decrypt operations. + decryptedKeys[i] = raw.(string) + continue + } + + // If a folder is included in the keys it will have a trailing "/". + // We need to remove this before decoding/decrypting and add it back + // later. + appendSlash := strings.HasSuffix(k, "/") + if appendSlash { + k = strings.TrimSuffix(k, "/") + } + + decoded := Base62Decode(k) + if len(decoded) == 0 { + return nil, errors.New("could not decode key") + } + + // Decrypt the data with the object's key policy. + encodedPlaintext, err := s.policy.Decrypt(context, nil, string(decoded[:])) + if err != nil { + return nil, err + } + + // The plaintext is still base64 encoded, decode it. + decoded, err = base64.StdEncoding.DecodeString(encodedPlaintext) + if err != nil { + return nil, err + } + + plaintext := string(decoded[:]) + + // Add the slash back to the plaintext value + if appendSlash { + plaintext += "/" + k += "/" + } + + // We want to store the unencoded version of the key in the cache. + // This will make it more performent when it's a HIT. + s.lru.Add(k, plaintext) + + decryptedKeys[i] = plaintext + } + + return decryptedKeys, nil +} + +// Get implements the logical.Storage Get method. +func (s *encryptedKeyStorage) Get(ctx context.Context, path string) (*logical.StorageEntry, error) { + encPath, err := s.encryptPath(path) + if err != nil { + return nil, err + } + + return s.s.Get(ctx, encPath) +} + +// Put implements the logical.Storage Put method. +func (s *encryptedKeyStorage) Put(ctx context.Context, entry *logical.StorageEntry) error { + encPath, err := s.encryptPath(entry.Key) + if err != nil { + return err + } + e := &logical.StorageEntry{} + *e = *entry + + e.Key = encPath + + return s.s.Put(ctx, e) +} + +// Delete implements the logical.Storage Delete method. +func (s *encryptedKeyStorage) Delete(ctx context.Context, path string) error { + encPath, err := s.encryptPath(path) + if err != nil { + return err + } + + return s.s.Delete(ctx, encPath) +} + +// encryptPath takes a plaintext path and encrypts each path section (separated +// by "/") with the object's key policy. The context for each encryption is the +// plaintext path prefix for the key. +func (s *encryptedKeyStorage) encryptPath(path string) (string, error) { + if path == "" || path == "/" { + return s.prefix, nil + } + + path = paths.Clean(path) + + // Trim the prefix if it starts with a "/" + path = strings.TrimPrefix(path, "/") + + parts := strings.Split(path, "/") + + encPath := s.prefix + context := strings.TrimSuffix(s.prefix, "/") + for _, p := range parts { + encoded := base64.StdEncoding.EncodeToString([]byte(p)) + ciphertext, err := s.policy.Encrypt(0, []byte(context), nil, encoded) + if err != nil { + return "", err + } + + encPath = paths.Join(encPath, Base62Encode([]byte(ciphertext))) + context = paths.Join(context, p) + } + + return encPath, nil +} + +func Base62Encode(buf []byte) string { + encoder := &big.Int{} + + encoder.SetBytes(buf) + return encoder.Text(62) +} + +func Base62Decode(input string) []byte { + decoder := &big.Int{} + + decoder.SetString(input, 62) + return decoder.Bytes() +} diff --git a/vendor/github.com/hashicorp/vault/helper/keysutil/lock_manager.go b/vendor/github.com/hashicorp/vault/helper/keysutil/lock_manager.go new file mode 100644 index 0000000..1fb3a33 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/keysutil/lock_manager.go @@ -0,0 +1,513 @@ +package keysutil + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "sync" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" +) + +const ( + shared = false + exclusive = true + currentConvergentVersion = 3 +) + +var ( + errNeedExclusiveLock = errors.New("an exclusive lock is needed for this operation") +) + +// PolicyRequest holds values used when requesting a policy. Most values are +// only used during an upsert. +type PolicyRequest struct { + // The storage to use + Storage logical.Storage + + // The name of the policy + Name string + + // The key type + KeyType KeyType + + // Whether it should be derived + Derived bool + + // Whether to enable convergent encryption + Convergent bool + + // Whether to allow export + Exportable bool + + // Whether to upsert + Upsert bool + + // Whether to allow plaintext backup + AllowPlaintextBackup bool +} + +type LockManager struct { + // A lock for each named key + locks map[string]*sync.RWMutex + + // A mutex for the map itself + locksMutex sync.RWMutex + + // If caching is enabled, the map of name to in-memory policy cache + cache map[string]*Policy + + // Used for global locking, and as the cache map mutex + cacheMutex sync.RWMutex +} + +func NewLockManager(cacheDisabled bool) *LockManager { + lm := &LockManager{ + locks: map[string]*sync.RWMutex{}, + } + if !cacheDisabled { + lm.cache = map[string]*Policy{} + } + return lm +} + +func (lm *LockManager) CacheActive() bool { + return lm.cache != nil +} + +func (lm *LockManager) InvalidatePolicy(name string) { + // Check if it's in our cache. If so, return right away. + if lm.CacheActive() { + lm.cacheMutex.Lock() + defer lm.cacheMutex.Unlock() + delete(lm.cache, name) + } +} + +func (lm *LockManager) policyLock(name string, lockType bool) *sync.RWMutex { + lm.locksMutex.RLock() + lock := lm.locks[name] + if lock != nil { + // We want to give this up before locking the lock, but it's safe -- + // the only time we ever write to a value in this map is the first time + // we access the value, so it won't be changing out from under us + lm.locksMutex.RUnlock() + if lockType == exclusive { + lock.Lock() + } else { + lock.RLock() + } + return lock + } + + lm.locksMutex.RUnlock() + lm.locksMutex.Lock() + + // Don't defer the unlock call because if we get a valid lock below we want + // to release the lock mutex right away to avoid the possibility of + // deadlock by trying to grab the second lock + + // Check to make sure it hasn't been created since + lock = lm.locks[name] + if lock != nil { + lm.locksMutex.Unlock() + if lockType == exclusive { + lock.Lock() + } else { + lock.RLock() + } + return lock + } + + lock = &sync.RWMutex{} + lm.locks[name] = lock + lm.locksMutex.Unlock() + if lockType == exclusive { + lock.Lock() + } else { + lock.RLock() + } + + return lock +} + +func (lm *LockManager) UnlockPolicy(lock *sync.RWMutex, lockType bool) { + if lockType == exclusive { + lock.Unlock() + } else { + lock.RUnlock() + } +} + +func (lm *LockManager) UpdateCache(name string, policy *Policy) { + if lm.CacheActive() { + lm.cacheMutex.Lock() + defer lm.cacheMutex.Unlock() + lm.cache[name] = policy + } +} + +// Get the policy with a read lock. If we get an error saying an exclusive lock +// is needed (for instance, for an upgrade/migration), give up the read lock, +// call again with an exclusive lock, then swap back out for a read lock. +func (lm *LockManager) GetPolicyShared(ctx context.Context, storage logical.Storage, name string) (*Policy, *sync.RWMutex, error) { + p, lock, _, err := lm.getPolicyCommon(ctx, PolicyRequest{ + Storage: storage, + Name: name, + }, shared) + if err == nil || + (err != nil && err != errNeedExclusiveLock) { + return p, lock, err + } + + // Try again while asking for an exclusive lock + p, lock, _, err = lm.getPolicyCommon(ctx, PolicyRequest{ + Storage: storage, + Name: name, + }, exclusive) + if err != nil || p == nil || lock == nil { + return p, lock, err + } + + lock.Unlock() + + p, lock, _, err = lm.getPolicyCommon(ctx, PolicyRequest{ + Storage: storage, + Name: name, + }, shared) + return p, lock, err +} + +// Get the policy with an exclusive lock +func (lm *LockManager) GetPolicyExclusive(ctx context.Context, storage logical.Storage, name string) (*Policy, *sync.RWMutex, error) { + p, lock, _, err := lm.getPolicyCommon(ctx, PolicyRequest{ + Storage: storage, + Name: name, + }, exclusive) + return p, lock, err +} + +// Get the policy with a read lock; if it returns that an exclusive lock is +// needed, retry. If successful, call one more time to get a read lock and +// return the value. +func (lm *LockManager) GetPolicyUpsert(ctx context.Context, req PolicyRequest) (*Policy, *sync.RWMutex, bool, error) { + req.Upsert = true + + p, lock, _, err := lm.getPolicyCommon(ctx, req, shared) + if err == nil || + (err != nil && err != errNeedExclusiveLock) { + return p, lock, false, err + } + + // Try again while asking for an exclusive lock + p, lock, upserted, err := lm.getPolicyCommon(ctx, req, exclusive) + if err != nil || p == nil || lock == nil { + return p, lock, upserted, err + } + lock.Unlock() + + req.Upsert = false + // Now get a shared lock for the return, but preserve the value of upserted + p, lock, _, err = lm.getPolicyCommon(ctx, req, shared) + + return p, lock, upserted, err +} + +// RestorePolicy acquires an exclusive lock on the policy name and restores the +// given policy along with the archive. +func (lm *LockManager) RestorePolicy(ctx context.Context, storage logical.Storage, name, backup string) error { + var p *Policy + var err error + + backupBytes, err := base64.StdEncoding.DecodeString(backup) + if err != nil { + return err + } + + var keyData KeyData + err = jsonutil.DecodeJSON(backupBytes, &keyData) + if err != nil { + return err + } + + // Set a different name if desired + if name != "" { + keyData.Policy.Name = name + } + + name = keyData.Policy.Name + + // set the policy version cache + keyData.Policy.versionPrefixCache = &sync.Map{} + + lockType := exclusive + lock := lm.policyLock(name, lockType) + defer lm.UnlockPolicy(lock, lockType) + + // If the policy is in cache, error out + if lm.CacheActive() { + lm.cacheMutex.RLock() + p = lm.cache[name] + if p != nil { + lm.cacheMutex.RUnlock() + return fmt.Errorf(fmt.Sprintf("policy %q already exists", name)) + } + lm.cacheMutex.RUnlock() + } + + // If the policy exists in storage, error out + p, err = lm.getStoredPolicy(ctx, storage, name) + if err != nil { + return err + } + if p != nil { + return fmt.Errorf(fmt.Sprintf("policy %q already exists", name)) + } + + // Restore the archived keys + if keyData.ArchivedKeys != nil { + err = keyData.Policy.storeArchive(ctx, storage, keyData.ArchivedKeys) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to restore archived keys for policy %q: {{err}}", name), err) + } + } + + // Mark that policy as a restored key + keyData.Policy.RestoreInfo = &RestoreInfo{ + Time: time.Now(), + Version: keyData.Policy.LatestVersion, + } + + // Restore the policy. This will also attempt to adjust the archive. + err = keyData.Policy.Persist(ctx, storage) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to restore the policy %q: {{err}}", name), err) + } + + // Update the cache to contain the restored policy + lm.UpdateCache(name, keyData.Policy) + + return nil +} + +func (lm *LockManager) BackupPolicy(ctx context.Context, storage logical.Storage, name string) (string, error) { + p, lock, err := lm.GetPolicyExclusive(ctx, storage, name) + if lock != nil { + defer lock.Unlock() + } + if err != nil { + return "", err + } + if p == nil { + return "", fmt.Errorf("invalid key %q", name) + } + + backup, err := p.Backup(ctx, storage) + if err != nil { + return "", err + } + + // Update the cache since the policy would now have the backup information + lm.UpdateCache(name, p) + + return backup, nil +} + +// When the function returns, a lock will be held on the policy if err == nil. +// It is the caller's responsibility to unlock. +func (lm *LockManager) getPolicyCommon(ctx context.Context, req PolicyRequest, lockType bool) (*Policy, *sync.RWMutex, bool, error) { + lock := lm.policyLock(req.Name, lockType) + + var p *Policy + var err error + + // Check if it's in our cache. If so, return right away. + if lm.CacheActive() { + lm.cacheMutex.RLock() + p = lm.cache[req.Name] + if p != nil { + lm.cacheMutex.RUnlock() + return p, lock, false, nil + } + lm.cacheMutex.RUnlock() + } + + // Load it from storage + p, err = lm.getStoredPolicy(ctx, req.Storage, req.Name) + if err != nil { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, err + } + + if p == nil { + // This is the only place we upsert a new policy, so if upsert is not + // specified, or the lock type is wrong, unlock before returning + if !req.Upsert { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, nil + } + + if lockType != exclusive { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, errNeedExclusiveLock + } + + switch req.KeyType { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + if req.Convergent && !req.Derived { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled") + } + + case KeyType_ECDSA_P256: + if req.Derived || req.Convergent { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType) + } + + case KeyType_ED25519: + if req.Convergent { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, fmt.Errorf("convergent encryption not supported for keys of type %v", req.KeyType) + } + + case KeyType_RSA2048, KeyType_RSA4096: + if req.Derived || req.Convergent { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType) + } + + default: + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, fmt.Errorf("unsupported key type %v", req.KeyType) + } + + p = &Policy{ + Name: req.Name, + Type: req.KeyType, + Derived: req.Derived, + Exportable: req.Exportable, + AllowPlaintextBackup: req.AllowPlaintextBackup, + versionPrefixCache: &sync.Map{}, + } + if req.Derived { + p.KDF = Kdf_hkdf_sha256 + if req.Convergent { + p.ConvergentEncryption = true + // As of version 3 we store the version within each key, so we + // set to -1 to indicate that the value in the policy has no + // meaning. We still, for backwards compatibility, fall back to + // this value if the key doesn't have one, which means it will + // only be -1 in the case where every key version is >= 3 + p.ConvergentVersion = -1 + } + } + + err = p.Rotate(ctx, req.Storage) + if err != nil { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, err + } + + if lm.CacheActive() { + // Since we didn't have the policy in the cache, if there was no + // error, write the value in. + lm.cacheMutex.Lock() + defer lm.cacheMutex.Unlock() + // Make sure a policy didn't appear. If so, it will only be set if + // there was no error, so assume it's good and return that + exp := lm.cache[req.Name] + if exp != nil { + return exp, lock, false, nil + } + if err == nil { + lm.cache[req.Name] = p + } + } + + // We don't need to worry about upgrading since it will be a new policy + return p, lock, true, nil + } + + if p.NeedsUpgrade() { + if lockType == shared { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, errNeedExclusiveLock + } + + err = p.Upgrade(ctx, req.Storage) + if err != nil { + lm.UnlockPolicy(lock, lockType) + return nil, nil, false, err + } + } + + if lm.CacheActive() { + // Since we didn't have the policy in the cache, if there was no + // error, write the value in. + lm.cacheMutex.Lock() + defer lm.cacheMutex.Unlock() + // Make sure a policy didn't appear. If so, it will only be set if + // there was no error, so assume it's good and return that + exp := lm.cache[req.Name] + if exp != nil { + return exp, lock, false, nil + } + if err == nil { + lm.cache[req.Name] = p + } + } + + return p, lock, false, nil +} + +func (lm *LockManager) DeletePolicy(ctx context.Context, storage logical.Storage, name string) error { + lm.cacheMutex.Lock() + lock := lm.policyLock(name, exclusive) + defer lock.Unlock() + defer lm.cacheMutex.Unlock() + + var p *Policy + var err error + + if lm.CacheActive() { + p = lm.cache[name] + } + if p == nil { + p, err = lm.getStoredPolicy(ctx, storage, name) + if err != nil { + return err + } + if p == nil { + return fmt.Errorf("could not delete policy; not found") + } + } + + if !p.DeletionAllowed { + return fmt.Errorf("deletion is not allowed for this policy") + } + + err = storage.Delete(ctx, "policy/"+name) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting policy %q: {{err}}", name), err) + } + + err = storage.Delete(ctx, "archive/"+name) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting archive %q: {{err}}", name), err) + } + + if lm.CacheActive() { + delete(lm.cache, name) + } + + return nil +} + +func (lm *LockManager) getStoredPolicy(ctx context.Context, storage logical.Storage, name string) (*Policy, error) { + return LoadPolicy(ctx, storage, "policy/"+name) +} diff --git a/vendor/github.com/hashicorp/vault/helper/keysutil/policy.go b/vendor/github.com/hashicorp/vault/helper/keysutil/policy.go new file mode 100644 index 0000000..6413d1a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/keysutil/policy.go @@ -0,0 +1,1427 @@ +package keysutil + +import ( + "bytes" + "context" + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/asn1" + "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "io" + "math/big" + "path" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/hkdf" + + "github.com/hashicorp/errwrap" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/kdf" + "github.com/hashicorp/vault/logical" +) + +// Careful with iota; don't put anything before it in this const block because +// we need the default of zero to be the old-style KDF +const ( + Kdf_hmac_sha256_counter = iota // built-in helper + Kdf_hkdf_sha256 // golang.org/x/crypto/hkdf +) + +// Or this one...we need the default of zero to be the original AES256-GCM96 +const ( + KeyType_AES256_GCM96 = iota + KeyType_ECDSA_P256 + KeyType_ED25519 + KeyType_RSA2048 + KeyType_RSA4096 + KeyType_ChaCha20_Poly1305 +) + +const ( + // ErrTooOld is returned whtn the ciphertext or signatures's key version is + // too old. + ErrTooOld = "ciphertext or signature version is disallowed by policy (too old)" + + // DefaultVersionTemplate is used when no version template is provided. + DefaultVersionTemplate = "vault:v{{version}}:" +) + +type RestoreInfo struct { + Time time.Time `json:"time"` + Version int `json:"version"` +} + +type BackupInfo struct { + Time time.Time `json:"time"` + Version int `json:"version"` +} + +type SigningResult struct { + Signature string + PublicKey []byte +} + +type ecdsaSignature struct { + R, S *big.Int +} + +type KeyType int + +func (kt KeyType) EncryptionSupported() bool { + switch kt { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096: + return true + } + return false +} + +func (kt KeyType) DecryptionSupported() bool { + switch kt { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096: + return true + } + return false +} + +func (kt KeyType) SigningSupported() bool { + switch kt { + case KeyType_ECDSA_P256, KeyType_ED25519, KeyType_RSA2048, KeyType_RSA4096: + return true + } + return false +} + +func (kt KeyType) HashSignatureInput() bool { + switch kt { + case KeyType_ECDSA_P256, KeyType_RSA2048, KeyType_RSA4096: + return true + } + return false +} + +func (kt KeyType) DerivationSupported() bool { + switch kt { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_ED25519: + return true + } + return false +} + +func (kt KeyType) String() string { + switch kt { + case KeyType_AES256_GCM96: + return "aes256-gcm96" + case KeyType_ChaCha20_Poly1305: + return "chacha20-poly1305" + case KeyType_ECDSA_P256: + return "ecdsa-p256" + case KeyType_ED25519: + return "ed25519" + case KeyType_RSA2048: + return "rsa-2048" + case KeyType_RSA4096: + return "rsa-4096" + } + + return "[unknown]" +} + +type KeyData struct { + Policy *Policy `json:"policy"` + ArchivedKeys *archivedKeys `json:"archived_keys"` +} + +// KeyEntry stores the key and metadata +type KeyEntry struct { + // AES or some other kind that is a pure byte slice like ED25519 + Key []byte `json:"key"` + + // Key used for HMAC functions + HMACKey []byte `json:"hmac_key"` + + // Time of creation + CreationTime time.Time `json:"time"` + + EC_X *big.Int `json:"ec_x"` + EC_Y *big.Int `json:"ec_y"` + EC_D *big.Int `json:"ec_d"` + + RSAKey *rsa.PrivateKey `json:"rsa_key"` + + // The public key in an appropriate format for the type of key + FormattedPublicKey string `json:"public_key"` + + // If convergent is enabled, the version (falling back to what's in the + // policy) + ConvergentVersion int `json:"convergent_version"` + + // This is deprecated (but still filled) in favor of the value above which + // is more precise + DeprecatedCreationTime int64 `json:"creation_time"` +} + +// deprecatedKeyEntryMap is used to allow JSON marshal/unmarshal +type deprecatedKeyEntryMap map[int]KeyEntry + +// MarshalJSON implements JSON marshaling +func (kem deprecatedKeyEntryMap) MarshalJSON() ([]byte, error) { + intermediate := map[string]KeyEntry{} + for k, v := range kem { + intermediate[strconv.Itoa(k)] = v + } + return json.Marshal(&intermediate) +} + +// MarshalJSON implements JSON unmarshalling +func (kem deprecatedKeyEntryMap) UnmarshalJSON(data []byte) error { + intermediate := map[string]KeyEntry{} + if err := jsonutil.DecodeJSON(data, &intermediate); err != nil { + return err + } + for k, v := range intermediate { + keyval, err := strconv.Atoi(k) + if err != nil { + return err + } + kem[keyval] = v + } + + return nil +} + +// keyEntryMap is used to allow JSON marshal/unmarshal +type keyEntryMap map[string]KeyEntry + +// PolicyConfig is used to create a new policy +type PolicyConfig struct { + // The name of the policy + Name string `json:"name"` + + // The type of key + Type KeyType + + // Derived keys MUST provide a context and the master underlying key is + // never used. + Derived bool + KDF int + ConvergentEncryption bool + + // Whether the key is exportable + Exportable bool + + // Whether the key is allowed to be deleted + DeletionAllowed bool + + // AllowPlaintextBackup allows taking backup of the policy in plaintext + AllowPlaintextBackup bool + + // VersionTemplate is used to prefix the ciphertext with information about + // the key version. It must inclide {{version}} and a delimiter between the + // version prefix and the ciphertext. + VersionTemplate string + + // StoragePrefix is used to add a prefix when storing and retrieving the + // policy object. + StoragePrefix string +} + +// NewPolicy takes a policy config and returns a Policy with those settings. +func NewPolicy(config PolicyConfig) *Policy { + return &Policy{ + Name: config.Name, + Type: config.Type, + Derived: config.Derived, + KDF: config.KDF, + ConvergentEncryption: config.ConvergentEncryption, + ConvergentVersion: -1, + Exportable: config.Exportable, + DeletionAllowed: config.DeletionAllowed, + AllowPlaintextBackup: config.AllowPlaintextBackup, + VersionTemplate: config.VersionTemplate, + StoragePrefix: config.StoragePrefix, + versionPrefixCache: &sync.Map{}, + } +} + +// LoadPolicy will load a policy from the provided storage path and set the +// necessary un-exported variables. It is particularly useful when accessing a +// policy without the lock manager. +func LoadPolicy(ctx context.Context, s logical.Storage, path string) (*Policy, error) { + raw, err := s.Get(ctx, path) + if err != nil { + return nil, err + } + if raw == nil { + return nil, nil + } + + var policy Policy + err = jsonutil.DecodeJSON(raw.Value, &policy) + if err != nil { + return nil, err + } + + policy.versionPrefixCache = &sync.Map{} + return &policy, nil +} + +// Policy is the struct used to store metadata +type Policy struct { + Name string `json:"name"` + Key []byte `json:"key,omitempty"` //DEPRECATED + Keys keyEntryMap `json:"keys"` + + // Derived keys MUST provide a context and the master underlying key is + // never used. If convergent encryption is true, the context will be used + // as the nonce as well. + Derived bool `json:"derived"` + KDF int `json:"kdf"` + ConvergentEncryption bool `json:"convergent_encryption"` + + // Whether the key is exportable + Exportable bool `json:"exportable"` + + // The minimum version of the key allowed to be used for decryption + MinDecryptionVersion int `json:"min_decryption_version"` + + // The minimum version of the key allowed to be used for encryption + MinEncryptionVersion int `json:"min_encryption_version"` + + // The latest key version in this policy + LatestVersion int `json:"latest_version"` + + // The latest key version in the archive. We never delete these, so this is + // a max. + ArchiveVersion int `json:"archive_version"` + + // Whether the key is allowed to be deleted + DeletionAllowed bool `json:"deletion_allowed"` + + // The version of the convergent nonce to use + ConvergentVersion int `json:"convergent_version"` + + // The type of key + Type KeyType `json:"type"` + + // BackupInfo indicates the information about the backup action taken on + // this policy + BackupInfo *BackupInfo `json:"backup_info"` + + // RestoreInfo indicates the information about the restore action taken on + // this policy + RestoreInfo *RestoreInfo `json:"restore_info"` + + // AllowPlaintextBackup allows taking backup of the policy in plaintext + AllowPlaintextBackup bool `json:"allow_plaintext_backup"` + + // VersionTemplate is used to prefix the ciphertext with information about + // the key version. It must inclide {{version}} and a delimiter between the + // version prefix and the ciphertext. + VersionTemplate string `json:"version_template"` + + // StoragePrefix is used to add a prefix when storing and retrieving the + // policy object. + StoragePrefix string `json:"storage_prefix"` + + // versionPrefixCache stores caches of verison prefix strings and the split + // version template. + versionPrefixCache *sync.Map +} + +// ArchivedKeys stores old keys. This is used to keep the key loading time sane +// when there are huge numbers of rotations. +type archivedKeys struct { + Keys []KeyEntry `json:"keys"` +} + +func (p *Policy) LoadArchive(ctx context.Context, storage logical.Storage) (*archivedKeys, error) { + archive := &archivedKeys{} + + raw, err := storage.Get(ctx, path.Join(p.StoragePrefix, "archive", p.Name)) + if err != nil { + return nil, err + } + if raw == nil { + archive.Keys = make([]KeyEntry, 0) + return archive, nil + } + + if err := jsonutil.DecodeJSON(raw.Value, archive); err != nil { + return nil, err + } + + return archive, nil +} + +func (p *Policy) storeArchive(ctx context.Context, storage logical.Storage, archive *archivedKeys) error { + // Encode the policy + buf, err := json.Marshal(archive) + if err != nil { + return err + } + + // Write the policy into storage + err = storage.Put(ctx, &logical.StorageEntry{ + Key: path.Join(p.StoragePrefix, "archive", p.Name), + Value: buf, + }) + if err != nil { + return err + } + + return nil +} + +// handleArchiving manages the movement of keys to and from the policy archive. +// This should *ONLY* be called from Persist() since it assumes that the policy +// will be persisted afterwards. +func (p *Policy) handleArchiving(ctx context.Context, storage logical.Storage) error { + // We need to move keys that are no longer accessible to archivedKeys, and keys + // that now need to be accessible back here. + // + // For safety, because there isn't really a good reason to, we never delete + // keys from the archive even when we move them back. + + // Check if we have the latest minimum version in the current set of keys + _, keysContainsMinimum := p.Keys[strconv.Itoa(p.MinDecryptionVersion)] + + // Sanity checks + switch { + case p.MinDecryptionVersion < 1: + return fmt.Errorf("minimum decryption version of %d is less than 1", p.MinDecryptionVersion) + case p.LatestVersion < 1: + return fmt.Errorf("latest version of %d is less than 1", p.LatestVersion) + case !keysContainsMinimum && p.ArchiveVersion != p.LatestVersion: + return fmt.Errorf("need to move keys from archive but archive version not up-to-date") + case p.ArchiveVersion > p.LatestVersion: + return fmt.Errorf("archive version of %d is greater than the latest version %d", + p.ArchiveVersion, p.LatestVersion) + case p.MinEncryptionVersion > 0 && p.MinEncryptionVersion < p.MinDecryptionVersion: + return fmt.Errorf("minimum decryption version of %d is greater than minimum encryption version %d", + p.MinDecryptionVersion, p.MinEncryptionVersion) + case p.MinDecryptionVersion > p.LatestVersion: + return fmt.Errorf("minimum decryption version of %d is greater than the latest version %d", + p.MinDecryptionVersion, p.LatestVersion) + } + + archive, err := p.LoadArchive(ctx, storage) + if err != nil { + return err + } + + if !keysContainsMinimum { + // Need to move keys *from* archive + for i := p.MinDecryptionVersion; i <= p.LatestVersion; i++ { + p.Keys[strconv.Itoa(i)] = archive.Keys[i] + } + + return nil + } + + // Need to move keys *to* archive + + // We need a size that is equivalent to the latest version (number of keys) + // but adding one since slice numbering starts at 0 and we're indexing by + // key version + if len(archive.Keys) < p.LatestVersion+1 { + // Increase the size of the archive slice + newKeys := make([]KeyEntry, p.LatestVersion+1) + copy(newKeys, archive.Keys) + archive.Keys = newKeys + } + + // We are storing all keys in the archive, so we ensure that it is up to + // date up to p.LatestVersion + for i := p.ArchiveVersion + 1; i <= p.LatestVersion; i++ { + archive.Keys[i] = p.Keys[strconv.Itoa(i)] + p.ArchiveVersion = i + } + + err = p.storeArchive(ctx, storage, archive) + if err != nil { + return err + } + + // Perform deletion afterwards so that if there is an error saving we + // haven't messed with the current policy + for i := p.LatestVersion - len(p.Keys) + 1; i < p.MinDecryptionVersion; i++ { + delete(p.Keys, strconv.Itoa(i)) + } + + return nil +} + +func (p *Policy) Persist(ctx context.Context, storage logical.Storage) (retErr error) { + // Other functions will take care of restoring other values; this is just + // responsible for archiving and keys since the archive function can modify + // keys. At the moment one of the other functions calling persist will also + // roll back keys, but better safe than sorry and this doesn't happen + // enough to worry about the speed tradeoff. + priorArchiveVersion := p.ArchiveVersion + var priorKeys keyEntryMap + + if p.Keys != nil { + priorKeys = keyEntryMap{} + for k, v := range p.Keys { + priorKeys[k] = v + } + } + + defer func() { + if retErr != nil { + p.ArchiveVersion = priorArchiveVersion + p.Keys = priorKeys + } + }() + + err := p.handleArchiving(ctx, storage) + if err != nil { + return err + } + + // Encode the policy + buf, err := p.Serialize() + if err != nil { + return err + } + + // Write the policy into storage + err = storage.Put(ctx, &logical.StorageEntry{ + Key: path.Join(p.StoragePrefix, "policy", p.Name), + Value: buf, + }) + if err != nil { + return err + } + + return nil +} + +func (p *Policy) Serialize() ([]byte, error) { + return json.Marshal(p) +} + +func (p *Policy) NeedsUpgrade() bool { + // Ensure we've moved from Key -> Keys + if p.Key != nil && len(p.Key) > 0 { + return true + } + + // With archiving, past assumptions about the length of the keys map are no + // longer valid + if p.LatestVersion == 0 && len(p.Keys) != 0 { + return true + } + + // We disallow setting the version to 0, since they start at 1 since moving + // to rotate-able keys, so update if it's set to 0 + if p.MinDecryptionVersion == 0 { + return true + } + + // On first load after an upgrade, copy keys to the archive + if p.ArchiveVersion == 0 { + return true + } + + // Need to write the version if zero; for version 3 on we set this to -1 to + // ignore it since we store this information in each key entry + if p.ConvergentEncryption && p.ConvergentVersion == 0 { + return true + } + + if p.Keys[strconv.Itoa(p.LatestVersion)].HMACKey == nil || len(p.Keys[strconv.Itoa(p.LatestVersion)].HMACKey) == 0 { + return true + } + + return false +} + +func (p *Policy) Upgrade(ctx context.Context, storage logical.Storage) (retErr error) { + priorKey := p.Key + priorLatestVersion := p.LatestVersion + priorMinDecryptionVersion := p.MinDecryptionVersion + priorConvergentVersion := p.ConvergentVersion + var priorKeys keyEntryMap + + if p.Keys != nil { + priorKeys = keyEntryMap{} + for k, v := range p.Keys { + priorKeys[k] = v + } + } + + defer func() { + if retErr != nil { + p.Key = priorKey + p.LatestVersion = priorLatestVersion + p.MinDecryptionVersion = priorMinDecryptionVersion + p.ConvergentVersion = priorConvergentVersion + p.Keys = priorKeys + } + }() + + persistNeeded := false + // Ensure we've moved from Key -> Keys + if p.Key != nil && len(p.Key) > 0 { + p.MigrateKeyToKeysMap() + persistNeeded = true + } + + // With archiving, past assumptions about the length of the keys map are no + // longer valid + if p.LatestVersion == 0 && len(p.Keys) != 0 { + p.LatestVersion = len(p.Keys) + persistNeeded = true + } + + // We disallow setting the version to 0, since they start at 1 since moving + // to rotate-able keys, so update if it's set to 0 + if p.MinDecryptionVersion == 0 { + p.MinDecryptionVersion = 1 + persistNeeded = true + } + + // On first load after an upgrade, copy keys to the archive + if p.ArchiveVersion == 0 { + persistNeeded = true + } + + if p.ConvergentEncryption && p.ConvergentVersion == 0 { + p.ConvergentVersion = 1 + persistNeeded = true + } + + if p.Keys[strconv.Itoa(p.LatestVersion)].HMACKey == nil || len(p.Keys[strconv.Itoa(p.LatestVersion)].HMACKey) == 0 { + entry := p.Keys[strconv.Itoa(p.LatestVersion)] + hmacKey, err := uuid.GenerateRandomBytes(32) + if err != nil { + return err + } + entry.HMACKey = hmacKey + p.Keys[strconv.Itoa(p.LatestVersion)] = entry + persistNeeded = true + } + + if persistNeeded { + err := p.Persist(ctx, storage) + if err != nil { + return err + } + } + + return nil +} + +// DeriveKey is used to derive the encryption key that should be used depending +// on the policy. If derivation is disabled the raw key is used and no context +// is required, otherwise the KDF mode is used with the context to derive the +// proper key. +func (p *Policy) DeriveKey(context []byte, ver, numBytes int) ([]byte, error) { + // Fast-path non-derived keys + if !p.Derived { + return p.Keys[strconv.Itoa(ver)].Key, nil + } + + if !p.Type.DerivationSupported() { + return nil, errutil.UserError{Err: fmt.Sprintf("derivation not supported for key type %v", p.Type)} + } + + if p.Keys == nil || p.LatestVersion == 0 { + return nil, errutil.InternalError{Err: "unable to access the key; no key versions found"} + } + + if ver <= 0 || ver > p.LatestVersion { + return nil, errutil.UserError{Err: "invalid key version"} + } + + // Ensure a context is provided + if len(context) == 0 { + return nil, errutil.UserError{Err: "missing 'context' for key derivation; the key was created using a derived key, which means additional, per-request information must be included in order to perform operations with the key"} + } + + switch p.KDF { + case Kdf_hmac_sha256_counter: + prf := kdf.HMACSHA256PRF + prfLen := kdf.HMACSHA256PRFLen + return kdf.CounterMode(prf, prfLen, p.Keys[strconv.Itoa(ver)].Key, context, 256) + + case Kdf_hkdf_sha256: + reader := hkdf.New(sha256.New, p.Keys[strconv.Itoa(ver)].Key, nil, context) + derBytes := bytes.NewBuffer(nil) + derBytes.Grow(numBytes) + limReader := &io.LimitedReader{ + R: reader, + N: int64(numBytes), + } + + switch p.Type { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + n, err := derBytes.ReadFrom(limReader) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error reading returned derived bytes: %v", err)} + } + if n != int64(numBytes) { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to read enough derived bytes, needed %d, got %d", numBytes, n)} + } + return derBytes.Bytes(), nil + + case KeyType_ED25519: + // We use the limited reader containing the derived bytes as the + // "random" input to the generation function + _, pri, err := ed25519.GenerateKey(limReader) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error generating derived key: %v", err)} + } + return pri, nil + + default: + return nil, errutil.InternalError{Err: "unsupported key type for derivation"} + } + + default: + return nil, errutil.InternalError{Err: "unsupported key derivation mode"} + } +} + +func (p *Policy) convergentVersion(ver int) int { + if !p.ConvergentEncryption { + return 0 + } + + convergentVersion := p.ConvergentVersion + if convergentVersion == 0 { + // For some reason, not upgraded yet + convergentVersion = 1 + } + currKey := p.Keys[strconv.Itoa(ver)] + if currKey.ConvergentVersion != 0 { + convergentVersion = currKey.ConvergentVersion + } + + return convergentVersion +} + +func (p *Policy) Encrypt(ver int, context, nonce []byte, value string) (string, error) { + if !p.Type.EncryptionSupported() { + return "", errutil.UserError{Err: fmt.Sprintf("message encryption not supported for key type %v", p.Type)} + } + + // Decode the plaintext value + plaintext, err := base64.StdEncoding.DecodeString(value) + if err != nil { + return "", errutil.UserError{Err: err.Error()} + } + + switch { + case ver == 0: + ver = p.LatestVersion + case ver < 0: + return "", errutil.UserError{Err: "requested version for encryption is negative"} + case ver > p.LatestVersion: + return "", errutil.UserError{Err: "requested version for encryption is higher than the latest key version"} + case ver < p.MinEncryptionVersion: + return "", errutil.UserError{Err: "requested version for encryption is less than the minimum encryption key version"} + } + + var ciphertext []byte + + switch p.Type { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + hmacKey := context + + var aead cipher.AEAD + var encKey []byte + var deriveHMAC bool + + numBytes := 32 + if p.convergentVersion(ver) > 2 { + deriveHMAC = true + numBytes = 64 + } + key, err := p.DeriveKey(context, ver, numBytes) + if err != nil { + return "", err + } + + if len(key) < numBytes { + return "", errutil.InternalError{Err: "could not derive key, length too small"} + } + + encKey = key[:32] + if len(encKey) != 32 { + return "", errutil.InternalError{Err: "could not derive enc key, length not correct"} + } + if deriveHMAC { + hmacKey = key[32:] + if len(hmacKey) != 32 { + return "", errutil.InternalError{Err: "could not derive hmac key, length not correct"} + } + } + + switch p.Type { + case KeyType_AES256_GCM96: + // Setup the cipher + aesCipher, err := aes.NewCipher(encKey) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + // Setup the GCM AEAD + gcm, err := cipher.NewGCM(aesCipher) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + aead = gcm + + case KeyType_ChaCha20_Poly1305: + cha, err := chacha20poly1305.New(encKey) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + aead = cha + } + + if p.ConvergentEncryption { + convergentVersion := p.convergentVersion(ver) + switch convergentVersion { + case 1: + if len(nonce) != aead.NonceSize() { + return "", errutil.UserError{Err: fmt.Sprintf("base64-decoded nonce must be %d bytes long when using convergent encryption with this key", aead.NonceSize())} + } + case 2, 3: + if len(hmacKey) == 0 { + return "", errutil.InternalError{Err: fmt.Sprintf("invalid hmac key length of zero")} + } + nonceHmac := hmac.New(sha256.New, hmacKey) + nonceHmac.Write(plaintext) + nonceSum := nonceHmac.Sum(nil) + nonce = nonceSum[:aead.NonceSize()] + default: + return "", errutil.InternalError{Err: fmt.Sprintf("unhandled convergent version %d", convergentVersion)} + } + } else { + // Compute random nonce + nonce, err = uuid.GenerateRandomBytes(aead.NonceSize()) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + } + + // Encrypt and tag with AEAD + ciphertext = aead.Seal(nil, nonce, plaintext, nil) + + // Place the encrypted data after the nonce + if !p.ConvergentEncryption || p.convergentVersion(ver) > 1 { + ciphertext = append(nonce, ciphertext...) + } + + case KeyType_RSA2048, KeyType_RSA4096: + key := p.Keys[strconv.Itoa(ver)].RSAKey + ciphertext, err = rsa.EncryptOAEP(sha256.New(), rand.Reader, &key.PublicKey, plaintext, nil) + if err != nil { + return "", errutil.InternalError{Err: fmt.Sprintf("failed to RSA encrypt the plaintext: %v", err)} + } + + default: + return "", errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)} + } + + // Convert to base64 + encoded := base64.StdEncoding.EncodeToString(ciphertext) + + // Prepend some information + encoded = p.getVersionPrefix(ver) + encoded + + return encoded, nil +} + +func (p *Policy) Decrypt(context, nonce []byte, value string) (string, error) { + if !p.Type.DecryptionSupported() { + return "", errutil.UserError{Err: fmt.Sprintf("message decryption not supported for key type %v", p.Type)} + } + + tplParts, err := p.getTemplateParts() + if err != nil { + return "", err + } + + // Verify the prefix + if !strings.HasPrefix(value, tplParts[0]) { + return "", errutil.UserError{Err: "invalid ciphertext: no prefix"} + } + + splitVerCiphertext := strings.SplitN(strings.TrimPrefix(value, tplParts[0]), tplParts[1], 2) + if len(splitVerCiphertext) != 2 { + return "", errutil.UserError{Err: "invalid ciphertext: wrong number of fields"} + } + + ver, err := strconv.Atoi(splitVerCiphertext[0]) + if err != nil { + return "", errutil.UserError{Err: "invalid ciphertext: version number could not be decoded"} + } + + if ver == 0 { + // Compatibility mode with initial implementation, where keys start at + // zero + ver = 1 + } + + if ver > p.LatestVersion { + return "", errutil.UserError{Err: "invalid ciphertext: version is too new"} + } + + if p.MinDecryptionVersion > 0 && ver < p.MinDecryptionVersion { + return "", errutil.UserError{Err: ErrTooOld} + } + + convergentVersion := p.convergentVersion(ver) + if convergentVersion == 1 && (nonce == nil || len(nonce) == 0) { + return "", errutil.UserError{Err: "invalid convergent nonce supplied"} + } + + // Decode the base64 + decoded, err := base64.StdEncoding.DecodeString(splitVerCiphertext[1]) + if err != nil { + return "", errutil.UserError{Err: "invalid ciphertext: could not decode base64"} + } + + var plain []byte + + switch p.Type { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + var aead cipher.AEAD + + encKey, err := p.DeriveKey(context, ver, 32) + if err != nil { + return "", err + } + + if len(encKey) != 32 { + return "", errutil.InternalError{Err: "could not derive enc key, length not correct"} + } + + switch p.Type { + case KeyType_AES256_GCM96: + // Setup the cipher + aesCipher, err := aes.NewCipher(encKey) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + // Setup the GCM AEAD + gcm, err := cipher.NewGCM(aesCipher) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + aead = gcm + + case KeyType_ChaCha20_Poly1305: + cha, err := chacha20poly1305.New(encKey) + if err != nil { + return "", errutil.InternalError{Err: err.Error()} + } + + aead = cha + } + + if len(decoded) < aead.NonceSize() { + return "", errutil.UserError{Err: "invalid ciphertext length"} + } + + // Extract the nonce and ciphertext + var ciphertext []byte + if p.ConvergentEncryption && convergentVersion == 1 { + ciphertext = decoded + } else { + nonce = decoded[:aead.NonceSize()] + ciphertext = decoded[aead.NonceSize():] + } + + // Verify and Decrypt + plain, err = aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + return "", errutil.UserError{Err: "invalid ciphertext: unable to decrypt"} + } + + case KeyType_RSA2048, KeyType_RSA4096: + key := p.Keys[strconv.Itoa(ver)].RSAKey + plain, err = rsa.DecryptOAEP(sha256.New(), rand.Reader, key, decoded, nil) + if err != nil { + return "", errutil.InternalError{Err: fmt.Sprintf("failed to RSA decrypt the ciphertext: %v", err)} + } + + default: + return "", errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)} + } + + return base64.StdEncoding.EncodeToString(plain), nil +} + +func (p *Policy) HMACKey(version int) ([]byte, error) { + switch { + case version < 0: + return nil, fmt.Errorf("key version does not exist (cannot be negative)") + case version > p.LatestVersion: + return nil, fmt.Errorf("key version does not exist; latest key version is %d", p.LatestVersion) + } + + if p.Keys[strconv.Itoa(version)].HMACKey == nil { + return nil, fmt.Errorf("no HMAC key exists for that key version") + } + + return p.Keys[strconv.Itoa(version)].HMACKey, nil +} + +func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorithm string) (*SigningResult, error) { + if !p.Type.SigningSupported() { + return nil, fmt.Errorf("message signing not supported for key type %v", p.Type) + } + + switch { + case ver == 0: + ver = p.LatestVersion + case ver < 0: + return nil, errutil.UserError{Err: "requested version for signing is negative"} + case ver > p.LatestVersion: + return nil, errutil.UserError{Err: "requested version for signing is higher than the latest key version"} + case p.MinEncryptionVersion > 0 && ver < p.MinEncryptionVersion: + return nil, errutil.UserError{Err: "requested version for signing is less than the minimum encryption key version"} + } + + var sig []byte + var pubKey []byte + var err error + switch p.Type { + case KeyType_ECDSA_P256: + keyParams := p.Keys[strconv.Itoa(ver)] + key := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: keyParams.EC_X, + Y: keyParams.EC_Y, + }, + D: keyParams.EC_D, + } + r, s, err := ecdsa.Sign(rand.Reader, key, input) + if err != nil { + return nil, err + } + marshaledSig, err := asn1.Marshal(ecdsaSignature{ + R: r, + S: s, + }) + if err != nil { + return nil, err + } + sig = marshaledSig + + case KeyType_ED25519: + var key ed25519.PrivateKey + + if p.Derived { + // Derive the key that should be used + var err error + key, err = p.DeriveKey(context, ver, 32) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} + } + pubKey = key.Public().(ed25519.PublicKey) + } else { + key = ed25519.PrivateKey(p.Keys[strconv.Itoa(ver)].Key) + } + + // Per docs, do not pre-hash ed25519; it does two passes and performs + // its own hashing + sig, err = key.Sign(rand.Reader, input, crypto.Hash(0)) + if err != nil { + return nil, err + } + + case KeyType_RSA2048, KeyType_RSA4096: + key := p.Keys[strconv.Itoa(ver)].RSAKey + + var algo crypto.Hash + switch hashAlgorithm { + case "sha2-224": + algo = crypto.SHA224 + case "sha2-256": + algo = crypto.SHA256 + case "sha2-384": + algo = crypto.SHA384 + case "sha2-512": + algo = crypto.SHA512 + default: + return nil, errutil.InternalError{Err: fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)} + } + + if sigAlgorithm == "" { + sigAlgorithm = "pss" + } + + switch sigAlgorithm { + case "pss": + sig, err = rsa.SignPSS(rand.Reader, key, algo, input, nil) + if err != nil { + return nil, err + } + case "pkcs1v15": + sig, err = rsa.SignPKCS1v15(rand.Reader, key, algo, input) + if err != nil { + return nil, err + } + default: + return nil, errutil.InternalError{Err: fmt.Sprintf("unsupported rsa signature algorithm %s", sigAlgorithm)} + } + + default: + return nil, fmt.Errorf("unsupported key type %v", p.Type) + } + + // Convert to base64 + encoded := base64.StdEncoding.EncodeToString(sig) + res := &SigningResult{ + Signature: p.getVersionPrefix(ver) + encoded, + PublicKey: pubKey, + } + + return res, nil +} + +func (p *Policy) VerifySignature(context, input []byte, sig, hashAlgorithm string, sigAlgorithm string) (bool, error) { + if !p.Type.SigningSupported() { + return false, errutil.UserError{Err: fmt.Sprintf("message verification not supported for key type %v", p.Type)} + } + + tplParts, err := p.getTemplateParts() + if err != nil { + return false, err + } + + // Verify the prefix + if !strings.HasPrefix(sig, tplParts[0]) { + return false, errutil.UserError{Err: "invalid signature: no prefix"} + } + + splitVerSig := strings.SplitN(strings.TrimPrefix(sig, tplParts[0]), tplParts[1], 2) + if len(splitVerSig) != 2 { + return false, errutil.UserError{Err: "invalid signature: wrong number of fields"} + } + + ver, err := strconv.Atoi(splitVerSig[0]) + if err != nil { + return false, errutil.UserError{Err: "invalid signature: version number could not be decoded"} + } + + if ver > p.LatestVersion { + return false, errutil.UserError{Err: "invalid signature: version is too new"} + } + + if p.MinDecryptionVersion > 0 && ver < p.MinDecryptionVersion { + return false, errutil.UserError{Err: ErrTooOld} + } + + sigBytes, err := base64.StdEncoding.DecodeString(splitVerSig[1]) + if err != nil { + return false, errutil.UserError{Err: "invalid base64 signature value"} + } + + switch p.Type { + case KeyType_ECDSA_P256: + var ecdsaSig ecdsaSignature + rest, err := asn1.Unmarshal(sigBytes, &ecdsaSig) + if err != nil { + return false, errutil.UserError{Err: "supplied signature is invalid"} + } + if rest != nil && len(rest) != 0 { + return false, errutil.UserError{Err: "supplied signature contains extra data"} + } + + keyParams := p.Keys[strconv.Itoa(ver)] + key := &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: keyParams.EC_X, + Y: keyParams.EC_Y, + } + + return ecdsa.Verify(key, input, ecdsaSig.R, ecdsaSig.S), nil + + case KeyType_ED25519: + var key ed25519.PrivateKey + + if p.Derived { + // Derive the key that should be used + var err error + key, err = p.DeriveKey(context, ver, 32) + if err != nil { + return false, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} + } + } else { + key = ed25519.PrivateKey(p.Keys[strconv.Itoa(ver)].Key) + } + + return ed25519.Verify(key.Public().(ed25519.PublicKey), input, sigBytes), nil + + case KeyType_RSA2048, KeyType_RSA4096: + key := p.Keys[strconv.Itoa(ver)].RSAKey + + var algo crypto.Hash + switch hashAlgorithm { + case "sha2-224": + algo = crypto.SHA224 + case "sha2-256": + algo = crypto.SHA256 + case "sha2-384": + algo = crypto.SHA384 + case "sha2-512": + algo = crypto.SHA512 + default: + return false, errutil.InternalError{Err: fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)} + } + + if sigAlgorithm == "" { + sigAlgorithm = "pss" + } + + switch sigAlgorithm { + case "pss": + err = rsa.VerifyPSS(&key.PublicKey, algo, input, sigBytes, nil) + case "pkcs1v15": + err = rsa.VerifyPKCS1v15(&key.PublicKey, algo, input, sigBytes) + default: + return false, errutil.InternalError{Err: fmt.Sprintf("unsupported rsa signature algorithm %s", sigAlgorithm)} + } + + return err == nil, nil + + default: + return false, errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)} + } +} + +func (p *Policy) Rotate(ctx context.Context, storage logical.Storage) (retErr error) { + priorLatestVersion := p.LatestVersion + priorMinDecryptionVersion := p.MinDecryptionVersion + var priorKeys keyEntryMap + + if p.Keys != nil { + priorKeys = keyEntryMap{} + for k, v := range p.Keys { + priorKeys[k] = v + } + } + + defer func() { + if retErr != nil { + p.LatestVersion = priorLatestVersion + p.MinDecryptionVersion = priorMinDecryptionVersion + p.Keys = priorKeys + } + }() + + if p.Keys == nil { + // This is an initial key rotation when generating a new policy. We + // don't need to call migrate here because if we've called getPolicy to + // get the policy in the first place it will have been run. + p.Keys = keyEntryMap{} + } + + p.LatestVersion += 1 + now := time.Now() + entry := KeyEntry{ + CreationTime: now, + DeprecatedCreationTime: now.Unix(), + } + + hmacKey, err := uuid.GenerateRandomBytes(32) + if err != nil { + return err + } + entry.HMACKey = hmacKey + + switch p.Type { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + // Generate a 256bit key + newKey, err := uuid.GenerateRandomBytes(32) + if err != nil { + return err + } + entry.Key = newKey + + case KeyType_ECDSA_P256: + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return err + } + entry.EC_D = privKey.D + entry.EC_X = privKey.X + entry.EC_Y = privKey.Y + derBytes, err := x509.MarshalPKIXPublicKey(privKey.Public()) + if err != nil { + return errwrap.Wrapf("error marshaling public key: {{err}}", err) + } + pemBlock := &pem.Block{ + Type: "PUBLIC KEY", + Bytes: derBytes, + } + pemBytes := pem.EncodeToMemory(pemBlock) + if pemBytes == nil || len(pemBytes) == 0 { + return fmt.Errorf("error PEM-encoding public key") + } + entry.FormattedPublicKey = string(pemBytes) + + case KeyType_ED25519: + pub, pri, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return err + } + entry.Key = pri + entry.FormattedPublicKey = base64.StdEncoding.EncodeToString(pub) + + case KeyType_RSA2048, KeyType_RSA4096: + bitSize := 2048 + if p.Type == KeyType_RSA4096 { + bitSize = 4096 + } + + entry.RSAKey, err = rsa.GenerateKey(rand.Reader, bitSize) + if err != nil { + return err + } + } + + if p.ConvergentEncryption { + if p.ConvergentVersion == -1 || p.ConvergentVersion > 1 { + entry.ConvergentVersion = currentConvergentVersion + } + } + + p.Keys[strconv.Itoa(p.LatestVersion)] = entry + + // This ensures that with new key creations min decryption version is set + // to 1 rather than the int default of 0, since keys start at 1 (either + // fresh or after migration to the key map) + if p.MinDecryptionVersion == 0 { + p.MinDecryptionVersion = 1 + } + + return p.Persist(ctx, storage) +} + +func (p *Policy) MigrateKeyToKeysMap() { + now := time.Now() + p.Keys = keyEntryMap{ + "1": KeyEntry{ + Key: p.Key, + CreationTime: now, + DeprecatedCreationTime: now.Unix(), + }, + } + p.Key = nil +} + +// Backup should be called with an exclusive lock held on the policy +func (p *Policy) Backup(ctx context.Context, storage logical.Storage) (out string, retErr error) { + if !p.Exportable { + return "", fmt.Errorf("exporting is disallowed on the policy") + } + + if !p.AllowPlaintextBackup { + return "", fmt.Errorf("plaintext backup is disallowed on the policy") + } + + priorBackupInfo := p.BackupInfo + + defer func() { + if retErr != nil { + p.BackupInfo = priorBackupInfo + } + }() + + // Create a record of this backup operation in the policy + p.BackupInfo = &BackupInfo{ + Time: time.Now(), + Version: p.LatestVersion, + } + err := p.Persist(ctx, storage) + if err != nil { + return "", errwrap.Wrapf("failed to persist policy with backup info: {{err}}", err) + } + + // Load the archive only after persisting the policy as the archive can get + // adjusted while persisting the policy + archivedKeys, err := p.LoadArchive(ctx, storage) + if err != nil { + return "", err + } + + keyData := &KeyData{ + Policy: p, + ArchivedKeys: archivedKeys, + } + + encodedBackup, err := jsonutil.EncodeJSON(keyData) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(encodedBackup), nil +} + +func (p *Policy) getTemplateParts() ([]string, error) { + partsRaw, ok := p.versionPrefixCache.Load("template-parts") + if ok { + return partsRaw.([]string), nil + } + + template := p.VersionTemplate + if template == "" { + template = DefaultVersionTemplate + } + + tplParts := strings.Split(template, "{{version}}") + if len(tplParts) != 2 { + return nil, errutil.InternalError{Err: "error parsing version template"} + } + + p.versionPrefixCache.Store("template-parts", tplParts) + return tplParts, nil +} + +func (p *Policy) getVersionPrefix(ver int) string { + prefixRaw, ok := p.versionPrefixCache.Load(ver) + if ok { + return prefixRaw.(string) + } + + template := p.VersionTemplate + if template == "" { + template = DefaultVersionTemplate + } + + prefix := strings.Replace(template, "{{version}}", strconv.Itoa(ver), -1) + p.versionPrefixCache.Store(ver, prefix) + + return prefix +} diff --git a/vendor/github.com/hashicorp/vault/helper/locksutil/locks.go b/vendor/github.com/hashicorp/vault/helper/locksutil/locks.go new file mode 100644 index 0000000..e0c2fcd --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/locksutil/locks.go @@ -0,0 +1,60 @@ +package locksutil + +import ( + "crypto/md5" + "sync" +) + +const ( + LockCount = 256 +) + +type LockEntry struct { + sync.RWMutex +} + +// CreateLocks returns an array so that the locks can be iterated over in +// order. +// +// This is only threadsafe if a process is using a single lock, or iterating +// over the entire lock slice in order. Using a consistent order avoids +// deadlocks because you can never have the following: +// +// Lock A, Lock B +// Lock B, Lock A +// +// Where process 1 is now deadlocked trying to lock B, and process 2 deadlocked trying to lock A +// +func CreateLocks() []*LockEntry { + ret := make([]*LockEntry, LockCount) + for i := range ret { + ret[i] = new(LockEntry) + } + return ret +} + +func LockIndexForKey(key string) uint8 { + hf := md5.New() + hf.Write([]byte(key)) + return uint8(hf.Sum(nil)[0]) +} + +func LockForKey(locks []*LockEntry, key string) *LockEntry { + return locks[LockIndexForKey(key)] +} + +func LocksForKeys(locks []*LockEntry, keys []string) []*LockEntry { + lockIndexes := make(map[uint8]struct{}, len(keys)) + for _, k := range keys { + lockIndexes[LockIndexForKey(k)] = struct{}{} + } + + locksToReturn := make([]*LockEntry, 0, len(keys)) + for i, l := range locks { + if _, ok := lockIndexes[uint8(i)]; ok { + locksToReturn = append(locksToReturn, l) + } + } + + return locksToReturn +} diff --git a/vendor/github.com/hashicorp/vault/helper/logging/vault.go b/vendor/github.com/hashicorp/vault/helper/logging/vault.go new file mode 100644 index 0000000..3e7e476 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/logging/vault.go @@ -0,0 +1,39 @@ +package logging + +import ( + "io" + "os" + "strings" + + log "github.com/hashicorp/go-hclog" +) + +// NewVaultLogger creates a new logger with the specified level and a Vault +// formatter +func NewVaultLogger(level log.Level) log.Logger { + return NewVaultLoggerWithWriter(log.DefaultOutput, level) +} + +// NewVaultLoggerWithWriter creates a new logger with the specified level and +// writer and a Vault formatter +func NewVaultLoggerWithWriter(w io.Writer, level log.Level) log.Logger { + opts := &log.LoggerOptions{ + Level: level, + Output: w, + JSONFormat: useJson(), + } + return log.New(opts) +} + +func useJson() bool { + logFormat := os.Getenv("VAULT_LOG_FORMAT") + if logFormat == "" { + logFormat = os.Getenv("LOGXI_FORMAT") + } + switch strings.ToLower(logFormat) { + case "json", "vault_json", "vault-json", "vaultjson": + return true + default: + return false + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/mfa/duo/duo.go b/vendor/github.com/hashicorp/vault/helper/mfa/duo/duo.go new file mode 100644 index 0000000..51d3371 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mfa/duo/duo.go @@ -0,0 +1,149 @@ +// Package duo provides a Duo MFA handler to authenticate users +// with Duo. This handler is registered as the "duo" type in +// mfa_config. +package duo + +import ( + "context" + "fmt" + "net/url" + + "github.com/duosecurity/duo_api_golang/authapi" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// DuoPaths returns path functions to configure Duo. +func DuoPaths() []*framework.Path { + return []*framework.Path{ + pathDuoConfig(), + pathDuoAccess(), + } +} + +// DuoRootPaths returns the paths that are used to configure Duo. +func DuoRootPaths() []string { + return []string{ + "duo/access", + "duo/config", + } +} + +// DuoHandler interacts with the Duo Auth API to authenticate a user +// login request. If successful, the original response from the login +// backend is returned. +func DuoHandler(ctx context.Context, req *logical.Request, d *framework.FieldData, resp *logical.Response) ( + *logical.Response, error) { + duoConfig, err := GetDuoConfig(ctx, req) + if err != nil || duoConfig == nil { + return logical.ErrorResponse("Could not load Duo configuration"), nil + } + + duoAuthClient, err := GetDuoAuthClient(ctx, req, duoConfig) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + + username, ok := resp.Auth.Metadata["username"] + if !ok { + return logical.ErrorResponse("Could not read username for MFA"), nil + } + + var request *duoAuthRequest = &duoAuthRequest{} + request.successResp = resp + request.username = username + request.method = d.Get("method").(string) + request.passcode = d.Get("passcode").(string) + request.ipAddr = req.Connection.RemoteAddr + + return duoHandler(duoConfig, duoAuthClient, request) +} + +type duoAuthRequest struct { + successResp *logical.Response + username string + method string + passcode string + ipAddr string +} + +func duoHandler(duoConfig *DuoConfig, duoAuthClient AuthClient, request *duoAuthRequest) ( + *logical.Response, error) { + + duoUser := fmt.Sprintf(duoConfig.UsernameFormat, request.username) + + preauth, err := duoAuthClient.Preauth( + authapi.PreauthUsername(duoUser), + authapi.PreauthIpAddr(request.ipAddr), + ) + + if err != nil || preauth == nil { + return logical.ErrorResponse("Could not call Duo preauth"), nil + } + + if preauth.StatResult.Stat != "OK" { + errorMsg := "Could not look up Duo user information" + if preauth.StatResult.Message != nil { + errorMsg = errorMsg + ": " + *preauth.StatResult.Message + } + if preauth.StatResult.Message_Detail != nil { + errorMsg = errorMsg + " (" + *preauth.StatResult.Message_Detail + ")" + } + return logical.ErrorResponse(errorMsg), nil + } + + switch preauth.Response.Result { + case "allow": + return request.successResp, err + case "deny": + return logical.ErrorResponse(preauth.Response.Status_Msg), nil + case "enroll": + return logical.ErrorResponse(fmt.Sprintf("%s (%s)", + preauth.Response.Status_Msg, + preauth.Response.Enroll_Portal_Url)), nil + case "auth": + break + default: + return logical.ErrorResponse(fmt.Sprintf("Invalid Duo preauth response: %s", + preauth.Response.Result)), nil + } + + options := []func(*url.Values){authapi.AuthUsername(duoUser)} + if request.method == "" { + request.method = "auto" + } + if request.method == "auto" || request.method == "push" { + if duoConfig.PushInfo != "" { + options = append(options, authapi.AuthPushinfo(duoConfig.PushInfo)) + } + } + if request.passcode != "" { + request.method = "passcode" + options = append(options, authapi.AuthPasscode(request.passcode)) + } else { + options = append(options, authapi.AuthDevice("auto")) + } + + result, err := duoAuthClient.Auth(request.method, options...) + + if err != nil || result == nil { + return logical.ErrorResponse("Could not call Duo auth"), nil + } + + if result.StatResult.Stat != "OK" { + errorMsg := "Could not authenticate Duo user" + if result.StatResult.Message != nil { + errorMsg = errorMsg + ": " + *result.StatResult.Message + } + if result.StatResult.Message_Detail != nil { + errorMsg = errorMsg + " (" + *result.StatResult.Message_Detail + ")" + } + return logical.ErrorResponse(errorMsg), nil + } + + if result.Response.Result != "allow" { + return logical.ErrorResponse(result.Response.Status_Msg), nil + } + + return request.successResp, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_access.go b/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_access.go new file mode 100644 index 0000000..04ed79a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_access.go @@ -0,0 +1,119 @@ +package duo + +import ( + "context" + "fmt" + "net/url" + + "github.com/duosecurity/duo_api_golang" + "github.com/duosecurity/duo_api_golang/authapi" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +type AuthClient interface { + Preauth(options ...func(*url.Values)) (*authapi.PreauthResult, error) + Auth(factor string, options ...func(*url.Values)) (*authapi.AuthResult, error) +} + +func pathDuoAccess() *framework.Path { + return &framework.Path{ + Pattern: `duo/access`, + Fields: map[string]*framework.FieldSchema{ + "skey": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Duo secret key", + }, + "ikey": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Duo integration key", + }, + "host": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Duo api host", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: pathDuoAccessWrite, + }, + + HelpSynopsis: pathDuoAccessHelpSyn, + HelpDescription: pathDuoAccessHelpDesc, + } +} + +func GetDuoAuthClient(ctx context.Context, req *logical.Request, config *DuoConfig) (AuthClient, error) { + entry, err := req.Storage.Get(ctx, "duo/access") + if err != nil { + return nil, err + } + if entry == nil { + return nil, fmt.Errorf( + "Duo access credentials haven't been configured. Please configure\n" + + "them at the 'duo/access' endpoint") + } + var access DuoAccess + if err := entry.DecodeJSON(&access); err != nil { + return nil, err + } + + duoClient := duoapi.NewDuoApi( + access.IKey, + access.SKey, + access.Host, + config.UserAgent, + ) + duoAuthClient := authapi.NewAuthApi(*duoClient) + check, err := duoAuthClient.Check() + if err != nil { + return nil, err + } + if check == nil { + return nil, fmt.Errorf("could not connect to Duo; got nil result back from API check call") + } + var msg, detail string + if check.StatResult.Message != nil { + msg = *check.StatResult.Message + } + if check.StatResult.Message_Detail != nil { + detail = *check.StatResult.Message_Detail + } + if check.StatResult.Stat != "OK" { + return nil, fmt.Errorf("could not connect to Duo: %q (%q)", msg, detail) + } + return duoAuthClient, nil +} + +func pathDuoAccessWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := logical.StorageEntryJSON("duo/access", DuoAccess{ + SKey: d.Get("skey").(string), + IKey: d.Get("ikey").(string), + Host: d.Get("host").(string), + }) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + return nil, nil +} + +type DuoAccess struct { + SKey string `json:"skey"` + IKey string `json:"ikey"` + Host string `json:"host"` +} + +const pathDuoAccessHelpSyn = ` +Configure the access keys and host for Duo API connections. +` + +const pathDuoAccessHelpDesc = ` +To authenticate users with Duo, the backend needs to know what host to connect to +and must authenticate with an integration key and secret key. This endpoint is used +to configure that information. +` diff --git a/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_config.go b/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_config.go new file mode 100644 index 0000000..9aee9b0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mfa/duo/path_duo_config.go @@ -0,0 +1,110 @@ +package duo + +import ( + "context" + "errors" + "strings" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathDuoConfig() *framework.Path { + return &framework.Path{ + Pattern: `duo/config`, + Fields: map[string]*framework.FieldSchema{ + "user_agent": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "User agent to connect to Duo (default \"\")", + }, + "username_format": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Format string given auth method username as argument to create Duo username (default '%s')", + }, + "push_info": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "A string of URL-encoded key/value pairs that provides additional context about the authentication attempt in the Duo Mobile app", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: pathDuoConfigWrite, + logical.ReadOperation: pathDuoConfigRead, + }, + + HelpSynopsis: pathDuoConfigHelpSyn, + HelpDescription: pathDuoConfigHelpDesc, + } +} + +func GetDuoConfig(ctx context.Context, req *logical.Request) (*DuoConfig, error) { + var result DuoConfig + // all config parameters are optional, so path need not exist + entry, err := req.Storage.Get(ctx, "duo/config") + if err == nil && entry != nil { + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + } + if result.UsernameFormat == "" { + result.UsernameFormat = "%s" + } + return &result, nil +} + +func pathDuoConfigWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + username_format := d.Get("username_format").(string) + if username_format == "" { + username_format = "%s" + } + if !strings.Contains(username_format, "%s") { + return nil, errors.New("username_format must include username ('%s')") + } + entry, err := logical.StorageEntryJSON("duo/config", DuoConfig{ + UsernameFormat: username_format, + UserAgent: d.Get("user_agent").(string), + PushInfo: d.Get("push_info").(string), + }) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + return nil, nil +} + +func pathDuoConfigRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + config, err := GetDuoConfig(ctx, req) + if err != nil { + return nil, err + } + if config == nil { + return nil, nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username_format": config.UsernameFormat, + "user_agent": config.UserAgent, + "push_info": config.PushInfo, + }, + }, nil +} + +type DuoConfig struct { + UsernameFormat string `json:"username_format"` + UserAgent string `json:"user_agent"` + PushInfo string `json:"push_info"` +} + +const pathDuoConfigHelpSyn = ` +Configure Duo second factor behavior. +` + +const pathDuoConfigHelpDesc = ` +This endpoint allows you to configure how the original auth method username maps to +the Duo username by providing a template format string. +` diff --git a/vendor/github.com/hashicorp/vault/helper/mfa/mfa.go b/vendor/github.com/hashicorp/vault/helper/mfa/mfa.go new file mode 100644 index 0000000..69697f3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mfa/mfa.go @@ -0,0 +1,88 @@ +// Package mfa provides wrappers to add multi-factor authentication +// to any auth method. +// +// To add MFA to a backend, replace its login path with the +// paths returned by MFAPaths and add the additional root +// paths returned by MFARootPaths. The backend provides +// the username to the MFA wrapper in Auth.Metadata['username']. +// +// To add an additional MFA type, create a subpackage that +// implements [Type]Paths, [Type]RootPaths, and [Type]Handler +// functions and add them to MFAPaths, MFARootPaths, and +// handlers respectively. +package mfa + +import ( + "context" + + "github.com/hashicorp/vault/helper/mfa/duo" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// MFAPaths returns paths to wrap the original login path and configure MFA. +// When adding MFA to a backend, these paths should be included instead of +// the login path in Backend.Paths. +func MFAPaths(originalBackend *framework.Backend, loginPath *framework.Path) []*framework.Path { + var b backend + b.Backend = originalBackend + return append(duo.DuoPaths(), pathMFAConfig(&b), wrapLoginPath(&b, loginPath)) +} + +// MFARootPaths returns path strings used to configure MFA. When adding MFA +// to a backend, these paths should be included in +// Backend.PathsSpecial.Root. +func MFARootPaths() []string { + return append(duo.DuoRootPaths(), "mfa_config") +} + +// HandlerFunc is the callback called to handle MFA for a login request. +type HandlerFunc func(context.Context, *logical.Request, *framework.FieldData, *logical.Response) (*logical.Response, error) + +// handlers maps each supported MFA type to its handler. +var handlers = map[string]HandlerFunc{ + "duo": duo.DuoHandler, +} + +type backend struct { + *framework.Backend +} + +func wrapLoginPath(b *backend, loginPath *framework.Path) *framework.Path { + loginPath.Fields["passcode"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: "One time passcode (optional)", + } + loginPath.Fields["method"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Multi-factor auth method to use (optional)", + } + // wrap write callback to do MFA after auth + loginHandler := loginPath.Callbacks[logical.UpdateOperation] + loginPath.Callbacks[logical.UpdateOperation] = b.wrapLoginHandler(loginHandler) + return loginPath +} + +func (b *backend) wrapLoginHandler(loginHandler framework.OperationFunc) framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // login with original login function first + resp, err := loginHandler(ctx, req, d) + if err != nil || resp.Auth == nil { + return resp, err + } + + // check if multi-factor enabled + mfa_config, err := b.MFAConfig(ctx, req) + if err != nil || mfa_config == nil { + return resp, nil + } + + // perform multi-factor authentication if type supported + handler, ok := handlers[mfa_config.Type] + if ok { + return handler(ctx, req, d, resp) + } else { + return resp, err + } + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/mfa/path_mfa_config.go b/vendor/github.com/hashicorp/vault/helper/mfa/path_mfa_config.go new file mode 100644 index 0000000..d290baa --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mfa/path_mfa_config.go @@ -0,0 +1,87 @@ +package mfa + +import ( + "context" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathMFAConfig(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `mfa_config`, + Fields: map[string]*framework.FieldSchema{ + "type": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Enables MFA with given backend (available: duo)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathMFAConfigWrite, + logical.ReadOperation: b.pathMFAConfigRead, + }, + + HelpSynopsis: pathMFAConfigHelpSyn, + HelpDescription: pathMFAConfigHelpDesc, + } +} + +func (b *backend) MFAConfig(ctx context.Context, req *logical.Request) (*MFAConfig, error) { + entry, err := req.Storage.Get(ctx, "mfa_config") + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + var result MFAConfig + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + return &result, nil +} + +func (b *backend) pathMFAConfigWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := logical.StorageEntryJSON("mfa_config", MFAConfig{ + Type: d.Get("type").(string), + }) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + return nil, nil +} + +func (b *backend) pathMFAConfigRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + config, err := b.MFAConfig(ctx, req) + if err != nil { + return nil, err + } + if config == nil { + return nil, nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "type": config.Type, + }, + }, nil +} + +type MFAConfig struct { + Type string `json:"type"` +} + +const pathMFAConfigHelpSyn = ` +Configure multi factor backend. +` + +const pathMFAConfigHelpDesc = ` +This endpoint allows you to turn on multi-factor authentication with a given backend. +Currently only Duo is supported. +` diff --git a/vendor/github.com/hashicorp/vault/helper/mlock/mlock.go b/vendor/github.com/hashicorp/vault/helper/mlock/mlock.go new file mode 100644 index 0000000..1675633 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mlock/mlock.go @@ -0,0 +1,15 @@ +package mlock + +// This should be set by the OS-specific packages to tell whether LockMemory +// is supported or not. +var supported bool + +// Supported returns true if LockMemory is functional on this system. +func Supported() bool { + return supported +} + +// LockMemory prevents any memory from being swapped to disk. +func LockMemory() error { + return lockMemory() +} diff --git a/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unavail.go b/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unavail.go new file mode 100644 index 0000000..8084963 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unavail.go @@ -0,0 +1,13 @@ +// +build android darwin nacl netbsd plan9 windows + +package mlock + +func init() { + supported = false +} + +func lockMemory() error { + // XXX: No good way to do this on Windows. There is the VirtualLock + // method, but it requires a specific address and offset. + return nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unix.go b/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unix.go new file mode 100644 index 0000000..af0a69d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/mlock/mlock_unix.go @@ -0,0 +1,18 @@ +// +build dragonfly freebsd linux openbsd solaris + +package mlock + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +func init() { + supported = true +} + +func lockMemory() error { + // Mlockall prevents all current and future pages from being swapped out. + return unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE) +} diff --git a/vendor/github.com/hashicorp/vault/helper/parseutil/parseutil.go b/vendor/github.com/hashicorp/vault/helper/parseutil/parseutil.go new file mode 100644 index 0000000..ae8c58b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/parseutil/parseutil.go @@ -0,0 +1,163 @@ +package parseutil + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/hashicorp/errwrap" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/helper/strutil" + "github.com/mitchellh/mapstructure" +) + +func ParseDurationSecond(in interface{}) (time.Duration, error) { + var dur time.Duration + jsonIn, ok := in.(json.Number) + if ok { + in = jsonIn.String() + } + switch in.(type) { + case string: + inp := in.(string) + if inp == "" { + return time.Duration(0), nil + } + var err error + // Look for a suffix otherwise its a plain second value + if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") { + dur, err = time.ParseDuration(inp) + if err != nil { + return dur, err + } + } else { + // Plain integer + secs, err := strconv.ParseInt(inp, 10, 64) + if err != nil { + return dur, err + } + dur = time.Duration(secs) * time.Second + } + case int: + dur = time.Duration(in.(int)) * time.Second + case int32: + dur = time.Duration(in.(int32)) * time.Second + case int64: + dur = time.Duration(in.(int64)) * time.Second + case uint: + dur = time.Duration(in.(uint)) * time.Second + case uint32: + dur = time.Duration(in.(uint32)) * time.Second + case uint64: + dur = time.Duration(in.(uint64)) * time.Second + default: + return 0, errors.New("could not parse duration from input") + } + + return dur, nil +} + +func ParseInt(in interface{}) (int64, error) { + var ret int64 + jsonIn, ok := in.(json.Number) + if ok { + in = jsonIn.String() + } + switch in.(type) { + case string: + inp := in.(string) + if inp == "" { + return 0, nil + } + var err error + left, err := strconv.ParseInt(inp, 10, 64) + if err != nil { + return ret, err + } + ret = left + case int: + ret = int64(in.(int)) + case int32: + ret = int64(in.(int32)) + case int64: + ret = in.(int64) + case uint: + ret = int64(in.(uint)) + case uint32: + ret = int64(in.(uint32)) + case uint64: + ret = int64(in.(uint64)) + default: + return 0, errors.New("could not parse value from input") + } + + return ret, nil +} + +func ParseBool(in interface{}) (bool, error) { + var result bool + if err := mapstructure.WeakDecode(in, &result); err != nil { + return false, err + } + return result, nil +} + +func ParseCommaStringSlice(in interface{}) ([]string, error) { + var result []string + config := &mapstructure.DecoderConfig{ + Result: &result, + WeaklyTypedInput: true, + DecodeHook: mapstructure.StringToSliceHookFunc(","), + } + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return nil, err + } + if err := decoder.Decode(in); err != nil { + return nil, err + } + return strutil.TrimStrings(result), nil +} + +func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) { + out := make([]*sockaddr.SockAddrMarshaler, 0) + stringAddrs := make([]string, 0) + + switch addrs.(type) { + case string: + stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",") + if len(stringAddrs) == 0 { + return nil, fmt.Errorf("unable to parse addresses from %v", addrs) + } + + case []string: + stringAddrs = addrs.([]string) + + case []interface{}: + for _, v := range addrs.([]interface{}) { + stringAddr, ok := v.(string) + if !ok { + return nil, fmt.Errorf("error parsing %v as string", v) + } + stringAddrs = append(stringAddrs, stringAddr) + } + + default: + return nil, fmt.Errorf("unknown address input type %T", addrs) + } + + for _, addr := range stringAddrs { + sa, err := sockaddr.NewSockAddr(addr) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error parsing address %q: {{err}}", addr), err) + } + out = append(out, &sockaddr.SockAddrMarshaler{ + SockAddr: sa, + }) + } + + return out, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/password/password.go b/vendor/github.com/hashicorp/vault/helper/password/password.go new file mode 100644 index 0000000..102fbe8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/password/password.go @@ -0,0 +1,64 @@ +// password is a package for reading a password securely from a terminal. +// The code in this package disables echo in the terminal so that the +// password is not echoed back in plaintext to the user. +package password + +import ( + "errors" + "io" + "os" + "os/signal" +) + +var ErrInterrupted = errors.New("interrupted") + +// Read reads the password from the given os.File. The password +// will not be echoed back to the user. Ctrl-C will automatically return +// from this function with a blank string and an ErrInterrupted. +func Read(f *os.File) (string, error) { + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt) + defer signal.Stop(ch) + + // Run the actual read in a go-routine so that we can still detect signals + var result string + var resultErr error + doneCh := make(chan struct{}) + go func() { + defer close(doneCh) + result, resultErr = read(f) + }() + + // Wait on either the read to finish or the signal to come through + select { + case <-ch: + return "", ErrInterrupted + case <-doneCh: + return result, resultErr + } +} + +func readline(f *os.File) (string, error) { + var buf [1]byte + resultBuf := make([]byte, 0, 64) + for { + n, err := f.Read(buf[:]) + if err != nil && err != io.EOF { + return "", err + } + if n == 0 || buf[0] == '\n' || buf[0] == '\r' { + break + } + + // ASCII code 3 is what is sent for a Ctrl-C while reading raw. + // If we see that, then get the interrupt. We have to do this here + // because terminals in raw mode won't catch it at the shell level. + if buf[0] == 3 { + return "", ErrInterrupted + } + + resultBuf = append(resultBuf, buf[0]) + } + + return string(resultBuf), nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/password/password_solaris.go b/vendor/github.com/hashicorp/vault/helper/password/password_solaris.go new file mode 100644 index 0000000..66ec86d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/password/password_solaris.go @@ -0,0 +1,55 @@ +// +build solaris + +package password + +import ( + "fmt" + "os" + "syscall" + + "golang.org/x/sys/unix" +) + +func read(f *os.File) (string, error) { + fd := int(f.Fd()) + if !isTerminal(fd) { + return "", fmt.Errorf("file descriptor %d is not a terminal", fd) + } + + oldState, err := makeRaw(fd) + if err != nil { + return "", err + } + defer unix.IoctlSetTermios(fd, unix.TCSETS, oldState) + + return readline(f) +} + +// isTerminal returns true if there is a terminal attached to the given +// file descriptor. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +func isTerminal(fd int) bool { + var termio unix.Termio + err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio) + return err == nil +} + +// makeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c +func makeRaw(fd int) (*unix.Termios, error) { + oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + if err != nil { + return nil, err + } + oldTermios := *oldTermiosPtr + + newTermios := oldTermios + newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL + if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { + return nil, err + } + + return oldTermiosPtr, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/password/password_unix.go b/vendor/github.com/hashicorp/vault/helper/password/password_unix.go new file mode 100644 index 0000000..6d04978 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/password/password_unix.go @@ -0,0 +1,25 @@ +// +build linux darwin freebsd netbsd openbsd + +package password + +import ( + "fmt" + "os" + + "golang.org/x/crypto/ssh/terminal" +) + +func read(f *os.File) (string, error) { + fd := int(f.Fd()) + if !terminal.IsTerminal(fd) { + return "", fmt.Errorf("file descriptor %d is not a terminal", fd) + } + + oldState, err := terminal.MakeRaw(fd) + if err != nil { + return "", err + } + defer terminal.Restore(fd, oldState) + + return readline(f) +} diff --git a/vendor/github.com/hashicorp/vault/helper/password/password_windows.go b/vendor/github.com/hashicorp/vault/helper/password/password_windows.go new file mode 100644 index 0000000..7325698 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/password/password_windows.go @@ -0,0 +1,48 @@ +// +build windows + +package password + +import ( + "os" + "syscall" +) + +var ( + kernel32 = syscall.MustLoadDLL("kernel32.dll") + setConsoleModeProc = kernel32.MustFindProc("SetConsoleMode") +) + +// Magic constant from MSDN to control whether characters read are +// repeated back on the console. +// +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx +const ENABLE_ECHO_INPUT = 0x0004 + +func read(f *os.File) (string, error) { + handle := syscall.Handle(f.Fd()) + + // Grab the old console mode so we can reset it. We defer the reset + // right away because it doesn't matter (it is idempotent). + var oldMode uint32 + if err := syscall.GetConsoleMode(handle, &oldMode); err != nil { + return "", err + } + defer setConsoleMode(handle, oldMode) + + // The new mode is the old mode WITHOUT the echo input flag set. + var newMode uint32 = uint32(int(oldMode) & ^ENABLE_ECHO_INPUT) + if err := setConsoleMode(handle, newMode); err != nil { + return "", err + } + + return readline(f) +} + +func setConsoleMode(console syscall.Handle, mode uint32) error { + r, _, err := setConsoleModeProc.Call(uintptr(console), uintptr(mode)) + if r == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/pathmanager/pathmanager.go b/vendor/github.com/hashicorp/vault/helper/pathmanager/pathmanager.go new file mode 100644 index 0000000..e0e3944 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pathmanager/pathmanager.go @@ -0,0 +1,136 @@ +package pathmanager + +import ( + "strings" + "sync" + + iradix "github.com/hashicorp/go-immutable-radix" +) + +// PathManager is a prefix searchable index of paths +type PathManager struct { + l sync.RWMutex + paths *iradix.Tree +} + +// New creates a new path manager +func New() *PathManager { + return &PathManager{ + paths: iradix.New(), + } +} + +// AddPaths adds path to the paths list +func (p *PathManager) AddPaths(paths []string) { + p.l.Lock() + defer p.l.Unlock() + + txn := p.paths.Txn() + for _, prefix := range paths { + if len(prefix) == 0 { + continue + } + + var exception bool + if strings.HasPrefix(prefix, "!") { + prefix = strings.TrimPrefix(prefix, "!") + exception = true + } + + // We trim any trailing *, but we don't touch whether it is a trailing + // slash or not since we want to be able to ignore prefixes that fully + // specify a file + txn.Insert([]byte(strings.TrimSuffix(prefix, "*")), exception) + } + p.paths = txn.Commit() +} + +// RemovePaths removes paths from the paths list +func (p *PathManager) RemovePaths(paths []string) { + p.l.Lock() + defer p.l.Unlock() + + txn := p.paths.Txn() + for _, prefix := range paths { + if len(prefix) == 0 { + continue + } + + // Exceptions aren't stored with the leading ! so strip it + if strings.HasPrefix(prefix, "!") { + prefix = strings.TrimPrefix(prefix, "!") + } + + // We trim any trailing *, but we don't touch whether it is a trailing + // slash or not since we want to be able to ignore prefixes that fully + // specify a file + txn.Delete([]byte(strings.TrimSuffix(prefix, "*"))) + } + p.paths = txn.Commit() +} + +// RemovePathPrefix removes all paths with the given prefix +func (p *PathManager) RemovePathPrefix(prefix string) { + p.l.Lock() + defer p.l.Unlock() + + // We trim any trailing *, but we don't touch whether it is a trailing + // slash or not since we want to be able to ignore prefixes that fully + // specify a file + p.paths, _ = p.paths.DeletePrefix([]byte(strings.TrimSuffix(prefix, "*"))) +} + +// Len returns the number of paths +func (p *PathManager) Len() int { + return p.paths.Len() +} + +// Paths returns the path list +func (p *PathManager) Paths() []string { + p.l.RLock() + defer p.l.RUnlock() + + paths := make([]string, 0, p.paths.Len()) + walkFn := func(k []byte, v interface{}) bool { + paths = append(paths, string(k)) + return false + } + p.paths.Root().Walk(walkFn) + return paths +} + +// HasPath returns if the prefix for the path exists regardless if it is a path +// (ending with /) or a prefix for a leaf node +func (p *PathManager) HasPath(path string) bool { + p.l.RLock() + defer p.l.RUnlock() + + if _, exceptionRaw, ok := p.paths.Root().LongestPrefix([]byte(path)); ok { + var exception bool + if exceptionRaw != nil { + exception = exceptionRaw.(bool) + } + return !exception + } + return false +} + +// HasExactPath returns if the longest match is an exact match for the +// full path +func (p *PathManager) HasExactPath(path string) bool { + p.l.RLock() + defer p.l.RUnlock() + + if val, exceptionRaw, ok := p.paths.Root().LongestPrefix([]byte(path)); ok { + var exception bool + if exceptionRaw != nil { + exception = exceptionRaw.(bool) + } + + strVal := string(val) + if strings.HasSuffix(strVal, "/") || strVal == path { + return !exception + } + } + return false +} diff --git a/vendor/github.com/hashicorp/vault/helper/pgpkeys/encrypt_decrypt.go b/vendor/github.com/hashicorp/vault/helper/pgpkeys/encrypt_decrypt.go new file mode 100644 index 0000000..eef4c5e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pgpkeys/encrypt_decrypt.go @@ -0,0 +1,118 @@ +package pgpkeys + +import ( + "bytes" + "encoding/base64" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/keybase/go-crypto/openpgp" + "github.com/keybase/go-crypto/openpgp/packet" +) + +// EncryptShares takes an ordered set of byte slices to encrypt and the +// corresponding base64-encoded public keys to encrypt them with, encrypts each +// byte slice with the corresponding public key. +// +// Note: There is no corresponding test function; this functionality is +// thoroughly tested in the init and rekey command unit tests +func EncryptShares(input [][]byte, pgpKeys []string) ([]string, [][]byte, error) { + if len(input) != len(pgpKeys) { + return nil, nil, fmt.Errorf("mismatch between number items to encrypt and number of PGP keys") + } + encryptedShares := make([][]byte, 0, len(pgpKeys)) + entities, err := GetEntities(pgpKeys) + if err != nil { + return nil, nil, err + } + for i, entity := range entities { + ctBuf := bytes.NewBuffer(nil) + pt, err := openpgp.Encrypt(ctBuf, []*openpgp.Entity{entity}, nil, nil, nil) + if err != nil { + return nil, nil, errwrap.Wrapf("error setting up encryption for PGP message: {{err}}", err) + } + _, err = pt.Write(input[i]) + if err != nil { + return nil, nil, errwrap.Wrapf("error encrypting PGP message: {{err}}", err) + } + pt.Close() + encryptedShares = append(encryptedShares, ctBuf.Bytes()) + } + + fingerprints, err := GetFingerprints(nil, entities) + if err != nil { + return nil, nil, err + } + + return fingerprints, encryptedShares, nil +} + +// GetFingerprints takes in a list of openpgp Entities and returns the +// fingerprints. If entities is nil, it will instead parse both entities and +// fingerprints from the pgpKeys string slice. +func GetFingerprints(pgpKeys []string, entities []*openpgp.Entity) ([]string, error) { + if entities == nil { + var err error + entities, err = GetEntities(pgpKeys) + + if err != nil { + return nil, err + } + } + ret := make([]string, 0, len(entities)) + for _, entity := range entities { + ret = append(ret, fmt.Sprintf("%x", entity.PrimaryKey.Fingerprint)) + } + return ret, nil +} + +// GetEntities takes in a string array of base64-encoded PGP keys and returns +// the openpgp Entities +func GetEntities(pgpKeys []string) ([]*openpgp.Entity, error) { + ret := make([]*openpgp.Entity, 0, len(pgpKeys)) + for _, keystring := range pgpKeys { + data, err := base64.StdEncoding.DecodeString(keystring) + if err != nil { + return nil, errwrap.Wrapf("error decoding given PGP key: {{err}}", err) + } + entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) + if err != nil { + return nil, errwrap.Wrapf("error parsing given PGP key: {{err}}", err) + } + ret = append(ret, entity) + } + return ret, nil +} + +// DecryptBytes takes in base64-encoded encrypted bytes and the base64-encoded +// private key and decrypts it. A bytes.Buffer is returned to allow the caller +// to do useful thing with it (get it as a []byte, get it as a string, use it +// as an io.Reader, etc), and also because this function doesn't know if what +// comes out is binary data or a string, so let the caller decide. +func DecryptBytes(encodedCrypt, privKey string) (*bytes.Buffer, error) { + privKeyBytes, err := base64.StdEncoding.DecodeString(privKey) + if err != nil { + return nil, errwrap.Wrapf("error decoding base64 private key: {{err}}", err) + } + + cryptBytes, err := base64.StdEncoding.DecodeString(encodedCrypt) + if err != nil { + return nil, errwrap.Wrapf("error decoding base64 crypted bytes: {{err}}", err) + } + + entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(privKeyBytes))) + if err != nil { + return nil, errwrap.Wrapf("error parsing private key: {{err}}", err) + } + + entityList := &openpgp.EntityList{entity} + md, err := openpgp.ReadMessage(bytes.NewBuffer(cryptBytes), entityList, nil, nil) + if err != nil { + return nil, errwrap.Wrapf("error decrypting the messages: {{err}}", err) + } + + ptBuf := bytes.NewBuffer(nil) + ptBuf.ReadFrom(md.UnverifiedBody) + + return ptBuf, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/pgpkeys/flag.go b/vendor/github.com/hashicorp/vault/helper/pgpkeys/flag.go new file mode 100644 index 0000000..bb0f367 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pgpkeys/flag.go @@ -0,0 +1,140 @@ +package pgpkeys + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "os" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/keybase/go-crypto/openpgp" +) + +// PubKeyFileFlag implements flag.Value and command.Example to receive exactly +// one PGP or keybase key via a flag. +type PubKeyFileFlag string + +func (p *PubKeyFileFlag) String() string { return string(*p) } + +func (p *PubKeyFileFlag) Set(val string) error { + if p != nil && *p != "" { + return errors.New("can only be specified once") + } + + keys, err := ParsePGPKeys(strings.Split(val, ",")) + if err != nil { + return err + } + + if len(keys) > 1 { + return errors.New("can only specify one pgp key") + } + + *p = PubKeyFileFlag(keys[0]) + return nil +} + +func (p *PubKeyFileFlag) Example() string { return "keybase:user" } + +// PGPPubKeyFiles implements the flag.Value interface and allows parsing and +// reading a list of PGP public key files. +type PubKeyFilesFlag []string + +func (p *PubKeyFilesFlag) String() string { + return fmt.Sprint(*p) +} + +func (p *PubKeyFilesFlag) Set(val string) error { + if len(*p) > 0 { + return errors.New("can only be specified once") + } + + keys, err := ParsePGPKeys(strings.Split(val, ",")) + if err != nil { + return err + } + + *p = PubKeyFilesFlag(keys) + return nil +} + +func (p *PubKeyFilesFlag) Example() string { return "keybase:user1, keybase:user2, ..." } + +// ParsePGPKeys takes a list of PGP keys and parses them either using keybase +// or reading them from disk and returns the "expanded" list of pgp keys in +// the same order. +func ParsePGPKeys(keyfiles []string) ([]string, error) { + keys := make([]string, len(keyfiles)) + + keybaseMap, err := FetchKeybasePubkeys(keyfiles) + if err != nil { + return nil, err + } + + for i, keyfile := range keyfiles { + keyfile = strings.TrimSpace(keyfile) + + if strings.HasPrefix(keyfile, kbPrefix) { + key, ok := keybaseMap[keyfile] + if !ok || key == "" { + return nil, fmt.Errorf("keybase user %q not found", strings.TrimPrefix(keyfile, kbPrefix)) + } + keys[i] = key + continue + } + + pgpStr, err := ReadPGPFile(keyfile) + if err != nil { + return nil, err + } + keys[i] = pgpStr + } + + return keys, nil +} + +// ReadPGPFile reads the given PGP file from disk. +func ReadPGPFile(path string) (string, error) { + if path[0] == '@' { + path = path[1:] + } + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + buf := bytes.NewBuffer(nil) + _, err = buf.ReadFrom(f) + if err != nil { + return "", err + } + + // First parse as an armored keyring file, if that doesn't work, treat it as a straight binary/b64 string + keyReader := bytes.NewReader(buf.Bytes()) + entityList, err := openpgp.ReadArmoredKeyRing(keyReader) + if err == nil { + if len(entityList) != 1 { + return "", fmt.Errorf("more than one key found in file %q", path) + } + if entityList[0] == nil { + return "", fmt.Errorf("primary key was nil for file %q", path) + } + + serializedEntity := bytes.NewBuffer(nil) + err = entityList[0].Serialize(serializedEntity) + if err != nil { + return "", errwrap.Wrapf(fmt.Sprintf("error serializing entity for file %q: {{err}}", path), err) + } + + return base64.StdEncoding.EncodeToString(serializedEntity.Bytes()), nil + } + + _, err = base64.StdEncoding.DecodeString(buf.String()) + if err == nil { + return buf.String(), nil + } + return base64.StdEncoding.EncodeToString(buf.Bytes()), nil + +} diff --git a/vendor/github.com/hashicorp/vault/helper/pgpkeys/keybase.go b/vendor/github.com/hashicorp/vault/helper/pgpkeys/keybase.go new file mode 100644 index 0000000..eba0677 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pgpkeys/keybase.go @@ -0,0 +1,117 @@ +package pgpkeys + +import ( + "bytes" + "encoding/base64" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/keybase/go-crypto/openpgp" +) + +const ( + kbPrefix = "keybase:" +) + +// FetchKeybasePubkeys fetches public keys from Keybase given a set of +// usernames, which are derived from correctly formatted input entries. It +// doesn't use their client code due to both the API and the fact that it is +// considered alpha and probably best not to rely on it. The keys are returned +// as base64-encoded strings. +func FetchKeybasePubkeys(input []string) (map[string]string, error) { + client := cleanhttp.DefaultClient() + if client == nil { + return nil, fmt.Errorf("unable to create an http client") + } + + if len(input) == 0 { + return nil, nil + } + + usernames := make([]string, 0, len(input)) + for _, v := range input { + if strings.HasPrefix(v, kbPrefix) { + usernames = append(usernames, strings.TrimPrefix(v, kbPrefix)) + } + } + + if len(usernames) == 0 { + return nil, nil + } + + ret := make(map[string]string, len(usernames)) + url := fmt.Sprintf("https://keybase.io/_/api/1.0/user/lookup.json?usernames=%s&fields=public_keys", strings.Join(usernames, ",")) + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + type PublicKeys struct { + Primary struct { + Bundle string + } + } + + type LThem struct { + PublicKeys `json:"public_keys"` + } + + type KbResp struct { + Status struct { + Name string + } + Them []LThem + } + + out := &KbResp{ + Them: []LThem{}, + } + + if err := jsonutil.DecodeJSONFromReader(resp.Body, out); err != nil { + return nil, err + } + + if out.Status.Name != "OK" { + return nil, fmt.Errorf("got non-OK response: %q", out.Status.Name) + } + + missingNames := make([]string, 0, len(usernames)) + var keyReader *bytes.Reader + serializedEntity := bytes.NewBuffer(nil) + for i, themVal := range out.Them { + if themVal.Primary.Bundle == "" { + missingNames = append(missingNames, usernames[i]) + continue + } + keyReader = bytes.NewReader([]byte(themVal.Primary.Bundle)) + entityList, err := openpgp.ReadArmoredKeyRing(keyReader) + if err != nil { + return nil, err + } + if len(entityList) != 1 { + return nil, fmt.Errorf("primary key could not be parsed for user %q", usernames[i]) + } + if entityList[0] == nil { + return nil, fmt.Errorf("primary key was nil for user %q", usernames[i]) + } + + serializedEntity.Reset() + err = entityList[0].Serialize(serializedEntity) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error serializing entity for user %q: {{err}}", usernames[i]), err) + } + + // The API returns values in the same ordering requested, so this should properly match + ret[kbPrefix+usernames[i]] = base64.StdEncoding.EncodeToString(serializedEntity.Bytes()) + } + + if len(missingNames) > 0 { + return nil, fmt.Errorf("unable to fetch keys for user(s) %q from keybase", strings.Join(missingNames, ",")) + } + + return ret, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/pgpkeys/test_keys.go b/vendor/github.com/hashicorp/vault/helper/pgpkeys/test_keys.go new file mode 100644 index 0000000..c10a905 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pgpkeys/test_keys.go @@ -0,0 +1,271 @@ +package pgpkeys + +const ( + TestPrivKey1 = `lQOYBFXbjPUBCADjNjCUQwfxKL+RR2GA6pv/1K+zJZ8UWIF9S0lk7cVIEfJiprzzwiMwBS5cD0da +rGin1FHvIWOZxujA7oW0O2TUuatqI3aAYDTfRYurh6iKLC+VS+F7H+/mhfFvKmgr0Y5kDCF1j0T/ +063QZ84IRGucR/X43IY7kAtmxGXH0dYOCzOe5UBX1fTn3mXGe2ImCDWBH7gOViynXmb6XNvXkP0f +sF5St9jhO7mbZU9EFkv9O3t3EaURfHopsCVDOlCkFCw5ArY+DUORHRzoMX0PnkyQb5OzibkChzpg +8hQssKeVGpuskTdz5Q7PtdW71jXd4fFVzoNH8fYwRpziD2xNvi6HABEBAAEAB/wL+KX0mdeISEpX +oDgt766Key1Kthe8nbEs5dOXIsP7OR7ZPcnE2hy6gftgVFnBGEZnWVN70vmJd6Z5y9d1mI+GecXj +UL0EpI0EmohyYDJsHUnght/5ecRNFA+VeNmGPYNQGCeHJyZOiFunGGENpHU7BbubAht8delz37Mx +JQgvMyR6AKvg8HKBoQeqV1uMWNJE/vKwV/z1dh1sjK/GFxu05Qaq0GTfAjVLuFOyJTS95yq6gblD +jUdbHLp7tBeqIKo9voWCJF5mGOlq3973vVoWETy9b0YYPCE/M7fXmK9dJITHqkROLMW6TgcFeIw4 +yL5KOBCHk+QGPSvyQN7R7Fd5BADwuT1HZmvg7Y9GjarKXDjxdNemUiHtba2rUzfH6uNmKNQvwQek +nma5palNUJ4/dz1aPB21FUBXJF5yWwXEdApl+lIDU0J5m4UD26rqEVRq9Kx3GsX+yfcwObkrSzW6 +kmnQSB5KI0fIuegMTM+Jxo3pB/mIRwDTMmk+vfzIGyW+7QQA8aFwFLMdKdfLgSGbl5Z6etmOAVQ2 +Oe2ebegU9z/ewi/Rdt2s9yQiAdGVM8+q15Saz8a+kyS/l1CjNPzr3VpYx1OdZ3gb7i2xoy9GdMYR +ZpTq3TuST95kx/9DqA97JrP23G47U0vwF/cg8ixCYF8Fz5dG4DEsxgMwKqhGdW58wMMD/iytkfMk +Vk6Z958Rpy7lhlC6L3zpO38767bSeZ8gRRi/NMFVOSGYepKFarnfxcTiNa+EoSVA6hUo1N64nALE +sJBpyOoTfKIpz7WwTF1+WogkiYrfM6lHon1+3qlziAcRW0IohM3g2C1i3GWdON4Cl8/PDO3R0E52 +N6iG/ctNNeMiPe60EFZhdWx0IFRlc3QgS2V5IDGJATgEEwECACIFAlXbjPUCGy8GCwkIBwMCBhUI +AgkKCwQWAgMBAh4BAheAAAoJEOfLr44BHbeTo+sH/i7bapIgPnZsJ81hmxPj4W12uvunksGJiC7d +4hIHsG7kmJRTJfjECi+AuTGeDwBy84TDcRaOB6e79fj65Fg6HgSahDUtKJbGxj/lWzmaBuTzlN3C +Ee8cMwIPqPT2kajJVdOyrvkyuFOdPFOEA7bdCH0MqgIdM2SdF8t40k/ATfuD2K1ZmumJ508I3gF3 +9jgTnPzD4C8quswrMQ3bzfvKC3klXRlBC0yoArn+0QA3cf2B9T4zJ2qnvgotVbeK/b1OJRNj6Poe +o+SsWNc/A5mw7lGScnDgL3yfwCm1gQXaQKfOt5x+7GqhWDw10q+bJpJlI10FfzAnhMF9etSqSeUR +BRWdA5gEVduM9QEIAL53hJ5bZJ7oEDCnaY+SCzt9QsAfnFTAnZJQrvkvusJzrTQ088eUQmAjvxkf +Rqnv981fFwGnh2+I1Ktm698UAZS9Jt8yjak9wWUICKQO5QUt5k8cHwldQXNXVXFa+TpQWQR5yW1a +9okjh5o/3d4cBt1yZPUJJyLKY43Wvptb6EuEsScO2DnRkh5wSMDQ7dTooddJCmaq3LTjOleRFQbu +9ij386Do6jzK69mJU56TfdcydkxkWF5NZLGnED3lq+hQNbe+8UI5tD2oP/3r5tXKgMy1R/XPvR/z +bfwvx4FAKFOP01awLq4P3d/2xOkMu4Lu9p315E87DOleYwxk+FoTqXEAEQEAAQAH+wVyQXaNwnjQ +xfW+M8SJNo0C7e+0d7HsuBTA/d/eP4bj6+X8RaRFVwiMvSAoxsqBNCLJP00qzzKfRQWJseD1H35z +UjM7rNVUEL2k1yppyp61S0qj0TdhVUfJDYZqRYonVgRMvzfDTB1ryKrefKenQYL/jGd9VYMnKmWZ +6GVk4WWXXx61iOt2HNcmSXKetMM1Mg67woPZkA3fJaXZ+zW0zMu4lTSB7yl3+vLGIFYILkCFnREr +drQ+pmIMwozUAt+pBq8dylnkHh6g/FtRfWmLIMDqM1NlyuHRp3dyLDFdTA93osLG0QJblfX54W34 +byX7a4HASelGi3nPjjOAsTFDkuEEANV2viaWk1CV4ryDrXGmy4Xo32Md+laGPRcVfbJ0mjZjhQsO +gWC1tjMs1qZMPhcrKIBCjjdAcAIrGV9h3CXc0uGuez4XxLO+TPBKaS0B8rKhnKph1YZuf+HrOhzS +astDnOjNIT+qucCL/qSbdYpj9of3yY61S59WphPOBjoVM3BFBADka6ZCk81gx8jA2E1e9UqQDmdM +FZaVA1E7++kqVSFRDJGnq+5GrBTwCJ+sevi+Rvf8Nx4AXvpCdtMBPX9RogsUFcR0pMrKBrgRo/Vg +EpuodY2Ef1VtqXR24OxtRf1UwvHKydIsU05rzMAy5uGgQvTzRTXxZFLGUY31wjWqmo9VPQP+PnwA +K83EV2kk2bsXwZ9MXg05iXqGQYR4bEc/12v04BtaNaDS53hBDO4JIa3Bnz+5oUoYhb8FgezUKA9I +n6RdKTTP1BLAu8titeozpNF07V++dPiSE2wrIVsaNHL1pUwW0ql50titVwe+EglWiCKPtJBcCPUA +3oepSPchiDjPqrNCYIkCPgQYAQIACQUCVduM9QIbLgEpCRDny6+OAR23k8BdIAQZAQIABgUCVduM +9QAKCRAID0JGyHtSGmqYB/4m4rJbbWa7dBJ8VqRU7ZKnNRDR9CVhEGipBmpDGRYulEimOPzLUX/Z +XZmTZzgemeXLBaJJlWnopVUWuAsyjQuZAfdd8nHkGRHG0/DGum0l4sKTta3OPGHNC1z1dAcQ1RCr +9bTD3PxjLBczdGqhzw71trkQRBRdtPiUchltPMIyjUHqVJ0xmg0hPqFic0fICsr0YwKoz3h9+QEc +ZHvsjSZjgydKvfLYcm+4DDMCCqcHuJrbXJKUWmJcXR0y/+HQONGrGJ5xWdO+6eJioPn2jVMnXCm4 +EKc7fcLFrz/LKmJ8seXhxjM3EdFtylBGCrx3xdK0f+JDNQaC/rhUb5V2XuX6VwoH/AtY+XsKVYRf +NIupLOUcf/srsm3IXT4SXWVomOc9hjGQiJ3rraIbADsc+6bCAr4XNZS7moViAAcIPXFv3m3WfUln +G/om78UjQqyVACRZqqAGmuPq+TSkRUCpt9h+A39LQWkojHqyob3cyLgy6z9Q557O9uK3lQozbw2g +H9zC0RqnePl+rsWIUU/ga16fH6pWc1uJiEBt8UZGypQ/E56/343epmYAe0a87sHx8iDV+dNtDVKf +PRENiLOOc19MmS+phmUyrbHqI91c0pmysYcJZCD3a502X1gpjFbPZcRtiTmGnUKdOIu60YPNE4+h +7u2CfYyFPu3AlUaGNMBlvy6PEpU=` + + TestPrivKey2 = `lQOYBFXbkJEBCADKb1ZvlT14XrJa2rTOe5924LQr2PTZlRv+651TXy33yEhelZ+V4sMrELN8fKEG +Zy1kNixmbq3MCF/671k3LigHA7VrOaH9iiQgr6IIq2MeIkUYKZ27C992vQkYLjbYUG8+zl5h69S4 +0Ixm0yL0M54XOJ0gm+maEK1ZESKTUlDNkIS7l0jLZSYwfUeGXSEt6FWs8OgbyRTaHw4PDHrDEE9e +Q67K6IZ3YMhPOL4fVk4Jwrp5R/RwiklT+lNozWEyFVwPFH4MeQMs9nMbt+fWlTzEA7tI4acI9yDk +Cm1yN2R9rmY0UjODRiJw6z6sLV2T+Pf32n3MNSUOYczOjZa4VBwjABEBAAEAB/oCBqTIsxlUgLtz +HRpWW5MJ+93xvmVV0JHhRK/ygKghq+zpC6S+cn7dwrEj1JTPh+17lyemYQK+RMeiBEduoWNKuHUd +WX353w2411rrc/VuGTglzhd8Ir2BdJlPesCzw4JQnrWqcBqN52W+iwhnE7PWVhnvItWnx6APK5Se +q7dzFWy8Z8tNIHm0pBQbeyo6x2rHHSWkr2fs7V02qFQhii1ayFRMcgdOWSNX6CaZJuYhk/DyjApN +9pVhi3P1pNMpFeV0Pt8Gl1f/9o6/HpAYYEt/6vtVRhFUGgtNi95oc0oyzIJxliRvd6+Z236osigQ +QEBwj1ImRK8TKyWPlykiJWc5BADfldgOCA55o3Qz/z/oVE1mm+a3FmPPTQlHBXotNEsrWV2wmJHe +lNQPI6ZwMtLrBSg8PUpG2Rvao6XJ4ZBl/VcDwfcLgCnALPCcL0L0Z3vH3Sc9Ta/bQWJODG7uSaI1 +iVJ7ArKNtVzTqRQWK967mol9CCqh4A0jRrH0aVEFbrqQ/QQA58iEJaFhzFZjufjC9N8Isn3Ky7xu +h+dk001RNCb1GnNZcx4Ld2IB+uXyYjtg7dNaUhGgGuCBo9nax89bMsBzzUukx3SHq1pxopMg6Dm8 +ImBoIAicuQWgEkaP2T0rlwCozUalJZaG1gyrzkPhkeY7CglpJycHLHfY2MIb46c8+58D/iJ83Q5j +Y4x+sqW2QeUYFwqCcOW8Urg64UxEkgXZXiNMwTAJCaxp/Pz7cgeUDwgv+6CXEdnT1910+byzK9ha +V1Q/65+/JYuCeyHxcoAb4Wtpdl7GALGd/1G0UAmq47yrefEr/b00uS35i1qUUhOzo1NmEZch/bvF +kmJ+WtAHunZcOCu0EFZhdWx0IFRlc3QgS2V5IDKJATgEEwECACIFAlXbkJECGy8GCwkIBwMCBhUI +AgkKCwQWAgMBAh4BAheAAAoJEOuDLGfrXolXqz4H/28IuoRxGKoJ064YHjPkkpoddW6zdzzNfHip +ZnNfEUiTEls4qF1IB81M2xqfiXIFRIdO2kaLkRPFhO0hRxbtI6VuZYLgG3QCaXhxW6GyFa5zKABq +hb5ojexdnAYRswaHV201ZCclj9rnJN1PAg0Rz6MdX/w1euEWktQxWKo42oZKyx8oT9p6lrv5KRmG +kdrg8K8ARmRILjmwuBAgJM0eXBZHNGWXelk4YmOgnAAcZA6ZAo1G+8Pg6pKKP61ETewuCg3/u7N0 +vDttB+ZXqF88W9jAYlvdgbTtajNF5IDYDjTzWfeCaIB18F9gOzXq15SwWeDDI+CU9Nmq358IzXlx +k4edA5gEVduQkQEIAOjZV5tbpfIh5QefpIp2dpGMVfpgPj4RNc15CyFnb8y6dhCrdybkY9GveXJe +4F3GNYnSfB42cgxrfhizX3LakmZQ/SAg+YO5KxfCIN7Q9LPNeTgPsZZT6h8lVuXUxOFKXfRaR3/t +GF5xE3e5CoZRsHV/c92h3t1LdJNOnC5mUKIPO4zDxiw/C2T2q3rP1kmIMaOH724kEH5A+xcp1cBH +yt0tdHtIWuQv6joTJzujqViRhlCwQYzQSKpSBxwhBsorPvyinZI/ZXA4XXZc5RoMqV9rikedrb1r +ENO8JOuPu6tMS+znFu67skq2gFFZwCQWIjdHm+2ukE+PE580WAWudyMAEQEAAQAH/i7ndRPI+t0T +AdEu0dTIdyrrg3g7gd471kQtIVZZwTYSy2yhNY/Ciu72s3ab8QNCxY8dNL5bRk8FKjHslAoNSFdO +8iZSLiDgIHOZOcjYe6pqdgQaeTHodm1Otrn2SbB+K/3oX6W/y1xe18aSojGba/nHMj5PeJbIN9Pi +jmh0WMLD/0rmkTTxR7qQ5+kMV4O29xY4qjdYRD5O0adeZX0mNncmlmQ+rX9yxrtSgFROu1jwVtfP +hcNetifTTshJnTwND8hux5ECEadlIVBHypW28Hth9TRBXmddTmv7L7mdtUO6DybgkpWpw4k4LPsk +uZ6aY4wcGRp7EVfWGr9NHbq/n+0EAOlhDXIGdylkQsndjBMyhPsXZa5fFBmOyHjXj733195Jgr1v +ZjaIomrA9cvYrmN75oKrG1jJsMEl6HfC/ZPzEj6E51/p1PRdHP7CdUUA+DG8x4M3jn+e43psVuAR +a1XbN+8/bOa0ubt7ljVPjAEvWRSvU9dRaQz93w3fduAuM07dBAD/ayK3e0d6JMJMrU50lNOXQBgL +rFbg4rWzPO9BJQdhjOhmOZQiUa1Q+EV+s95yIUg1OAfaMP9KRIljr5RCdGNS6WoMNBAQOSrZpelf +jW4NpzphNfWDGVkUoPoskVtJz/nu9d860dGd3Al0kSmtUpMu5QKlo+sSxXUPbWLUn8V9/wP/ScCW +H+0gtL4R7SFazPeTIP+Cu5oR7A/DlFVLJKa3vo+atkhSvwxHGbg04vb/W4mKhGGVtMBtlhRmaWOe +PhUulU5FdaYsdlpN/Yd+hhgU6NHlyImPGVEHWD8c6CG8qoZfpR33j2sqshs4i/MtJZeBvl62vxPn +9bDN7KAjFNll9axAjIkCPgQYAQIACQUCVduQkQIbLgEpCRDrgyxn616JV8BdIAQZAQIABgUCVduQ +kQAKCRArYtevdF38xtzgB/4zVzozBpVOnagRkA7FDsHo36xX60Lik+ew0m28ueDDhnV3bXQsCvn/ +6wiCVWqLOTDeYCPlyTTpEMyk8zwdCICW6MgSkVHWcEDOrRqIrqm86rirjTGjJSgQe3l4CqJvkn6j +ybShYoBk1OZZV6vVv9hPTXXv9E6dLKoEW5YZBrrF+VC0w1iOIvaAQ+QXph20eV4KBIrp/bhG6Pdn +igKxuBZ79cdqDnXIzT9UiIa6LYpR0rbeg+7BmuZTTPS8t+41hIiKS+UZFdKa67eYENtyOmEMWOFC +LLRJGxkleukchiMJ70rknloZXsvJIweXBzSZ6m7mJQBgaig/L/dXyjv6+j2pNB4H/1trYUtJjXQK +HmqlgCmpCkHt3g7JoxWvglnDNmE6q3hIWuVIYQpnzZy1g05+X9Egwc1WVpBB02H7PkUZTfpaP/L6 +DLneMmSKPhZE3I+lPIPjwrxqh6xy5uQezcWkJTNKvPWF4FJzrVvx7XTPjfGvOB0UPEnjvtZTp5yO +hTeZK7DgIEtb/Wcrqs+iRArQKboM930ORSZhwvGK3F9V/gMDpIrvge5vDFsTEYQdw/2epIewH0L/ +FUb/6jBRcVEpGo9Ayg+Jnhq14GOGcd1y9oMZ48kYVLVBTA9tQ+82WE8Bch7uFPj4MFOMVRn1dc3q +dXlg3mimA+iK7tABQfG0RJ9YzWs=` + + TestPrivKey3 = `lQOXBFXbkiMBCACiHW4/VI2JkfvSEINddS7vE6wEu5e1leNQDaLUh6PrATQZS2a4Q6kRE6WlJumj +6wCeN753Cm93UGQl2Bi3USIEeArIZnPTcocrckOVXxtoLBNKXgqKvEsDXgfw8A+doSfXoDm/3Js4 +Wy3WsYKNR9LaPuJZHnpjsFAJhvRVyhH4UFD+1RTSSefq1mozPfDdMoZeZNEpfhwt3DuTJs7RqcTH +CgR2CqhEHnOOE5jJUljHKYLCglE2+8dth1bZlQi4xly/VHZzP3Bn7wKeolK/ROP6VZz/e0xq/BKy +resmxvlBWZ1zWwqGIrV9b0uwYvGrh2hOd5C5+5oGaA2MGcjxwaLBABEBAAEAB/dQbElFIa0VklZa +39ZLhtbBxACSWH3ql3EtRZaB2Mh4zSALbFyJDQfScOy8AZHmv66Ozxit9X9WsYr9OzcHujgl/2da +A3lybF6iLw1YDNaL11G6kuyn5sFP6lYGMRGOIWSik9oSVF6slo8m8ujRLdBsdMXVcElHKzCJiWmt +JZHEnUkl9X96fIPajMBfWjHHwcaeMOc77nvjwqy5wC4EY8TSVYzxeZHL7DADQ0EHBcThlmfizpCq +26LMVb6ju8STH7uDDFyKmhr/hC2vOkt+PKsvBCmW8/ESanO1zKPD9cvSsOWr2rZWNnkDRftqzOU5 +OCrI+3o9E74+toNb07bPntEEAMEStOzSvqZ6NKdh7EZYPA4mkkFC+EiHYIoinP1sd9V8O2Hq+dzx +yFHtWu0LmP6uWXk45vsP9y1UMJcEa33ew5JJa7zgucI772/BNvd/Oys/PqwIAl6uNIY8uYLgmn4L +1IPatp7vDiXzZSivPZd4yN4S4zCypZp9cnpO3qv8q7CtBADW87IA0TabdoxiN+m4XL7sYDRIfglr +MRPAlfrkAUaGDBx/t1xb6IaKk7giFdwHpTI6+g9XNkqKqogMe4Fp+nsd1xtfsNUBn6iKZavm5kXe +Lp9QgE+K6mvIreOTe2PKQqXqgPRG6+SRGatoKeY76fIpd8AxOJyWERxcq2lUHLn45QP/UXDTcYB7 +gzJtZrfpXN0GqQ0lYXMzbQfLnkUsu3mYzArfNy0otzEmKTkwmKclNY1/EJSzSdHfgmeA260a0nLK +64C0wPgSmOqw90qwi5odAYSjSFBapDbyGF86JpHrLxyEEpGoXanRPwWfbiWp19Nwg6nknA87AtaM +3+AHjbWzwCpHL7QQVmF1bHQgVGVzdCBLZXkgM4kBOAQTAQIAIgUCVduSIwIbLwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQ9HlLVvwtxt1aMQf/aaGoL1rRWTUjM6DEShXFhWpV29rEjSdNk5N+ +ZwVifgdCVD5IsSjI1Z7mO2SHHiTm4eKnHAofM6/TZgzXg1YLpu8rDYJARMsM8bgK/xgxSamGjm2c +wN220jOnwePIlG0drNTW5N6zb/K6qHoscJ6NUkjS5JPdGJuq7B0bdCM8/xSbG75gL34U5bYqK38B +DwmW4UMl2rf/BJfxV9hmsZ2Cat4TspgyiWEKTMZI+PugXKDDwuoqgm+320K4EqFkwG4y/WwHkKgk +hZ0+io5lzhTsvVd2p8q8VlH9GG5eA3WWQj0yqucsOmKQvcuT5y0vFY6NQJbyuioqgdlgEXtc+p0B ++Z0DmARV25IjAQgA49yN3hCBsuWoiTezoE9FHJXOCVOBR1/4jStQPJtoMl8mhtl3xTp7iGQ+9GhD +y0l5+fP+qcP/rfBq0BslhxVOZ7jQjdUoM6ZUZzJoPGIo/V2KwqpwQl3tdCIjvagCJeYQfTL7lTCc +4ySz+XBoAYMwZVGMcRcjp+JE8Wx9Ovzuq8wnelbU6I5dVJ7O4E1OWbIkLuytDX+fDEvfft6/oPXN +Bl3cm6FzEuQetQQss3DOG9xnvS+DrjmMCbPwR2a++ioQ8+geoqA/kB4cAI6xOb3ncoeGDHc1i4Y9 +T9Ggi+6Aq3girmfDtNYVOM8cZUXcZNCvLkJn8DNeIvnuFUSEO+a5PwARAQABAAf/TPd98CmRNdV/ +VUI8aYT9Kkervdi4DVzsfvrHcoFn88PSJrCkVTmI6qw526Kwa6VZD0YMmll7LszLt5nD1lorDrwN +rir3FmMzlVwge20IvXRwX4rkunYxtA2oFvL+LsEEhtXGx0ERbWRDapk+eGxQ15hxIO4Y/Cdg9E+a +CWfQUrTSnC6qMVfVYMGfnM1yNX3OWattEFfmxQas5XqQk/0FgjCZALixdanjN/r1tjp5/2MiSD8N +Wkemzsr6yPicnc3+BOZc5YOOnH8FqBvVHcDlSJI6pCOCEiO3Pq2QEk/1evONulbF116mLnQoGrpp +W77l+5O42VUpZfjROCPd5DYyMQQA492CFXZpDIJ2emB9/nK8X6IzdVRK3oof8btbSNnme5afIzhs +wR1ruX30O7ThfB+5ezpbgK1C988CWkr9SNSTy43omarafGig6/Y1RzdiITILuIGfbChoSpc70jXx +U0nzJ/1i9yZ/vDgP3EC2miRhlDcp5w0Bu0oMBlgG/1uhj0cEAP/+7aFGP0fo2MZPhyl5feHKWj4k +85XoAIpMBnzF6HTGU3ljAE56a+4sVw3bWB755DPhvpZvDkX60I9iIJxio8TK5ITdfjlLhxuskXyt +ycwWI/4J+soeq4meoxK9jxZJuDl/qvoGfyzNg1oy2OBehX8+6erW46kr6Z/MQutS3zJJBACmJHrK +VR40qD7a8KbvfuM3ruwlm5JqT/Ykq1gfKKxHjWDIUIeyBX/axGQvAGNYeuuQCzZ0+QsEWur3C4kN +U+Pb5K1WGyOKkhJzivSI56AG3d8TA/Q0JhqST6maY0fvUoahWSCcpd7MULa3n1zx5Wsvi8mkVtup +Js/IDi/kqneqM0XviQI+BBgBAgAJBQJV25IjAhsuASkJEPR5S1b8LcbdwF0gBBkBAgAGBQJV25Ij +AAoJEAUj/03Hcrkg84UIAKxn9nizYtwSgDnVNb5PnD5h6+Ui6r7ffYm2o0im4YhakbFTHIPI9PRh +BavRI5sE5Fg2vtE/x38jattoUrJoNoq9Gh9iv5PBfL3amEGjul0RRqYGl+ub+yv7YGAAHbHcdZen +4gx15VWGpB7y3hycWbdzV8h3EAPKIm5XmB7YyXmArnI3CoJA+HtTZGoL6WZWUwka9YichGfaZ/oD +umENg1l87Pp2RqvjLKHmv2tGCtnDzyv/IiWur9zopFQiCc8ysVgRq6CA5x5nzbv6MqRspYUS4e2I +LFbuREA3blR+caw9oX41IYzarW8IbgeIXJ3HqUyhczRKF/z5nDKtX/kHMCqlbAgAnfu0TALnwVuj +KeXLo4Y7OA9LTEqfORcw62q5OjSoQf/VsRSwGSefv3kGZk5N/igELluU3qpG/twZI/TSL6zGqXU2 +FOMlyMm1849TOB9b4B//4dHrjzPhztzowKMMUqeTxmSgYtFTshKN6eQ0XO+7ZuOXEmSKXS4kOUs9 +ttfzSiPNXUZL2D5nFU9H7rw3VAuXYVTrOx+Dfi6mYsscbxUbi8THODI2Q7B9Ni92DJE1OOe4+57o +fXZ9ln24I14bna/uVHd6hBwLEE6eLCCKkHxQnnZFZduXDHMK0a0OL8RYHfMtNSem4pyC5wDQui1u +KFIzGEPKVoBF9U7VBXpyxpsz+A==` + + TestPubKey1 = `mQENBFXbjPUBCADjNjCUQwfxKL+RR2GA6pv/1K+zJZ8UWIF9S0lk7cVIEfJiprzzwiMwBS5cD0da +rGin1FHvIWOZxujA7oW0O2TUuatqI3aAYDTfRYurh6iKLC+VS+F7H+/mhfFvKmgr0Y5kDCF1j0T/ +063QZ84IRGucR/X43IY7kAtmxGXH0dYOCzOe5UBX1fTn3mXGe2ImCDWBH7gOViynXmb6XNvXkP0f +sF5St9jhO7mbZU9EFkv9O3t3EaURfHopsCVDOlCkFCw5ArY+DUORHRzoMX0PnkyQb5OzibkChzpg +8hQssKeVGpuskTdz5Q7PtdW71jXd4fFVzoNH8fYwRpziD2xNvi6HABEBAAG0EFZhdWx0IFRlc3Qg +S2V5IDGJATgEEwECACIFAlXbjPUCGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOfLr44B +HbeTo+sH/i7bapIgPnZsJ81hmxPj4W12uvunksGJiC7d4hIHsG7kmJRTJfjECi+AuTGeDwBy84TD +cRaOB6e79fj65Fg6HgSahDUtKJbGxj/lWzmaBuTzlN3CEe8cMwIPqPT2kajJVdOyrvkyuFOdPFOE +A7bdCH0MqgIdM2SdF8t40k/ATfuD2K1ZmumJ508I3gF39jgTnPzD4C8quswrMQ3bzfvKC3klXRlB +C0yoArn+0QA3cf2B9T4zJ2qnvgotVbeK/b1OJRNj6Poeo+SsWNc/A5mw7lGScnDgL3yfwCm1gQXa +QKfOt5x+7GqhWDw10q+bJpJlI10FfzAnhMF9etSqSeURBRW5AQ0EVduM9QEIAL53hJ5bZJ7oEDCn +aY+SCzt9QsAfnFTAnZJQrvkvusJzrTQ088eUQmAjvxkfRqnv981fFwGnh2+I1Ktm698UAZS9Jt8y +jak9wWUICKQO5QUt5k8cHwldQXNXVXFa+TpQWQR5yW1a9okjh5o/3d4cBt1yZPUJJyLKY43Wvptb +6EuEsScO2DnRkh5wSMDQ7dTooddJCmaq3LTjOleRFQbu9ij386Do6jzK69mJU56TfdcydkxkWF5N +ZLGnED3lq+hQNbe+8UI5tD2oP/3r5tXKgMy1R/XPvR/zbfwvx4FAKFOP01awLq4P3d/2xOkMu4Lu +9p315E87DOleYwxk+FoTqXEAEQEAAYkCPgQYAQIACQUCVduM9QIbLgEpCRDny6+OAR23k8BdIAQZ +AQIABgUCVduM9QAKCRAID0JGyHtSGmqYB/4m4rJbbWa7dBJ8VqRU7ZKnNRDR9CVhEGipBmpDGRYu +lEimOPzLUX/ZXZmTZzgemeXLBaJJlWnopVUWuAsyjQuZAfdd8nHkGRHG0/DGum0l4sKTta3OPGHN +C1z1dAcQ1RCr9bTD3PxjLBczdGqhzw71trkQRBRdtPiUchltPMIyjUHqVJ0xmg0hPqFic0fICsr0 +YwKoz3h9+QEcZHvsjSZjgydKvfLYcm+4DDMCCqcHuJrbXJKUWmJcXR0y/+HQONGrGJ5xWdO+6eJi +oPn2jVMnXCm4EKc7fcLFrz/LKmJ8seXhxjM3EdFtylBGCrx3xdK0f+JDNQaC/rhUb5V2XuX6VwoH +/AtY+XsKVYRfNIupLOUcf/srsm3IXT4SXWVomOc9hjGQiJ3rraIbADsc+6bCAr4XNZS7moViAAcI +PXFv3m3WfUlnG/om78UjQqyVACRZqqAGmuPq+TSkRUCpt9h+A39LQWkojHqyob3cyLgy6z9Q557O +9uK3lQozbw2gH9zC0RqnePl+rsWIUU/ga16fH6pWc1uJiEBt8UZGypQ/E56/343epmYAe0a87sHx +8iDV+dNtDVKfPRENiLOOc19MmS+phmUyrbHqI91c0pmysYcJZCD3a502X1gpjFbPZcRtiTmGnUKd +OIu60YPNE4+h7u2CfYyFPu3AlUaGNMBlvy6PEpU=` + + TestPubKey2 = `mQENBFXbkJEBCADKb1ZvlT14XrJa2rTOe5924LQr2PTZlRv+651TXy33yEhelZ+V4sMrELN8fKEG +Zy1kNixmbq3MCF/671k3LigHA7VrOaH9iiQgr6IIq2MeIkUYKZ27C992vQkYLjbYUG8+zl5h69S4 +0Ixm0yL0M54XOJ0gm+maEK1ZESKTUlDNkIS7l0jLZSYwfUeGXSEt6FWs8OgbyRTaHw4PDHrDEE9e +Q67K6IZ3YMhPOL4fVk4Jwrp5R/RwiklT+lNozWEyFVwPFH4MeQMs9nMbt+fWlTzEA7tI4acI9yDk +Cm1yN2R9rmY0UjODRiJw6z6sLV2T+Pf32n3MNSUOYczOjZa4VBwjABEBAAG0EFZhdWx0IFRlc3Qg +S2V5IDKJATgEEwECACIFAlXbkJECGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOuDLGfr +XolXqz4H/28IuoRxGKoJ064YHjPkkpoddW6zdzzNfHipZnNfEUiTEls4qF1IB81M2xqfiXIFRIdO +2kaLkRPFhO0hRxbtI6VuZYLgG3QCaXhxW6GyFa5zKABqhb5ojexdnAYRswaHV201ZCclj9rnJN1P +Ag0Rz6MdX/w1euEWktQxWKo42oZKyx8oT9p6lrv5KRmGkdrg8K8ARmRILjmwuBAgJM0eXBZHNGWX +elk4YmOgnAAcZA6ZAo1G+8Pg6pKKP61ETewuCg3/u7N0vDttB+ZXqF88W9jAYlvdgbTtajNF5IDY +DjTzWfeCaIB18F9gOzXq15SwWeDDI+CU9Nmq358IzXlxk4e5AQ0EVduQkQEIAOjZV5tbpfIh5Qef +pIp2dpGMVfpgPj4RNc15CyFnb8y6dhCrdybkY9GveXJe4F3GNYnSfB42cgxrfhizX3LakmZQ/SAg ++YO5KxfCIN7Q9LPNeTgPsZZT6h8lVuXUxOFKXfRaR3/tGF5xE3e5CoZRsHV/c92h3t1LdJNOnC5m +UKIPO4zDxiw/C2T2q3rP1kmIMaOH724kEH5A+xcp1cBHyt0tdHtIWuQv6joTJzujqViRhlCwQYzQ +SKpSBxwhBsorPvyinZI/ZXA4XXZc5RoMqV9rikedrb1rENO8JOuPu6tMS+znFu67skq2gFFZwCQW +IjdHm+2ukE+PE580WAWudyMAEQEAAYkCPgQYAQIACQUCVduQkQIbLgEpCRDrgyxn616JV8BdIAQZ +AQIABgUCVduQkQAKCRArYtevdF38xtzgB/4zVzozBpVOnagRkA7FDsHo36xX60Lik+ew0m28ueDD +hnV3bXQsCvn/6wiCVWqLOTDeYCPlyTTpEMyk8zwdCICW6MgSkVHWcEDOrRqIrqm86rirjTGjJSgQ +e3l4CqJvkn6jybShYoBk1OZZV6vVv9hPTXXv9E6dLKoEW5YZBrrF+VC0w1iOIvaAQ+QXph20eV4K +BIrp/bhG6PdnigKxuBZ79cdqDnXIzT9UiIa6LYpR0rbeg+7BmuZTTPS8t+41hIiKS+UZFdKa67eY +ENtyOmEMWOFCLLRJGxkleukchiMJ70rknloZXsvJIweXBzSZ6m7mJQBgaig/L/dXyjv6+j2pNB4H +/1trYUtJjXQKHmqlgCmpCkHt3g7JoxWvglnDNmE6q3hIWuVIYQpnzZy1g05+X9Egwc1WVpBB02H7 +PkUZTfpaP/L6DLneMmSKPhZE3I+lPIPjwrxqh6xy5uQezcWkJTNKvPWF4FJzrVvx7XTPjfGvOB0U +PEnjvtZTp5yOhTeZK7DgIEtb/Wcrqs+iRArQKboM930ORSZhwvGK3F9V/gMDpIrvge5vDFsTEYQd +w/2epIewH0L/FUb/6jBRcVEpGo9Ayg+Jnhq14GOGcd1y9oMZ48kYVLVBTA9tQ+82WE8Bch7uFPj4 +MFOMVRn1dc3qdXlg3mimA+iK7tABQfG0RJ9YzWs=` + + TestPubKey3 = `mQENBFXbkiMBCACiHW4/VI2JkfvSEINddS7vE6wEu5e1leNQDaLUh6PrATQZS2a4Q6kRE6WlJumj +6wCeN753Cm93UGQl2Bi3USIEeArIZnPTcocrckOVXxtoLBNKXgqKvEsDXgfw8A+doSfXoDm/3Js4 +Wy3WsYKNR9LaPuJZHnpjsFAJhvRVyhH4UFD+1RTSSefq1mozPfDdMoZeZNEpfhwt3DuTJs7RqcTH +CgR2CqhEHnOOE5jJUljHKYLCglE2+8dth1bZlQi4xly/VHZzP3Bn7wKeolK/ROP6VZz/e0xq/BKy +resmxvlBWZ1zWwqGIrV9b0uwYvGrh2hOd5C5+5oGaA2MGcjxwaLBABEBAAG0EFZhdWx0IFRlc3Qg +S2V5IDOJATgEEwECACIFAlXbkiMCGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPR5S1b8 +LcbdWjEH/2mhqC9a0Vk1IzOgxEoVxYVqVdvaxI0nTZOTfmcFYn4HQlQ+SLEoyNWe5jtkhx4k5uHi +pxwKHzOv02YM14NWC6bvKw2CQETLDPG4Cv8YMUmpho5tnMDdttIzp8HjyJRtHazU1uTes2/yuqh6 +LHCejVJI0uST3RibquwdG3QjPP8Umxu+YC9+FOW2Kit/AQ8JluFDJdq3/wSX8VfYZrGdgmreE7KY +MolhCkzGSPj7oFygw8LqKoJvt9tCuBKhZMBuMv1sB5CoJIWdPoqOZc4U7L1XdqfKvFZR/RhuXgN1 +lkI9MqrnLDpikL3Lk+ctLxWOjUCW8roqKoHZYBF7XPqdAfm5AQ0EVduSIwEIAOPcjd4QgbLlqIk3 +s6BPRRyVzglTgUdf+I0rUDybaDJfJobZd8U6e4hkPvRoQ8tJefnz/qnD/63watAbJYcVTme40I3V +KDOmVGcyaDxiKP1disKqcEJd7XQiI72oAiXmEH0y+5UwnOMks/lwaAGDMGVRjHEXI6fiRPFsfTr8 +7qvMJ3pW1OiOXVSezuBNTlmyJC7srQ1/nwxL337ev6D1zQZd3JuhcxLkHrUELLNwzhvcZ70vg645 +jAmz8EdmvvoqEPPoHqKgP5AeHACOsTm953KHhgx3NYuGPU/RoIvugKt4Iq5nw7TWFTjPHGVF3GTQ +ry5CZ/AzXiL57hVEhDvmuT8AEQEAAYkCPgQYAQIACQUCVduSIwIbLgEpCRD0eUtW/C3G3cBdIAQZ +AQIABgUCVduSIwAKCRAFI/9Nx3K5IPOFCACsZ/Z4s2LcEoA51TW+T5w+YevlIuq+332JtqNIpuGI +WpGxUxyDyPT0YQWr0SObBORYNr7RP8d/I2rbaFKyaDaKvRofYr+TwXy92phBo7pdEUamBpfrm/sr ++2BgAB2x3HWXp+IMdeVVhqQe8t4cnFm3c1fIdxADyiJuV5ge2Ml5gK5yNwqCQPh7U2RqC+lmVlMJ +GvWInIRn2mf6A7phDYNZfOz6dkar4yyh5r9rRgrZw88r/yIlrq/c6KRUIgnPMrFYEauggOceZ827 ++jKkbKWFEuHtiCxW7kRAN25UfnGsPaF+NSGM2q1vCG4HiFydx6lMoXM0Shf8+ZwyrV/5BzAqpWwI +AJ37tEwC58Fboynly6OGOzgPS0xKnzkXMOtquTo0qEH/1bEUsBknn795BmZOTf4oBC5blN6qRv7c +GSP00i+sxql1NhTjJcjJtfOPUzgfW+Af/+HR648z4c7c6MCjDFKnk8ZkoGLRU7ISjenkNFzvu2bj +lxJkil0uJDlLPbbX80ojzV1GS9g+ZxVPR+68N1QLl2FU6zsfg34upmLLHG8VG4vExzgyNkOwfTYv +dgyRNTjnuPue6H12fZZ9uCNeG52v7lR3eoQcCxBOniwgipB8UJ52RWXblwxzCtGtDi/EWB3zLTUn +puKcgucA0LotbihSMxhDylaARfVO1QV6csabM/g=` + + TestAAPubKey1 = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFXbjPUBCADjNjCUQwfxKL+RR2GA6pv/1K+zJZ8UWIF9S0lk7cVIEfJiprzz +wiMwBS5cD0darGin1FHvIWOZxujA7oW0O2TUuatqI3aAYDTfRYurh6iKLC+VS+F7 +H+/mhfFvKmgr0Y5kDCF1j0T/063QZ84IRGucR/X43IY7kAtmxGXH0dYOCzOe5UBX +1fTn3mXGe2ImCDWBH7gOViynXmb6XNvXkP0fsF5St9jhO7mbZU9EFkv9O3t3EaUR +fHopsCVDOlCkFCw5ArY+DUORHRzoMX0PnkyQb5OzibkChzpg8hQssKeVGpuskTdz +5Q7PtdW71jXd4fFVzoNH8fYwRpziD2xNvi6HABEBAAG0EFZhdWx0IFRlc3QgS2V5 +IDGJATgEEwECACIFAlXbjPUCGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJ +EOfLr44BHbeTo+sH/i7bapIgPnZsJ81hmxPj4W12uvunksGJiC7d4hIHsG7kmJRT +JfjECi+AuTGeDwBy84TDcRaOB6e79fj65Fg6HgSahDUtKJbGxj/lWzmaBuTzlN3C +Ee8cMwIPqPT2kajJVdOyrvkyuFOdPFOEA7bdCH0MqgIdM2SdF8t40k/ATfuD2K1Z +mumJ508I3gF39jgTnPzD4C8quswrMQ3bzfvKC3klXRlBC0yoArn+0QA3cf2B9T4z +J2qnvgotVbeK/b1OJRNj6Poeo+SsWNc/A5mw7lGScnDgL3yfwCm1gQXaQKfOt5x+ +7GqhWDw10q+bJpJlI10FfzAnhMF9etSqSeURBRW5AQ0EVduM9QEIAL53hJ5bZJ7o +EDCnaY+SCzt9QsAfnFTAnZJQrvkvusJzrTQ088eUQmAjvxkfRqnv981fFwGnh2+I +1Ktm698UAZS9Jt8yjak9wWUICKQO5QUt5k8cHwldQXNXVXFa+TpQWQR5yW1a9okj +h5o/3d4cBt1yZPUJJyLKY43Wvptb6EuEsScO2DnRkh5wSMDQ7dTooddJCmaq3LTj +OleRFQbu9ij386Do6jzK69mJU56TfdcydkxkWF5NZLGnED3lq+hQNbe+8UI5tD2o +P/3r5tXKgMy1R/XPvR/zbfwvx4FAKFOP01awLq4P3d/2xOkMu4Lu9p315E87DOle +Ywxk+FoTqXEAEQEAAYkCPgQYAQIACQUCVduM9QIbLgEpCRDny6+OAR23k8BdIAQZ +AQIABgUCVduM9QAKCRAID0JGyHtSGmqYB/4m4rJbbWa7dBJ8VqRU7ZKnNRDR9CVh +EGipBmpDGRYulEimOPzLUX/ZXZmTZzgemeXLBaJJlWnopVUWuAsyjQuZAfdd8nHk +GRHG0/DGum0l4sKTta3OPGHNC1z1dAcQ1RCr9bTD3PxjLBczdGqhzw71trkQRBRd +tPiUchltPMIyjUHqVJ0xmg0hPqFic0fICsr0YwKoz3h9+QEcZHvsjSZjgydKvfLY +cm+4DDMCCqcHuJrbXJKUWmJcXR0y/+HQONGrGJ5xWdO+6eJioPn2jVMnXCm4EKc7 +fcLFrz/LKmJ8seXhxjM3EdFtylBGCrx3xdK0f+JDNQaC/rhUb5V2XuX6VwoH/AtY ++XsKVYRfNIupLOUcf/srsm3IXT4SXWVomOc9hjGQiJ3rraIbADsc+6bCAr4XNZS7 +moViAAcIPXFv3m3WfUlnG/om78UjQqyVACRZqqAGmuPq+TSkRUCpt9h+A39LQWko +jHqyob3cyLgy6z9Q557O9uK3lQozbw2gH9zC0RqnePl+rsWIUU/ga16fH6pWc1uJ +iEBt8UZGypQ/E56/343epmYAe0a87sHx8iDV+dNtDVKfPRENiLOOc19MmS+phmUy +rbHqI91c0pmysYcJZCD3a502X1gpjFbPZcRtiTmGnUKdOIu60YPNE4+h7u2CfYyF +Pu3AlUaGNMBlvy6PEpU= +=NUTS +-----END PGP PUBLIC KEY BLOCK-----` +) diff --git a/vendor/github.com/hashicorp/vault/helper/pluginutil/env.go b/vendor/github.com/hashicorp/vault/helper/pluginutil/env.go new file mode 100644 index 0000000..337c7b7 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pluginutil/env.go @@ -0,0 +1,66 @@ +package pluginutil + +import ( + "os" + + version "github.com/hashicorp/go-version" + "github.com/hashicorp/vault/helper/mlock" +) + +var ( + // PluginMlockEnabled is the ENV name used to pass the configuration for + // enabling mlock + PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED" + + // PluginVaultVersionEnv is the ENV name used to pass the version of the + // vault server to the plugin + PluginVaultVersionEnv = "VAULT_VERSION" + + // PluginMetadataModeEnv is an ENV name used to disable TLS communication + // to bootstrap mounting plugins. + PluginMetadataModeEnv = "VAULT_PLUGIN_METADATA_MODE" +) + +// OptionallyEnableMlock determines if mlock should be called, and if so enables +// mlock. +func OptionallyEnableMlock() error { + if os.Getenv(PluginMlockEnabled) == "true" { + return mlock.LockMemory() + } + + return nil +} + +// GRPCSupport defaults to returning true, unless VAULT_VERSION is missing or +// it fails to meet the version constraint. +func GRPCSupport() bool { + verString := os.Getenv(PluginVaultVersionEnv) + + // If the env var is empty, we fall back to netrpc for backward compatibility. + if verString == "" { + return false + } + + if verString != "unknown" { + ver, err := version.NewVersion(verString) + if err != nil { + return true + } + + // Due to some regressions on 0.9.2 & 0.9.3 we now require version 0.9.4 + // to allow the plugin framework to default to gRPC. + constraint, err := version.NewConstraint(">= 0.9.4") + if err != nil { + return true + } + + return constraint.Check(ver) + } + + return true +} + +// Returns true if the plugin calling this function is running in metadata mode. +func InMetadataMode() bool { + return os.Getenv(PluginMetadataModeEnv) == "true" +} diff --git a/vendor/github.com/hashicorp/vault/helper/pluginutil/runner.go b/vendor/github.com/hashicorp/vault/helper/pluginutil/runner.go new file mode 100644 index 0000000..436e169 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pluginutil/runner.go @@ -0,0 +1,182 @@ +package pluginutil + +import ( + "context" + "crypto/sha256" + "crypto/tls" + "flag" + "fmt" + "os/exec" + "time" + + log "github.com/hashicorp/go-hclog" + plugin "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/version" +) + +// Looker defines the plugin Lookup function that looks into the plugin catalog +// for available plugins and returns a PluginRunner +type Looker interface { + LookupPlugin(context.Context, string) (*PluginRunner, error) +} + +// Wrapper interface defines the functions needed by the runner to wrap the +// metadata needed to run a plugin process. This includes looking up Mlock +// configuration and wrapping data in a response wrapped token. +// logical.SystemView implementations satisfy this interface. +type RunnerUtil interface { + ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) + MlockEnabled() bool +} + +// LookWrapper defines the functions for both Looker and Wrapper +type LookRunnerUtil interface { + Looker + RunnerUtil +} + +// PluginRunner defines the metadata needed to run a plugin securely with +// go-plugin. +type PluginRunner struct { + Name string `json:"name" structs:"name"` + Command string `json:"command" structs:"command"` + Args []string `json:"args" structs:"args"` + Sha256 []byte `json:"sha256" structs:"sha256"` + Builtin bool `json:"builtin" structs:"builtin"` + BuiltinFactory func() (interface{}, error) `json:"-" structs:"-"` +} + +// Run takes a wrapper RunnerUtil instance along with the go-plugin parameters and +// returns a configured plugin.Client with TLS Configured and a wrapping token set +// on PluginUnwrapTokenEnv for plugin process consumption. +func (r *PluginRunner) Run(ctx context.Context, wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { + return r.runCommon(ctx, wrapper, pluginMap, hs, env, logger, false) +} + +// RunMetadataMode returns a configured plugin.Client that will dispense a plugin +// in metadata mode. The PluginMetadataModeEnv is passed in as part of the Cmd to +// plugin.Client, and consumed by the plugin process on pluginutil.VaultPluginTLSProvider. +func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { + return r.runCommon(ctx, wrapper, pluginMap, hs, env, logger, true) + +} + +func (r *PluginRunner) runCommon(ctx context.Context, wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string, logger log.Logger, isMetadataMode bool) (*plugin.Client, error) { + cmd := exec.Command(r.Command, r.Args...) + cmd.Env = append(cmd.Env, env...) + + // Add the mlock setting to the ENV of the plugin + if wrapper.MlockEnabled() { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMlockEnabled, "true")) + } + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version)) + + var clientTLSConfig *tls.Config + if !isMetadataMode { + // Add the metadata mode ENV and set it to false + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "false")) + + // Get a CA TLS Certificate + certBytes, key, err := generateCert() + if err != nil { + return nil, err + } + + // Use CA to sign a client cert and return a configured TLS config + clientTLSConfig, err = createClientTLSConfig(certBytes, key) + if err != nil { + return nil, err + } + + // Use CA to sign a server cert and wrap the values in a response wrapped + // token. + wrapToken, err := wrapServerConfig(ctx, wrapper, certBytes, key) + if err != nil { + return nil, err + } + + // Add the response wrap token to the ENV of the plugin + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, wrapToken)) + } else { + logger = logger.With("metadata", "true") + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "true")) + } + + secureConfig := &plugin.SecureConfig{ + Checksum: r.Sha256, + Hash: sha256.New(), + } + + clientConfig := &plugin.ClientConfig{ + HandshakeConfig: hs, + Plugins: pluginMap, + Cmd: cmd, + SecureConfig: secureConfig, + TLSConfig: clientTLSConfig, + Logger: logger, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + } + + client := plugin.NewClient(clientConfig) + + return client, nil +} + +type APIClientMeta struct { + // These are set by the command line flags. + flagCACert string + flagCAPath string + flagClientCert string + flagClientKey string + flagInsecure bool +} + +func (f *APIClientMeta) FlagSet() *flag.FlagSet { + fs := flag.NewFlagSet("vault plugin settings", flag.ContinueOnError) + + fs.StringVar(&f.flagCACert, "ca-cert", "", "") + fs.StringVar(&f.flagCAPath, "ca-path", "", "") + fs.StringVar(&f.flagClientCert, "client-cert", "", "") + fs.StringVar(&f.flagClientKey, "client-key", "", "") + fs.BoolVar(&f.flagInsecure, "tls-skip-verify", false, "") + + return fs +} + +func (f *APIClientMeta) GetTLSConfig() *api.TLSConfig { + // If we need custom TLS configuration, then set it + if f.flagCACert != "" || f.flagCAPath != "" || f.flagClientCert != "" || f.flagClientKey != "" || f.flagInsecure { + t := &api.TLSConfig{ + CACert: f.flagCACert, + CAPath: f.flagCAPath, + ClientCert: f.flagClientCert, + ClientKey: f.flagClientKey, + TLSServerName: "", + Insecure: f.flagInsecure, + } + + return t + } + + return nil +} + +// CancelIfCanceled takes a context cancel func and a context. If the context is +// shutdown the cancelfunc is called. This is useful for merging two cancel +// functions. +func CtxCancelIfCanceled(f context.CancelFunc, ctxCanceler context.Context) chan struct{} { + quitCh := make(chan struct{}) + go func() { + select { + case <-quitCh: + case <-ctxCanceler.Done(): + f() + } + }() + return quitCh +} diff --git a/vendor/github.com/hashicorp/vault/helper/pluginutil/tls.go b/vendor/github.com/hashicorp/vault/helper/pluginutil/tls.go new file mode 100644 index 0000000..d43f778 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/pluginutil/tls.go @@ -0,0 +1,241 @@ +package pluginutil + +import ( + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "errors" + "net/url" + "os" + "time" + + "github.com/SermoDigital/jose/jws" + "github.com/hashicorp/errwrap" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/certutil" +) + +var ( + // PluginUnwrapTokenEnv is the ENV name used to pass unwrap tokens to the + // plugin. + PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN" + + // PluginCACertPEMEnv is an ENV name used for holding a CA PEM-encoded + // string. Used for testing. + PluginCACertPEMEnv = "VAULT_TESTING_PLUGIN_CA_PEM" +) + +// generateCert is used internally to create certificates for the plugin +// client and server. +func generateCert() ([]byte, *ecdsa.PrivateKey, error) { + key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + return nil, nil, err + } + + host, err := uuid.GenerateUUID() + if err != nil { + return nil, nil, err + } + + sn, err := certutil.GenerateSerialNumber() + if err != nil { + return nil, nil, err + } + + template := &x509.Certificate{ + Subject: pkix.Name{ + CommonName: host, + }, + DNSNames: []string{host}, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageClientAuth, + x509.ExtKeyUsageServerAuth, + }, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement, + SerialNumber: sn, + NotBefore: time.Now().Add(-30 * time.Second), + NotAfter: time.Now().Add(262980 * time.Hour), + IsCA: true, + } + + certBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) + if err != nil { + return nil, nil, errwrap.Wrapf("unable to generate client certificate: {{err}}", err) + } + + return certBytes, key, nil +} + +// createClientTLSConfig creates a signed certificate and returns a configured +// TLS config. +func createClientTLSConfig(certBytes []byte, key *ecdsa.PrivateKey) (*tls.Config, error) { + clientCert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, errwrap.Wrapf("error parsing generated plugin certificate: {{err}}", err) + } + + cert := tls.Certificate{ + Certificate: [][]byte{certBytes}, + PrivateKey: key, + Leaf: clientCert, + } + + clientCertPool := x509.NewCertPool() + clientCertPool.AddCert(clientCert) + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: clientCertPool, + ClientCAs: clientCertPool, + ClientAuth: tls.RequireAndVerifyClientCert, + ServerName: clientCert.Subject.CommonName, + MinVersion: tls.VersionTLS12, + } + + tlsConfig.BuildNameToCertificate() + + return tlsConfig, nil +} + +// wrapServerConfig is used to create a server certificate and private key, then +// wrap them in an unwrap token for later retrieval by the plugin. +func wrapServerConfig(ctx context.Context, sys RunnerUtil, certBytes []byte, key *ecdsa.PrivateKey) (string, error) { + rawKey, err := x509.MarshalECPrivateKey(key) + if err != nil { + return "", err + } + + wrapInfo, err := sys.ResponseWrapData(ctx, map[string]interface{}{ + "ServerCert": certBytes, + "ServerKey": rawKey, + }, time.Second*60, true) + if err != nil { + return "", err + } + + return wrapInfo.Token, nil +} + +// VaultPluginTLSProvider is run inside a plugin and retrieves the response +// wrapped TLS certificate from vault. It returns a configured TLS Config. +func VaultPluginTLSProvider(apiTLSConfig *api.TLSConfig) func() (*tls.Config, error) { + if os.Getenv(PluginMetadataModeEnv) == "true" { + return nil + } + + return func() (*tls.Config, error) { + unwrapToken := os.Getenv(PluginUnwrapTokenEnv) + + // Parse the JWT and retrieve the vault address + wt, err := jws.ParseJWT([]byte(unwrapToken)) + if err != nil { + return nil, errwrap.Wrapf("error decoding token: {{err}}", err) + } + if wt == nil { + return nil, errors.New("nil decoded token") + } + + addrRaw := wt.Claims().Get("addr") + if addrRaw == nil { + return nil, errors.New("decoded token does not contain the active node's api_addr") + } + vaultAddr, ok := addrRaw.(string) + if !ok { + return nil, errors.New("decoded token's api_addr not valid") + } + if vaultAddr == "" { + return nil, errors.New(`no vault api_addr found`) + } + + // Sanity check the value + if _, err := url.Parse(vaultAddr); err != nil { + return nil, errwrap.Wrapf("error parsing the vault api_addr: {{err}}", err) + } + + // Unwrap the token + clientConf := api.DefaultConfig() + clientConf.Address = vaultAddr + if apiTLSConfig != nil { + err := clientConf.ConfigureTLS(apiTLSConfig) + if err != nil { + return nil, errwrap.Wrapf("error configuring api client {{err}}", err) + } + } + client, err := api.NewClient(clientConf) + if err != nil { + return nil, errwrap.Wrapf("error during api client creation: {{err}}", err) + } + + secret, err := client.Logical().Unwrap(unwrapToken) + if err != nil { + return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err) + } + if secret == nil { + return nil, errors.New("error during token unwrap request: secret is nil") + } + + // Retrieve and parse the server's certificate + serverCertBytesRaw, ok := secret.Data["ServerCert"].(string) + if !ok { + return nil, errors.New("error unmarshalling certificate") + } + + serverCertBytes, err := base64.StdEncoding.DecodeString(serverCertBytesRaw) + if err != nil { + return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) + } + + serverCert, err := x509.ParseCertificate(serverCertBytes) + if err != nil { + return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) + } + + // Retrieve and parse the server's private key + serverKeyB64, ok := secret.Data["ServerKey"].(string) + if !ok { + return nil, errors.New("error unmarshalling certificate") + } + + serverKeyRaw, err := base64.StdEncoding.DecodeString(serverKeyB64) + if err != nil { + return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) + } + + serverKey, err := x509.ParseECPrivateKey(serverKeyRaw) + if err != nil { + return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) + } + + // Add CA cert to the cert pool + caCertPool := x509.NewCertPool() + caCertPool.AddCert(serverCert) + + // Build a certificate object out of the server's cert and private key. + cert := tls.Certificate{ + Certificate: [][]byte{serverCertBytes}, + PrivateKey: serverKey, + Leaf: serverCert, + } + + // Setup TLS config + tlsConfig := &tls.Config{ + ClientCAs: caCertPool, + RootCAs: caCertPool, + ClientAuth: tls.RequireAndVerifyClientCert, + // TLS 1.2 minimum + MinVersion: tls.VersionTLS12, + Certificates: []tls.Certificate{cert}, + ServerName: serverCert.Subject.CommonName, + } + tlsConfig.BuildNameToCertificate() + + return tlsConfig, nil + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/policyutil/policyutil.go b/vendor/github.com/hashicorp/vault/helper/policyutil/policyutil.go new file mode 100644 index 0000000..f6d9f66 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/policyutil/policyutil.go @@ -0,0 +1,128 @@ +package policyutil + +import ( + "sort" + "strings" + + "github.com/hashicorp/vault/helper/strutil" +) + +const ( + AddDefaultPolicy = true + DoNotAddDefaultPolicy = false +) + +// ParsePolicies parses a comma-delimited list of policies. +// The resulting collection will have no duplicate elements. +// If 'root' policy was present in the list of policies, then +// all other policies will be ignored, the result will contain +// just the 'root'. In cases where 'root' is not present, if +// 'default' policy is not already present, it will be added. +func ParsePolicies(policiesRaw interface{}) []string { + if policiesRaw == nil { + return []string{"default"} + } + + var policies []string + switch policiesRaw.(type) { + case string: + if policiesRaw.(string) == "" { + return []string{} + } + policies = strings.Split(policiesRaw.(string), ",") + case []string: + policies = policiesRaw.([]string) + } + + return SanitizePolicies(policies, false) +} + +// SanitizePolicies performs the common input validation tasks +// which are performed on the list of policies across Vault. +// The resulting collection will have no duplicate elements. +// If 'root' policy was present in the list of policies, then +// all other policies will be ignored, the result will contain +// just the 'root'. In cases where 'root' is not present, if +// 'default' policy is not already present, it will be added +// if addDefault is set to true. +func SanitizePolicies(policies []string, addDefault bool) []string { + defaultFound := false + for i, p := range policies { + policies[i] = strings.ToLower(strings.TrimSpace(p)) + // Eliminate unnamed policies. + if policies[i] == "" { + continue + } + + // If 'root' policy is present, ignore all other policies. + if policies[i] == "root" { + policies = []string{"root"} + defaultFound = true + break + } + if policies[i] == "default" { + defaultFound = true + } + } + + // Always add 'default' except only if the policies contain 'root'. + if addDefault && (len(policies) == 0 || !defaultFound) { + policies = append(policies, "default") + } + + return strutil.RemoveDuplicates(policies, true) +} + +// EquivalentPolicies checks whether the given policy sets are equivalent, as in, +// they contain the same values. The benefit of this method is that it leaves +// the "default" policy out of its comparisons as it may be added later by core +// after a set of policies has been saved by a backend. +func EquivalentPolicies(a, b []string) bool { + if a == nil && b == nil { + return true + } + + if a == nil || b == nil { + return false + } + + // First we'll build maps to ensure unique values and filter default + mapA := map[string]bool{} + mapB := map[string]bool{} + for _, keyA := range a { + if keyA == "default" { + continue + } + mapA[keyA] = true + } + for _, keyB := range b { + if keyB == "default" { + continue + } + mapB[keyB] = true + } + + // Now we'll build our checking slices + var sortedA, sortedB []string + for keyA, _ := range mapA { + sortedA = append(sortedA, keyA) + } + for keyB, _ := range mapB { + sortedB = append(sortedB, keyB) + } + sort.Strings(sortedA) + sort.Strings(sortedB) + + // Finally, compare + if len(sortedA) != len(sortedB) { + return false + } + + for i := range sortedA { + if sortedA[i] != sortedB[i] { + return false + } + } + + return true +} diff --git a/vendor/github.com/hashicorp/vault/helper/reload/reload.go b/vendor/github.com/hashicorp/vault/helper/reload/reload.go new file mode 100644 index 0000000..44526c0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/reload/reload.go @@ -0,0 +1,85 @@ +package reload + +import ( + "crypto/tls" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "sync" + + "github.com/hashicorp/errwrap" +) + +// ReloadFunc are functions that are called when a reload is requested +type ReloadFunc func(map[string]interface{}) error + +// CertificateGetter satisfies ReloadFunc and its GetCertificate method +// satisfies the tls.GetCertificate function signature. Currently it does not +// allow changing paths after the fact. +type CertificateGetter struct { + sync.RWMutex + + cert *tls.Certificate + + certFile string + keyFile string + passphrase string +} + +func NewCertificateGetter(certFile, keyFile, passphrase string) *CertificateGetter { + return &CertificateGetter{ + certFile: certFile, + keyFile: keyFile, + passphrase: passphrase, + } +} + +func (cg *CertificateGetter) Reload(_ map[string]interface{}) error { + certPEMBlock, err := ioutil.ReadFile(cg.certFile) + if err != nil { + return err + } + keyPEMBlock, err := ioutil.ReadFile(cg.keyFile) + if err != nil { + return err + } + + // Check for encrypted pem block + keyBlock, _ := pem.Decode(keyPEMBlock) + if keyBlock == nil { + return errors.New("decoded PEM is blank") + } + + if x509.IsEncryptedPEMBlock(keyBlock) { + keyBlock.Bytes, err = x509.DecryptPEMBlock(keyBlock, []byte(cg.passphrase)) + if err != nil { + return errwrap.Wrapf("Decrypting PEM block failed {{err}}", err) + } + keyPEMBlock = pem.EncodeToMemory(keyBlock) + } + + cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) + if err != nil { + return err + } + + cg.Lock() + defer cg.Unlock() + + cg.cert = &cert + + return nil +} + +func (cg *CertificateGetter) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { + cg.RLock() + defer cg.RUnlock() + + if cg.cert == nil { + return nil, fmt.Errorf("nil certificate") + } + + return cg.cert, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/salt/salt.go b/vendor/github.com/hashicorp/vault/helper/salt/salt.go new file mode 100644 index 0000000..4fd5620 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/salt/salt.go @@ -0,0 +1,178 @@ +package salt + +import ( + "context" + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "encoding/hex" + "fmt" + "hash" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/logical" +) + +const ( + // DefaultLocation is the path in the view we store our key salt + // if no other path is provided. + DefaultLocation = "salt" +) + +// Salt is used to manage a persistent salt key which is used to +// hash values. This allows keys to be generated and recovered +// using the global salt. Primarily, this allows paths in the storage +// backend to be obfuscated if they may contain sensitive information. +type Salt struct { + config *Config + salt string + generated bool +} + +type HashFunc func([]byte) []byte + +// Config is used to parameterize the Salt +type Config struct { + // Location is the path in the storage backend for the + // salt. Uses DefaultLocation if not specified. + Location string + + // HashFunc is the hashing function to use for salting. + // Defaults to SHA1 if not provided. + HashFunc HashFunc + + // HMAC allows specification of a hash function to use for + // the HMAC helpers + HMAC func() hash.Hash + + // String prepended to HMAC strings for identification. + // Required if using HMAC + HMACType string +} + +// NewSalt creates a new salt based on the configuration +func NewSalt(ctx context.Context, view logical.Storage, config *Config) (*Salt, error) { + // Setup the configuration + if config == nil { + config = &Config{} + } + if config.Location == "" { + config.Location = DefaultLocation + } + if config.HashFunc == nil { + config.HashFunc = SHA256Hash + } + if config.HMAC == nil { + config.HMAC = sha256.New + config.HMACType = "hmac-sha256" + } + + // Create the salt + s := &Salt{ + config: config, + } + + // Look for the salt + var raw *logical.StorageEntry + var err error + if view != nil { + raw, err = view.Get(ctx, config.Location) + if err != nil { + return nil, errwrap.Wrapf("failed to read salt: {{err}}", err) + } + } + + // Restore the salt if it exists + if raw != nil { + s.salt = string(raw.Value) + } + + // Generate a new salt if necessary + if s.salt == "" { + s.salt, err = uuid.GenerateUUID() + if err != nil { + return nil, errwrap.Wrapf("failed to generate uuid: {{err}}", err) + } + s.generated = true + if view != nil { + raw := &logical.StorageEntry{ + Key: config.Location, + Value: []byte(s.salt), + } + if err := view.Put(ctx, raw); err != nil { + return nil, errwrap.Wrapf("failed to persist salt: {{err}}", err) + } + } + } + + if config.HMAC != nil { + if len(config.HMACType) == 0 { + return nil, fmt.Errorf("HMACType must be defined") + } + } + + return s, nil +} + +// SaltID is used to apply a salt and hash function to an ID to make sure +// it is not reversible +func (s *Salt) SaltID(id string) string { + return SaltID(s.salt, id, s.config.HashFunc) +} + +// GetHMAC is used to apply a salt and hash function to data to make sure it is +// not reversible, with an additional HMAC +func (s *Salt) GetHMAC(data string) string { + hm := hmac.New(s.config.HMAC, []byte(s.salt)) + hm.Write([]byte(data)) + return hex.EncodeToString(hm.Sum(nil)) +} + +// GetIdentifiedHMAC is used to apply a salt and hash function to data to make +// sure it is not reversible, with an additional HMAC, and ID prepended +func (s *Salt) GetIdentifiedHMAC(data string) string { + return s.config.HMACType + ":" + s.GetHMAC(data) +} + +// DidGenerate returns if the underlying salt value was generated +// on initialization or if an existing salt value was loaded +func (s *Salt) DidGenerate() bool { + return s.generated +} + +// SaltIDHashFunc uses the supplied hash function instead of the configured +// hash func in the salt. +func (s *Salt) SaltIDHashFunc(id string, hashFunc HashFunc) string { + return SaltID(s.salt, id, hashFunc) +} + +// SaltID is used to apply a salt and hash function to an ID to make sure +// it is not reversible +func SaltID(salt, id string, hash HashFunc) string { + comb := salt + id + hashVal := hash([]byte(comb)) + return hex.EncodeToString(hashVal) +} + +func HMACValue(salt, val string, hashFunc func() hash.Hash) string { + hm := hmac.New(hashFunc, []byte(salt)) + hm.Write([]byte(val)) + return hex.EncodeToString(hm.Sum(nil)) +} + +func HMACIdentifiedValue(salt, val, hmacType string, hashFunc func() hash.Hash) string { + return hmacType + ":" + HMACValue(salt, val, hashFunc) +} + +// SHA1Hash returns the SHA1 of the input +func SHA1Hash(inp []byte) []byte { + hashed := sha1.Sum(inp) + return hashed[:] +} + +// SHA256Hash returns the SHA256 of the input +func SHA256Hash(inp []byte) []byte { + hashed := sha256.Sum256(inp) + return hashed[:] +} diff --git a/vendor/github.com/hashicorp/vault/helper/storagepacker/storagepacker.go b/vendor/github.com/hashicorp/vault/helper/storagepacker/storagepacker.go new file mode 100644 index 0000000..67c05b9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/storagepacker/storagepacker.go @@ -0,0 +1,355 @@ +package storagepacker + +import ( + "context" + "crypto/md5" + "encoding/hex" + "fmt" + "strconv" + "strings" + + "github.com/golang/protobuf/proto" + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/helper/compressutil" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/logical" +) + +const ( + bucketCount = 256 + StoragePackerBucketsPrefix = "packer/buckets/" +) + +// StoragePacker packs the objects into a specific number of buckets by hashing +// its ID and indexing it. Currently this supports only 256 bucket entries and +// hence relies on the first byte of the hash value for indexing. The items +// that gets inserted into the packer should implement StorageBucketItem +// interface. +type StoragePacker struct { + view logical.Storage + logger log.Logger + storageLocks []*locksutil.LockEntry + viewPrefix string +} + +// BucketPath returns the storage entry key for a given bucket key +func (s *StoragePacker) BucketPath(bucketKey string) string { + return s.viewPrefix + bucketKey +} + +// BucketKeyHash returns the MD5 hash of the bucket storage key in which +// the item will be stored. The choice of MD5 is only for hash performance +// reasons since its value is not used for any security sensitive operation. +func (s *StoragePacker) BucketKeyHashByItemID(itemID string) string { + return s.BucketKeyHashByKey(s.BucketPath(s.BucketKey(itemID))) +} + +// BucketKeyHashByKey returns the MD5 hash of the bucket storage key +func (s *StoragePacker) BucketKeyHashByKey(bucketKey string) string { + hf := md5.New() + hf.Write([]byte(bucketKey)) + return hex.EncodeToString(hf.Sum(nil)) +} + +// View returns the storage view configured to be used by the packer +func (s *StoragePacker) View() logical.Storage { + return s.view +} + +// Get returns a bucket for a given key +func (s *StoragePacker) GetBucket(key string) (*Bucket, error) { + if key == "" { + return nil, fmt.Errorf("missing bucket key") + } + + lock := locksutil.LockForKey(s.storageLocks, key) + lock.RLock() + defer lock.RUnlock() + + // Read from the underlying view + storageEntry, err := s.view.Get(context.Background(), key) + if err != nil { + return nil, errwrap.Wrapf("failed to read packed storage entry: {{err}}", err) + } + if storageEntry == nil { + return nil, nil + } + + uncompressedData, notCompressed, err := compressutil.Decompress(storageEntry.Value) + if err != nil { + return nil, errwrap.Wrapf("failed to decompress packed storage entry: {{err}}", err) + } + if notCompressed { + uncompressedData = storageEntry.Value + } + + var bucket Bucket + err = proto.Unmarshal(uncompressedData, &bucket) + if err != nil { + return nil, errwrap.Wrapf("failed to decode packed storage entry: {{err}}", err) + } + + return &bucket, nil +} + +// upsert either inserts a new item into the bucket or updates an existing one +// if an item with a matching key is already present. +func (s *Bucket) upsert(item *Item) error { + if s == nil { + return fmt.Errorf("nil storage bucket") + } + + if item == nil { + return fmt.Errorf("nil item") + } + + if item.ID == "" { + return fmt.Errorf("missing item ID") + } + + // Look for an item with matching key and don't modify the collection + // while iterating + foundIdx := -1 + for itemIdx, bucketItems := range s.Items { + if bucketItems.ID == item.ID { + foundIdx = itemIdx + break + } + } + + // If there is no match, append the item, otherwise update it + if foundIdx == -1 { + s.Items = append(s.Items, item) + } else { + s.Items[foundIdx] = item + } + + return nil +} + +// BucketIndex returns the bucket key index for a given storage key +func (s *StoragePacker) BucketIndex(key string) uint8 { + hf := md5.New() + hf.Write([]byte(key)) + return uint8(hf.Sum(nil)[0]) +} + +// BucketKey returns the bucket key for a given item ID +func (s *StoragePacker) BucketKey(itemID string) string { + return strconv.Itoa(int(s.BucketIndex(itemID))) +} + +// DeleteItem removes the storage entry which the given key refers to from its +// corresponding bucket. +func (s *StoragePacker) DeleteItem(itemID string) error { + + if itemID == "" { + return fmt.Errorf("empty item ID") + } + + // Get the bucket key + bucketKey := s.BucketKey(itemID) + + // Prepend the view prefix + bucketPath := s.BucketPath(bucketKey) + + // Read from underlying view + storageEntry, err := s.view.Get(context.Background(), bucketPath) + if err != nil { + return errwrap.Wrapf("failed to read packed storage value: {{err}}", err) + } + if storageEntry == nil { + return nil + } + + uncompressedData, notCompressed, err := compressutil.Decompress(storageEntry.Value) + if err != nil { + return errwrap.Wrapf("failed to decompress packed storage value: {{err}}", err) + } + if notCompressed { + uncompressedData = storageEntry.Value + } + + var bucket Bucket + err = proto.Unmarshal(uncompressedData, &bucket) + if err != nil { + return errwrap.Wrapf("failed decoding packed storage entry: {{err}}", err) + } + + // Look for a matching storage entry + foundIdx := -1 + for itemIdx, item := range bucket.Items { + if item.ID == itemID { + foundIdx = itemIdx + break + } + } + + // If there is a match, remove it from the collection and persist the + // resulting collection + if foundIdx != -1 { + bucket.Items = append(bucket.Items[:foundIdx], bucket.Items[foundIdx+1:]...) + + // Persist bucket entry only if there is an update + err = s.PutBucket(&bucket) + if err != nil { + return err + } + } + + return nil +} + +// Put stores a packed bucket entry +func (s *StoragePacker) PutBucket(bucket *Bucket) error { + if bucket == nil { + return fmt.Errorf("nil bucket entry") + } + + if bucket.Key == "" { + return fmt.Errorf("missing key") + } + + if !strings.HasPrefix(bucket.Key, s.viewPrefix) { + return fmt.Errorf("incorrect prefix; bucket entry key should have %q prefix", s.viewPrefix) + } + + marshaledBucket, err := proto.Marshal(bucket) + if err != nil { + return errwrap.Wrapf("failed to marshal bucket: {{err}}", err) + } + + compressedBucket, err := compressutil.Compress(marshaledBucket, &compressutil.CompressionConfig{ + Type: compressutil.CompressionTypeSnappy, + }) + if err != nil { + return errwrap.Wrapf("failed to compress packed bucket: {{err}}", err) + } + + // Store the compressed value + err = s.view.Put(context.Background(), &logical.StorageEntry{ + Key: bucket.Key, + Value: compressedBucket, + }) + if err != nil { + return errwrap.Wrapf("failed to persist packed storage entry: {{err}}", err) + } + + return nil +} + +// GetItem fetches the storage entry for a given key from its corresponding +// bucket. +func (s *StoragePacker) GetItem(itemID string) (*Item, error) { + if itemID == "" { + return nil, fmt.Errorf("empty item ID") + } + + bucketKey := s.BucketKey(itemID) + bucketPath := s.BucketPath(bucketKey) + + // Fetch the bucket entry + bucket, err := s.GetBucket(bucketPath) + if err != nil { + return nil, errwrap.Wrapf("failed to read packed storage item: {{err}}", err) + } + if bucket == nil { + return nil, nil + } + + // Look for a matching storage entry in the bucket items + for _, item := range bucket.Items { + if item.ID == itemID { + return item, nil + } + } + + return nil, nil +} + +// PutItem stores a storage entry in its corresponding bucket +func (s *StoragePacker) PutItem(item *Item) error { + if item == nil { + return fmt.Errorf("nil item") + } + + if item.ID == "" { + return fmt.Errorf("missing ID in item") + } + + var err error + bucketKey := s.BucketKey(item.ID) + bucketPath := s.BucketPath(bucketKey) + + bucket := &Bucket{ + Key: bucketPath, + } + + // In this case, we persist the storage entry regardless of the read + // storageEntry below is nil or not. Hence, directly acquire write lock + // even to read the entry. + lock := locksutil.LockForKey(s.storageLocks, bucketPath) + lock.Lock() + defer lock.Unlock() + + // Check if there is an existing bucket for a given key + storageEntry, err := s.view.Get(context.Background(), bucketPath) + if err != nil { + return errwrap.Wrapf("failed to read packed storage bucket entry: {{err}}", err) + } + + if storageEntry == nil { + // If the bucket entry does not exist, this will be the only item the + // bucket that is going to be persisted. + bucket.Items = []*Item{ + item, + } + } else { + uncompressedData, notCompressed, err := compressutil.Decompress(storageEntry.Value) + if err != nil { + return errwrap.Wrapf("failed to decompress packed storage entry: {{err}}", err) + } + if notCompressed { + uncompressedData = storageEntry.Value + } + + err = proto.Unmarshal(uncompressedData, bucket) + if err != nil { + return errwrap.Wrapf("failed to decode packed storage entry: {{err}}", err) + } + + err = bucket.upsert(item) + if err != nil { + return errwrap.Wrapf("failed to update entry in packed storage entry: {{err}}", err) + } + } + + // Persist the result + return s.PutBucket(bucket) +} + +// NewStoragePacker creates a new storage packer for a given view +func NewStoragePacker(view logical.Storage, logger log.Logger, viewPrefix string) (*StoragePacker, error) { + if view == nil { + return nil, fmt.Errorf("nil view") + } + + if viewPrefix == "" { + viewPrefix = StoragePackerBucketsPrefix + } + + if !strings.HasSuffix(viewPrefix, "/") { + viewPrefix = viewPrefix + "/" + } + + // Create a new packer object for the given view + packer := &StoragePacker{ + view: view, + viewPrefix: viewPrefix, + logger: logger.Named("storagepacker"), + storageLocks: locksutil.CreateLocks(), + } + + return packer, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/storagepacker/types.pb.go b/vendor/github.com/hashicorp/vault/helper/storagepacker/types.pb.go new file mode 100644 index 0000000..2e82344 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/storagepacker/types.pb.go @@ -0,0 +1,139 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: helper/storagepacker/types.proto + +package storagepacker // import "github.com/hashicorp/vault/helper/storagepacker" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import any "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Item struct { + ID string `sentinel:"" protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Message *any.Any `sentinel:"" protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Item) Reset() { *m = Item{} } +func (m *Item) String() string { return proto.CompactTextString(m) } +func (*Item) ProtoMessage() {} +func (*Item) Descriptor() ([]byte, []int) { + return fileDescriptor_types_d6d76d5cfa424ba8, []int{0} +} +func (m *Item) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Item.Unmarshal(m, b) +} +func (m *Item) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Item.Marshal(b, m, deterministic) +} +func (dst *Item) XXX_Merge(src proto.Message) { + xxx_messageInfo_Item.Merge(dst, src) +} +func (m *Item) XXX_Size() int { + return xxx_messageInfo_Item.Size(m) +} +func (m *Item) XXX_DiscardUnknown() { + xxx_messageInfo_Item.DiscardUnknown(m) +} + +var xxx_messageInfo_Item proto.InternalMessageInfo + +func (m *Item) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Item) GetMessage() *any.Any { + if m != nil { + return m.Message + } + return nil +} + +type Bucket struct { + Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Items []*Item `sentinel:"" protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Bucket) Reset() { *m = Bucket{} } +func (m *Bucket) String() string { return proto.CompactTextString(m) } +func (*Bucket) ProtoMessage() {} +func (*Bucket) Descriptor() ([]byte, []int) { + return fileDescriptor_types_d6d76d5cfa424ba8, []int{1} +} +func (m *Bucket) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Bucket.Unmarshal(m, b) +} +func (m *Bucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Bucket.Marshal(b, m, deterministic) +} +func (dst *Bucket) XXX_Merge(src proto.Message) { + xxx_messageInfo_Bucket.Merge(dst, src) +} +func (m *Bucket) XXX_Size() int { + return xxx_messageInfo_Bucket.Size(m) +} +func (m *Bucket) XXX_DiscardUnknown() { + xxx_messageInfo_Bucket.DiscardUnknown(m) +} + +var xxx_messageInfo_Bucket proto.InternalMessageInfo + +func (m *Bucket) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *Bucket) GetItems() []*Item { + if m != nil { + return m.Items + } + return nil +} + +func init() { + proto.RegisterType((*Item)(nil), "storagepacker.Item") + proto.RegisterType((*Bucket)(nil), "storagepacker.Bucket") +} + +func init() { + proto.RegisterFile("helper/storagepacker/types.proto", fileDescriptor_types_d6d76d5cfa424ba8) +} + +var fileDescriptor_types_d6d76d5cfa424ba8 = []byte{ + // 219 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x8f, 0x41, 0x4b, 0xc3, 0x40, + 0x10, 0x85, 0x49, 0xaa, 0x15, 0xb7, 0x28, 0xb2, 0x7a, 0x88, 0x9e, 0x42, 0x4f, 0xf1, 0x32, 0x83, + 0xf5, 0x17, 0x58, 0x50, 0xf0, 0x9a, 0xa3, 0xb7, 0x4d, 0x3a, 0x6e, 0x96, 0x64, 0xbb, 0xcb, 0xee, + 0xac, 0xb0, 0xff, 0x5e, 0xda, 0xd8, 0x43, 0xc1, 0xdb, 0xc0, 0xfb, 0xf8, 0xe6, 0x3d, 0x51, 0x0f, + 0x34, 0x79, 0x0a, 0x18, 0xd9, 0x05, 0xa5, 0xc9, 0xab, 0x7e, 0xa4, 0x80, 0x9c, 0x3d, 0x45, 0xf0, + 0xc1, 0xb1, 0x93, 0x37, 0x67, 0xd1, 0xd3, 0xa3, 0x76, 0x4e, 0x4f, 0x84, 0xc7, 0xb0, 0x4b, 0xdf, + 0xa8, 0xf6, 0x79, 0x26, 0xd7, 0x1f, 0xe2, 0xe2, 0x93, 0xc9, 0xca, 0x5b, 0x51, 0x9a, 0x5d, 0x55, + 0xd4, 0x45, 0x73, 0xdd, 0x96, 0x66, 0x27, 0x41, 0x5c, 0x59, 0x8a, 0x51, 0x69, 0xaa, 0xca, 0xba, + 0x68, 0x56, 0x9b, 0x07, 0x98, 0x25, 0x70, 0x92, 0xc0, 0xdb, 0x3e, 0xb7, 0x27, 0x68, 0xfd, 0x2e, + 0x96, 0xdb, 0xd4, 0x8f, 0xc4, 0xf2, 0x4e, 0x2c, 0x46, 0xca, 0x7f, 0xaa, 0xc3, 0x29, 0x9f, 0xc5, + 0xa5, 0x61, 0xb2, 0xb1, 0x2a, 0xeb, 0x45, 0xb3, 0xda, 0xdc, 0xc3, 0x59, 0x3b, 0x38, 0xfc, 0x6f, + 0x67, 0x62, 0xfb, 0xf2, 0x85, 0xda, 0xf0, 0x90, 0x3a, 0xe8, 0x9d, 0xc5, 0x41, 0xc5, 0xc1, 0xf4, + 0x2e, 0x78, 0xfc, 0x51, 0x69, 0x62, 0xfc, 0x6f, 0x77, 0xb7, 0x3c, 0x16, 0x7a, 0xfd, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0x1c, 0x8e, 0xb4, 0xa9, 0x16, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/helper/storagepacker/types.proto b/vendor/github.com/hashicorp/vault/helper/storagepacker/types.proto new file mode 100644 index 0000000..8d8a998 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/storagepacker/types.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/helper/storagepacker"; + +package storagepacker; + +import "google/protobuf/any.proto"; + +message Item { + string id = 1; + google.protobuf.Any message = 2; +} + +message Bucket { + string key = 1; + repeated Item items = 2; +} diff --git a/vendor/github.com/hashicorp/vault/helper/strutil/strutil.go b/vendor/github.com/hashicorp/vault/helper/strutil/strutil.go new file mode 100644 index 0000000..a77e60d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/strutil/strutil.go @@ -0,0 +1,327 @@ +package strutil + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/hashicorp/errwrap" + glob "github.com/ryanuber/go-glob" +) + +// StrListContainsGlob looks for a string in a list of strings and allows +// globs. +func StrListContainsGlob(haystack []string, needle string) bool { + for _, item := range haystack { + if glob.Glob(item, needle) { + return true + } + } + return false +} + +// StrListContains looks for a string in a list of strings. +func StrListContains(haystack []string, needle string) bool { + for _, item := range haystack { + if item == needle { + return true + } + } + return false +} + +// StrListSubset checks if a given list is a subset +// of another set +func StrListSubset(super, sub []string) bool { + for _, item := range sub { + if !StrListContains(super, item) { + return false + } + } + return true +} + +// Parses a comma separated list of strings into a slice of strings. +// The return slice will be sorted and will not contain duplicate or +// empty items. +func ParseDedupAndSortStrings(input string, sep string) []string { + input = strings.TrimSpace(input) + parsed := []string{} + if input == "" { + // Don't return nil + return parsed + } + return RemoveDuplicates(strings.Split(input, sep), false) +} + +// Parses a comma separated list of strings into a slice of strings. +// The return slice will be sorted and will not contain duplicate or +// empty items. The values will be converted to lower case. +func ParseDedupLowercaseAndSortStrings(input string, sep string) []string { + input = strings.TrimSpace(input) + parsed := []string{} + if input == "" { + // Don't return nil + return parsed + } + return RemoveDuplicates(strings.Split(input, sep), true) +} + +// Parses a comma separated list of `=` tuples into a +// map[string]string. +func ParseKeyValues(input string, out map[string]string, sep string) error { + if out == nil { + return fmt.Errorf("'out is nil") + } + + keyValues := ParseDedupLowercaseAndSortStrings(input, sep) + if len(keyValues) == 0 { + return nil + } + + for _, keyValue := range keyValues { + shards := strings.Split(keyValue, "=") + if len(shards) != 2 { + return fmt.Errorf("invalid format") + } + + key := strings.TrimSpace(shards[0]) + value := strings.TrimSpace(shards[1]) + if key == "" || value == "" { + return fmt.Errorf("invalid pair: key: %q value: %q", key, value) + } + out[key] = value + } + return nil +} + +// Parses arbitrary tuples. The input can be one of +// the following: +// * JSON string +// * Base64 encoded JSON string +// * Comma separated list of `=` pairs +// * Base64 encoded string containing comma separated list of +// `=` pairs +// +// Input will be parsed into the output parameter, which should +// be a non-nil map[string]string. +func ParseArbitraryKeyValues(input string, out map[string]string, sep string) error { + input = strings.TrimSpace(input) + if input == "" { + return nil + } + if out == nil { + return fmt.Errorf("'out' is nil") + } + + // Try to base64 decode the input. If successful, consider the decoded + // value as input. + inputBytes, err := base64.StdEncoding.DecodeString(input) + if err == nil { + input = string(inputBytes) + } + + // Try to JSON unmarshal the input. If successful, consider that the + // metadata was supplied as JSON input. + err = json.Unmarshal([]byte(input), &out) + if err != nil { + // If JSON unmarshalling fails, consider that the input was + // supplied as a comma separated string of 'key=value' pairs. + if err = ParseKeyValues(input, out, sep); err != nil { + return errwrap.Wrapf("failed to parse the input: {{err}}", err) + } + } + + // Validate the parsed input + for key, value := range out { + if key != "" && value == "" { + return fmt.Errorf("invalid value for key %q", key) + } + } + + return nil +} + +// Parses a `sep`-separated list of strings into a +// []string. +// +// The output will always be a valid slice but may be of length zero. +func ParseStringSlice(input string, sep string) []string { + input = strings.TrimSpace(input) + if input == "" { + return []string{} + } + + splitStr := strings.Split(input, sep) + ret := make([]string, len(splitStr)) + for i, val := range splitStr { + ret[i] = val + } + + return ret +} + +// Parses arbitrary string slice. The input can be one of +// the following: +// * JSON string +// * Base64 encoded JSON string +// * `sep` separated list of values +// * Base64-encoded string containing a `sep` separated list of values +// +// Note that the separator is ignored if the input is found to already be in a +// structured format (e.g., JSON) +// +// The output will always be a valid slice but may be of length zero. +func ParseArbitraryStringSlice(input string, sep string) []string { + input = strings.TrimSpace(input) + if input == "" { + return []string{} + } + + // Try to base64 decode the input. If successful, consider the decoded + // value as input. + inputBytes, err := base64.StdEncoding.DecodeString(input) + if err == nil { + input = string(inputBytes) + } + + ret := []string{} + + // Try to JSON unmarshal the input. If successful, consider that the + // metadata was supplied as JSON input. + err = json.Unmarshal([]byte(input), &ret) + if err != nil { + // If JSON unmarshalling fails, consider that the input was + // supplied as a separated string of values. + return ParseStringSlice(input, sep) + } + + if ret == nil { + return []string{} + } + + return ret +} + +// TrimStrings takes a slice of strings and returns a slice of strings +// with trimmed spaces +func TrimStrings(items []string) []string { + ret := make([]string, len(items)) + for i, item := range items { + ret[i] = strings.TrimSpace(item) + } + return ret +} + +// Removes duplicate and empty elements from a slice of strings. This also may +// convert the items in the slice to lower case and returns a sorted slice. +func RemoveDuplicates(items []string, lowercase bool) []string { + itemsMap := map[string]bool{} + for _, item := range items { + item = strings.TrimSpace(item) + if lowercase { + item = strings.ToLower(item) + } + if item == "" { + continue + } + itemsMap[item] = true + } + items = make([]string, 0, len(itemsMap)) + for item, _ := range itemsMap { + items = append(items, item) + } + sort.Strings(items) + return items +} + +// EquivalentSlices checks whether the given string sets are equivalent, as in, +// they contain the same values. +func EquivalentSlices(a, b []string) bool { + if a == nil && b == nil { + return true + } + + if a == nil || b == nil { + return false + } + + // First we'll build maps to ensure unique values + mapA := map[string]bool{} + mapB := map[string]bool{} + for _, keyA := range a { + mapA[keyA] = true + } + for _, keyB := range b { + mapB[keyB] = true + } + + // Now we'll build our checking slices + var sortedA, sortedB []string + for keyA, _ := range mapA { + sortedA = append(sortedA, keyA) + } + for keyB, _ := range mapB { + sortedB = append(sortedB, keyB) + } + sort.Strings(sortedA) + sort.Strings(sortedB) + + // Finally, compare + if len(sortedA) != len(sortedB) { + return false + } + + for i := range sortedA { + if sortedA[i] != sortedB[i] { + return false + } + } + + return true +} + +// StrListDelete removes the first occurrence of the given item from the slice +// of strings if the item exists. +func StrListDelete(s []string, d string) []string { + if s == nil { + return s + } + + for index, element := range s { + if element == d { + return append(s[:index], s[index+1:]...) + } + } + + return s +} + +func GlobbedStringsMatch(item, val string) bool { + if len(item) < 2 { + return val == item + } + + hasPrefix := strings.HasPrefix(item, "*") + hasSuffix := strings.HasSuffix(item, "*") + + if hasPrefix && hasSuffix { + return strings.Contains(val, item[1:len(item)-1]) + } else if hasPrefix { + return strings.HasSuffix(val, item[1:]) + } else if hasSuffix { + return strings.HasPrefix(val, item[:len(item)-1]) + } + + return val == item +} + +// AppendIfMissing adds a string to a slice if the given string is not present +func AppendIfMissing(slice []string, i string) []string { + if StrListContains(slice, i) { + return slice + } + return append(slice, i) +} diff --git a/vendor/github.com/hashicorp/vault/helper/tlsutil/tlsutil.go b/vendor/github.com/hashicorp/vault/helper/tlsutil/tlsutil.go new file mode 100644 index 0000000..08b3ebd --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/tlsutil/tlsutil.go @@ -0,0 +1,54 @@ +package tlsutil + +import ( + "crypto/tls" + "fmt" + + "github.com/hashicorp/vault/helper/strutil" +) + +// TLSLookup maps the tls_min_version configuration to the internal value +var TLSLookup = map[string]uint16{ + "tls10": tls.VersionTLS10, + "tls11": tls.VersionTLS11, + "tls12": tls.VersionTLS12, +} + +// ParseCiphers parse ciphersuites from the comma-separated string into recognized slice +func ParseCiphers(cipherStr string) ([]uint16, error) { + suites := []uint16{} + ciphers := strutil.ParseStringSlice(cipherStr, ",") + cipherMap := map[string]uint16{ + "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, + "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, + "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, + "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + } + for _, cipher := range ciphers { + if v, ok := cipherMap[cipher]; ok { + suites = append(suites, v) + } else { + return suites, fmt.Errorf("unsupported cipher %q", cipher) + } + } + + return suites, nil +} diff --git a/vendor/github.com/hashicorp/vault/helper/wrapping/wrapinfo.go b/vendor/github.com/hashicorp/vault/helper/wrapping/wrapinfo.go new file mode 100644 index 0000000..9c84a1d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/wrapping/wrapinfo.go @@ -0,0 +1,37 @@ +package wrapping + +import "time" + +type ResponseWrapInfo struct { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl" sentinel:""` + + // The token containing the wrapped response + Token string `json:"token" structs:"token" mapstructure:"token" sentinel:""` + + // The token accessor for the wrapped response token + Accessor string `json:"accessor" structs:"accessor" mapstructure:"accessor"` + + // The creation time. This can be used with the TTL to figure out an + // expected expiration. + CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time" sentinel:""` + + // If the contained response is the output of a token creation call, the + // created token's accessor will be accessible here + WrappedAccessor string `json:"wrapped_accessor" structs:"wrapped_accessor" mapstructure:"wrapped_accessor" sentinel:""` + + // WrappedEntityID is the entity identifier of the caller who initiated the + // wrapping request + WrappedEntityID string `json:"wrapped_entity_id" structs:"wrapped_entity_id" mapstructure:"wrapped_entity_id" sentinel:""` + + // The format to use. This doesn't get returned, it's only internal. + Format string `json:"format" structs:"format" mapstructure:"format" sentinel:""` + + // CreationPath is the original request path that was used to create + // the wrapped response. + CreationPath string `json:"creation_path" structs:"creation_path" mapstructure:"creation_path" sentinel:""` + + // Controls seal wrapping behavior downstream for specific use cases + SealWrap bool `json:"seal_wrap" structs:"seal_wrap" mapstructure:"seal_wrap" sentinel:""` +} diff --git a/vendor/github.com/hashicorp/vault/helper/xor/xor.go b/vendor/github.com/hashicorp/vault/helper/xor/xor.go new file mode 100644 index 0000000..0d9567e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/xor/xor.go @@ -0,0 +1,48 @@ +package xor + +import ( + "encoding/base64" + "fmt" + + "github.com/hashicorp/errwrap" +) + +// XORBytes takes two byte slices and XORs them together, returning the final +// byte slice. It is an error to pass in two byte slices that do not have the +// same length. +func XORBytes(a, b []byte) ([]byte, error) { + if len(a) != len(b) { + return nil, fmt.Errorf("length of byte slices is not equivalent: %d != %d", len(a), len(b)) + } + + buf := make([]byte, len(a)) + + for i, _ := range a { + buf[i] = a[i] ^ b[i] + } + + return buf, nil +} + +// XORBase64 takes two base64-encoded strings and XORs the decoded byte slices +// together, returning the final byte slice. It is an error to pass in two +// strings that do not have the same length to their base64-decoded byte slice. +func XORBase64(a, b string) ([]byte, error) { + aBytes, err := base64.StdEncoding.DecodeString(a) + if err != nil { + return nil, errwrap.Wrapf("error decoding first base64 value: {{err}}", err) + } + if aBytes == nil || len(aBytes) == 0 { + return nil, fmt.Errorf("decoded first base64 value is nil or empty") + } + + bBytes, err := base64.StdEncoding.DecodeString(b) + if err != nil { + return nil, errwrap.Wrapf("error decoding second base64 value: {{err}}", err) + } + if bBytes == nil || len(bBytes) == 0 { + return nil, fmt.Errorf("decoded second base64 value is nil or empty") + } + + return XORBytes(aBytes, bBytes) +} diff --git a/vendor/github.com/hashicorp/vault/http/cors.go b/vendor/github.com/hashicorp/vault/http/cors.go new file mode 100644 index 0000000..a01228b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/cors.go @@ -0,0 +1,62 @@ +package http + +import ( + "fmt" + "net/http" + "strings" + + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/vault" +) + +var allowedMethods = []string{ + http.MethodDelete, + http.MethodGet, + http.MethodOptions, + http.MethodPost, + http.MethodPut, + "LIST", // LIST is not an official HTTP method, but Vault supports it. +} + +func wrapCORSHandler(h http.Handler, core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + corsConf := core.CORSConfig() + + origin := req.Header.Get("Origin") + requestMethod := req.Header.Get("Access-Control-Request-Method") + + // If CORS is not enabled or if no Origin header is present (i.e. the request + // is from the Vault CLI. A browser will always send an Origin header), then + // just return a 204. + if !corsConf.IsEnabled() || origin == "" { + h.ServeHTTP(w, req) + return + } + + // Return a 403 if the origin is not allowed to make cross-origin requests. + if !corsConf.IsValidOrigin(origin) { + respondError(w, http.StatusForbidden, fmt.Errorf("origin not allowed")) + return + } + + if req.Method == http.MethodOptions && !strutil.StrListContains(allowedMethods, requestMethod) { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + w.Header().Set("Access-Control-Allow-Origin", origin) + w.Header().Set("Vary", "Origin") + + // apply headers for preflight requests + if req.Method == http.MethodOptions { + w.Header().Set("Access-Control-Allow-Methods", strings.Join(allowedMethods, ",")) + w.Header().Set("Access-Control-Allow-Headers", strings.Join(corsConf.AllowedHeaders, ",")) + w.Header().Set("Access-Control-Max-Age", "300") + + return + } + + h.ServeHTTP(w, req) + return + }) +} diff --git a/vendor/github.com/hashicorp/vault/http/handler.go b/vendor/github.com/hashicorp/vault/http/handler.go new file mode 100644 index 0000000..f7d6437 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/handler.go @@ -0,0 +1,576 @@ +package http + +import ( + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/textproto" + "net/url" + "os" + "strings" + "time" + + "github.com/NYTimes/gziphandler" + "github.com/elazarl/go-bindata-assetfs" + "github.com/hashicorp/errwrap" + cleanhttp "github.com/hashicorp/go-cleanhttp" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" +) + +const ( + // AuthHeaderName is the name of the header containing the token. + AuthHeaderName = "X-Vault-Token" + + // WrapTTLHeaderName is the name of the header containing a directive to + // wrap the response + WrapTTLHeaderName = "X-Vault-Wrap-TTL" + + // WrapFormatHeaderName is the name of the header containing the format to + // wrap in; has no effect if the wrap TTL is not set + WrapFormatHeaderName = "X-Vault-Wrap-Format" + + // NoRequestForwardingHeaderName is the name of the header telling Vault + // not to use request forwarding + NoRequestForwardingHeaderName = "X-Vault-No-Request-Forwarding" + + // MFAHeaderName represents the HTTP header which carries the credentials + // required to perform MFA on any path. + MFAHeaderName = "X-Vault-MFA" + + // canonicalMFAHeaderName is the MFA header value's format in the request + // headers. Do not alter the casing of this string. + canonicalMFAHeaderName = "X-Vault-Mfa" + + // PolicyOverrideHeaderName is the header set to request overriding + // soft-mandatory Sentinel policies. + PolicyOverrideHeaderName = "X-Vault-Policy-Override" + + // MaxRequestSize is the maximum accepted request size. This is to prevent + // a denial of service attack where no Content-Length is provided and the server + // is fed ever more data until it exhausts memory. + MaxRequestSize = 32 * 1024 * 1024 +) + +var ( + ReplicationStaleReadTimeout = 2 * time.Second + + // Set to false by stub_asset if the ui build tag isn't enabled + uiBuiltIn = true +) + +// Handler returns an http.Handler for the API. This can be used on +// its own to mount the Vault API within another web server. +func Handler(core *vault.Core) http.Handler { + // Create the muxer to handle the actual endpoints + mux := http.NewServeMux() + mux.Handle("/v1/sys/init", handleSysInit(core)) + mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core)) + mux.Handle("/v1/sys/seal", handleSysSeal(core)) + mux.Handle("/v1/sys/step-down", handleRequestForwarding(core, handleSysStepDown(core))) + mux.Handle("/v1/sys/unseal", handleSysUnseal(core)) + mux.Handle("/v1/sys/leader", handleSysLeader(core)) + mux.Handle("/v1/sys/health", handleSysHealth(core)) + mux.Handle("/v1/sys/generate-root/attempt", handleRequestForwarding(core, handleSysGenerateRootAttempt(core, vault.GenerateStandardRootTokenStrategy))) + mux.Handle("/v1/sys/generate-root/update", handleRequestForwarding(core, handleSysGenerateRootUpdate(core, vault.GenerateStandardRootTokenStrategy))) + mux.Handle("/v1/sys/rekey/init", handleRequestForwarding(core, handleSysRekeyInit(core, false))) + mux.Handle("/v1/sys/rekey/update", handleRequestForwarding(core, handleSysRekeyUpdate(core, false))) + mux.Handle("/v1/sys/rekey/verify", handleRequestForwarding(core, handleSysRekeyVerify(core, false))) + mux.Handle("/v1/sys/rekey-recovery-key/init", handleRequestForwarding(core, handleSysRekeyInit(core, true))) + mux.Handle("/v1/sys/rekey-recovery-key/update", handleRequestForwarding(core, handleSysRekeyUpdate(core, true))) + mux.Handle("/v1/sys/rekey-recovery-key/verify", handleRequestForwarding(core, handleSysRekeyVerify(core, true))) + mux.Handle("/v1/sys/wrapping/lookup", handleRequestForwarding(core, handleLogical(core, false, wrappingVerificationFunc))) + mux.Handle("/v1/sys/wrapping/rewrap", handleRequestForwarding(core, handleLogical(core, false, wrappingVerificationFunc))) + mux.Handle("/v1/sys/wrapping/unwrap", handleRequestForwarding(core, handleLogical(core, false, wrappingVerificationFunc))) + for _, path := range injectDataIntoTopRoutes { + mux.Handle(path, handleRequestForwarding(core, handleLogical(core, true, nil))) + } + mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core, false, nil))) + mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core, false, nil))) + if core.UIEnabled() == true { + if uiBuiltIn { + mux.Handle("/ui/", http.StripPrefix("/ui/", gziphandler.GzipHandler(handleUIHeaders(core, handleUI(http.FileServer(&UIAssetWrapper{FileSystem: assetFS()})))))) + } else { + mux.Handle("/ui/", handleUIHeaders(core, handleUIStub())) + } + mux.Handle("/", handleRootRedirect()) + } + + // Wrap the handler in another handler to trigger all help paths. + helpWrappedHandler := wrapHelpHandler(mux, core) + corsWrappedHandler := wrapCORSHandler(helpWrappedHandler, core) + + // Wrap the help wrapped handler with another layer with a generic + // handler + genericWrappedHandler := wrapGenericHandler(corsWrappedHandler) + + // Wrap the handler with PrintablePathCheckHandler to check for non-printable + // characters in the request path. + printablePathCheckHandler := cleanhttp.PrintablePathCheckHandler(genericWrappedHandler, nil) + + return printablePathCheckHandler +} + +// wrapGenericHandler wraps the handler with an extra layer of handler where +// tasks that should be commonly handled for all the requests and/or responses +// are performed. +func wrapGenericHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Set the Cache-Control header for all the responses returned + // by Vault + w.Header().Set("Cache-Control", "no-store") + h.ServeHTTP(w, r) + return + }) +} + +func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAddrMarshaler, rejectNotPresent, rejectNonAuthz bool, hopSkips int) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + headers, headersOK := r.Header[textproto.CanonicalMIMEHeaderKey("X-Forwarded-For")] + if !headersOK || len(headers) == 0 { + if !rejectNotPresent { + h.ServeHTTP(w, r) + return + } + respondError(w, http.StatusBadRequest, fmt.Errorf("missing x-forwarded-for header and configured to reject when not present")) + return + } + + host, port, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + // If not rejecting treat it like we just don't have a valid + // header because we can't do a comparison against an address we + // can't understand + if !rejectNotPresent { + h.ServeHTTP(w, r) + return + } + respondError(w, http.StatusBadRequest, errwrap.Wrapf("error parsing client hostport: {{err}}", err)) + return + } + + addr, err := sockaddr.NewIPAddr(host) + if err != nil { + // We treat this the same as the case above + if !rejectNotPresent { + h.ServeHTTP(w, r) + return + } + respondError(w, http.StatusBadRequest, errwrap.Wrapf("error parsing client address: {{err}}", err)) + return + } + + var found bool + for _, authz := range authorizedAddrs { + if authz.Contains(addr) { + found = true + break + } + } + if !found { + // If we didn't find it and aren't configured to reject, simply + // don't trust it + if !rejectNonAuthz { + h.ServeHTTP(w, r) + return + } + respondError(w, http.StatusBadRequest, fmt.Errorf("client address not authorized for x-forwarded-for and configured to reject connection")) + return + } + + // At this point we have at least one value and it's authorized + + // Split comma separated ones, which are common. This brings it in line + // to the multiple-header case. + var acc []string + for _, header := range headers { + vals := strings.Split(header, ",") + for _, v := range vals { + acc = append(acc, strings.TrimSpace(v)) + } + } + + indexToUse := len(acc) - 1 - hopSkips + if indexToUse < 0 { + // This is likely an error in either configuration or other + // infrastructure. We could either deny the request, or we + // could simply not trust the value. Denying the request is + // "safer" since if this logic is configured at all there may + // be an assumption it can always be trusted. Given that we can + // deny accepting the request at all if it's not from an + // authorized address, if we're at this point the address is + // authorized (or we've turned off explicit rejection) and we + // should assume that what comes in should be properly + // formatted. + respondError(w, http.StatusBadRequest, fmt.Errorf("malformed x-forwarded-for configuration or request, hops to skip (%d) would skip before earliest chain link (chain length %d)", hopSkips, len(headers))) + return + } + + r.RemoteAddr = net.JoinHostPort(acc[indexToUse], port) + h.ServeHTTP(w, r) + return + }) +} + +// A lookup on a token that is about to expire returns nil, which means by the +// time we can validate a wrapping token lookup will return nil since it will +// be revoked after the call. So we have to do the validation here. +func wrappingVerificationFunc(core *vault.Core, req *logical.Request) error { + if req == nil { + return fmt.Errorf("invalid request") + } + + valid, err := core.ValidateWrappingToken(req) + if err != nil { + return errwrap.Wrapf("error validating wrapping token: {{err}}", err) + } + if !valid { + return fmt.Errorf("wrapping token is not valid or does not exist") + } + + return nil +} + +// stripPrefix is a helper to strip a prefix from the path. It will +// return false from the second return value if it the prefix doesn't exist. +func stripPrefix(prefix, path string) (string, bool) { + if !strings.HasPrefix(path, prefix) { + return "", false + } + + path = path[len(prefix):] + if path == "" { + return "", false + } + + return path, true +} + +func handleUIHeaders(core *vault.Core, h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + header := w.Header() + + userHeaders, err := core.UIHeaders() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + if userHeaders != nil { + for k := range userHeaders { + v := userHeaders.Get(k) + header.Set(k, v) + } + } + h.ServeHTTP(w, req) + }) +} + +func handleUI(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + + // The fileserver handler strips trailing slashes and does a redirect. + // We don't want the redirect to happen so we preemptively trim the slash + // here. + req.URL.Path = strings.TrimSuffix(req.URL.Path, "/") + h.ServeHTTP(w, req) + return + }) +} + +func handleUIStub() http.Handler { + stubHTML := ` + + +

Vault UI is not available in this binary. To get Vault UI do one of the following:

+
    +
  • Download an official release
  • +
  • Run make release to create your own release binaries. +
  • Run make dev-ui to create a development binary with the UI. +
+ + ` + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(stubHTML)) + }) +} + +func handleRootRedirect() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + http.Redirect(w, req, "/ui/", 307) + return + }) +} + +type UIAssetWrapper struct { + FileSystem *assetfs.AssetFS +} + +func (fs *UIAssetWrapper) Open(name string) (http.File, error) { + file, err := fs.FileSystem.Open(name) + if err == nil { + return file, nil + } + // serve index.html instead of 404ing + if err == os.ErrNotExist { + return fs.FileSystem.Open("index.html") + } + return nil, err +} + +func parseRequest(r *http.Request, w http.ResponseWriter, out interface{}) error { + // Limit the maximum number of bytes to MaxRequestSize to protect + // against an indefinite amount of data being read. + limit := http.MaxBytesReader(w, r.Body, MaxRequestSize) + err := jsonutil.DecodeJSONFromReader(limit, out) + if err != nil && err != io.EOF { + return errwrap.Wrapf("failed to parse JSON input: {{err}}", err) + } + return err +} + +// handleRequestForwarding determines whether to forward a request or not, +// falling back on the older behavior of redirecting the client +func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get(vault.IntNoForwardingHeaderName) != "" { + handler.ServeHTTP(w, r) + return + } + + if r.Header.Get(NoRequestForwardingHeaderName) != "" { + // Forwarding explicitly disabled, fall back to previous behavior + core.Logger().Debug("handleRequestForwarding: forwarding disabled by client request") + handler.ServeHTTP(w, r) + return + } + + // Note: in an HA setup, this call will also ensure that connections to + // the leader are set up, as that happens once the advertised cluster + // values are read during this function + isLeader, leaderAddr, _, err := core.Leader() + if err != nil { + if err == vault.ErrHANotEnabled { + // Standalone node, serve request normally + handler.ServeHTTP(w, r) + return + } + // Some internal error occurred + respondError(w, http.StatusInternalServerError, err) + return + } + if isLeader { + // No forwarding needed, we're leader + handler.ServeHTTP(w, r) + return + } + if leaderAddr == "" { + respondError(w, http.StatusInternalServerError, fmt.Errorf("local node not active but active cluster node not found")) + return + } + + // Attempt forwarding the request. If we cannot forward -- perhaps it's + // been disabled on the active node -- this will return with an + // ErrCannotForward and we simply fall back + statusCode, header, retBytes, err := core.ForwardRequest(r) + if err != nil { + if err == vault.ErrCannotForward { + core.Logger().Debug("handleRequestForwarding: cannot forward (possibly disabled on active node), falling back") + } else { + core.Logger().Error("handleRequestForwarding: error forwarding request", "error", err) + } + + // Fall back to redirection + handler.ServeHTTP(w, r) + return + } + + if header != nil { + for k, v := range header { + w.Header()[k] = v + } + } + + w.WriteHeader(statusCode) + w.Write(retBytes) + return + }) +} + +// request is a helper to perform a request and properly exit in the +// case of an error. +func request(core *vault.Core, w http.ResponseWriter, rawReq *http.Request, r *logical.Request) (*logical.Response, bool) { + resp, err := core.HandleRequest(r) + if errwrap.Contains(err, consts.ErrStandby.Error()) { + respondStandby(core, w, rawReq.URL) + return resp, false + } + if respondErrorCommon(w, r, resp, err) { + return resp, false + } + + return resp, true +} + +// respondStandby is used to trigger a redirect in the case that this Vault is currently a hot standby +func respondStandby(core *vault.Core, w http.ResponseWriter, reqURL *url.URL) { + // Request the leader address + _, redirectAddr, _, err := core.Leader() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + // If there is no leader, generate a 503 error + if redirectAddr == "" { + err = fmt.Errorf("no active Vault instance found") + respondError(w, http.StatusServiceUnavailable, err) + return + } + + // Parse the redirect location + redirectURL, err := url.Parse(redirectAddr) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + // Generate a redirect URL + finalURL := url.URL{ + Scheme: redirectURL.Scheme, + Host: redirectURL.Host, + Path: reqURL.Path, + RawQuery: reqURL.RawQuery, + } + + // Ensure there is a scheme, default to https + if finalURL.Scheme == "" { + finalURL.Scheme = "https" + } + + // If we have an address, redirect! We use a 307 code + // because we don't actually know if its permanent and + // the request method should be preserved. + w.Header().Set("Location", finalURL.String()) + w.WriteHeader(307) +} + +// requestAuth adds the token to the logical.Request if it exists. +func requestAuth(core *vault.Core, r *http.Request, req *logical.Request) *logical.Request { + // Attach the header value if we have it + if v := r.Header.Get(AuthHeaderName); v != "" { + req.ClientToken = v + + // Also attach the accessor if we have it. This doesn't fail if it + // doesn't exist because the request may be to an unauthenticated + // endpoint/login endpoint where a bad current token doesn't matter, or + // a token from a Vault version pre-accessors. + te, err := core.LookupToken(v) + if err == nil && te != nil { + req.ClientTokenAccessor = te.Accessor + req.ClientTokenRemainingUses = te.NumUses + } + } + + return req +} + +// requestWrapInfo adds the WrapInfo value to the logical.Request if wrap info exists +func requestWrapInfo(r *http.Request, req *logical.Request) (*logical.Request, error) { + // First try for the header value + wrapTTL := r.Header.Get(WrapTTLHeaderName) + if wrapTTL == "" { + return req, nil + } + + // If it has an allowed suffix parse as a duration string + dur, err := parseutil.ParseDurationSecond(wrapTTL) + if err != nil { + return req, err + } + if int64(dur) < 0 { + return req, fmt.Errorf("requested wrap ttl cannot be negative") + } + + req.WrapInfo = &logical.RequestWrapInfo{ + TTL: dur, + } + + wrapFormat := r.Header.Get(WrapFormatHeaderName) + switch wrapFormat { + case "jwt": + req.WrapInfo.Format = "jwt" + } + + return req, nil +} + +func respondError(w http.ResponseWriter, status int, err error) { + logical.AdjustErrorStatusCode(&status, err) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + + resp := &ErrorResponse{Errors: make([]string, 0, 1)} + if err != nil { + resp.Errors = append(resp.Errors, err.Error()) + } + + enc := json.NewEncoder(w) + enc.Encode(resp) +} + +func respondErrorCommon(w http.ResponseWriter, req *logical.Request, resp *logical.Response, err error) bool { + statusCode, newErr := logical.RespondErrorCommon(req, resp, err) + if newErr == nil && statusCode == 0 { + return false + } + + respondError(w, statusCode, newErr) + return true +} + +func respondOk(w http.ResponseWriter, body interface{}) { + w.Header().Set("Content-Type", "application/json") + + if body == nil { + w.WriteHeader(http.StatusNoContent) + } else { + w.WriteHeader(http.StatusOK) + enc := json.NewEncoder(w) + enc.Encode(body) + } +} + +type ErrorResponse struct { + Errors []string `json:"errors"` +} + +var injectDataIntoTopRoutes = []string{ + "/v1/sys/audit", + "/v1/sys/audit/", + "/v1/sys/audit-hash/", + "/v1/sys/auth", + "/v1/sys/auth/", + "/v1/sys/config/cors", + "/v1/sys/config/auditing/request-headers/", + "/v1/sys/config/auditing/request-headers", + "/v1/sys/capabilities", + "/v1/sys/capabilities-accessor", + "/v1/sys/capabilities-self", + "/v1/sys/key-status", + "/v1/sys/mounts", + "/v1/sys/mounts/", + "/v1/sys/policy", + "/v1/sys/policy/", + "/v1/sys/rekey/backup", + "/v1/sys/rekey/recovery-key-backup", + "/v1/sys/remount", + "/v1/sys/rotate", + "/v1/sys/wrapping/wrap", +} diff --git a/vendor/github.com/hashicorp/vault/http/help.go b/vendor/github.com/hashicorp/vault/http/help.go new file mode 100644 index 0000000..1c3a956 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/help.go @@ -0,0 +1,47 @@ +package http + +import ( + "net/http" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" +) + +func wrapHelpHandler(h http.Handler, core *vault.Core) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) { + // If the help parameter is not blank, then show the help. We request + // forward because standby nodes do not have mounts and other state. + if v := req.URL.Query().Get("help"); v != "" || req.Method == "HELP" { + handleRequestForwarding(core, + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handleHelp(core, w, r) + })).ServeHTTP(writer, req) + return + } + + h.ServeHTTP(writer, req) + return + }) +} + +func handleHelp(core *vault.Core, w http.ResponseWriter, req *http.Request) { + path, ok := stripPrefix("/v1/", req.URL.Path) + if !ok { + respondError(w, http.StatusNotFound, nil) + return + } + + lreq := requestAuth(core, req, &logical.Request{ + Operation: logical.HelpOperation, + Path: path, + Connection: getConnection(req), + }) + + resp, err := core.HandleRequest(lreq) + if err != nil { + respondErrorCommon(w, lreq, resp, err) + return + } + + respondOk(w, resp.Data) +} diff --git a/vendor/github.com/hashicorp/vault/http/logical.go b/vendor/github.com/hashicorp/vault/http/logical.go new file mode 100644 index 0000000..7b31c87 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/logical.go @@ -0,0 +1,317 @@ +package http + +import ( + "encoding/base64" + "encoding/json" + "io" + "net" + "net/http" + "strconv" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" +) + +type PrepareRequestFunc func(*vault.Core, *logical.Request) error + +func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) (*logical.Request, int, error) { + // Determine the path... + if !strings.HasPrefix(r.URL.Path, "/v1/") { + return nil, http.StatusNotFound, nil + } + path := r.URL.Path[len("/v1/"):] + if path == "" { + return nil, http.StatusNotFound, nil + } + + // Determine the operation + var op logical.Operation + switch r.Method { + case "DELETE": + op = logical.DeleteOperation + case "GET": + op = logical.ReadOperation + // Need to call ParseForm to get query params loaded + queryVals := r.URL.Query() + listStr := queryVals.Get("list") + if listStr != "" { + list, err := strconv.ParseBool(listStr) + if err != nil { + return nil, http.StatusBadRequest, nil + } + if list { + op = logical.ListOperation + } + } + case "POST", "PUT": + op = logical.UpdateOperation + case "LIST": + op = logical.ListOperation + case "OPTIONS": + default: + return nil, http.StatusMethodNotAllowed, nil + } + + if op == logical.ListOperation { + if !strings.HasSuffix(path, "/") { + path += "/" + } + } + + // Parse the request if we can + var data map[string]interface{} + if op == logical.UpdateOperation { + err := parseRequest(r, w, &data) + if err == io.EOF { + data = nil + err = nil + } + if err != nil { + return nil, http.StatusBadRequest, err + } + } + + // If we are a read operation, try and parse any parameters + if op == logical.ReadOperation { + getData := map[string]interface{}{} + + for k, v := range r.URL.Query() { + // Skip the help key as this is a reserved parameter + if k == "help" { + continue + } + + switch { + case len(v) == 0: + case len(v) == 1: + getData[k] = v[0] + default: + getData[k] = v + } + } + + if len(getData) > 0 { + data = getData + } + } + + var err error + request_id, err := uuid.GenerateUUID() + if err != nil { + return nil, http.StatusBadRequest, errwrap.Wrapf("failed to generate identifier for the request: {{err}}", err) + } + + req := requestAuth(core, r, &logical.Request{ + ID: request_id, + Operation: op, + Path: path, + Data: data, + Connection: getConnection(r), + Headers: r.Header, + }) + + req, err = requestWrapInfo(r, req) + if err != nil { + return nil, http.StatusBadRequest, errwrap.Wrapf("error parsing X-Vault-Wrap-TTL header: {{err}}", err) + } + + return req, 0, nil +} + +func handleLogical(core *vault.Core, injectDataIntoTopLevel bool, prepareRequestCallback PrepareRequestFunc) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req, statusCode, err := buildLogicalRequest(core, w, r) + if err != nil || statusCode != 0 { + respondError(w, statusCode, err) + return + } + + // Certain endpoints may require changes to the request object. They + // will have a callback registered to do the needed operations, so + // invoke it before proceeding. + if prepareRequestCallback != nil { + if err := prepareRequestCallback(core, req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + } + + // Make the internal request. We attach the connection info + // as well in case this is an authentication request that requires + // it. Vault core handles stripping this if we need to. This also + // handles all error cases; if we hit respondLogical, the request is a + // success. + resp, ok := request(core, w, r, req) + if !ok { + return + } + + // Build the proper response + respondLogical(w, r, req, injectDataIntoTopLevel, resp) + }) +} + +func respondLogical(w http.ResponseWriter, r *http.Request, req *logical.Request, injectDataIntoTopLevel bool, resp *logical.Response) { + var httpResp *logical.HTTPResponse + var ret interface{} + + if resp != nil { + if resp.Redirect != "" { + // If we have a redirect, redirect! We use a 307 code + // because we don't actually know if its permanent. + http.Redirect(w, r, resp.Redirect, 307) + return + } + + // Check if this is a raw response + if _, ok := resp.Data[logical.HTTPStatusCode]; ok { + respondRaw(w, r, resp) + return + } + + if resp.WrapInfo != nil && resp.WrapInfo.Token != "" { + httpResp = &logical.HTTPResponse{ + WrapInfo: &logical.HTTPWrapInfo{ + Token: resp.WrapInfo.Token, + Accessor: resp.WrapInfo.Accessor, + TTL: int(resp.WrapInfo.TTL.Seconds()), + CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano), + CreationPath: resp.WrapInfo.CreationPath, + WrappedAccessor: resp.WrapInfo.WrappedAccessor, + }, + } + } else { + httpResp = logical.LogicalResponseToHTTPResponse(resp) + httpResp.RequestID = req.ID + } + + ret = httpResp + + if injectDataIntoTopLevel { + injector := logical.HTTPSysInjector{ + Response: httpResp, + } + ret = injector + } + } + + // Respond + respondOk(w, ret) + return +} + +// respondRaw is used when the response is using HTTPContentType and HTTPRawBody +// to change the default response handling. This is only used for specific things like +// returning the CRL information on the PKI backends. +func respondRaw(w http.ResponseWriter, r *http.Request, resp *logical.Response) { + retErr := func(w http.ResponseWriter, err string) { + w.Header().Set("X-Vault-Raw-Error", err) + w.WriteHeader(http.StatusInternalServerError) + w.Write(nil) + } + + // Ensure this is never a secret or auth response + if resp.Secret != nil || resp.Auth != nil { + retErr(w, "raw responses cannot contain secrets or auth") + return + } + + // Get the status code + statusRaw, ok := resp.Data[logical.HTTPStatusCode] + if !ok { + retErr(w, "no status code given") + return + } + + var status int + switch statusRaw.(type) { + case int: + status = statusRaw.(int) + case float64: + status = int(statusRaw.(float64)) + case json.Number: + s64, err := statusRaw.(json.Number).Float64() + if err != nil { + retErr(w, "cannot decode status code") + return + } + status = int(s64) + default: + retErr(w, "cannot decode status code") + return + } + + nonEmpty := status != http.StatusNoContent + + var contentType string + var body []byte + + // Get the content type header; don't require it if the body is empty + contentTypeRaw, ok := resp.Data[logical.HTTPContentType] + if !ok && nonEmpty { + retErr(w, "no content type given") + return + } + if ok { + contentType, ok = contentTypeRaw.(string) + if !ok { + retErr(w, "cannot decode content type") + return + } + } + + if nonEmpty { + // Get the body + bodyRaw, ok := resp.Data[logical.HTTPRawBody] + if !ok { + retErr(w, "no body given") + return + } + + switch bodyRaw.(type) { + case string: + // This is best effort. The value may already be base64-decoded so + // if it doesn't work we just use as-is + bodyDec, err := base64.StdEncoding.DecodeString(bodyRaw.(string)) + if err == nil { + body = bodyDec + } else { + body = []byte(bodyRaw.(string)) + } + case []byte: + body = bodyRaw.([]byte) + default: + retErr(w, "cannot decode body") + return + } + } + + // Write the response + if contentType != "" { + w.Header().Set("Content-Type", contentType) + } + + w.WriteHeader(status) + w.Write(body) +} + +// getConnection is used to format the connection information for +// attaching to a logical request +func getConnection(r *http.Request) (connection *logical.Connection) { + var remoteAddr string + + remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + remoteAddr = "" + } + + connection = &logical.Connection{ + RemoteAddr: remoteAddr, + ConnState: r.TLS, + } + return +} diff --git a/vendor/github.com/hashicorp/vault/http/stub_assets.go b/vendor/github.com/hashicorp/vault/http/stub_assets.go new file mode 100644 index 0000000..c64ac58 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/stub_assets.go @@ -0,0 +1,16 @@ +// +build !ui + +package http + +import ( + assetfs "github.com/elazarl/go-bindata-assetfs" +) + +func init() { + uiBuiltIn = false +} + +// assetFS is a stub for building Vault without a UI. +func assetFS() *assetfs.AssetFS { + return nil +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_generate_root.go b/vendor/github.com/hashicorp/vault/http/sys_generate_root.go new file mode 100644 index 0000000..74456b9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_generate_root.go @@ -0,0 +1,192 @@ +package http + +import ( + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "net/http" + + "github.com/hashicorp/vault/vault" +) + +func handleSysGenerateRootAttempt(core *vault.Core, generateStrategy vault.GenerateRootStrategy) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + handleSysGenerateRootAttemptGet(core, w, r) + case "POST", "PUT": + handleSysGenerateRootAttemptPut(core, w, r, generateStrategy) + case "DELETE": + handleSysGenerateRootAttemptDelete(core, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysGenerateRootAttemptGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + ctx, cancel := core.GetContext() + defer cancel() + + // Get the current seal configuration + barrierConfig, err := core.SealAccess().BarrierConfig(ctx) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + if barrierConfig == nil { + respondError(w, http.StatusBadRequest, fmt.Errorf("server is not yet initialized")) + return + } + + sealConfig := barrierConfig + if core.SealAccess().RecoveryKeySupported() { + sealConfig, err = core.SealAccess().RecoveryConfig(ctx) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + } + + // Get the generation configuration + generationConfig, err := core.GenerateRootConfiguration() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + // Get the progress + progress, err := core.GenerateRootProgress() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + // Format the status + status := &GenerateRootStatusResponse{ + Started: false, + Progress: progress, + Required: sealConfig.SecretThreshold, + Complete: false, + } + if generationConfig != nil { + status.Nonce = generationConfig.Nonce + status.Started = true + status.PGPFingerprint = generationConfig.PGPFingerprint + } + + respondOk(w, status) +} + +func handleSysGenerateRootAttemptPut(core *vault.Core, w http.ResponseWriter, r *http.Request, generateStrategy vault.GenerateRootStrategy) { + // Parse the request + var req GenerateRootInitRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + if len(req.OTP) > 0 && len(req.PGPKey) > 0 { + respondError(w, http.StatusBadRequest, fmt.Errorf("only one of \"otp\" and \"pgp_key\" must be specified")) + return + } + + // Attemptialize the generation + err := core.GenerateRootInit(req.OTP, req.PGPKey, generateStrategy) + if err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + handleSysGenerateRootAttemptGet(core, w, r) +} + +func handleSysGenerateRootAttemptDelete(core *vault.Core, w http.ResponseWriter, r *http.Request) { + err := core.GenerateRootCancel() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + respondOk(w, nil) +} + +func handleSysGenerateRootUpdate(core *vault.Core, generateStrategy vault.GenerateRootStrategy) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Parse the request + var req GenerateRootUpdateRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + if req.Key == "" { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be specified in request body as JSON")) + return + } + + // Decode the key, which is base64 or hex encoded + min, max := core.BarrierKeyLength() + key, err := hex.DecodeString(req.Key) + // We check min and max here to ensure that a string that is base64 + // encoded but also valid hex will not be valid and we instead base64 + // decode it + if err != nil || len(key) < min || len(key) > max { + key, err = base64.StdEncoding.DecodeString(req.Key) + if err != nil { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be a valid hex or base64 string")) + return + } + } + + ctx, cancel := core.GetContext() + defer cancel() + + // Use the key to make progress on root generation + result, err := core.GenerateRootUpdate(ctx, key, req.Nonce, generateStrategy) + if err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + resp := &GenerateRootStatusResponse{ + Complete: result.Progress == result.Required, + Nonce: req.Nonce, + Progress: result.Progress, + Required: result.Required, + Started: true, + EncodedToken: result.EncodedToken, + PGPFingerprint: result.PGPFingerprint, + } + + if generateStrategy == vault.GenerateStandardRootTokenStrategy { + resp.EncodedRootToken = result.EncodedToken + } + + respondOk(w, resp) + }) +} + +type GenerateRootInitRequest struct { + OTP string `json:"otp"` + PGPKey string `json:"pgp_key"` +} + +type GenerateRootStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + Progress int `json:"progress"` + Required int `json:"required"` + Complete bool `json:"complete"` + EncodedToken string `json:"encoded_token"` + EncodedRootToken string `json:"encoded_root_token"` + PGPFingerprint string `json:"pgp_fingerprint"` +} + +type GenerateRootUpdateRequest struct { + Nonce string + Key string +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_health.go b/vendor/github.com/hashicorp/vault/http/sys_health.go new file mode 100644 index 0000000..be67f2f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_health.go @@ -0,0 +1,183 @@ +package http + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strconv" + "time" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/vault" + "github.com/hashicorp/vault/version" +) + +func handleSysHealth(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + handleSysHealthGet(core, w, r) + case "HEAD": + handleSysHealthHead(core, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func fetchStatusCode(r *http.Request, field string) (int, bool, bool) { + var err error + statusCode := http.StatusOK + if statusCodeStr, statusCodeOk := r.URL.Query()[field]; statusCodeOk { + statusCode, err = strconv.Atoi(statusCodeStr[0]) + if err != nil || len(statusCodeStr) < 1 { + return http.StatusBadRequest, false, false + } + return statusCode, true, true + } + return statusCode, false, true +} + +func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + code, body, err := getSysHealth(core, r) + if err != nil { + core.Logger().Error("error checking health", "error", err) + respondError(w, http.StatusInternalServerError, nil) + return + } + + if body == nil { + respondError(w, code, nil) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + + // Generate the response + enc := json.NewEncoder(w) + enc.Encode(body) +} + +func handleSysHealthHead(core *vault.Core, w http.ResponseWriter, r *http.Request) { + code, body, err := getSysHealth(core, r) + if err != nil { + code = http.StatusInternalServerError + } + + if body != nil { + w.Header().Set("Content-Type", "application/json") + } + w.WriteHeader(code) +} + +func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, error) { + // Check if being a standby is allowed for the purpose of a 200 OK + _, standbyOK := r.URL.Query()["standbyok"] + + uninitCode := http.StatusNotImplemented + if code, found, ok := fetchStatusCode(r, "uninitcode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + uninitCode = code + } + + sealedCode := http.StatusServiceUnavailable + if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + sealedCode = code + } + + standbyCode := http.StatusTooManyRequests // Consul warning code + if code, found, ok := fetchStatusCode(r, "standbycode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + standbyCode = code + } + + activeCode := http.StatusOK + if code, found, ok := fetchStatusCode(r, "activecode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + activeCode = code + } + + drSecondaryCode := 472 // unofficial 4xx status code + if code, found, ok := fetchStatusCode(r, "drsecondarycode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + drSecondaryCode = code + } + + ctx := context.Background() + + // Check system status + sealed, _ := core.Sealed() + standby, _ := core.Standby() + var replicationState consts.ReplicationState + if standby { + replicationState = core.ActiveNodeReplicationState() + } else { + replicationState = core.ReplicationState() + } + + init, err := core.Initialized(ctx) + if err != nil { + return http.StatusInternalServerError, nil, err + } + + // Determine the status code + code := activeCode + switch { + case !init: + code = uninitCode + case sealed: + code = sealedCode + case replicationState.HasState(consts.ReplicationDRSecondary): + code = drSecondaryCode + case !standbyOK && standby: + code = standbyCode + } + + // Fetch the local cluster name and identifier + var clusterName, clusterID string + if !sealed { + cluster, err := core.Cluster(ctx) + if err != nil { + return http.StatusInternalServerError, nil, err + } + if cluster == nil { + return http.StatusInternalServerError, nil, fmt.Errorf("failed to fetch cluster details") + } + clusterName = cluster.Name + clusterID = cluster.ID + } + + // Format the body + body := &HealthResponse{ + Initialized: init, + Sealed: sealed, + Standby: standby, + ReplicationPerformanceMode: replicationState.GetPerformanceString(), + ReplicationDRMode: replicationState.GetDRString(), + ServerTimeUTC: time.Now().UTC().Unix(), + Version: version.GetVersion().VersionNumber(), + ClusterName: clusterName, + ClusterID: clusterID, + } + return code, body, nil +} + +type HealthResponse struct { + Initialized bool `json:"initialized"` + Sealed bool `json:"sealed"` + Standby bool `json:"standby"` + ReplicationPerformanceMode string `json:"replication_performance_mode"` + ReplicationDRMode string `json:"replication_dr_mode"` + ServerTimeUTC int64 `json:"server_time_utc"` + Version string `json:"version"` + ClusterName string `json:"cluster_name,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_init.go b/vendor/github.com/hashicorp/vault/http/sys_init.go new file mode 100644 index 0000000..f13ff5d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_init.go @@ -0,0 +1,165 @@ +package http + +import ( + "context" + "encoding/base64" + "encoding/hex" + "fmt" + "net/http" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/vault" +) + +func handleSysInit(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + handleSysInitGet(core, w, r) + case "PUT", "POST": + handleSysInitPut(core, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysInitGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + init, err := core.Initialized(context.Background()) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + respondOk(w, &InitStatusResponse{ + Initialized: init, + }) +} + +func handleSysInitPut(core *vault.Core, w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + // Parse the request + var req InitRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + // Initialize + barrierConfig := &vault.SealConfig{ + SecretShares: req.SecretShares, + SecretThreshold: req.SecretThreshold, + StoredShares: req.StoredShares, + PGPKeys: req.PGPKeys, + } + + recoveryConfig := &vault.SealConfig{ + SecretShares: req.RecoveryShares, + SecretThreshold: req.RecoveryThreshold, + PGPKeys: req.RecoveryPGPKeys, + } + + // N.B. Although the core is capable of handling situations where some keys + // are stored and some aren't, in practice, replication + HSMs makes this + // extremely hard to reason about, to the point that it will probably never + // be supported. The reason is that each HSM needs to encode the master key + // separately, which means the shares must be generated independently, + // which means both that the shares will be different *AND* there would + // need to be a way to actually allow fetching of the generated keys by + // operators. + if core.SealAccess().StoredKeysSupported() { + if len(barrierConfig.PGPKeys) > 0 { + respondError(w, http.StatusBadRequest, fmt.Errorf("PGP keys not supported when storing shares")) + return + } + barrierConfig.SecretShares = 1 + barrierConfig.SecretThreshold = 1 + barrierConfig.StoredShares = 1 + core.Logger().Warn("init: stored keys supported, forcing shares/threshold to 1") + } else { + if barrierConfig.StoredShares > 0 { + respondError(w, http.StatusBadRequest, fmt.Errorf("stored keys are not supported by the current seal type")) + return + } + } + + if len(barrierConfig.PGPKeys) > 0 && len(barrierConfig.PGPKeys) != barrierConfig.SecretShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys")) + return + } + + if core.SealAccess().RecoveryKeySupported() { + if len(recoveryConfig.PGPKeys) > 0 && len(recoveryConfig.PGPKeys) != recoveryConfig.SecretShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys for recovery")) + return + } + } + + initParams := &vault.InitParams{ + BarrierConfig: barrierConfig, + RecoveryConfig: recoveryConfig, + RootTokenPGPKey: req.RootTokenPGPKey, + } + + result, initErr := core.Initialize(ctx, initParams) + if initErr != nil { + if !errwrap.ContainsType(initErr, new(vault.NonFatalError)) { + respondError(w, http.StatusBadRequest, initErr) + return + } else { + // Add a warnings field? The error will be logged in the vault log + // already. + } + } + + // Encode the keys + keys := make([]string, 0, len(result.SecretShares)) + keysB64 := make([]string, 0, len(result.SecretShares)) + for _, k := range result.SecretShares { + keys = append(keys, hex.EncodeToString(k)) + keysB64 = append(keysB64, base64.StdEncoding.EncodeToString(k)) + } + + resp := &InitResponse{ + Keys: keys, + KeysB64: keysB64, + RootToken: result.RootToken, + } + + if len(result.RecoveryShares) > 0 { + resp.RecoveryKeys = make([]string, 0, len(result.RecoveryShares)) + resp.RecoveryKeysB64 = make([]string, 0, len(result.RecoveryShares)) + for _, k := range result.RecoveryShares { + resp.RecoveryKeys = append(resp.RecoveryKeys, hex.EncodeToString(k)) + resp.RecoveryKeysB64 = append(resp.RecoveryKeysB64, base64.StdEncoding.EncodeToString(k)) + } + } + + core.UnsealWithStoredKeys(ctx) + + respondOk(w, resp) +} + +type InitRequest struct { + SecretShares int `json:"secret_shares"` + SecretThreshold int `json:"secret_threshold"` + StoredShares int `json:"stored_shares"` + PGPKeys []string `json:"pgp_keys"` + RecoveryShares int `json:"recovery_shares"` + RecoveryThreshold int `json:"recovery_threshold"` + RecoveryPGPKeys []string `json:"recovery_pgp_keys"` + RootTokenPGPKey string `json:"root_token_pgp_key"` +} + +type InitResponse struct { + Keys []string `json:"keys"` + KeysB64 []string `json:"keys_base64"` + RecoveryKeys []string `json:"recovery_keys,omitempty"` + RecoveryKeysB64 []string `json:"recovery_keys_base64,omitempty"` + RootToken string `json:"root_token"` +} + +type InitStatusResponse struct { + Initialized bool `json:"initialized"` +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_leader.go b/vendor/github.com/hashicorp/vault/http/sys_leader.go new file mode 100644 index 0000000..98eb04a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_leader.go @@ -0,0 +1,46 @@ +package http + +import ( + "net/http" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/vault" +) + +func handleSysLeader(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + handleSysLeaderGet(core, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + haEnabled := true + isLeader, address, clusterAddr, err := core.Leader() + if errwrap.Contains(err, vault.ErrHANotEnabled.Error()) { + haEnabled = false + err = nil + } + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + respondOk(w, &LeaderResponse{ + HAEnabled: haEnabled, + IsSelf: isLeader, + LeaderAddress: address, + LeaderClusterAddress: clusterAddr, + }) +} + +type LeaderResponse struct { + HAEnabled bool `json:"ha_enabled"` + IsSelf bool `json:"is_self"` + LeaderAddress string `json:"leader_address"` + LeaderClusterAddress string `json:"leader_cluster_address"` +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_rekey.go b/vendor/github.com/hashicorp/vault/http/sys_rekey.go new file mode 100644 index 0000000..54149c4 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_rekey.go @@ -0,0 +1,411 @@ +package http + +import ( + "context" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "net/http" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pgpkeys" + "github.com/hashicorp/vault/vault" +) + +func handleSysRekeyInit(core *vault.Core, recovery bool) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + standby, _ := core.Standby() + if standby { + respondStandby(core, w, r.URL) + return + } + + repState := core.ReplicationState() + if repState.HasState(consts.ReplicationPerformanceSecondary) { + respondError(w, http.StatusBadRequest, + fmt.Errorf("rekeying can only be performed on the primary cluster when replication is activated")) + return + } + + ctx, cancel := core.GetContext() + defer cancel() + + switch { + case recovery && !core.SealAccess().RecoveryKeySupported(): + respondError(w, http.StatusBadRequest, fmt.Errorf("recovery rekeying not supported")) + case r.Method == "GET": + handleSysRekeyInitGet(ctx, core, recovery, w, r) + case r.Method == "POST" || r.Method == "PUT": + handleSysRekeyInitPut(ctx, core, recovery, w, r) + case r.Method == "DELETE": + handleSysRekeyInitDelete(ctx, core, recovery, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysRekeyInitGet(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + barrierConfig, barrierConfErr := core.SealAccess().BarrierConfig(ctx) + if barrierConfErr != nil { + respondError(w, http.StatusInternalServerError, barrierConfErr) + return + } + if barrierConfig == nil { + respondError(w, http.StatusBadRequest, fmt.Errorf("server is not yet initialized")) + return + } + + // Get the rekey configuration + rekeyConf, err := core.RekeyConfig(recovery) + if err != nil { + respondError(w, err.Code(), err) + return + } + + sealThreshold, err := core.RekeyThreshold(ctx, recovery) + if err != nil { + respondError(w, err.Code(), err) + return + } + + // Format the status + status := &RekeyStatusResponse{ + Started: false, + T: 0, + N: 0, + Required: sealThreshold, + } + if rekeyConf != nil { + // Get the progress + started, progress, err := core.RekeyProgress(recovery, false) + if err != nil { + respondError(w, err.Code(), err) + return + } + + status.Nonce = rekeyConf.Nonce + status.Started = started + status.T = rekeyConf.SecretThreshold + status.N = rekeyConf.SecretShares + status.Progress = progress + status.VerificationRequired = rekeyConf.VerificationRequired + status.VerificationNonce = rekeyConf.VerificationNonce + if rekeyConf.PGPKeys != nil && len(rekeyConf.PGPKeys) != 0 { + pgpFingerprints, err := pgpkeys.GetFingerprints(rekeyConf.PGPKeys, nil) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + status.PGPFingerprints = pgpFingerprints + status.Backup = rekeyConf.Backup + } + } + respondOk(w, status) +} + +func handleSysRekeyInitPut(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + // Parse the request + var req RekeyRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + if req.Backup && len(req.PGPKeys) == 0 { + respondError(w, http.StatusBadRequest, fmt.Errorf("cannot request a backup of the new keys without providing PGP keys for encryption")) + return + } + + if len(req.PGPKeys) > 0 && len(req.PGPKeys) != req.SecretShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys for rekey")) + return + } + + // Initialize the rekey + err := core.RekeyInit(&vault.SealConfig{ + SecretShares: req.SecretShares, + SecretThreshold: req.SecretThreshold, + StoredShares: req.StoredShares, + PGPKeys: req.PGPKeys, + Backup: req.Backup, + VerificationRequired: req.RequireVerification, + }, recovery) + if err != nil { + respondError(w, err.Code(), err) + return + } + + handleSysRekeyInitGet(ctx, core, recovery, w, r) +} + +func handleSysRekeyInitDelete(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + if err := core.RekeyCancel(recovery); err != nil { + respondError(w, err.Code(), err) + return + } + respondOk(w, nil) +} + +func handleSysRekeyUpdate(core *vault.Core, recovery bool) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + standby, _ := core.Standby() + if standby { + respondStandby(core, w, r.URL) + return + } + + // Parse the request + var req RekeyUpdateRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + if req.Key == "" { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be specified in request body as JSON")) + return + } + + // Decode the key, which is base64 or hex encoded + min, max := core.BarrierKeyLength() + key, err := hex.DecodeString(req.Key) + // We check min and max here to ensure that a string that is base64 + // encoded but also valid hex will not be valid and we instead base64 + // decode it + if err != nil || len(key) < min || len(key) > max { + key, err = base64.StdEncoding.DecodeString(req.Key) + if err != nil { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be a valid hex or base64 string")) + return + } + } + + ctx, cancel := core.GetContext() + defer cancel() + + // Use the key to make progress on rekey + result, rekeyErr := core.RekeyUpdate(ctx, key, req.Nonce, recovery) + if rekeyErr != nil { + respondError(w, rekeyErr.Code(), rekeyErr) + return + } + + // Format the response + resp := &RekeyUpdateResponse{} + if result != nil { + resp.Complete = true + resp.Nonce = req.Nonce + resp.Backup = result.Backup + resp.PGPFingerprints = result.PGPFingerprints + resp.VerificationRequired = result.VerificationRequired + resp.VerificationNonce = result.VerificationNonce + + // Encode the keys + keys := make([]string, 0, len(result.SecretShares)) + keysB64 := make([]string, 0, len(result.SecretShares)) + for _, k := range result.SecretShares { + keys = append(keys, hex.EncodeToString(k)) + keysB64 = append(keysB64, base64.StdEncoding.EncodeToString(k)) + } + resp.Keys = keys + resp.KeysB64 = keysB64 + respondOk(w, resp) + } else { + handleSysRekeyInitGet(ctx, core, recovery, w, r) + } + }) +} + +func handleSysRekeyVerify(core *vault.Core, recovery bool) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + standby, _ := core.Standby() + if standby { + respondStandby(core, w, r.URL) + return + } + + repState := core.ReplicationState() + if repState.HasState(consts.ReplicationPerformanceSecondary) { + respondError(w, http.StatusBadRequest, + fmt.Errorf("rekeying can only be performed on the primary cluster when replication is activated")) + return + } + + ctx, cancel := core.GetContext() + defer cancel() + + switch { + case recovery && !core.SealAccess().RecoveryKeySupported(): + respondError(w, http.StatusBadRequest, fmt.Errorf("recovery rekeying not supported")) + case r.Method == "GET": + handleSysRekeyVerifyGet(ctx, core, recovery, w, r) + case r.Method == "POST" || r.Method == "PUT": + handleSysRekeyVerifyPut(ctx, core, recovery, w, r) + case r.Method == "DELETE": + handleSysRekeyVerifyDelete(ctx, core, recovery, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysRekeyVerifyGet(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + barrierConfig, barrierConfErr := core.SealAccess().BarrierConfig(ctx) + if barrierConfErr != nil { + respondError(w, http.StatusInternalServerError, barrierConfErr) + return + } + if barrierConfig == nil { + respondError(w, http.StatusBadRequest, fmt.Errorf("server is not yet initialized")) + return + } + + // Get the rekey configuration + rekeyConf, err := core.RekeyConfig(recovery) + if err != nil { + respondError(w, err.Code(), err) + return + } + if rekeyConf == nil { + respondError(w, http.StatusBadRequest, errors.New("no rekey configuration found")) + return + } + + // Get the progress + started, progress, err := core.RekeyProgress(recovery, true) + if err != nil { + respondError(w, err.Code(), err) + return + } + + // Format the status + status := &RekeyVerificationStatusResponse{ + Started: started, + Nonce: rekeyConf.VerificationNonce, + T: rekeyConf.SecretThreshold, + N: rekeyConf.SecretShares, + Progress: progress, + } + respondOk(w, status) +} + +func handleSysRekeyVerifyDelete(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + if err := core.RekeyVerifyRestart(recovery); err != nil { + respondError(w, err.Code(), err) + return + } + + handleSysRekeyVerifyGet(ctx, core, recovery, w, r) +} + +func handleSysRekeyVerifyPut(ctx context.Context, core *vault.Core, recovery bool, w http.ResponseWriter, r *http.Request) { + // Parse the request + var req RekeyVerificationUpdateRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + if req.Key == "" { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be specified in request body as JSON")) + return + } + + // Decode the key, which is base64 or hex encoded + min, max := core.BarrierKeyLength() + key, err := hex.DecodeString(req.Key) + // We check min and max here to ensure that a string that is base64 + // encoded but also valid hex will not be valid and we instead base64 + // decode it + if err != nil || len(key) < min || len(key) > max { + key, err = base64.StdEncoding.DecodeString(req.Key) + if err != nil { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be a valid hex or base64 string")) + return + } + } + + ctx, cancel := core.GetContext() + defer cancel() + + // Use the key to make progress on rekey + result, rekeyErr := core.RekeyVerify(ctx, key, req.Nonce, recovery) + if rekeyErr != nil { + respondError(w, rekeyErr.Code(), rekeyErr) + return + } + + // Format the response + resp := &RekeyVerificationUpdateResponse{} + if result != nil { + resp.Complete = true + resp.Nonce = result.Nonce + respondOk(w, resp) + } else { + handleSysRekeyVerifyGet(ctx, core, recovery, w, r) + } +} + +type RekeyRequest struct { + SecretShares int `json:"secret_shares"` + SecretThreshold int `json:"secret_threshold"` + StoredShares int `json:"stored_shares"` + PGPKeys []string `json:"pgp_keys"` + Backup bool `json:"backup"` + RequireVerification bool `json:"require_verification"` +} + +type RekeyStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` + Required int `json:"required"` + PGPFingerprints []string `json:"pgp_fingerprints"` + Backup bool `json:"backup"` + VerificationRequired bool `json:"verification_required"` + VerificationNonce string `json:"verification_nonce,omitempty"` +} + +type RekeyUpdateRequest struct { + Nonce string + Key string +} + +type RekeyUpdateResponse struct { + Nonce string `json:"nonce"` + Complete bool `json:"complete"` + Keys []string `json:"keys"` + KeysB64 []string `json:"keys_base64"` + PGPFingerprints []string `json:"pgp_fingerprints"` + Backup bool `json:"backup"` + VerificationRequired bool `json:"verification_required"` + VerificationNonce string `json:"verification_nonce,omitempty"` +} + +type RekeyVerificationUpdateRequest struct { + Nonce string `json:"nonce"` + Key string `json:"key"` +} + +type RekeyVerificationStatusResponse struct { + Nonce string `json:"nonce"` + Started bool `json:"started"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` +} + +type RekeyVerificationUpdateResponse struct { + Nonce string `json:"nonce"` + Complete bool `json:"complete"` +} diff --git a/vendor/github.com/hashicorp/vault/http/sys_seal.go b/vendor/github.com/hashicorp/vault/http/sys_seal.go new file mode 100644 index 0000000..d86d7f2 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/sys_seal.go @@ -0,0 +1,235 @@ +package http + +import ( + "context" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "net/http" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" + "github.com/hashicorp/vault/version" +) + +func handleSysSeal(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req, statusCode, err := buildLogicalRequest(core, w, r) + if err != nil || statusCode != 0 { + respondError(w, statusCode, err) + return + } + + switch req.Operation { + case logical.UpdateOperation: + default: + respondError(w, http.StatusMethodNotAllowed, nil) + return + } + + // Seal with the token above + // We use context.Background since there won't be a request context if the node isn't active + if err := core.SealWithRequest(req); err != nil { + if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) { + respondError(w, http.StatusForbidden, err) + return + } else { + respondError(w, http.StatusInternalServerError, err) + return + } + } + + respondOk(w, nil) + }) +} + +func handleSysStepDown(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req, statusCode, err := buildLogicalRequest(core, w, r) + if err != nil || statusCode != 0 { + respondError(w, statusCode, err) + return + } + + switch req.Operation { + case logical.UpdateOperation: + default: + respondError(w, http.StatusMethodNotAllowed, nil) + return + } + + // Seal with the token above + if err := core.StepDown(req); err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + respondOk(w, nil) + }) +} + +func handleSysUnseal(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "PUT": + case "POST": + default: + respondError(w, http.StatusMethodNotAllowed, nil) + return + } + + // Parse the request + var req UnsealRequest + if err := parseRequest(r, w, &req); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + if !req.Reset && req.Key == "" { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be specified in request body as JSON, or 'reset' set to true")) + return + } + + if req.Reset { + sealed, err := core.Sealed() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + if !sealed { + respondError(w, http.StatusBadRequest, errors.New("vault is unsealed")) + return + } + core.ResetUnsealProcess() + } else { + // Decode the key, which is base64 or hex encoded + min, max := core.BarrierKeyLength() + key, err := hex.DecodeString(req.Key) + // We check min and max here to ensure that a string that is base64 + // encoded but also valid hex will not be valid and we instead base64 + // decode it + if err != nil || len(key) < min || len(key) > max { + key, err = base64.StdEncoding.DecodeString(req.Key) + if err != nil { + respondError( + w, http.StatusBadRequest, + errors.New("'key' must be a valid hex or base64 string")) + return + } + } + + // Attempt the unseal + ctx := context.Background() + if core.SealAccess().RecoveryKeySupported() { + _, err = core.UnsealWithRecoveryKeys(ctx, key) + } else { + _, err = core.Unseal(key) + } + if err != nil { + switch { + case errwrap.ContainsType(err, new(vault.ErrInvalidKey)): + case errwrap.Contains(err, vault.ErrBarrierInvalidKey.Error()): + case errwrap.Contains(err, vault.ErrBarrierNotInit.Error()): + case errwrap.Contains(err, vault.ErrBarrierSealed.Error()): + case errwrap.Contains(err, consts.ErrStandby.Error()): + default: + respondError(w, http.StatusInternalServerError, err) + return + } + respondError(w, http.StatusBadRequest, err) + return + } + } + + // Return the seal status + handleSysSealStatusRaw(core, w, r) + }) +} + +func handleSysSealStatus(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + respondError(w, http.StatusMethodNotAllowed, nil) + return + } + + handleSysSealStatusRaw(core, w, r) + }) +} + +func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + sealed, err := core.Sealed() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + var sealConfig *vault.SealConfig + if core.SealAccess().RecoveryKeySupported() { + sealConfig, err = core.SealAccess().RecoveryConfig(ctx) + } else { + sealConfig, err = core.SealAccess().BarrierConfig(ctx) + } + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + if sealConfig == nil { + respondError(w, http.StatusBadRequest, fmt.Errorf("server is not yet initialized")) + return + } + + // Fetch the local cluster name and identifier + var clusterName, clusterID string + if !sealed { + cluster, err := core.Cluster(ctx) + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + if cluster == nil { + respondError(w, http.StatusInternalServerError, fmt.Errorf("failed to fetch cluster details")) + return + } + clusterName = cluster.Name + clusterID = cluster.ID + } + + progress, nonce := core.SecretProgress() + + respondOk(w, &SealStatusResponse{ + Type: sealConfig.Type, + Sealed: sealed, + T: sealConfig.SecretThreshold, + N: sealConfig.SecretShares, + Progress: progress, + Nonce: nonce, + Version: version.GetVersion().VersionNumber(), + ClusterName: clusterName, + ClusterID: clusterID, + }) +} + +type SealStatusResponse struct { + Type string `json:"type"` + Sealed bool `json:"sealed"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` + Nonce string `json:"nonce"` + Version string `json:"version"` + ClusterName string `json:"cluster_name,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` +} + +type UnsealRequest struct { + Key string + Reset bool +} diff --git a/vendor/github.com/hashicorp/vault/http/testing.go b/vendor/github.com/hashicorp/vault/http/testing.go new file mode 100644 index 0000000..2299006 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/testing.go @@ -0,0 +1,56 @@ +package http + +import ( + "fmt" + "net" + "net/http" + "testing" + + "github.com/hashicorp/vault/vault" +) + +func TestListener(tb testing.TB) (net.Listener, string) { + fail := func(format string, args ...interface{}) { + panic(fmt.Sprintf(format, args...)) + } + if tb != nil { + fail = tb.Fatalf + } + + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + fail("err: %s", err) + } + addr := "http://" + ln.Addr().String() + return ln, addr +} + +func TestServerWithListener(tb testing.TB, ln net.Listener, addr string, core *vault.Core) { + // Create a muxer to handle our requests so that we can authenticate + // for tests. + mux := http.NewServeMux() + mux.Handle("/_test/auth", http.HandlerFunc(testHandleAuth)) + mux.Handle("/", Handler(core)) + + server := &http.Server{ + Addr: ln.Addr().String(), + Handler: mux, + } + go server.Serve(ln) +} + +func TestServer(tb testing.TB, core *vault.Core) (net.Listener, string) { + ln, addr := TestListener(tb) + TestServerWithListener(tb, ln, addr, core) + return ln, addr +} + +func TestServerAuth(tb testing.TB, addr string, token string) { + if _, err := http.Get(addr + "/_test/auth?token=" + token); err != nil { + tb.Fatalf("error authenticating: %s", err) + } +} + +func testHandleAuth(w http.ResponseWriter, req *http.Request) { + respondOk(w, nil) +} diff --git a/vendor/github.com/hashicorp/vault/logical/auth.go b/vendor/github.com/hashicorp/vault/logical/auth.go new file mode 100644 index 0000000..59975b7 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/auth.go @@ -0,0 +1,87 @@ +package logical + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-sockaddr" +) + +// Auth is the resulting authentication information that is part of +// Response for credential backends. +type Auth struct { + LeaseOptions + + // InternalData is JSON-encodable data that is stored with the auth struct. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + InternalData map[string]interface{} `json:"internal_data" mapstructure:"internal_data" structs:"internal_data"` + + // DisplayName is a non-security sensitive identifier that is + // applicable to this Auth. It is used for logging and prefixing + // of dynamic secrets. For example, DisplayName may be "armon" for + // the github credential backend. If the client token is used to + // generate a SQL credential, the user may be "github-armon-uuid". + // This is to help identify the source without using audit tables. + DisplayName string `json:"display_name" mapstructure:"display_name" structs:"display_name"` + + // Policies is the list of policies that the authenticated user + // is associated with. + Policies []string `json:"policies" mapstructure:"policies" structs:"policies"` + + // Metadata is used to attach arbitrary string-type metadata to + // an authenticated user. This metadata will be outputted into the + // audit log. + Metadata map[string]string `json:"metadata" mapstructure:"metadata" structs:"metadata"` + + // ClientToken is the token that is generated for the authentication. + // This will be filled in by Vault core when an auth structure is + // returned. Setting this manually will have no effect. + ClientToken string `json:"client_token" mapstructure:"client_token" structs:"client_token"` + + // Accessor is the identifier for the ClientToken. This can be used + // to perform management functionalities (especially revocation) when + // ClientToken in the audit logs are obfuscated. Accessor can be used + // to revoke a ClientToken and to lookup the capabilities of the ClientToken, + // both without actually knowing the ClientToken. + Accessor string `json:"accessor" mapstructure:"accessor" structs:"accessor"` + + // Period indicates that the token generated using this Auth object + // should never expire. The token should be renewed within the duration + // specified by this period. + Period time.Duration `json:"period" mapstructure:"period" structs:"period"` + + // ExplicitMaxTTL is the max TTL that constrains periodic tokens. For normal + // tokens, this value is constrained by the configured max ttl. + ExplicitMaxTTL time.Duration `json:"-" mapstructure:"-" structs:"-"` + + // Number of allowed uses of the issued token + NumUses int `json:"num_uses" mapstructure:"num_uses" structs:"num_uses"` + + // EntityID is the identifier of the entity in identity store to which the + // identity of the authenticating client belongs to. + EntityID string `json:"entity_id" mapstructure:"entity_id" structs:"entity_id"` + + // Alias is the information about the authenticated client returned by + // the auth backend + Alias *Alias `json:"alias" mapstructure:"alias" structs:"alias"` + + // GroupAliases are the informational mappings of external groups which an + // authenticated user belongs to. This is used to check if there are + // mappings groups for the group aliases in identity store. For all the + // matching groups, the entity ID of the user will be added. + GroupAliases []*Alias `json:"group_aliases" mapstructure:"group_aliases" structs:"group_aliases"` + + // The set of CIDRs that this token can be used with + BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"` + + // CreationPath is a path that the backend can return to use in the lease. + // This is currently only supported for the token store where roles may + // change the perceived path of the lease, even though they don't change + // the request path itself. + CreationPath string `json:"creation_path"` +} + +func (a *Auth) GoString() string { + return fmt.Sprintf("*%#v", *a) +} diff --git a/vendor/github.com/hashicorp/vault/logical/connection.go b/vendor/github.com/hashicorp/vault/logical/connection.go new file mode 100644 index 0000000..a504b10 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/connection.go @@ -0,0 +1,15 @@ +package logical + +import ( + "crypto/tls" +) + +// Connection represents the connection information for a request. This +// is present on the Request structure for credential backends. +type Connection struct { + // RemoteAddr is the network address that sent the request. + RemoteAddr string `json:"remote_addr"` + + // ConnState is the TLS connection state if applicable. + ConnState *tls.ConnectionState `sentinel:""` +} diff --git a/vendor/github.com/hashicorp/vault/logical/error.go b/vendor/github.com/hashicorp/vault/logical/error.go new file mode 100644 index 0000000..00a6409 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/error.go @@ -0,0 +1,50 @@ +package logical + +type HTTPCodedError interface { + Error() string + Code() int +} + +func CodedError(status int, msg string) HTTPCodedError { + return &codedError{ + Status: status, + Message: msg, + } +} + +type codedError struct { + Status int + Message string +} + +func (e *codedError) Error() string { + return e.Message +} + +func (e *codedError) Code() int { + return e.Status +} + +// Struct to identify user input errors. This is helpful in responding the +// appropriate status codes to clients from the HTTP endpoints. +type StatusBadRequest struct { + Err string +} + +// Implementing error interface +func (s *StatusBadRequest) Error() string { + return s.Err +} + +// This is a new type declared to not cause potential compatibility problems if +// the logic around the CodedError changes; in particular for logical request +// paths it is basically ignored, and changing that behavior might cause +// unforseen issues. +type ReplicationCodedError struct { + Msg string + Code int +} + +func (r *ReplicationCodedError) Error() string { + return r.Msg +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/backend.go b/vendor/github.com/hashicorp/vault/logical/framework/backend.go new file mode 100644 index 0000000..3c674e3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/backend.go @@ -0,0 +1,583 @@ +package framework + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "regexp" + "sort" + "strings" + "sync" + "time" + + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/logging" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/logical" +) + +// Backend is an implementation of logical.Backend that allows +// the implementer to code a backend using a much more programmer-friendly +// framework that handles a lot of the routing and validation for you. +// +// This is recommended over implementing logical.Backend directly. +type Backend struct { + // Help is the help text that is shown when a help request is made + // on the root of this resource. The root help is special since we + // show all the paths that can be requested. + Help string + + // Paths are the various routes that the backend responds to. + // This cannot be modified after construction (i.e. dynamically changing + // paths, including adding or removing, is not allowed once the + // backend is in use). + // + // PathsSpecial is the list of path patterns that denote the + // paths above that require special privileges. These can't be + // regular expressions, it is either exact match or prefix match. + // For prefix match, append '*' as a suffix. + Paths []*Path + PathsSpecial *logical.Paths + + // Secrets is the list of secret types that this backend can + // return. It is used to automatically generate proper responses, + // and ease specifying callbacks for revocation, renewal, etc. + Secrets []*Secret + + // PeriodicFunc is the callback, which if set, will be invoked when the + // periodic timer of RollbackManager ticks. This can be used by + // backends to do anything it wishes to do periodically. + // + // PeriodicFunc can be invoked to, say to periodically delete stale + // entries in backend's storage, while the backend is still being used. + // (Note the different of this action from what `Clean` does, which is + // invoked just before the backend is unmounted). + PeriodicFunc periodicFunc + + // WALRollback is called when a WAL entry (see wal.go) has to be rolled + // back. It is called with the data from the entry. + // + // WALRollbackMinAge is the minimum age of a WAL entry before it is attempted + // to be rolled back. This should be longer than the maximum time it takes + // to successfully create a secret. + WALRollback WALRollbackFunc + WALRollbackMinAge time.Duration + + // Clean is called on unload to clean up e.g any existing connections + // to the backend, if required. + Clean CleanupFunc + + // Invalidate is called when a keys is modified if required + Invalidate InvalidateFunc + + // AuthRenew is the callback to call when a RenewRequest for an + // authentication comes in. By default, renewal won't be allowed. + // See the built-in AuthRenew helpers in lease.go for common callbacks. + AuthRenew OperationFunc + + // Type is the logical.BackendType for the backend implementation + BackendType logical.BackendType + + logger log.Logger + system logical.SystemView + once sync.Once + pathsRe []*regexp.Regexp +} + +// periodicFunc is the callback called when the RollbackManager's timer ticks. +// This can be utilized by the backends to do anything it wants. +type periodicFunc func(context.Context, *logical.Request) error + +// OperationFunc is the callback called for an operation on a path. +type OperationFunc func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) + +// ExistenceFunc is the callback called for an existence check on a path. +type ExistenceFunc func(context.Context, *logical.Request, *FieldData) (bool, error) + +// WALRollbackFunc is the callback for rollbacks. +type WALRollbackFunc func(context.Context, *logical.Request, string, interface{}) error + +// CleanupFunc is the callback for backend unload. +type CleanupFunc func(context.Context) + +// InvalidateFunc is the callback for backend key invalidation. +type InvalidateFunc func(context.Context, string) + +// HandleExistenceCheck is the logical.Backend implementation. +func (b *Backend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (checkFound bool, exists bool, err error) { + b.once.Do(b.init) + + // Ensure we are only doing this when one of the correct operations is in play + switch req.Operation { + case logical.CreateOperation: + case logical.UpdateOperation: + default: + return false, false, fmt.Errorf("incorrect operation type %v for an existence check", req.Operation) + } + + // Find the matching route + path, captures := b.route(req.Path) + if path == nil { + return false, false, logical.ErrUnsupportedPath + } + + if path.ExistenceCheck == nil { + return false, false, nil + } + + checkFound = true + + // Build up the data for the route, with the URL taking priority + // for the fields over the PUT data. + raw := make(map[string]interface{}, len(path.Fields)) + for k, v := range req.Data { + raw[k] = v + } + for k, v := range captures { + raw[k] = v + } + + fd := FieldData{ + Raw: raw, + Schema: path.Fields} + + err = fd.Validate() + if err != nil { + return false, false, errutil.UserError{Err: err.Error()} + } + + // Call the callback with the request and the data + exists, err = path.ExistenceCheck(ctx, req, &fd) + return +} + +// HandleRequest is the logical.Backend implementation. +func (b *Backend) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { + b.once.Do(b.init) + + // Check for special cased global operations. These don't route + // to a specific Path. + switch req.Operation { + case logical.RenewOperation: + fallthrough + case logical.RevokeOperation: + return b.handleRevokeRenew(ctx, req) + case logical.RollbackOperation: + return b.handleRollback(ctx, req) + } + + // If the path is empty and it is a help operation, handle that. + if req.Path == "" && req.Operation == logical.HelpOperation { + return b.handleRootHelp() + } + + // Find the matching route + path, captures := b.route(req.Path) + if path == nil { + return nil, logical.ErrUnsupportedPath + } + + // Build up the data for the route, with the URL taking priority + // for the fields over the PUT data. + raw := make(map[string]interface{}, len(path.Fields)) + for k, v := range req.Data { + raw[k] = v + } + for k, v := range captures { + raw[k] = v + } + + // Look up the callback for this operation + var callback OperationFunc + var ok bool + if path.Callbacks != nil { + callback, ok = path.Callbacks[req.Operation] + } + if !ok { + if req.Operation == logical.HelpOperation { + callback = path.helpCallback() + ok = true + } + } + if !ok { + return nil, logical.ErrUnsupportedOperation + } + + fd := FieldData{ + Raw: raw, + Schema: path.Fields} + + if req.Operation != logical.HelpOperation { + err := fd.Validate() + if err != nil { + return nil, err + } + } + + // Call the callback with the request and the data + return callback(ctx, req, &fd) +} + +// SpecialPaths is the logical.Backend implementation. +func (b *Backend) SpecialPaths() *logical.Paths { + return b.PathsSpecial +} + +// Cleanup is used to release resources and prepare to stop the backend +func (b *Backend) Cleanup(ctx context.Context) { + if b.Clean != nil { + b.Clean(ctx) + } +} + +// InvalidateKey is used to clear caches and reset internal state on key changes +func (b *Backend) InvalidateKey(ctx context.Context, key string) { + if b.Invalidate != nil { + b.Invalidate(ctx, key) + } +} + +// Setup is used to initialize the backend with the initial backend configuration +func (b *Backend) Setup(ctx context.Context, config *logical.BackendConfig) error { + b.logger = config.Logger + b.system = config.System + return nil +} + +// Logger can be used to get the logger. If no logger has been set, +// the logs will be discarded. +func (b *Backend) Logger() log.Logger { + if b.logger != nil { + return b.logger + } + + return logging.NewVaultLoggerWithWriter(ioutil.Discard, log.NoLevel) +} + +// System returns the backend's system view. +func (b *Backend) System() logical.SystemView { + return b.system +} + +// Type returns the backend type +func (b *Backend) Type() logical.BackendType { + return b.BackendType +} + +// Route looks up the path that would be used for a given path string. +func (b *Backend) Route(path string) *Path { + result, _ := b.route(path) + return result +} + +// Secret is used to look up the secret with the given type. +func (b *Backend) Secret(k string) *Secret { + for _, s := range b.Secrets { + if s.Type == k { + return s + } + } + + return nil +} + +func (b *Backend) init() { + b.pathsRe = make([]*regexp.Regexp, len(b.Paths)) + for i, p := range b.Paths { + if len(p.Pattern) == 0 { + panic(fmt.Sprintf("Routing pattern cannot be blank")) + } + // Automatically anchor the pattern + if p.Pattern[0] != '^' { + p.Pattern = "^" + p.Pattern + } + if p.Pattern[len(p.Pattern)-1] != '$' { + p.Pattern = p.Pattern + "$" + } + b.pathsRe[i] = regexp.MustCompile(p.Pattern) + } +} + +func (b *Backend) route(path string) (*Path, map[string]string) { + b.once.Do(b.init) + + for i, re := range b.pathsRe { + matches := re.FindStringSubmatch(path) + if matches == nil { + continue + } + + // We have a match, determine the mapping of the captures and + // store that for returning. + var captures map[string]string + path := b.Paths[i] + if captureNames := re.SubexpNames(); len(captureNames) > 1 { + captures = make(map[string]string, len(captureNames)) + for i, name := range captureNames { + if name != "" { + captures[name] = matches[i] + } + } + } + + return path, captures + } + + return nil, nil +} + +func (b *Backend) handleRootHelp() (*logical.Response, error) { + // Build a mapping of the paths and get the paths alphabetized to + // make the output prettier. + pathsMap := make(map[string]*Path) + paths := make([]string, 0, len(b.Paths)) + for i, p := range b.pathsRe { + paths = append(paths, p.String()) + pathsMap[p.String()] = b.Paths[i] + } + sort.Strings(paths) + + // Build the path data + pathData := make([]rootHelpTemplatePath, 0, len(paths)) + for _, route := range paths { + p := pathsMap[route] + pathData = append(pathData, rootHelpTemplatePath{ + Path: route, + Help: strings.TrimSpace(p.HelpSynopsis), + }) + } + + help, err := executeTemplate(rootHelpTemplate, &rootHelpTemplateData{ + Help: strings.TrimSpace(b.Help), + Paths: pathData, + }) + if err != nil { + return nil, err + } + + return logical.HelpResponse(help, nil), nil +} + +func (b *Backend) handleRevokeRenew(ctx context.Context, req *logical.Request) (*logical.Response, error) { + // Special case renewal of authentication for credential backends + if req.Operation == logical.RenewOperation && req.Auth != nil { + return b.handleAuthRenew(ctx, req) + } + + if req.Secret == nil { + return nil, fmt.Errorf("request has no secret") + } + + rawSecretType, ok := req.Secret.InternalData["secret_type"] + if !ok { + return nil, fmt.Errorf("secret is unsupported by this backend") + } + secretType, ok := rawSecretType.(string) + if !ok { + return nil, fmt.Errorf("secret is unsupported by this backend") + } + + secret := b.Secret(secretType) + if secret == nil { + return nil, fmt.Errorf("secret is unsupported by this backend") + } + + switch req.Operation { + case logical.RenewOperation: + return secret.HandleRenew(ctx, req) + case logical.RevokeOperation: + return secret.HandleRevoke(ctx, req) + default: + return nil, fmt.Errorf("invalid operation for revoke/renew: %q", req.Operation) + } +} + +// handleRollback invokes the PeriodicFunc set on the backend. It also does a WAL rollback operation. +func (b *Backend) handleRollback(ctx context.Context, req *logical.Request) (*logical.Response, error) { + // Response is not expected from the periodic operation. + if b.PeriodicFunc != nil { + if err := b.PeriodicFunc(ctx, req); err != nil { + return nil, err + } + } + + return b.handleWALRollback(ctx, req) +} + +func (b *Backend) handleAuthRenew(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if b.AuthRenew == nil { + return logical.ErrorResponse("this auth type doesn't support renew"), nil + } + + return b.AuthRenew(ctx, req, nil) +} + +func (b *Backend) handleWALRollback(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if b.WALRollback == nil { + return nil, logical.ErrUnsupportedOperation + } + + var merr error + keys, err := ListWAL(ctx, req.Storage) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + if len(keys) == 0 { + return nil, nil + } + + // Calculate the minimum time that the WAL entries could be + // created in order to be rolled back. + age := b.WALRollbackMinAge + if age == 0 { + age = 10 * time.Minute + } + minAge := time.Now().Add(-1 * age) + if _, ok := req.Data["immediate"]; ok { + minAge = time.Now().Add(1000 * time.Hour) + } + + for _, k := range keys { + entry, err := GetWAL(ctx, req.Storage, k) + if err != nil { + merr = multierror.Append(merr, err) + continue + } + if entry == nil { + continue + } + + // If the entry isn't old enough, then don't roll it back + if !time.Unix(entry.CreatedAt, 0).Before(minAge) { + continue + } + + // Attempt a WAL rollback + err = b.WALRollback(ctx, req, entry.Kind, entry.Data) + if err != nil { + err = errwrap.Wrapf(fmt.Sprintf("error rolling back %q entry: {{err}}", entry.Kind), err) + } + if err == nil { + err = DeleteWAL(ctx, req.Storage, k) + } + if err != nil { + merr = multierror.Append(merr, err) + } + } + + if merr == nil { + return nil, nil + } + + return logical.ErrorResponse(merr.Error()), nil +} + +// FieldSchema is a basic schema to describe the format of a path field. +type FieldSchema struct { + Type FieldType + Default interface{} + Description string +} + +// DefaultOrZero returns the default value if it is set, or otherwise +// the zero value of the type. +func (s *FieldSchema) DefaultOrZero() interface{} { + if s.Default != nil { + switch s.Type { + case TypeDurationSecond: + var result int + switch inp := s.Default.(type) { + case nil: + return s.Type.Zero() + case int: + result = inp + case int64: + result = int(inp) + case float32: + result = int(inp) + case float64: + result = int(inp) + case string: + dur, err := parseutil.ParseDurationSecond(inp) + if err != nil { + return s.Type.Zero() + } + result = int(dur.Seconds()) + case json.Number: + valInt64, err := inp.Int64() + if err != nil { + return s.Type.Zero() + } + result = int(valInt64) + default: + return s.Type.Zero() + } + return result + + default: + return s.Default + } + } + + return s.Type.Zero() +} + +// Zero returns the correct zero-value for a specific FieldType +func (t FieldType) Zero() interface{} { + switch t { + case TypeString, TypeNameString, TypeLowerCaseString: + return "" + case TypeInt: + return 0 + case TypeBool: + return false + case TypeMap: + return map[string]interface{}{} + case TypeKVPairs: + return map[string]string{} + case TypeDurationSecond: + return 0 + case TypeSlice: + return []interface{}{} + case TypeStringSlice, TypeCommaStringSlice: + return []string{} + case TypeCommaIntSlice: + return []int{} + default: + panic("unknown type: " + t.String()) + } +} + +type rootHelpTemplateData struct { + Help string + Paths []rootHelpTemplatePath +} + +type rootHelpTemplatePath struct { + Path string + Help string +} + +const rootHelpTemplate = ` +## DESCRIPTION + +{{.Help}} + +## PATHS + +The following paths are supported by this backend. To view help for +any of the paths below, use the help command with any route matching +the path pattern. Note that depending on the policy of your auth token, +you may or may not be able to access certain paths. + +{{range .Paths}}{{indent 4 .Path}} +{{indent 8 .Help}} + +{{end}} + +` diff --git a/vendor/github.com/hashicorp/vault/logical/framework/field_data.go b/vendor/github.com/hashicorp/vault/logical/framework/field_data.go new file mode 100644 index 0000000..117fd3b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/field_data.go @@ -0,0 +1,281 @@ +package framework + +import ( + "encoding/json" + "errors" + "fmt" + "regexp" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/mitchellh/mapstructure" +) + +// FieldData is the structure passed to the callback to handle a path +// containing the populated parameters for fields. This should be used +// instead of the raw (*vault.Request).Data to access data in a type-safe +// way. +type FieldData struct { + Raw map[string]interface{} + Schema map[string]*FieldSchema +} + +// Validate cycles through raw data and validate conversions in +// the schema, so we don't get an error/panic later when +// trying to get data out. Data not in the schema is not +// an error at this point, so we don't worry about it. +func (d *FieldData) Validate() error { + for field, value := range d.Raw { + + schema, ok := d.Schema[field] + if !ok { + continue + } + + switch schema.Type { + case TypeBool, TypeInt, TypeMap, TypeDurationSecond, TypeString, TypeLowerCaseString, + TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice, + TypeKVPairs, TypeCommaIntSlice: + _, _, err := d.getPrimitive(field, schema) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error converting input %v for field %q: {{err}}", value, field), err) + } + default: + return fmt.Errorf("unknown field type %q for field %q", schema.Type, field) + } + } + + return nil +} + +// Get gets the value for the given field. If the key is an invalid field, +// FieldData will panic. If you want a safer version of this method, use +// GetOk. If the field k is not set, the default value (if set) will be +// returned, otherwise the zero value will be returned. +func (d *FieldData) Get(k string) interface{} { + schema, ok := d.Schema[k] + if !ok { + panic(fmt.Sprintf("field %s not in the schema", k)) + } + + value, ok := d.GetOk(k) + if !ok { + value = schema.DefaultOrZero() + } + + return value +} + +// GetDefaultOrZero gets the default value set on the schema for the given +// field. If there is no default value set, the zero value of the type +// will be returned. +func (d *FieldData) GetDefaultOrZero(k string) interface{} { + schema, ok := d.Schema[k] + if !ok { + panic(fmt.Sprintf("field %s not in the schema", k)) + } + + return schema.DefaultOrZero() +} + +// GetOk gets the value for the given field. The second return value +// will be false if the key is invalid or the key is not set at all. +func (d *FieldData) GetOk(k string) (interface{}, bool) { + schema, ok := d.Schema[k] + if !ok { + return nil, false + } + + result, ok, err := d.GetOkErr(k) + if err != nil { + panic(fmt.Sprintf("error reading %s: %s", k, err)) + } + + if ok && result == nil { + result = schema.DefaultOrZero() + } + + return result, ok +} + +// GetOkErr is the most conservative of all the Get methods. It returns +// whether key is set or not, but also an error value. The error value is +// non-nil if the field doesn't exist or there was an error parsing the +// field value. +func (d *FieldData) GetOkErr(k string) (interface{}, bool, error) { + schema, ok := d.Schema[k] + if !ok { + return nil, false, fmt.Errorf("unknown field: %q", k) + } + + switch schema.Type { + case TypeBool, TypeInt, TypeMap, TypeDurationSecond, TypeString, TypeLowerCaseString, + TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice, + TypeKVPairs, TypeCommaIntSlice: + return d.getPrimitive(k, schema) + default: + return nil, false, + fmt.Errorf("unknown field type %q for field %q", schema.Type, k) + } +} + +func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bool, error) { + raw, ok := d.Raw[k] + if !ok { + return nil, false, nil + } + + switch schema.Type { + case TypeBool: + var result bool + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeInt: + var result int + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeString: + var result string + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeLowerCaseString: + var result string + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return strings.ToLower(result), true, nil + + case TypeNameString: + var result string + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + matched, err := regexp.MatchString("^\\w(([\\w-.]+)?\\w)?$", result) + if err != nil { + return nil, true, err + } + if !matched { + return nil, true, errors.New("field does not match the formatting rules") + } + return result, true, nil + + case TypeMap: + var result map[string]interface{} + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeDurationSecond: + var result int + switch inp := raw.(type) { + case nil: + return nil, false, nil + case int: + result = inp + case int32: + result = int(inp) + case int64: + result = int(inp) + case uint: + result = int(inp) + case uint32: + result = int(inp) + case uint64: + result = int(inp) + case float32: + result = int(inp) + case float64: + result = int(inp) + case string: + dur, err := parseutil.ParseDurationSecond(inp) + if err != nil { + return nil, true, err + } + result = int(dur.Seconds()) + case json.Number: + valInt64, err := inp.Int64() + if err != nil { + return nil, true, err + } + result = int(valInt64) + default: + return nil, false, fmt.Errorf("invalid input '%v'", raw) + } + return result, true, nil + + case TypeCommaIntSlice: + var result []int + config := &mapstructure.DecoderConfig{ + Result: &result, + WeaklyTypedInput: true, + DecodeHook: mapstructure.StringToSliceHookFunc(","), + } + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return nil, true, err + } + if err := decoder.Decode(raw); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeSlice: + var result []interface{} + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return result, true, nil + + case TypeStringSlice: + var result []string + if err := mapstructure.WeakDecode(raw, &result); err != nil { + return nil, true, err + } + return strutil.TrimStrings(result), true, nil + + case TypeCommaStringSlice: + res, err := parseutil.ParseCommaStringSlice(raw) + if err != nil { + return nil, false, err + } + return res, true, nil + + case TypeKVPairs: + // First try to parse this as a map + var mapResult map[string]string + if err := mapstructure.WeakDecode(raw, &mapResult); err == nil { + return mapResult, true, nil + } + + // If map parse fails, parse as a string list of = delimited pairs + var listResult []string + if err := mapstructure.WeakDecode(raw, &listResult); err != nil { + return nil, true, err + } + + result := make(map[string]string, len(listResult)) + for _, keyPair := range listResult { + keyPairSlice := strings.SplitN(keyPair, "=", 2) + if len(keyPairSlice) != 2 || keyPairSlice[0] == "" { + return nil, false, fmt.Errorf("invalid key pair %q", keyPair) + } + result[keyPairSlice[0]] = keyPairSlice[1] + } + return result, true, nil + + default: + panic(fmt.Sprintf("Unknown type: %s", schema.Type)) + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/field_type.go b/vendor/github.com/hashicorp/vault/logical/framework/field_type.go new file mode 100644 index 0000000..d447eab --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/field_type.go @@ -0,0 +1,70 @@ +package framework + +// FieldType is the enum of types that a field can be. +type FieldType uint + +const ( + TypeInvalid FieldType = 0 + TypeString FieldType = iota + TypeInt + TypeBool + TypeMap + + // TypeDurationSecond represent as seconds, this can be either an + // integer or go duration format string (e.g. 24h) + TypeDurationSecond + + // TypeSlice represents a slice of any type + TypeSlice + + // TypeStringSlice is a helper for TypeSlice that returns a sanitized + // slice of strings + TypeStringSlice + + // TypeCommaStringSlice is a helper for TypeSlice that returns a sanitized + // slice of strings and also supports parsing a comma-separated list in + // a string field + TypeCommaStringSlice + + // TypeLowerCaseString is a helper for TypeString that returns a lowercase + // version of the provided string + TypeLowerCaseString + + // TypeNameString represents a name that is URI safe and follows specific + // rules. These rules include start and end with an alphanumeric + // character and characters in the middle can be alphanumeric or . or -. + TypeNameString + + // TypeKVPairs allows you to represent the data as a map or a list of + // equal sign delimited key pairs + TypeKVPairs + + // TypeCommaIntSlice is a helper for TypeSlice that returns a sanitized + // slice of Ints + TypeCommaIntSlice +) + +func (t FieldType) String() string { + switch t { + case TypeString: + return "string" + case TypeLowerCaseString: + return "lowercase string" + case TypeNameString: + return "name string" + case TypeInt: + return "int" + case TypeBool: + return "bool" + case TypeMap: + return "map" + case TypeKVPairs: + return "keypair" + case TypeDurationSecond: + return "duration (sec)" + case TypeSlice, TypeStringSlice, TypeCommaStringSlice, TypeCommaIntSlice: + return "slice" + default: + return "unknown type" + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/lease.go b/vendor/github.com/hashicorp/vault/logical/framework/lease.go new file mode 100644 index 0000000..4f55ae0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/lease.go @@ -0,0 +1,106 @@ +package framework + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/vault/logical" +) + +// LeaseExtend is left for backwards compatibility for plugins. This function +// now just passes back the data that was passed into it to be processed in core. +// DEPRECATED +func LeaseExtend(backendIncrement, backendMax time.Duration, systemView logical.SystemView) OperationFunc { + return func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) { + switch { + case req.Auth != nil: + req.Auth.TTL = backendIncrement + req.Auth.MaxTTL = backendMax + return &logical.Response{Auth: req.Auth}, nil + case req.Secret != nil: + req.Secret.TTL = backendIncrement + req.Secret.MaxTTL = backendMax + return &logical.Response{Secret: req.Secret}, nil + } + return nil, fmt.Errorf("no lease options for request") + } +} + +// CalculateTTL takes all the user-specified, backend, and system inputs and calculates +// a TTL for a lease +func CalculateTTL(sysView logical.SystemView, increment, backendTTL, period, backendMaxTTL, explicitMaxTTL time.Duration, startTime time.Time) (ttl time.Duration, warnings []string, errors error) { + // Truncate all times to the second since that is the lowest precision for + // TTLs + now := time.Now().Truncate(time.Second) + if startTime.IsZero() { + startTime = now + } else { + startTime = startTime.Truncate(time.Second) + } + + // Use the mount's configured max unless the backend specifies + // something more restrictive (perhaps from a role configuration + // parameter) + maxTTL := sysView.MaxLeaseTTL() + if backendMaxTTL > 0 && backendMaxTTL < maxTTL { + maxTTL = backendMaxTTL + } + if explicitMaxTTL > 0 && explicitMaxTTL < maxTTL { + maxTTL = explicitMaxTTL + } + + // Should never happen, but guard anyways + if maxTTL <= 0 { + return 0, nil, fmt.Errorf("max TTL must be greater than zero") + } + + var maxValidTime time.Time + switch { + case period > 0: + // Cap the period value to the sys max_ttl value + if period > maxTTL { + warnings = append(warnings, + fmt.Sprintf("period of %q exceeded the effective max_ttl of %q; period value is capped accordingly", period, maxTTL)) + period = maxTTL + } + ttl = period + + if explicitMaxTTL > 0 { + maxValidTime = startTime.Add(explicitMaxTTL) + } + default: + switch { + case increment > 0: + ttl = increment + case backendTTL > 0: + ttl = backendTTL + default: + ttl = sysView.DefaultLeaseTTL() + } + + // We cannot go past this time + maxValidTime = startTime.Add(maxTTL) + } + + if !maxValidTime.IsZero() { + // Determine the max valid TTL + maxValidTTL := maxValidTime.Sub(now) + + // If we are past the max TTL, we shouldn't be in this function...but + // fast path out if we are + if maxValidTTL < 0 { + return 0, nil, fmt.Errorf("past the max TTL, cannot renew") + } + + // If the proposed expiration is after the maximum TTL of the lease, + // cap the increment to whatever is left + if maxValidTTL-ttl < 0 { + warnings = append(warnings, + fmt.Sprintf("TTL of %q exceeded the effective max_ttl of %q; TTL value is capped accordingly", ttl, maxValidTTL)) + ttl = maxValidTTL + } + } + + return ttl, warnings, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/path.go b/vendor/github.com/hashicorp/vault/logical/framework/path.go new file mode 100644 index 0000000..e53dd19 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/path.go @@ -0,0 +1,163 @@ +package framework + +import ( + "context" + "fmt" + "sort" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/logical" +) + +// Helper which returns a generic regex string for creating endpoint patterns +// that are identified by the given name in the backends +func GenericNameRegex(name string) string { + return fmt.Sprintf("(?P<%s>\\w(([\\w-.]+)?\\w)?)", name) +} + +// Helper which returns a regex string for optionally accepting the a field +// from the API URL +func OptionalParamRegex(name string) string { + return fmt.Sprintf("(/(?P<%s>.+))?", name) +} + +// PathAppend is a helper for appending lists of paths into a single +// list. +func PathAppend(paths ...[]*Path) []*Path { + result := make([]*Path, 0, 10) + for _, ps := range paths { + result = append(result, ps...) + } + + return result +} + +// Path is a single path that the backend responds to. +type Path struct { + // Pattern is the pattern of the URL that matches this path. + // + // This should be a valid regular expression. Named captures will be + // exposed as fields that should map to a schema in Fields. If a named + // capture is not a field in the Fields map, then it will be ignored. + Pattern string + + // Fields is the mapping of data fields to a schema describing that + // field. Named captures in the Pattern also map to fields. If a named + // capture name matches a PUT body name, the named capture takes + // priority. + // + // Note that only named capture fields are available in every operation, + // whereas all fields are available in the Write operation. + Fields map[string]*FieldSchema + + // Callbacks are the set of callbacks that are called for a given + // operation. If a callback for a specific operation is not present, + // then logical.ErrUnsupportedOperation is automatically generated. + // + // The help operation is the only operation that the Path will + // automatically handle if the Help field is set. If both the Help + // field is set and there is a callback registered here, then the + // callback will be called. + Callbacks map[logical.Operation]OperationFunc + + // ExistenceCheck, if implemented, is used to query whether a given + // resource exists or not. This is used for ACL purposes: if an Update + // action is specified, and the existence check returns false, the action + // is not allowed since the resource must first be created. The reverse is + // also true. If not specified, the Update action is forced and the user + // must have UpdateCapability on the path. + ExistenceCheck ExistenceFunc + + // Help is text describing how to use this path. This will be used + // to auto-generate the help operation. The Path will automatically + // generate a parameter listing and URL structure based on the + // regular expression, so the help text should just contain a description + // of what happens. + // + // HelpSynopsis is a one-sentence description of the path. This will + // be automatically line-wrapped at 80 characters. + // + // HelpDescription is a long-form description of the path. This will + // be automatically line-wrapped at 80 characters. + HelpSynopsis string + HelpDescription string +} + +func (p *Path) helpCallback() OperationFunc { + return func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) { + var tplData pathTemplateData + tplData.Request = req.Path + tplData.RoutePattern = p.Pattern + tplData.Synopsis = strings.TrimSpace(p.HelpSynopsis) + if tplData.Synopsis == "" { + tplData.Synopsis = "" + } + tplData.Description = strings.TrimSpace(p.HelpDescription) + if tplData.Description == "" { + tplData.Description = "" + } + + // Alphabetize the fields + fieldKeys := make([]string, 0, len(p.Fields)) + for k, _ := range p.Fields { + fieldKeys = append(fieldKeys, k) + } + sort.Strings(fieldKeys) + + // Build the field help + tplData.Fields = make([]pathTemplateFieldData, len(fieldKeys)) + for i, k := range fieldKeys { + schema := p.Fields[k] + description := strings.TrimSpace(schema.Description) + if description == "" { + description = "" + } + + tplData.Fields[i] = pathTemplateFieldData{ + Key: k, + Type: schema.Type.String(), + Description: description, + } + } + + help, err := executeTemplate(pathHelpTemplate, &tplData) + if err != nil { + return nil, errwrap.Wrapf("error executing template: {{err}}", err) + } + + return logical.HelpResponse(help, nil), nil + } +} + +type pathTemplateData struct { + Request string + RoutePattern string + Synopsis string + Description string + Fields []pathTemplateFieldData +} + +type pathTemplateFieldData struct { + Key string + Type string + Description string + URL bool +} + +const pathHelpTemplate = ` +Request: {{.Request}} +Matching Route: {{.RoutePattern}} + +{{.Synopsis}} + +{{ if .Fields -}} +## PARAMETERS +{{range .Fields}} +{{indent 4 .Key}} ({{.Type}}) +{{indent 8 .Description}} +{{end}}{{end}} +## DESCRIPTION + +{{.Description}} +` diff --git a/vendor/github.com/hashicorp/vault/logical/framework/path_map.go b/vendor/github.com/hashicorp/vault/logical/framework/path_map.go new file mode 100644 index 0000000..83aa0ba --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/path_map.go @@ -0,0 +1,283 @@ +package framework + +import ( + "context" + "fmt" + "strings" + "sync" + + saltpkg "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" +) + +// PathMap can be used to generate a path that stores mappings in the +// storage. It is a structure that also exports functions for querying the +// mappings. +// +// The primary use case for this is for credential providers to do their +// mapping to policies. +type PathMap struct { + Prefix string + Name string + Schema map[string]*FieldSchema + CaseSensitive bool + Salt *saltpkg.Salt + SaltFunc func(context.Context) (*saltpkg.Salt, error) + + once sync.Once +} + +func (p *PathMap) init() { + if p.Prefix == "" { + p.Prefix = "map" + } + + if p.Schema == nil { + p.Schema = map[string]*FieldSchema{ + "value": &FieldSchema{ + Type: TypeString, + Description: fmt.Sprintf("Value for %s mapping", p.Name), + }, + } + } +} + +// pathStruct returns the pathStruct for this mapping +func (p *PathMap) pathStruct(ctx context.Context, s logical.Storage, k string) (*PathStruct, error) { + p.once.Do(p.init) + + // If we don't care about casing, store everything lowercase + if !p.CaseSensitive { + k = strings.ToLower(k) + } + + // The original key before any salting + origKey := k + + // If we have a salt, apply it before lookup + salt := p.Salt + var err error + if p.SaltFunc != nil { + salt, err = p.SaltFunc(ctx) + if err != nil { + return nil, err + } + } + if salt != nil { + k = "s" + salt.SaltIDHashFunc(k, saltpkg.SHA256Hash) + } + + finalName := fmt.Sprintf("map/%s/%s", p.Name, k) + ps := &PathStruct{ + Name: finalName, + Schema: p.Schema, + } + + if !strings.HasPrefix(origKey, "s") && k != origKey { + // Ensure that no matter what happens what is returned is the final + // path + defer func() { + ps.Name = finalName + }() + + // + // Check for unsalted version and upgrade if so + // + + // Generate the unsalted name + unsaltedName := fmt.Sprintf("map/%s/%s", p.Name, origKey) + // Set the path struct to use the unsalted name + ps.Name = unsaltedName + + val, err := ps.Get(ctx, s) + if err != nil { + return nil, err + } + // If not nil, we have an unsalted entry -- upgrade it + if val != nil { + // Set the path struct to use the desired final name + ps.Name = finalName + err = ps.Put(ctx, s, val) + if err != nil { + return nil, err + } + // Set it back to the old path and delete + ps.Name = unsaltedName + err = ps.Delete(ctx, s) + if err != nil { + return nil, err + } + // We'll set this in the deferred function but doesn't hurt here + ps.Name = finalName + } + + // + // Check for SHA1 hashed version and upgrade if so + // + + // Generate the SHA1 hash suffixed path name + sha1SuffixedName := fmt.Sprintf("map/%s/%s", p.Name, salt.SaltID(origKey)) + + // Set the path struct to use the SHA1 hash suffixed path name + ps.Name = sha1SuffixedName + + val, err = ps.Get(ctx, s) + if err != nil { + return nil, err + } + // If not nil, we have an SHA1 hash suffixed entry -- upgrade it + if val != nil { + // Set the path struct to use the desired final name + ps.Name = finalName + err = ps.Put(ctx, s, val) + if err != nil { + return nil, err + } + // Set it back to the old path and delete + ps.Name = sha1SuffixedName + err = ps.Delete(ctx, s) + if err != nil { + return nil, err + } + // We'll set this in the deferred function but doesn't hurt here + ps.Name = finalName + } + } + + return ps, nil +} + +// Get reads a value out of the mapping +func (p *PathMap) Get(ctx context.Context, s logical.Storage, k string) (map[string]interface{}, error) { + ps, err := p.pathStruct(ctx, s, k) + if err != nil { + return nil, err + } + return ps.Get(ctx, s) +} + +// Put writes a value into the mapping +func (p *PathMap) Put(ctx context.Context, s logical.Storage, k string, v map[string]interface{}) error { + ps, err := p.pathStruct(ctx, s, k) + if err != nil { + return err + } + return ps.Put(ctx, s, v) +} + +// Delete removes a value from the mapping +func (p *PathMap) Delete(ctx context.Context, s logical.Storage, k string) error { + ps, err := p.pathStruct(ctx, s, k) + if err != nil { + return err + } + return ps.Delete(ctx, s) +} + +// List reads the keys under a given path +func (p *PathMap) List(ctx context.Context, s logical.Storage, prefix string) ([]string, error) { + stripPrefix := fmt.Sprintf("struct/map/%s/", p.Name) + fullPrefix := fmt.Sprintf("%s%s", stripPrefix, prefix) + out, err := s.List(ctx, fullPrefix) + if err != nil { + return nil, err + } + stripped := make([]string, len(out)) + for idx, k := range out { + stripped[idx] = strings.TrimPrefix(k, stripPrefix) + } + return stripped, nil +} + +// Paths are the paths to append to the Backend paths. +func (p *PathMap) Paths() []*Path { + p.once.Do(p.init) + + // Build the schema by simply adding the "key" + schema := make(map[string]*FieldSchema) + for k, v := range p.Schema { + schema[k] = v + } + schema["key"] = &FieldSchema{ + Type: TypeString, + Description: fmt.Sprintf("Key for the %s mapping", p.Name), + } + + return []*Path{ + &Path{ + Pattern: fmt.Sprintf("%s/%s/?$", p.Prefix, p.Name), + + Callbacks: map[logical.Operation]OperationFunc{ + logical.ListOperation: p.pathList(), + logical.ReadOperation: p.pathList(), + }, + + HelpSynopsis: fmt.Sprintf("Read mappings for %s", p.Name), + }, + + &Path{ + Pattern: fmt.Sprintf(`%s/%s/(?P[-\w]+)`, p.Prefix, p.Name), + + Fields: schema, + + Callbacks: map[logical.Operation]OperationFunc{ + logical.CreateOperation: p.pathSingleWrite(), + logical.ReadOperation: p.pathSingleRead(), + logical.UpdateOperation: p.pathSingleWrite(), + logical.DeleteOperation: p.pathSingleDelete(), + }, + + HelpSynopsis: fmt.Sprintf("Read/write/delete a single %s mapping", p.Name), + + ExistenceCheck: p.pathSingleExistenceCheck(), + }, + } +} + +func (p *PathMap) pathList() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + keys, err := p.List(ctx, req.Storage, "") + if err != nil { + return nil, err + } + + return logical.ListResponse(keys), nil + } +} + +func (p *PathMap) pathSingleRead() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + v, err := p.Get(ctx, req.Storage, d.Get("key").(string)) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: v, + }, nil + } +} + +func (p *PathMap) pathSingleWrite() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + err := p.Put(ctx, req.Storage, d.Get("key").(string), d.Raw) + return nil, err + } +} + +func (p *PathMap) pathSingleDelete() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + err := p.Delete(ctx, req.Storage, d.Get("key").(string)) + return nil, err + } +} + +func (p *PathMap) pathSingleExistenceCheck() ExistenceFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (bool, error) { + v, err := p.Get(ctx, req.Storage, d.Get("key").(string)) + if err != nil { + return false, err + } + return v != nil, nil + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/path_struct.go b/vendor/github.com/hashicorp/vault/logical/framework/path_struct.go new file mode 100644 index 0000000..beaed52 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/path_struct.go @@ -0,0 +1,124 @@ +package framework + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" +) + +// PathStruct can be used to generate a path that stores a struct +// in the storage. This structure is a map[string]interface{} but the +// types are set according to the schema in this structure. +type PathStruct struct { + Name string + Path string + Schema map[string]*FieldSchema + HelpSynopsis string + HelpDescription string + + Read bool +} + +// Get reads the structure. +func (p *PathStruct) Get(ctx context.Context, s logical.Storage) (map[string]interface{}, error) { + entry, err := s.Get(ctx, fmt.Sprintf("struct/%s", p.Name)) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var result map[string]interface{} + if err := jsonutil.DecodeJSON(entry.Value, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Put writes the structure. +func (p *PathStruct) Put(ctx context.Context, s logical.Storage, v map[string]interface{}) error { + bytes, err := json.Marshal(v) + if err != nil { + return err + } + + return s.Put(ctx, &logical.StorageEntry{ + Key: fmt.Sprintf("struct/%s", p.Name), + Value: bytes, + }) +} + +// Delete removes the structure. +func (p *PathStruct) Delete(ctx context.Context, s logical.Storage) error { + return s.Delete(ctx, fmt.Sprintf("struct/%s", p.Name)) +} + +// Paths are the paths to append to the Backend paths. +func (p *PathStruct) Paths() []*Path { + // The single path we support to read/write this config + path := &Path{ + Pattern: p.Path, + Fields: p.Schema, + + Callbacks: map[logical.Operation]OperationFunc{ + logical.CreateOperation: p.pathWrite(), + logical.UpdateOperation: p.pathWrite(), + logical.DeleteOperation: p.pathDelete(), + }, + + ExistenceCheck: p.pathExistenceCheck(), + + HelpSynopsis: p.HelpSynopsis, + HelpDescription: p.HelpDescription, + } + + // If we support reads, add that + if p.Read { + path.Callbacks[logical.ReadOperation] = p.pathRead() + } + + return []*Path{path} +} + +func (p *PathStruct) pathRead() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + v, err := p.Get(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: v, + }, nil + } +} + +func (p *PathStruct) pathWrite() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + err := p.Put(ctx, req.Storage, d.Raw) + return nil, err + } +} + +func (p *PathStruct) pathDelete() OperationFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { + err := p.Delete(ctx, req.Storage) + return nil, err + } +} + +func (p *PathStruct) pathExistenceCheck() ExistenceFunc { + return func(ctx context.Context, req *logical.Request, d *FieldData) (bool, error) { + v, err := p.Get(ctx, req.Storage) + if err != nil { + return false, err + } + + return v != nil, nil + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/policy_map.go b/vendor/github.com/hashicorp/vault/logical/framework/policy_map.go new file mode 100644 index 0000000..089cf7f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/policy_map.go @@ -0,0 +1,65 @@ +package framework + +import ( + "context" + "sort" + "strings" + + "github.com/hashicorp/vault/logical" +) + +// PolicyMap is a specialization of PathMap that expects the values to +// be lists of policies. This assists in querying and loading policies +// from the PathMap. +type PolicyMap struct { + PathMap + + DefaultKey string + PolicyKey string +} + +func (p *PolicyMap) Policies(ctx context.Context, s logical.Storage, names ...string) ([]string, error) { + policyKey := "value" + if p.PolicyKey != "" { + policyKey = p.PolicyKey + } + + if p.DefaultKey != "" { + newNames := make([]string, len(names)+1) + newNames[0] = p.DefaultKey + copy(newNames[1:], names) + names = newNames + } + + set := make(map[string]struct{}) + for _, name := range names { + v, err := p.Get(ctx, s, name) + if err != nil { + return nil, err + } + + valuesRaw, ok := v[policyKey] + if !ok { + continue + } + + values, ok := valuesRaw.(string) + if !ok { + continue + } + + for _, p := range strings.Split(values, ",") { + if p = strings.TrimSpace(p); p != "" { + set[p] = struct{}{} + } + } + } + + list := make([]string, 0, len(set)) + for k, _ := range set { + list = append(list, k) + } + sort.Strings(list) + + return list, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/secret.go b/vendor/github.com/hashicorp/vault/logical/framework/secret.go new file mode 100644 index 0000000..616a055 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/secret.go @@ -0,0 +1,91 @@ +package framework + +import ( + "context" + "time" + + "github.com/hashicorp/vault/logical" +) + +// Secret is a type of secret that can be returned from a backend. +type Secret struct { + // Type is the name of this secret type. This is used to setup the + // vault ID and to look up the proper secret structure when revocation/ + // renewal happens. Once this is set this should not be changed. + // + // The format of this must match (case insensitive): ^a-Z0-9_$ + Type string + + // Fields is the mapping of data fields and schema that comprise + // the structure of this secret. + Fields map[string]*FieldSchema + + // DefaultDuration is the default value for the duration of the lease for + // this secret. This can be manually overwritten with the result of + // Response(). + // + // If these aren't set, Vault core will set a default lease period which + // may come from a mount tuning. + DefaultDuration time.Duration + + // Renew is the callback called to renew this secret. If Renew is + // not specified then renewable is set to false in the secret. + // See lease.go for helpers for this value. + Renew OperationFunc + + // Revoke is the callback called to revoke this secret. This is required. + Revoke OperationFunc +} + +func (s *Secret) Renewable() bool { + return s.Renew != nil +} + +func (s *Secret) Response( + data, internal map[string]interface{}) *logical.Response { + internalData := make(map[string]interface{}) + for k, v := range internal { + internalData[k] = v + } + internalData["secret_type"] = s.Type + + return &logical.Response{ + Secret: &logical.Secret{ + LeaseOptions: logical.LeaseOptions{ + TTL: s.DefaultDuration, + Renewable: s.Renewable(), + }, + InternalData: internalData, + }, + + Data: data, + } +} + +// HandleRenew is the request handler for renewing this secret. +func (s *Secret) HandleRenew(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if !s.Renewable() { + return nil, logical.ErrUnsupportedOperation + } + + data := &FieldData{ + Raw: req.Data, + Schema: s.Fields, + } + + return s.Renew(ctx, req, data) +} + +// HandleRevoke is the request handler for renewing this secret. +func (s *Secret) HandleRevoke(ctx context.Context, req *logical.Request) (*logical.Response, error) { + data := &FieldData{ + Raw: req.Data, + Schema: s.Fields, + } + + if s.Revoke != nil { + return s.Revoke(ctx, req, data) + } + + return nil, logical.ErrUnsupportedOperation +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/template.go b/vendor/github.com/hashicorp/vault/logical/framework/template.go new file mode 100644 index 0000000..3abdd62 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/template.go @@ -0,0 +1,42 @@ +package framework + +import ( + "bufio" + "bytes" + "strings" + "text/template" + + "github.com/hashicorp/errwrap" +) + +func executeTemplate(tpl string, data interface{}) (string, error) { + // Define the functions + funcs := map[string]interface{}{ + "indent": funcIndent, + } + + // Parse the help template + t, err := template.New("root").Funcs(funcs).Parse(tpl) + if err != nil { + return "", errwrap.Wrapf("error parsing template: {{err}}", err) + } + + // Execute the template and store the output + var buf bytes.Buffer + if err := t.Execute(&buf, data); err != nil { + return "", errwrap.Wrapf("error executing template: {{err}}", err) + } + + return strings.TrimSpace(buf.String()), nil +} + +func funcIndent(count int, text string) string { + var buf bytes.Buffer + prefix := strings.Repeat(" ", count) + scan := bufio.NewScanner(strings.NewReader(text)) + for scan.Scan() { + buf.WriteString(prefix + scan.Text() + "\n") + } + + return strings.TrimRight(buf.String(), "\n") +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/testing.go b/vendor/github.com/hashicorp/vault/logical/framework/testing.go new file mode 100644 index 0000000..a00a324 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/testing.go @@ -0,0 +1,15 @@ +package framework + +import ( + "testing" +) + +// TestBackendRoutes is a helper to test that all the given routes will +// route properly in the backend. +func TestBackendRoutes(t *testing.T, b *Backend, rs []string) { + for _, r := range rs { + if b.Route(r) == nil { + t.Fatalf("bad route: %s", r) + } + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/framework/wal.go b/vendor/github.com/hashicorp/vault/logical/framework/wal.go new file mode 100644 index 0000000..c8fa3b8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/wal.go @@ -0,0 +1,101 @@ +package framework + +import ( + "context" + "encoding/json" + "strings" + "time" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" +) + +// WALPrefix is the prefix within Storage where WAL entries will be written. +const WALPrefix = "wal/" + +type WALEntry struct { + ID string `json:"-"` + Kind string `json:"type"` + Data interface{} `json:"data"` + CreatedAt int64 `json:"created_at"` +} + +// PutWAL writes some data to the WAL. +// +// The kind parameter is used by the framework to allow users to store +// multiple kinds of WAL data and to easily disambiguate what data they're +// expecting. +// +// Data within the WAL that is uncommitted (CommitWAL hasn't be called) +// will be given to the rollback callback when an rollback operation is +// received, allowing the backend to clean up some partial states. +// +// The data must be JSON encodable. +// +// This returns a unique ID that can be used to reference this WAL data. +// WAL data cannot be modified. You can only add to the WAL and commit existing +// WAL entries. +func PutWAL(ctx context.Context, s logical.Storage, kind string, data interface{}) (string, error) { + value, err := json.Marshal(&WALEntry{ + Kind: kind, + Data: data, + CreatedAt: time.Now().UTC().Unix(), + }) + if err != nil { + return "", err + } + + id, err := uuid.GenerateUUID() + if err != nil { + return "", err + } + + return id, s.Put(ctx, &logical.StorageEntry{ + Key: WALPrefix + id, + Value: value, + }) +} + +// GetWAL reads a specific entry from the WAL. If the entry doesn't exist, +// then nil value is returned. +// +// The kind, value, and error are returned. +func GetWAL(ctx context.Context, s logical.Storage, id string) (*WALEntry, error) { + entry, err := s.Get(ctx, WALPrefix+id) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var raw WALEntry + if err := jsonutil.DecodeJSON(entry.Value, &raw); err != nil { + return nil, err + } + raw.ID = id + + return &raw, nil +} + +// DeleteWAL commits the WAL entry with the given ID. Once committed, +// it is assumed that the operation was a success and doesn't need to +// be rolled back. +func DeleteWAL(ctx context.Context, s logical.Storage, id string) error { + return s.Delete(ctx, WALPrefix+id) +} + +// ListWAL lists all the entries in the WAL. +func ListWAL(ctx context.Context, s logical.Storage) ([]string, error) { + keys, err := s.List(ctx, WALPrefix) + if err != nil { + return nil, err + } + + for i, k := range keys { + keys[i] = strings.TrimPrefix(k, WALPrefix) + } + + return keys, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/identity.pb.go b/vendor/github.com/hashicorp/vault/logical/identity.pb.go new file mode 100644 index 0000000..0deed72 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/identity.pb.go @@ -0,0 +1,159 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: logical/identity.proto + +package logical // import "github.com/hashicorp/vault/logical" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Entity struct { + // ID is the unique identifier for the entity + ID string `protobuf:"bytes,1,opt,name=ID" json:"ID,omitempty"` + // Name is the human-friendly unique identifier for the entity + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // Aliases contains thhe alias mappings for the given entity + Aliases []*Alias `protobuf:"bytes,3,rep,name=aliases" json:"aliases,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Entity) Reset() { *m = Entity{} } +func (m *Entity) String() string { return proto.CompactTextString(m) } +func (*Entity) ProtoMessage() {} +func (*Entity) Descriptor() ([]byte, []int) { + return fileDescriptor_identity_63bdeae5187a0ba9, []int{0} +} +func (m *Entity) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Entity.Unmarshal(m, b) +} +func (m *Entity) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Entity.Marshal(b, m, deterministic) +} +func (dst *Entity) XXX_Merge(src proto.Message) { + xxx_messageInfo_Entity.Merge(dst, src) +} +func (m *Entity) XXX_Size() int { + return xxx_messageInfo_Entity.Size(m) +} +func (m *Entity) XXX_DiscardUnknown() { + xxx_messageInfo_Entity.DiscardUnknown(m) +} + +var xxx_messageInfo_Entity proto.InternalMessageInfo + +func (m *Entity) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Entity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Entity) GetAliases() []*Alias { + if m != nil { + return m.Aliases + } + return nil +} + +type Alias struct { + // MountType is the backend mount's type to which this identity belongs + MountType string `protobuf:"bytes,1,opt,name=mount_type,json=mountType" json:"mount_type,omitempty"` + // MountAccessor is the identifier of the mount entry to which this + // identity belongs + MountAccessor string `protobuf:"bytes,2,opt,name=mount_accessor,json=mountAccessor" json:"mount_accessor,omitempty"` + // Name is the identifier of this identity in its authentication source + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Alias) Reset() { *m = Alias{} } +func (m *Alias) String() string { return proto.CompactTextString(m) } +func (*Alias) ProtoMessage() {} +func (*Alias) Descriptor() ([]byte, []int) { + return fileDescriptor_identity_63bdeae5187a0ba9, []int{1} +} +func (m *Alias) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Alias.Unmarshal(m, b) +} +func (m *Alias) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Alias.Marshal(b, m, deterministic) +} +func (dst *Alias) XXX_Merge(src proto.Message) { + xxx_messageInfo_Alias.Merge(dst, src) +} +func (m *Alias) XXX_Size() int { + return xxx_messageInfo_Alias.Size(m) +} +func (m *Alias) XXX_DiscardUnknown() { + xxx_messageInfo_Alias.DiscardUnknown(m) +} + +var xxx_messageInfo_Alias proto.InternalMessageInfo + +func (m *Alias) GetMountType() string { + if m != nil { + return m.MountType + } + return "" +} + +func (m *Alias) GetMountAccessor() string { + if m != nil { + return m.MountAccessor + } + return "" +} + +func (m *Alias) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func init() { + proto.RegisterType((*Entity)(nil), "logical.Entity") + proto.RegisterType((*Alias)(nil), "logical.Alias") +} + +func init() { proto.RegisterFile("logical/identity.proto", fileDescriptor_identity_63bdeae5187a0ba9) } + +var fileDescriptor_identity_63bdeae5187a0ba9 = []byte{ + // 209 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0xcf, 0x31, 0x6b, 0x85, 0x30, + 0x14, 0x05, 0x60, 0xd4, 0x56, 0xf1, 0x96, 0x3a, 0x64, 0x28, 0x2e, 0x05, 0x91, 0x16, 0x9c, 0x12, + 0x68, 0x7f, 0x81, 0xc5, 0x0e, 0xae, 0x52, 0x3a, 0x74, 0x29, 0xd7, 0x34, 0x68, 0x20, 0x9a, 0x60, + 0x62, 0xc1, 0x7f, 0x5f, 0x9a, 0x97, 0xf7, 0xde, 0x16, 0xbe, 0x03, 0x27, 0xe7, 0xc2, 0x83, 0xd2, + 0x93, 0xe4, 0xa8, 0x98, 0xfc, 0x11, 0xab, 0x93, 0xee, 0xa0, 0x66, 0xd3, 0x4e, 0x93, 0x2c, 0x78, + 0xfd, 0x09, 0xe9, 0xbb, 0x0f, 0x48, 0x01, 0x71, 0xdf, 0x95, 0x51, 0x15, 0x35, 0xf9, 0x10, 0xf7, + 0x1d, 0x21, 0x70, 0xb3, 0xe2, 0x22, 0xca, 0xd8, 0x8b, 0x7f, 0x93, 0x06, 0x32, 0x54, 0x12, 0xad, + 0xb0, 0x65, 0x52, 0x25, 0xcd, 0xdd, 0x4b, 0x41, 0x43, 0x11, 0x6d, 0xff, 0x7d, 0x38, 0xc7, 0x35, + 0xc2, 0xad, 0x17, 0xf2, 0x08, 0xb0, 0xe8, 0x7d, 0x75, 0xdf, 0xee, 0x30, 0x22, 0xd4, 0xe7, 0x5e, + 0x3e, 0x0e, 0x23, 0xc8, 0x33, 0x14, 0xa7, 0x18, 0x39, 0x17, 0xd6, 0xea, 0x2d, 0xfc, 0x77, 0xef, + 0xb5, 0x0d, 0x78, 0x19, 0x93, 0x5c, 0xc7, 0xbc, 0x3d, 0x7d, 0xd5, 0x93, 0x74, 0xf3, 0x3e, 0x52, + 0xae, 0x17, 0x36, 0xa3, 0x9d, 0x25, 0xd7, 0x9b, 0x61, 0xbf, 0xb8, 0x2b, 0xc7, 0xc2, 0xae, 0x31, + 0xf5, 0x07, 0xbf, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x53, 0x90, 0x60, 0xf6, 0x0a, 0x01, 0x00, + 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/logical/identity.proto b/vendor/github.com/hashicorp/vault/logical/identity.proto new file mode 100644 index 0000000..914a6ad --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/identity.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/logical"; + +package logical; + +message Entity { + // ID is the unique identifier for the entity + string ID = 1; + + // Name is the human-friendly unique identifier for the entity + string name = 2; + + // Aliases contains thhe alias mappings for the given entity + repeated Alias aliases = 3; +} + +message Alias { + // MountType is the backend mount's type to which this identity belongs + string mount_type = 1; + + // MountAccessor is the identifier of the mount entry to which this + // identity belongs + string mount_accessor = 2; + + // Name is the identifier of this identity in its authentication source + string name = 3; +} + diff --git a/vendor/github.com/hashicorp/vault/logical/lease.go b/vendor/github.com/hashicorp/vault/logical/lease.go new file mode 100644 index 0000000..90c0894 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/lease.go @@ -0,0 +1,53 @@ +package logical + +import ( + "time" +) + +// LeaseOptions is an embeddable struct to capture common lease +// settings between a Secret and Auth +type LeaseOptions struct { + // TTL is the duration that this secret is valid for. Vault + // will automatically revoke it after the duration. + TTL time.Duration `json:"lease"` + + // MaxTTL is the maximum duration that this secret is valid for. + MaxTTL time.Duration `json:"max_ttl"` + + // Renewable, if true, means that this secret can be renewed. + Renewable bool `json:"renewable"` + + // Increment will be the lease increment that the user requested. + // This is only available on a Renew operation and has no effect + // when returning a response. + Increment time.Duration `json:"-"` + + // IssueTime is the time of issue for the original lease. This is + // only available on a Renew operation and has no effect when returning + // a response. It can be used to enforce maximum lease periods by + // a logical backend. + IssueTime time.Time `json:"-"` +} + +// LeaseEnabled checks if leasing is enabled +func (l *LeaseOptions) LeaseEnabled() bool { + return l.TTL > 0 +} + +// LeaseTotal is the lease duration with a guard against a negative TTL +func (l *LeaseOptions) LeaseTotal() time.Duration { + if l.TTL <= 0 { + return 0 + } + + return l.TTL +} + +// ExpirationTime computes the time until expiration including the grace period +func (l *LeaseOptions) ExpirationTime() time.Time { + var expireTime time.Time + if l.LeaseEnabled() { + expireTime = time.Now().Add(l.LeaseTotal()) + } + return expireTime +} diff --git a/vendor/github.com/hashicorp/vault/logical/logical.go b/vendor/github.com/hashicorp/vault/logical/logical.go new file mode 100644 index 0000000..a3456e9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/logical.go @@ -0,0 +1,126 @@ +package logical + +import ( + "context" + + log "github.com/hashicorp/go-hclog" +) + +// BackendType is the type of backend that is being implemented +type BackendType uint32 + +// The these are the types of backends that can be derived from +// logical.Backend +const ( + TypeUnknown BackendType = 0 // This is also the zero-value for BackendType + TypeLogical BackendType = 1 + TypeCredential BackendType = 2 +) + +// Stringer implementation +func (b BackendType) String() string { + switch b { + case TypeLogical: + return "secret" + case TypeCredential: + return "auth" + } + + return "unknown" +} + +// Backend interface must be implemented to be "mountable" at +// a given path. Requests flow through a router which has various mount +// points that flow to a logical backend. The logic of each backend is flexible, +// and this is what allows materialized keys to function. There can be specialized +// logical backends for various upstreams (Consul, PostgreSQL, MySQL, etc) that can +// interact with remote APIs to generate keys dynamically. This interface also +// allows for a "procfs" like interaction, as internal state can be exposed by +// acting like a logical backend and being mounted. +type Backend interface { + // HandleRequest is used to handle a request and generate a response. + // The backends must check the operation type and handle appropriately. + HandleRequest(context.Context, *Request) (*Response, error) + + // SpecialPaths is a list of paths that are special in some way. + // See PathType for the types of special paths. The key is the type + // of the special path, and the value is a list of paths for this type. + // This is not a regular expression but is an exact match. If the path + // ends in '*' then it is a prefix-based match. The '*' can only appear + // at the end. + SpecialPaths() *Paths + + // System provides an interface to access certain system configuration + // information, such as globally configured default and max lease TTLs. + System() SystemView + + // Logger provides an interface to access the underlying logger. This + // is useful when a struct embeds a Backend-implemented struct that + // contains a private instance of logger. + Logger() log.Logger + + // HandleExistenceCheck is used to handle a request and generate a response + // indicating whether the given path exists or not; this is used to + // understand whether the request must have a Create or Update capability + // ACL applied. The first bool indicates whether an existence check + // function was found for the backend; the second indicates whether, if an + // existence check function was found, the item exists or not. + HandleExistenceCheck(context.Context, *Request) (bool, bool, error) + + // Cleanup is invoked during an unmount of a backend to allow it to + // handle any cleanup like connection closing or releasing of file handles. + Cleanup(context.Context) + + // InvalidateKey may be invoked when an object is modified that belongs + // to the backend. The backend can use this to clear any caches or reset + // internal state as needed. + InvalidateKey(context.Context, string) + + // Setup is used to set up the backend based on the provided backend + // configuration. + Setup(context.Context, *BackendConfig) error + + // Type returns the BackendType for the particular backend + Type() BackendType +} + +// BackendConfig is provided to the factory to initialize the backend +type BackendConfig struct { + // View should not be stored, and should only be used for initialization + StorageView Storage + + // The backend should use this logger. The log should not contain any secrets. + Logger log.Logger + + // System provides a view into a subset of safe system information that + // is useful for backends, such as the default/max lease TTLs + System SystemView + + // BackendUUID is a unique identifier provided to this backend. It's useful + // when a backend needs a consistent and unique string without using storage. + BackendUUID string + + // Config is the opaque user configuration provided when mounting + Config map[string]string +} + +// Factory is the factory function to create a logical backend. +type Factory func(context.Context, *BackendConfig) (Backend, error) + +// Paths is the structure of special paths that is used for SpecialPaths. +type Paths struct { + // Root are the paths that require a root token to access + Root []string + + // Unauthenticated are the paths that can be accessed without any auth. + Unauthenticated []string + + // LocalStorage are paths (prefixes) that are local to this instance; this + // indicates that these paths should not be replicated + LocalStorage []string + + // SealWrapStorage are storage paths that, when using a capable seal, + // should be seal wrapped with extra encryption. It is exact matching + // unless it ends with '/' in which case it will be treated as a prefix. + SealWrapStorage []string +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/backend.go b/vendor/github.com/hashicorp/vault/logical/plugin/backend.go new file mode 100644 index 0000000..b55a0aa --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/backend.go @@ -0,0 +1,64 @@ +package plugin + +import ( + "context" + "net/rpc" + "sync/atomic" + + "google.golang.org/grpc" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/plugin/pb" +) + +// BackendPlugin is the plugin.Plugin implementation +type BackendPlugin struct { + Factory logical.Factory + metadataMode bool + Logger log.Logger +} + +// Server gets called when on plugin.Serve() +func (b *BackendPlugin) Server(broker *plugin.MuxBroker) (interface{}, error) { + return &backendPluginServer{ + factory: b.Factory, + broker: broker, + // We pass the logger down into the backend so go-plugin will forward + // logs for us. + logger: b.Logger, + }, nil +} + +// Client gets called on plugin.NewClient() +func (b BackendPlugin) Client(broker *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &backendPluginClient{client: c, broker: broker, metadataMode: b.metadataMode}, nil +} + +func (b BackendPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { + pb.RegisterBackendServer(s, &backendGRPCPluginServer{ + broker: broker, + factory: b.Factory, + // We pass the logger down into the backend so go-plugin will forward + // logs for us. + logger: b.Logger, + }) + return nil +} + +func (p *BackendPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { + ret := &backendGRPCPluginClient{ + client: pb.NewBackendClient(c), + clientConn: c, + broker: broker, + cleanupCh: make(chan struct{}), + doneCtx: ctx, + } + + // Create the value and set the type + ret.server = new(atomic.Value) + ret.server.Store((*grpc.Server)(nil)) + + return ret, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/backend_client.go b/vendor/github.com/hashicorp/vault/logical/plugin/backend_client.go new file mode 100644 index 0000000..43a442f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/backend_client.go @@ -0,0 +1,248 @@ +package plugin + +import ( + "context" + "errors" + "net/rpc" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/logical" +) + +var ( + ErrClientInMetadataMode = errors.New("plugin client can not perform action while in metadata mode") +) + +// backendPluginClient implements logical.Backend and is the +// go-plugin client. +type backendPluginClient struct { + broker *plugin.MuxBroker + client *rpc.Client + metadataMode bool + + system logical.SystemView + logger log.Logger +} + +// HandleRequestArgs is the args for HandleRequest method. +type HandleRequestArgs struct { + StorageID uint32 + Request *logical.Request +} + +// HandleRequestReply is the reply for HandleRequest method. +type HandleRequestReply struct { + Response *logical.Response + Error error +} + +// SpecialPathsReply is the reply for SpecialPaths method. +type SpecialPathsReply struct { + Paths *logical.Paths +} + +// SystemReply is the reply for System method. +type SystemReply struct { + SystemView logical.SystemView + Error error +} + +// HandleExistenceCheckArgs is the args for HandleExistenceCheck method. +type HandleExistenceCheckArgs struct { + StorageID uint32 + Request *logical.Request +} + +// HandleExistenceCheckReply is the reply for HandleExistenceCheck method. +type HandleExistenceCheckReply struct { + CheckFound bool + Exists bool + Error error +} + +// SetupArgs is the args for Setup method. +type SetupArgs struct { + StorageID uint32 + LoggerID uint32 + SysViewID uint32 + Config map[string]string + BackendUUID string +} + +// SetupReply is the reply for Setup method. +type SetupReply struct { + Error error +} + +// TypeReply is the reply for the Type method. +type TypeReply struct { + Type logical.BackendType +} + +func (b *backendPluginClient) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if b.metadataMode { + return nil, ErrClientInMetadataMode + } + + // Do not send the storage, since go-plugin cannot serialize + // interfaces. The server will pick up the storage from the shim. + req.Storage = nil + args := &HandleRequestArgs{ + Request: req, + } + var reply HandleRequestReply + + if req.Connection != nil { + oldConnState := req.Connection.ConnState + req.Connection.ConnState = nil + defer func() { + req.Connection.ConnState = oldConnState + }() + } + + err := b.client.Call("Plugin.HandleRequest", args, &reply) + if err != nil { + return nil, err + } + if reply.Error != nil { + if reply.Error.Error() == logical.ErrUnsupportedOperation.Error() { + return nil, logical.ErrUnsupportedOperation + } + + return reply.Response, reply.Error + } + + return reply.Response, nil +} + +func (b *backendPluginClient) SpecialPaths() *logical.Paths { + var reply SpecialPathsReply + err := b.client.Call("Plugin.SpecialPaths", new(interface{}), &reply) + if err != nil { + return nil + } + + return reply.Paths +} + +// System returns vault's system view. The backend client stores the view during +// Setup, so there is no need to shim the system just to get it back. +func (b *backendPluginClient) System() logical.SystemView { + return b.system +} + +// Logger returns vault's logger. The backend client stores the logger during +// Setup, so there is no need to shim the logger just to get it back. +func (b *backendPluginClient) Logger() log.Logger { + return b.logger +} + +func (b *backendPluginClient) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) { + if b.metadataMode { + return false, false, ErrClientInMetadataMode + } + + // Do not send the storage, since go-plugin cannot serialize + // interfaces. The server will pick up the storage from the shim. + req.Storage = nil + args := &HandleExistenceCheckArgs{ + Request: req, + } + var reply HandleExistenceCheckReply + + if req.Connection != nil { + oldConnState := req.Connection.ConnState + req.Connection.ConnState = nil + defer func() { + req.Connection.ConnState = oldConnState + }() + } + + err := b.client.Call("Plugin.HandleExistenceCheck", args, &reply) + if err != nil { + return false, false, err + } + if reply.Error != nil { + // THINKING: Should be be a switch on all error types? + if reply.Error.Error() == logical.ErrUnsupportedPath.Error() { + return false, false, logical.ErrUnsupportedPath + } + return false, false, reply.Error + } + + return reply.CheckFound, reply.Exists, nil +} + +func (b *backendPluginClient) Cleanup(ctx context.Context) { + b.client.Call("Plugin.Cleanup", new(interface{}), &struct{}{}) +} + +func (b *backendPluginClient) Initialize(ctx context.Context) error { + if b.metadataMode { + return ErrClientInMetadataMode + } + err := b.client.Call("Plugin.Initialize", new(interface{}), &struct{}{}) + return err +} + +func (b *backendPluginClient) InvalidateKey(ctx context.Context, key string) { + if b.metadataMode { + return + } + b.client.Call("Plugin.InvalidateKey", key, &struct{}{}) +} + +func (b *backendPluginClient) Setup(ctx context.Context, config *logical.BackendConfig) error { + // Shim logical.Storage + storageImpl := config.StorageView + if b.metadataMode { + storageImpl = &NOOPStorage{} + } + storageID := b.broker.NextId() + go b.broker.AcceptAndServe(storageID, &StorageServer{ + impl: storageImpl, + }) + + // Shim logical.SystemView + sysViewImpl := config.System + if b.metadataMode { + sysViewImpl = &logical.StaticSystemView{} + } + sysViewID := b.broker.NextId() + go b.broker.AcceptAndServe(sysViewID, &SystemViewServer{ + impl: sysViewImpl, + }) + + args := &SetupArgs{ + StorageID: storageID, + SysViewID: sysViewID, + Config: config.Config, + BackendUUID: config.BackendUUID, + } + var reply SetupReply + + err := b.client.Call("Plugin.Setup", args, &reply) + if err != nil { + return err + } + if reply.Error != nil { + return reply.Error + } + + // Set system and logger for getter methods + b.system = config.System + b.logger = config.Logger + + return nil +} + +func (b *backendPluginClient) Type() logical.BackendType { + var reply TypeReply + err := b.client.Call("Plugin.Type", new(interface{}), &reply) + if err != nil { + return logical.TypeUnknown + } + + return logical.BackendType(reply.Type) +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/backend_server.go b/vendor/github.com/hashicorp/vault/logical/plugin/backend_server.go new file mode 100644 index 0000000..a03e089 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/backend_server.go @@ -0,0 +1,148 @@ +package plugin + +import ( + "context" + "errors" + "net/rpc" + + "github.com/hashicorp/go-hclog" + + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" +) + +var ( + ErrServerInMetadataMode = errors.New("plugin server can not perform action while in metadata mode") +) + +// backendPluginServer is the RPC server that backendPluginClient talks to, +// it methods conforming to requirements by net/rpc +type backendPluginServer struct { + broker *plugin.MuxBroker + backend logical.Backend + factory logical.Factory + + logger hclog.Logger + sysViewClient *rpc.Client + storageClient *rpc.Client +} + +func (b *backendPluginServer) HandleRequest(args *HandleRequestArgs, reply *HandleRequestReply) error { + if pluginutil.InMetadataMode() { + return ErrServerInMetadataMode + } + + storage := &StorageClient{client: b.storageClient} + args.Request.Storage = storage + + resp, err := b.backend.HandleRequest(context.Background(), args.Request) + *reply = HandleRequestReply{ + Response: resp, + Error: wrapError(err), + } + + return nil +} + +func (b *backendPluginServer) SpecialPaths(_ interface{}, reply *SpecialPathsReply) error { + *reply = SpecialPathsReply{ + Paths: b.backend.SpecialPaths(), + } + return nil +} + +func (b *backendPluginServer) HandleExistenceCheck(args *HandleExistenceCheckArgs, reply *HandleExistenceCheckReply) error { + if pluginutil.InMetadataMode() { + return ErrServerInMetadataMode + } + + storage := &StorageClient{client: b.storageClient} + args.Request.Storage = storage + + checkFound, exists, err := b.backend.HandleExistenceCheck(context.TODO(), args.Request) + *reply = HandleExistenceCheckReply{ + CheckFound: checkFound, + Exists: exists, + Error: wrapError(err), + } + + return nil +} + +func (b *backendPluginServer) Cleanup(_ interface{}, _ *struct{}) error { + b.backend.Cleanup(context.Background()) + + // Close rpc clients + b.sysViewClient.Close() + b.storageClient.Close() + return nil +} + +func (b *backendPluginServer) InvalidateKey(args string, _ *struct{}) error { + if pluginutil.InMetadataMode() { + return ErrServerInMetadataMode + } + + b.backend.InvalidateKey(context.Background(), args) + return nil +} + +// Setup dials into the plugin's broker to get a shimmed storage, logger, and +// system view of the backend. This method also instantiates the underlying +// backend through its factory func for the server side of the plugin. +func (b *backendPluginServer) Setup(args *SetupArgs, reply *SetupReply) error { + // Dial for storage + storageConn, err := b.broker.Dial(args.StorageID) + if err != nil { + *reply = SetupReply{ + Error: wrapError(err), + } + return nil + } + rawStorageClient := rpc.NewClient(storageConn) + b.storageClient = rawStorageClient + + storage := &StorageClient{client: rawStorageClient} + + // Dial for sys view + sysViewConn, err := b.broker.Dial(args.SysViewID) + if err != nil { + *reply = SetupReply{ + Error: wrapError(err), + } + return nil + } + rawSysViewClient := rpc.NewClient(sysViewConn) + b.sysViewClient = rawSysViewClient + + sysView := &SystemViewClient{client: rawSysViewClient} + + config := &logical.BackendConfig{ + StorageView: storage, + Logger: b.logger, + System: sysView, + Config: args.Config, + BackendUUID: args.BackendUUID, + } + + // Call the underlying backend factory after shims have been created + // to set b.backend + backend, err := b.factory(context.Background(), config) + if err != nil { + *reply = SetupReply{ + Error: wrapError(err), + } + } + b.backend = backend + + return nil +} + +func (b *backendPluginServer) Type(_ interface{}, reply *TypeReply) error { + *reply = TypeReply{ + Type: b.backend.Type(), + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend.go b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend.go new file mode 100644 index 0000000..a65eeeb --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend.go @@ -0,0 +1,12 @@ +package plugin + +import ( + "math" + + "google.golang.org/grpc" +) + +var largeMsgGRPCCallOpts []grpc.CallOption = []grpc.CallOption{ + grpc.MaxCallSendMsgSize(math.MaxInt32), + grpc.MaxCallRecvMsgSize(math.MaxInt32), +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_client.go b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_client.go new file mode 100644 index 0000000..305ee10 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_client.go @@ -0,0 +1,241 @@ +package plugin + +import ( + "context" + "errors" + "sync/atomic" + + "google.golang.org/grpc" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/plugin/pb" +) + +var ErrPluginShutdown = errors.New("plugin is shut down") + +// Validate backendGRPCPluginClient satisfies the logical.Backend interface +var _ logical.Backend = &backendGRPCPluginClient{} + +// backendPluginClient implements logical.Backend and is the +// go-plugin client. +type backendGRPCPluginClient struct { + broker *plugin.GRPCBroker + client pb.BackendClient + metadataMode bool + + system logical.SystemView + logger log.Logger + + // This is used to signal to the Cleanup function that it can proceed + // because we have a defined server + cleanupCh chan struct{} + + // server is the grpc server used for serving storage and sysview requests. + server *atomic.Value + + // clientConn is the underlying grpc connection to the server, we store it + // so it can be cleaned up. + clientConn *grpc.ClientConn + doneCtx context.Context +} + +func (b *backendGRPCPluginClient) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if b.metadataMode { + return nil, ErrClientInMetadataMode + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx) + defer close(quitCh) + defer cancel() + + protoReq, err := pb.LogicalRequestToProtoRequest(req) + if err != nil { + return nil, err + } + + reply, err := b.client.HandleRequest(ctx, &pb.HandleRequestArgs{ + Request: protoReq, + }, largeMsgGRPCCallOpts...) + if err != nil { + if b.doneCtx.Err() != nil { + return nil, ErrPluginShutdown + } + + return nil, err + } + resp, err := pb.ProtoResponseToLogicalResponse(reply.Response) + if err != nil { + return nil, err + } + if reply.Err != nil { + return resp, pb.ProtoErrToErr(reply.Err) + } + + return resp, nil +} + +func (b *backendGRPCPluginClient) SpecialPaths() *logical.Paths { + reply, err := b.client.SpecialPaths(b.doneCtx, &pb.Empty{}) + if err != nil { + return nil + } + + if reply.Paths == nil { + return nil + } + + return &logical.Paths{ + Root: reply.Paths.Root, + Unauthenticated: reply.Paths.Unauthenticated, + LocalStorage: reply.Paths.LocalStorage, + SealWrapStorage: reply.Paths.SealWrapStorage, + } +} + +// System returns vault's system view. The backend client stores the view during +// Setup, so there is no need to shim the system just to get it back. +func (b *backendGRPCPluginClient) System() logical.SystemView { + return b.system +} + +// Logger returns vault's logger. The backend client stores the logger during +// Setup, so there is no need to shim the logger just to get it back. +func (b *backendGRPCPluginClient) Logger() log.Logger { + return b.logger +} + +func (b *backendGRPCPluginClient) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) { + if b.metadataMode { + return false, false, ErrClientInMetadataMode + } + + protoReq, err := pb.LogicalRequestToProtoRequest(req) + if err != nil { + return false, false, err + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx) + defer close(quitCh) + defer cancel() + reply, err := b.client.HandleExistenceCheck(ctx, &pb.HandleExistenceCheckArgs{ + Request: protoReq, + }, largeMsgGRPCCallOpts...) + if err != nil { + if b.doneCtx.Err() != nil { + return false, false, ErrPluginShutdown + } + return false, false, err + } + if reply.Err != nil { + return false, false, pb.ProtoErrToErr(reply.Err) + } + + return reply.CheckFound, reply.Exists, nil +} + +func (b *backendGRPCPluginClient) Cleanup(ctx context.Context) { + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx) + defer close(quitCh) + defer cancel() + + b.client.Cleanup(ctx, &pb.Empty{}) + + // This will block until Setup has run the function to create a new server + // in b.server. If we stop here before it has a chance to actually start + // listening, when it starts listening it will immediatley error out and + // exit, which is fine. Overall this ensures that we do not miss stopping + // the server if it ends up being created after Cleanup is called. + <-b.cleanupCh + server := b.server.Load() + if server != nil { + server.(*grpc.Server).GracefulStop() + } + b.clientConn.Close() +} + +func (b *backendGRPCPluginClient) InvalidateKey(ctx context.Context, key string) { + if b.metadataMode { + return + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx) + defer close(quitCh) + defer cancel() + + b.client.InvalidateKey(ctx, &pb.InvalidateKeyArgs{ + Key: key, + }) +} + +func (b *backendGRPCPluginClient) Setup(ctx context.Context, config *logical.BackendConfig) error { + // Shim logical.Storage + storageImpl := config.StorageView + if b.metadataMode { + storageImpl = &NOOPStorage{} + } + storage := &GRPCStorageServer{ + impl: storageImpl, + } + + // Shim logical.SystemView + sysViewImpl := config.System + if b.metadataMode { + sysViewImpl = &logical.StaticSystemView{} + } + sysView := &gRPCSystemViewServer{ + impl: sysViewImpl, + } + + // Register the server in this closure. + serverFunc := func(opts []grpc.ServerOption) *grpc.Server { + s := grpc.NewServer(opts...) + pb.RegisterSystemViewServer(s, sysView) + pb.RegisterStorageServer(s, storage) + b.server.Store(s) + close(b.cleanupCh) + return s + } + brokerID := b.broker.NextId() + go b.broker.AcceptAndServe(brokerID, serverFunc) + + args := &pb.SetupArgs{ + BrokerID: brokerID, + Config: config.Config, + BackendUUID: config.BackendUUID, + } + + ctx, cancel := context.WithCancel(ctx) + quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx) + defer close(quitCh) + defer cancel() + + reply, err := b.client.Setup(ctx, args) + if err != nil { + return err + } + if reply.Err != "" { + return errors.New(reply.Err) + } + + // Set system and logger for getter methods + b.system = config.System + b.logger = config.Logger + + return nil +} + +func (b *backendGRPCPluginClient) Type() logical.BackendType { + reply, err := b.client.Type(b.doneCtx, &pb.Empty{}) + if err != nil { + return logical.TypeUnknown + } + + return logical.BackendType(reply.Type) +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_server.go b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_server.go new file mode 100644 index 0000000..7869a70 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_backend_server.go @@ -0,0 +1,142 @@ +package plugin + +import ( + "context" + + log "github.com/hashicorp/go-hclog" + plugin "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/plugin/pb" + "google.golang.org/grpc" +) + +type backendGRPCPluginServer struct { + broker *plugin.GRPCBroker + backend logical.Backend + + factory logical.Factory + + brokeredClient *grpc.ClientConn + + logger log.Logger +} + +// Setup dials into the plugin's broker to get a shimmed storage, logger, and +// system view of the backend. This method also instantiates the underlying +// backend through its factory func for the server side of the plugin. +func (b *backendGRPCPluginServer) Setup(ctx context.Context, args *pb.SetupArgs) (*pb.SetupReply, error) { + // Dial for storage + brokeredClient, err := b.broker.Dial(args.BrokerID) + if err != nil { + return &pb.SetupReply{}, err + } + b.brokeredClient = brokeredClient + storage := newGRPCStorageClient(brokeredClient) + sysView := newGRPCSystemView(brokeredClient) + + config := &logical.BackendConfig{ + StorageView: storage, + Logger: b.logger, + System: sysView, + Config: args.Config, + BackendUUID: args.BackendUUID, + } + + // Call the underlying backend factory after shims have been created + // to set b.backend + backend, err := b.factory(ctx, config) + if err != nil { + return &pb.SetupReply{ + Err: pb.ErrToString(err), + }, nil + } + b.backend = backend + + return &pb.SetupReply{}, nil +} + +func (b *backendGRPCPluginServer) HandleRequest(ctx context.Context, args *pb.HandleRequestArgs) (*pb.HandleRequestReply, error) { + if pluginutil.InMetadataMode() { + return &pb.HandleRequestReply{}, ErrServerInMetadataMode + } + + logicalReq, err := pb.ProtoRequestToLogicalRequest(args.Request) + if err != nil { + return &pb.HandleRequestReply{}, err + } + + logicalReq.Storage = newGRPCStorageClient(b.brokeredClient) + + resp, respErr := b.backend.HandleRequest(ctx, logicalReq) + + pbResp, err := pb.LogicalResponseToProtoResponse(resp) + if err != nil { + return &pb.HandleRequestReply{}, err + } + + return &pb.HandleRequestReply{ + Response: pbResp, + Err: pb.ErrToProtoErr(respErr), + }, nil +} + +func (b *backendGRPCPluginServer) SpecialPaths(ctx context.Context, args *pb.Empty) (*pb.SpecialPathsReply, error) { + paths := b.backend.SpecialPaths() + if paths == nil { + return &pb.SpecialPathsReply{ + Paths: nil, + }, nil + } + + return &pb.SpecialPathsReply{ + Paths: &pb.Paths{ + Root: paths.Root, + Unauthenticated: paths.Unauthenticated, + LocalStorage: paths.LocalStorage, + SealWrapStorage: paths.SealWrapStorage, + }, + }, nil +} + +func (b *backendGRPCPluginServer) HandleExistenceCheck(ctx context.Context, args *pb.HandleExistenceCheckArgs) (*pb.HandleExistenceCheckReply, error) { + if pluginutil.InMetadataMode() { + return &pb.HandleExistenceCheckReply{}, ErrServerInMetadataMode + } + + logicalReq, err := pb.ProtoRequestToLogicalRequest(args.Request) + if err != nil { + return &pb.HandleExistenceCheckReply{}, err + } + logicalReq.Storage = newGRPCStorageClient(b.brokeredClient) + + checkFound, exists, err := b.backend.HandleExistenceCheck(ctx, logicalReq) + return &pb.HandleExistenceCheckReply{ + CheckFound: checkFound, + Exists: exists, + Err: pb.ErrToProtoErr(err), + }, nil +} + +func (b *backendGRPCPluginServer) Cleanup(ctx context.Context, _ *pb.Empty) (*pb.Empty, error) { + b.backend.Cleanup(ctx) + + // Close rpc clients + b.brokeredClient.Close() + return &pb.Empty{}, nil +} + +func (b *backendGRPCPluginServer) InvalidateKey(ctx context.Context, args *pb.InvalidateKeyArgs) (*pb.Empty, error) { + if pluginutil.InMetadataMode() { + return &pb.Empty{}, ErrServerInMetadataMode + } + + b.backend.InvalidateKey(ctx, args.Key) + return &pb.Empty{}, nil +} + +func (b *backendGRPCPluginServer) Type(ctx context.Context, _ *pb.Empty) (*pb.TypeReply, error) { + return &pb.TypeReply{ + Type: uint32(b.backend.Type()), + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/grpc_storage.go b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_storage.go new file mode 100644 index 0000000..ffe1339 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_storage.go @@ -0,0 +1,110 @@ +package plugin + +import ( + "context" + "errors" + + "google.golang.org/grpc" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/plugin/pb" +) + +func newGRPCStorageClient(conn *grpc.ClientConn) *GRPCStorageClient { + return &GRPCStorageClient{ + client: pb.NewStorageClient(conn), + } +} + +// GRPCStorageClient is an implementation of logical.Storage that communicates +// over RPC. +type GRPCStorageClient struct { + client pb.StorageClient +} + +func (s *GRPCStorageClient) List(ctx context.Context, prefix string) ([]string, error) { + reply, err := s.client.List(ctx, &pb.StorageListArgs{ + Prefix: prefix, + }, largeMsgGRPCCallOpts...) + if err != nil { + return []string{}, err + } + if reply.Err != "" { + return reply.Keys, errors.New(reply.Err) + } + return reply.Keys, nil +} + +func (s *GRPCStorageClient) Get(ctx context.Context, key string) (*logical.StorageEntry, error) { + reply, err := s.client.Get(ctx, &pb.StorageGetArgs{ + Key: key, + }, largeMsgGRPCCallOpts...) + if err != nil { + return nil, err + } + if reply.Err != "" { + return nil, errors.New(reply.Err) + } + return pb.ProtoStorageEntryToLogicalStorageEntry(reply.Entry), nil +} + +func (s *GRPCStorageClient) Put(ctx context.Context, entry *logical.StorageEntry) error { + reply, err := s.client.Put(ctx, &pb.StoragePutArgs{ + Entry: pb.LogicalStorageEntryToProtoStorageEntry(entry), + }, largeMsgGRPCCallOpts...) + if err != nil { + return err + } + if reply.Err != "" { + return errors.New(reply.Err) + } + return nil +} + +func (s *GRPCStorageClient) Delete(ctx context.Context, key string) error { + reply, err := s.client.Delete(ctx, &pb.StorageDeleteArgs{ + Key: key, + }) + if err != nil { + return err + } + if reply.Err != "" { + return errors.New(reply.Err) + } + return nil +} + +// StorageServer is a net/rpc compatible structure for serving +type GRPCStorageServer struct { + impl logical.Storage +} + +func (s *GRPCStorageServer) List(ctx context.Context, args *pb.StorageListArgs) (*pb.StorageListReply, error) { + keys, err := s.impl.List(ctx, args.Prefix) + return &pb.StorageListReply{ + Keys: keys, + Err: pb.ErrToString(err), + }, nil +} + +func (s *GRPCStorageServer) Get(ctx context.Context, args *pb.StorageGetArgs) (*pb.StorageGetReply, error) { + storageEntry, err := s.impl.Get(ctx, args.Key) + return &pb.StorageGetReply{ + Entry: pb.LogicalStorageEntryToProtoStorageEntry(storageEntry), + Err: pb.ErrToString(err), + }, nil +} + +func (s *GRPCStorageServer) Put(ctx context.Context, args *pb.StoragePutArgs) (*pb.StoragePutReply, error) { + err := s.impl.Put(ctx, pb.ProtoStorageEntryToLogicalStorageEntry(args.Entry)) + return &pb.StoragePutReply{ + Err: pb.ErrToString(err), + }, nil +} + +func (s *GRPCStorageServer) Delete(ctx context.Context, args *pb.StorageDeleteArgs) (*pb.StorageDeleteReply, error) { + err := s.impl.Delete(ctx, args.Key) + return &pb.StorageDeleteReply{ + Err: pb.ErrToString(err), + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/grpc_system.go b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_system.go new file mode 100644 index 0000000..df8fa67 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/grpc_system.go @@ -0,0 +1,244 @@ +package plugin + +import ( + "context" + "encoding/json" + "errors" + "time" + + "google.golang.org/grpc" + + "fmt" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/plugin/pb" +) + +func newGRPCSystemView(conn *grpc.ClientConn) *gRPCSystemViewClient { + return &gRPCSystemViewClient{ + client: pb.NewSystemViewClient(conn), + } +} + +type gRPCSystemViewClient struct { + client pb.SystemViewClient +} + +func (s *gRPCSystemViewClient) DefaultLeaseTTL() time.Duration { + reply, err := s.client.DefaultLeaseTTL(context.Background(), &pb.Empty{}) + if err != nil { + return 0 + } + + return time.Duration(reply.TTL) +} + +func (s *gRPCSystemViewClient) MaxLeaseTTL() time.Duration { + reply, err := s.client.MaxLeaseTTL(context.Background(), &pb.Empty{}) + if err != nil { + return 0 + } + + return time.Duration(reply.TTL) +} + +func (s *gRPCSystemViewClient) SudoPrivilege(ctx context.Context, path string, token string) bool { + reply, err := s.client.SudoPrivilege(ctx, &pb.SudoPrivilegeArgs{ + Path: path, + Token: token, + }) + if err != nil { + return false + } + + return reply.Sudo +} + +func (s *gRPCSystemViewClient) Tainted() bool { + reply, err := s.client.Tainted(context.Background(), &pb.Empty{}) + if err != nil { + return false + } + + return reply.Tainted +} + +func (s *gRPCSystemViewClient) CachingDisabled() bool { + reply, err := s.client.CachingDisabled(context.Background(), &pb.Empty{}) + if err != nil { + return false + } + + return reply.Disabled +} + +func (s *gRPCSystemViewClient) ReplicationState() consts.ReplicationState { + reply, err := s.client.ReplicationState(context.Background(), &pb.Empty{}) + if err != nil { + return consts.ReplicationUnknown + } + + return consts.ReplicationState(reply.State) +} + +func (s *gRPCSystemViewClient) ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) { + buf, err := json.Marshal(data) + if err != nil { + return nil, err + } + + reply, err := s.client.ResponseWrapData(ctx, &pb.ResponseWrapDataArgs{ + Data: string(buf[:]), + TTL: int64(ttl), + JWT: false, + }) + if err != nil { + return nil, err + } + if reply.Err != "" { + return nil, errors.New(reply.Err) + } + + info, err := pb.ProtoResponseWrapInfoToLogicalResponseWrapInfo(reply.WrapInfo) + if err != nil { + return nil, err + } + + return info, nil +} + +func (s *gRPCSystemViewClient) LookupPlugin(ctx context.Context, name string) (*pluginutil.PluginRunner, error) { + return nil, fmt.Errorf("cannot call LookupPlugin from a plugin backend") +} + +func (s *gRPCSystemViewClient) MlockEnabled() bool { + reply, err := s.client.MlockEnabled(context.Background(), &pb.Empty{}) + if err != nil { + return false + } + + return reply.Enabled +} + +func (s *gRPCSystemViewClient) LocalMount() bool { + reply, err := s.client.LocalMount(context.Background(), &pb.Empty{}) + if err != nil { + return false + } + + return reply.Local +} + +func (s *gRPCSystemViewClient) EntityInfo(entityID string) (*logical.Entity, error) { + reply, err := s.client.EntityInfo(context.Background(), &pb.EntityInfoArgs{ + EntityID: entityID, + }) + if err != nil { + return nil, err + } + if reply.Err != "" { + return nil, errors.New(reply.Err) + } + + return reply.Entity, nil +} + +type gRPCSystemViewServer struct { + impl logical.SystemView +} + +func (s *gRPCSystemViewServer) DefaultLeaseTTL(ctx context.Context, _ *pb.Empty) (*pb.TTLReply, error) { + ttl := s.impl.DefaultLeaseTTL() + return &pb.TTLReply{ + TTL: int64(ttl), + }, nil +} + +func (s *gRPCSystemViewServer) MaxLeaseTTL(ctx context.Context, _ *pb.Empty) (*pb.TTLReply, error) { + ttl := s.impl.MaxLeaseTTL() + return &pb.TTLReply{ + TTL: int64(ttl), + }, nil +} + +func (s *gRPCSystemViewServer) SudoPrivilege(ctx context.Context, args *pb.SudoPrivilegeArgs) (*pb.SudoPrivilegeReply, error) { + sudo := s.impl.SudoPrivilege(ctx, args.Path, args.Token) + return &pb.SudoPrivilegeReply{ + Sudo: sudo, + }, nil +} + +func (s *gRPCSystemViewServer) Tainted(ctx context.Context, _ *pb.Empty) (*pb.TaintedReply, error) { + tainted := s.impl.Tainted() + return &pb.TaintedReply{ + Tainted: tainted, + }, nil +} + +func (s *gRPCSystemViewServer) CachingDisabled(ctx context.Context, _ *pb.Empty) (*pb.CachingDisabledReply, error) { + cachingDisabled := s.impl.CachingDisabled() + return &pb.CachingDisabledReply{ + Disabled: cachingDisabled, + }, nil +} + +func (s *gRPCSystemViewServer) ReplicationState(ctx context.Context, _ *pb.Empty) (*pb.ReplicationStateReply, error) { + replicationState := s.impl.ReplicationState() + return &pb.ReplicationStateReply{ + State: int32(replicationState), + }, nil +} + +func (s *gRPCSystemViewServer) ResponseWrapData(ctx context.Context, args *pb.ResponseWrapDataArgs) (*pb.ResponseWrapDataReply, error) { + data := map[string]interface{}{} + err := json.Unmarshal([]byte(args.Data), &data) + if err != nil { + return &pb.ResponseWrapDataReply{}, err + } + + // Do not allow JWTs to be returned + info, err := s.impl.ResponseWrapData(ctx, data, time.Duration(args.TTL), false) + if err != nil { + return &pb.ResponseWrapDataReply{ + Err: pb.ErrToString(err), + }, nil + } + + pbInfo, err := pb.LogicalResponseWrapInfoToProtoResponseWrapInfo(info) + if err != nil { + return &pb.ResponseWrapDataReply{}, err + } + + return &pb.ResponseWrapDataReply{ + WrapInfo: pbInfo, + }, nil +} + +func (s *gRPCSystemViewServer) MlockEnabled(ctx context.Context, _ *pb.Empty) (*pb.MlockEnabledReply, error) { + enabled := s.impl.MlockEnabled() + return &pb.MlockEnabledReply{ + Enabled: enabled, + }, nil +} + +func (s *gRPCSystemViewServer) LocalMount(ctx context.Context, _ *pb.Empty) (*pb.LocalMountReply, error) { + local := s.impl.LocalMount() + return &pb.LocalMountReply{ + Local: local, + }, nil +} + +func (s *gRPCSystemViewServer) EntityInfo(ctx context.Context, args *pb.EntityInfoArgs) (*pb.EntityInfoReply, error) { + entity, err := s.impl.EntityInfo(args.EntityID) + if err != nil { + return &pb.EntityInfoReply{ + Err: pb.ErrToString(err), + }, nil + } + return &pb.EntityInfoReply{ + Entity: entity, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/logger.go b/vendor/github.com/hashicorp/vault/logical/plugin/logger.go new file mode 100644 index 0000000..a59a8a3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/logger.go @@ -0,0 +1,134 @@ +package plugin + +import hclog "github.com/hashicorp/go-hclog" + +type LoggerServer struct { + logger hclog.Logger +} + +func (l *LoggerServer) Trace(args *LoggerArgs, _ *struct{}) error { + l.logger.Trace(args.Msg, args.Args...) + return nil +} + +func (l *LoggerServer) Debug(args *LoggerArgs, _ *struct{}) error { + l.logger.Debug(args.Msg, args.Args...) + return nil +} + +func (l *LoggerServer) Info(args *LoggerArgs, _ *struct{}) error { + l.logger.Info(args.Msg, args.Args...) + return nil +} + +func (l *LoggerServer) Warn(args *LoggerArgs, reply *LoggerReply) error { + l.logger.Warn(args.Msg, args.Args...) + return nil +} + +func (l *LoggerServer) Error(args *LoggerArgs, reply *LoggerReply) error { + l.logger.Error(args.Msg, args.Args...) + return nil +} + +func (l *LoggerServer) Log(args *LoggerArgs, _ *struct{}) error { + + switch translateLevel(args.Level) { + + case hclog.Trace: + l.logger.Trace(args.Msg, args.Args...) + + case hclog.Debug: + l.logger.Debug(args.Msg, args.Args...) + + case hclog.Info: + l.logger.Info(args.Msg, args.Args...) + + case hclog.Warn: + l.logger.Warn(args.Msg, args.Args...) + + case hclog.Error: + l.logger.Error(args.Msg, args.Args...) + + case hclog.NoLevel: + } + return nil +} + +func (l *LoggerServer) SetLevel(args int, _ *struct{}) error { + level := translateLevel(args) + l.logger = hclog.New(&hclog.LoggerOptions{Level: level}) + return nil +} + +func (l *LoggerServer) IsTrace(args interface{}, reply *LoggerReply) error { + result := l.logger.IsTrace() + *reply = LoggerReply{ + IsTrue: result, + } + return nil +} + +func (l *LoggerServer) IsDebug(args interface{}, reply *LoggerReply) error { + result := l.logger.IsDebug() + *reply = LoggerReply{ + IsTrue: result, + } + return nil +} + +func (l *LoggerServer) IsInfo(args interface{}, reply *LoggerReply) error { + result := l.logger.IsInfo() + *reply = LoggerReply{ + IsTrue: result, + } + return nil +} + +func (l *LoggerServer) IsWarn(args interface{}, reply *LoggerReply) error { + result := l.logger.IsWarn() + *reply = LoggerReply{ + IsTrue: result, + } + return nil +} + +type LoggerArgs struct { + Level int + Msg string + Args []interface{} +} + +// LoggerReply contains the RPC reply. Not all fields may be used +// for a particular RPC call. +type LoggerReply struct { + IsTrue bool + Error error +} + +func translateLevel(logxiLevel int) hclog.Level { + + switch logxiLevel { + + case 1000, 10: + // logxi.LevelAll, logxi.LevelTrace: + return hclog.Trace + + case 7: + // logxi.LevelDebug: + return hclog.Debug + + case 6, 5: + // logxi.LevelInfo, logxi.LevelNotice: + return hclog.Info + + case 4: + // logxi.LevelWarn: + return hclog.Warn + + case 3, 2, 1, -1: + // logxi.LevelError, logxi.LevelFatal, logxi.LevelAlert, logxi.LevelEmergency: + return hclog.Error + } + return hclog.NoLevel +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/middleware.go b/vendor/github.com/hashicorp/vault/logical/plugin/middleware.go new file mode 100644 index 0000000..d9aeed0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/middleware.go @@ -0,0 +1,91 @@ +package plugin + +import ( + "context" + "time" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/logical" +) + +// backendPluginClient implements logical.Backend and is the +// go-plugin client. +type backendTracingMiddleware struct { + logger log.Logger + + next logical.Backend +} + +// Validate the backendTracingMiddle object satisfies the backend interface +var _ logical.Backend = &backendTracingMiddleware{} + +func (b *backendTracingMiddleware) HandleRequest(ctx context.Context, req *logical.Request) (resp *logical.Response, err error) { + defer func(then time.Time) { + b.logger.Trace("handle request", "path", req.Path, "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("handle request", "path", req.Path, "status", "started") + return b.next.HandleRequest(ctx, req) +} + +func (b *backendTracingMiddleware) SpecialPaths() *logical.Paths { + defer func(then time.Time) { + b.logger.Trace("special paths", "status", "finished", "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("special paths", "status", "started") + return b.next.SpecialPaths() +} + +func (b *backendTracingMiddleware) System() logical.SystemView { + return b.next.System() +} + +func (b *backendTracingMiddleware) Logger() log.Logger { + return b.next.Logger() +} + +func (b *backendTracingMiddleware) HandleExistenceCheck(ctx context.Context, req *logical.Request) (found bool, exists bool, err error) { + defer func(then time.Time) { + b.logger.Trace("handle existence check", "path", req.Path, "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("handle existence check", "path", req.Path, "status", "started") + return b.next.HandleExistenceCheck(ctx, req) +} + +func (b *backendTracingMiddleware) Cleanup(ctx context.Context) { + defer func(then time.Time) { + b.logger.Trace("cleanup", "status", "finished", "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("cleanup", "status", "started") + b.next.Cleanup(ctx) +} + +func (b *backendTracingMiddleware) InvalidateKey(ctx context.Context, key string) { + defer func(then time.Time) { + b.logger.Trace("invalidate key", "key", key, "status", "finished", "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("invalidate key", "key", key, "status", "started") + b.next.InvalidateKey(ctx, key) +} + +func (b *backendTracingMiddleware) Setup(ctx context.Context, config *logical.BackendConfig) (err error) { + defer func(then time.Time) { + b.logger.Trace("setup", "status", "finished", "err", err, "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("setup", "status", "started") + return b.next.Setup(ctx, config) +} + +func (b *backendTracingMiddleware) Type() logical.BackendType { + defer func(then time.Time) { + b.logger.Trace("type", "status", "finished", "took", time.Since(then)) + }(time.Now()) + + b.logger.Trace("type", "status", "started") + return b.next.Type() +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.pb.go b/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.pb.go new file mode 100644 index 0000000..85596c1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.pb.go @@ -0,0 +1,3434 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: logical/plugin/pb/backend.proto + +package pb // import "github.com/hashicorp/vault/logical/plugin/pb" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" +import logical "github.com/hashicorp/vault/logical" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{0} +} +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (dst *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(dst, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo + +type Header struct { + Header []string `sentinel:"" protobuf:"bytes,1,rep,name=header" json:"header,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{1} +} +func (m *Header) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Header.Unmarshal(m, b) +} +func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Header.Marshal(b, m, deterministic) +} +func (dst *Header) XXX_Merge(src proto.Message) { + xxx_messageInfo_Header.Merge(dst, src) +} +func (m *Header) XXX_Size() int { + return xxx_messageInfo_Header.Size(m) +} +func (m *Header) XXX_DiscardUnknown() { + xxx_messageInfo_Header.DiscardUnknown(m) +} + +var xxx_messageInfo_Header proto.InternalMessageInfo + +func (m *Header) GetHeader() []string { + if m != nil { + return m.Header + } + return nil +} + +type ProtoError struct { + // Error type can be one of: + // ErrTypeUnknown uint32 = iota + // ErrTypeUserError + // ErrTypeInternalError + // ErrTypeCodedError + // ErrTypeStatusBadRequest + // ErrTypeUnsupportedOperation + // ErrTypeUnsupportedPath + // ErrTypeInvalidRequest + // ErrTypePermissionDenied + // ErrTypeMultiAuthzPending + ErrType uint32 `sentinel:"" protobuf:"varint,1,opt,name=err_type,json=errType" json:"err_type,omitempty"` + ErrMsg string `sentinel:"" protobuf:"bytes,2,opt,name=err_msg,json=errMsg" json:"err_msg,omitempty"` + ErrCode int64 `sentinel:"" protobuf:"varint,3,opt,name=err_code,json=errCode" json:"err_code,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ProtoError) Reset() { *m = ProtoError{} } +func (m *ProtoError) String() string { return proto.CompactTextString(m) } +func (*ProtoError) ProtoMessage() {} +func (*ProtoError) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{2} +} +func (m *ProtoError) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ProtoError.Unmarshal(m, b) +} +func (m *ProtoError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ProtoError.Marshal(b, m, deterministic) +} +func (dst *ProtoError) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProtoError.Merge(dst, src) +} +func (m *ProtoError) XXX_Size() int { + return xxx_messageInfo_ProtoError.Size(m) +} +func (m *ProtoError) XXX_DiscardUnknown() { + xxx_messageInfo_ProtoError.DiscardUnknown(m) +} + +var xxx_messageInfo_ProtoError proto.InternalMessageInfo + +func (m *ProtoError) GetErrType() uint32 { + if m != nil { + return m.ErrType + } + return 0 +} + +func (m *ProtoError) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *ProtoError) GetErrCode() int64 { + if m != nil { + return m.ErrCode + } + return 0 +} + +// Paths is the structure of special paths that is used for SpecialPaths. +type Paths struct { + // Root are the paths that require a root token to access + Root []string `sentinel:"" protobuf:"bytes,1,rep,name=root" json:"root,omitempty"` + // Unauthenticated are the paths that can be accessed without any auth. + Unauthenticated []string `sentinel:"" protobuf:"bytes,2,rep,name=unauthenticated" json:"unauthenticated,omitempty"` + // LocalStorage are paths (prefixes) that are local to this instance; this + // indicates that these paths should not be replicated + LocalStorage []string `sentinel:"" protobuf:"bytes,3,rep,name=local_storage,json=localStorage" json:"local_storage,omitempty"` + // SealWrapStorage are storage paths that, when using a capable seal, + // should be seal wrapped with extra encryption. It is exact matching + // unless it ends with '/' in which case it will be treated as a prefix. + SealWrapStorage []string `sentinel:"" protobuf:"bytes,4,rep,name=seal_wrap_storage,json=sealWrapStorage" json:"seal_wrap_storage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Paths) Reset() { *m = Paths{} } +func (m *Paths) String() string { return proto.CompactTextString(m) } +func (*Paths) ProtoMessage() {} +func (*Paths) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{3} +} +func (m *Paths) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Paths.Unmarshal(m, b) +} +func (m *Paths) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Paths.Marshal(b, m, deterministic) +} +func (dst *Paths) XXX_Merge(src proto.Message) { + xxx_messageInfo_Paths.Merge(dst, src) +} +func (m *Paths) XXX_Size() int { + return xxx_messageInfo_Paths.Size(m) +} +func (m *Paths) XXX_DiscardUnknown() { + xxx_messageInfo_Paths.DiscardUnknown(m) +} + +var xxx_messageInfo_Paths proto.InternalMessageInfo + +func (m *Paths) GetRoot() []string { + if m != nil { + return m.Root + } + return nil +} + +func (m *Paths) GetUnauthenticated() []string { + if m != nil { + return m.Unauthenticated + } + return nil +} + +func (m *Paths) GetLocalStorage() []string { + if m != nil { + return m.LocalStorage + } + return nil +} + +func (m *Paths) GetSealWrapStorage() []string { + if m != nil { + return m.SealWrapStorage + } + return nil +} + +type Request struct { + // ID is the uuid associated with each request + ID string `sentinel:"" protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + // If set, the name given to the replication secondary where this request + // originated + ReplicationCluster string `sentinel:"" protobuf:"bytes,2,opt,name=ReplicationCluster" json:"ReplicationCluster,omitempty"` + // Operation is the requested operation type + Operation string `sentinel:"" protobuf:"bytes,3,opt,name=operation" json:"operation,omitempty"` + // Path is the part of the request path not consumed by the + // routing. As an example, if the original request path is "prod/aws/foo" + // and the AWS logical backend is mounted at "prod/aws/", then the + // final path is "foo" since the mount prefix is trimmed. + Path string `sentinel:"" protobuf:"bytes,4,opt,name=path" json:"path,omitempty"` + // Request data is a JSON object that must have keys with string type. + Data string `sentinel:"" protobuf:"bytes,5,opt,name=data" json:"data,omitempty"` + // Secret will be non-nil only for Revoke and Renew operations + // to represent the secret that was returned prior. + Secret *Secret `sentinel:"" protobuf:"bytes,6,opt,name=secret" json:"secret,omitempty"` + // Auth will be non-nil only for Renew operations + // to represent the auth that was returned prior. + Auth *Auth `sentinel:"" protobuf:"bytes,7,opt,name=auth" json:"auth,omitempty"` + // Headers will contain the http headers from the request. This value will + // be used in the audit broker to ensure we are auditing only the allowed + // headers. + Headers map[string]*Header `sentinel:"" protobuf:"bytes,8,rep,name=headers" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // ClientToken is provided to the core so that the identity + // can be verified and ACLs applied. This value is passed + // through to the logical backends but after being salted and + // hashed. + ClientToken string `sentinel:"" protobuf:"bytes,9,opt,name=client_token,json=clientToken" json:"client_token,omitempty"` + // ClientTokenAccessor is provided to the core so that the it can get + // logged as part of request audit logging. + ClientTokenAccessor string `sentinel:"" protobuf:"bytes,10,opt,name=client_token_accessor,json=clientTokenAccessor" json:"client_token_accessor,omitempty"` + // DisplayName is provided to the logical backend to help associate + // dynamic secrets with the source entity. This is not a sensitive + // name, but is useful for operators. + DisplayName string `sentinel:"" protobuf:"bytes,11,opt,name=display_name,json=displayName" json:"display_name,omitempty"` + // MountPoint is provided so that a logical backend can generate + // paths relative to itself. The `Path` is effectively the client + // request path with the MountPoint trimmed off. + MountPoint string `sentinel:"" protobuf:"bytes,12,opt,name=mount_point,json=mountPoint" json:"mount_point,omitempty"` + // MountType is provided so that a logical backend can make decisions + // based on the specific mount type (e.g., if a mount type has different + // aliases, generating different defaults depending on the alias) + MountType string `sentinel:"" protobuf:"bytes,13,opt,name=mount_type,json=mountType" json:"mount_type,omitempty"` + // MountAccessor is provided so that identities returned by the authentication + // backends can be tied to the mount it belongs to. + MountAccessor string `sentinel:"" protobuf:"bytes,14,opt,name=mount_accessor,json=mountAccessor" json:"mount_accessor,omitempty"` + // WrapInfo contains requested response wrapping parameters + WrapInfo *RequestWrapInfo `sentinel:"" protobuf:"bytes,15,opt,name=wrap_info,json=wrapInfo" json:"wrap_info,omitempty"` + // ClientTokenRemainingUses represents the allowed number of uses left on the + // token supplied + ClientTokenRemainingUses int64 `sentinel:"" protobuf:"varint,16,opt,name=client_token_remaining_uses,json=clientTokenRemainingUses" json:"client_token_remaining_uses,omitempty"` + // EntityID is the identity of the caller extracted out of the token used + // to make this request + EntityID string `sentinel:"" protobuf:"bytes,17,opt,name=entity_id,json=entityId" json:"entity_id,omitempty"` + // PolicyOverride indicates that the requestor wishes to override + // soft-mandatory Sentinel policies + PolicyOverride bool `sentinel:"" protobuf:"varint,18,opt,name=policy_override,json=policyOverride" json:"policy_override,omitempty"` + // Whether the request is unauthenticated, as in, had no client token + // attached. Useful in some situations where the client token is not made + // accessible. + Unauthenticated bool `sentinel:"" protobuf:"varint,19,opt,name=unauthenticated" json:"unauthenticated,omitempty"` + // Connection will be non-nil only for credential providers to + // inspect the connection information and potentially use it for + // authentication/protection. + Connection *Connection `sentinel:"" protobuf:"bytes,20,opt,name=connection" json:"connection,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{4} +} +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (dst *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(dst, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *Request) GetReplicationCluster() string { + if m != nil { + return m.ReplicationCluster + } + return "" +} + +func (m *Request) GetOperation() string { + if m != nil { + return m.Operation + } + return "" +} + +func (m *Request) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *Request) GetData() string { + if m != nil { + return m.Data + } + return "" +} + +func (m *Request) GetSecret() *Secret { + if m != nil { + return m.Secret + } + return nil +} + +func (m *Request) GetAuth() *Auth { + if m != nil { + return m.Auth + } + return nil +} + +func (m *Request) GetHeaders() map[string]*Header { + if m != nil { + return m.Headers + } + return nil +} + +func (m *Request) GetClientToken() string { + if m != nil { + return m.ClientToken + } + return "" +} + +func (m *Request) GetClientTokenAccessor() string { + if m != nil { + return m.ClientTokenAccessor + } + return "" +} + +func (m *Request) GetDisplayName() string { + if m != nil { + return m.DisplayName + } + return "" +} + +func (m *Request) GetMountPoint() string { + if m != nil { + return m.MountPoint + } + return "" +} + +func (m *Request) GetMountType() string { + if m != nil { + return m.MountType + } + return "" +} + +func (m *Request) GetMountAccessor() string { + if m != nil { + return m.MountAccessor + } + return "" +} + +func (m *Request) GetWrapInfo() *RequestWrapInfo { + if m != nil { + return m.WrapInfo + } + return nil +} + +func (m *Request) GetClientTokenRemainingUses() int64 { + if m != nil { + return m.ClientTokenRemainingUses + } + return 0 +} + +func (m *Request) GetEntityID() string { + if m != nil { + return m.EntityID + } + return "" +} + +func (m *Request) GetPolicyOverride() bool { + if m != nil { + return m.PolicyOverride + } + return false +} + +func (m *Request) GetUnauthenticated() bool { + if m != nil { + return m.Unauthenticated + } + return false +} + +func (m *Request) GetConnection() *Connection { + if m != nil { + return m.Connection + } + return nil +} + +type Auth struct { + LeaseOptions *LeaseOptions `sentinel:"" protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions" json:"lease_options,omitempty"` + // InternalData is a JSON object that is stored with the auth struct. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + InternalData string `sentinel:"" protobuf:"bytes,2,opt,name=internal_data,json=internalData" json:"internal_data,omitempty"` + // DisplayName is a non-security sensitive identifier that is + // applicable to this Auth. It is used for logging and prefixing + // of dynamic secrets. For example, DisplayName may be "armon" for + // the github credential backend. If the client token is used to + // generate a SQL credential, the user may be "github-armon-uuid". + // This is to help identify the source without using audit tables. + DisplayName string `sentinel:"" protobuf:"bytes,3,opt,name=display_name,json=displayName" json:"display_name,omitempty"` + // Policies is the list of policies that the authenticated user + // is associated with. + Policies []string `sentinel:"" protobuf:"bytes,4,rep,name=policies" json:"policies,omitempty"` + // Metadata is used to attach arbitrary string-type metadata to + // an authenticated user. This metadata will be outputted into the + // audit log. + Metadata map[string]string `sentinel:"" protobuf:"bytes,5,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // ClientToken is the token that is generated for the authentication. + // This will be filled in by Vault core when an auth structure is + // returned. Setting this manually will have no effect. + ClientToken string `sentinel:"" protobuf:"bytes,6,opt,name=client_token,json=clientToken" json:"client_token,omitempty"` + // Accessor is the identifier for the ClientToken. This can be used + // to perform management functionalities (especially revocation) when + // ClientToken in the audit logs are obfuscated. Accessor can be used + // to revoke a ClientToken and to lookup the capabilities of the ClientToken, + // both without actually knowing the ClientToken. + Accessor string `sentinel:"" protobuf:"bytes,7,opt,name=accessor" json:"accessor,omitempty"` + // Period indicates that the token generated using this Auth object + // should never expire. The token should be renewed within the duration + // specified by this period. + Period int64 `sentinel:"" protobuf:"varint,8,opt,name=period" json:"period,omitempty"` + // Number of allowed uses of the issued token + NumUses int64 `sentinel:"" protobuf:"varint,9,opt,name=num_uses,json=numUses" json:"num_uses,omitempty"` + // EntityID is the identifier of the entity in identity store to which the + // identity of the authenticating client belongs to. + EntityID string `sentinel:"" protobuf:"bytes,10,opt,name=entity_id,json=entityId" json:"entity_id,omitempty"` + // Alias is the information about the authenticated client returned by + // the auth backend + Alias *logical.Alias `sentinel:"" protobuf:"bytes,11,opt,name=alias" json:"alias,omitempty"` + // GroupAliases are the informational mappings of external groups which an + // authenticated user belongs to. This is used to check if there are + // mappings groups for the group aliases in identity store. For all the + // matching groups, the entity ID of the user will be added. + GroupAliases []*logical.Alias `sentinel:"" protobuf:"bytes,12,rep,name=group_aliases,json=groupAliases" json:"group_aliases,omitempty"` + // If set, restricts usage of the certificates to client IPs falling within + // the range of the specified CIDR(s). + BoundCidrs []string `sentinel:"" protobuf:"bytes,13,rep,name=bound_cidrs,json=boundCidrs" json:"bound_cidrs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Auth) Reset() { *m = Auth{} } +func (m *Auth) String() string { return proto.CompactTextString(m) } +func (*Auth) ProtoMessage() {} +func (*Auth) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{5} +} +func (m *Auth) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Auth.Unmarshal(m, b) +} +func (m *Auth) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Auth.Marshal(b, m, deterministic) +} +func (dst *Auth) XXX_Merge(src proto.Message) { + xxx_messageInfo_Auth.Merge(dst, src) +} +func (m *Auth) XXX_Size() int { + return xxx_messageInfo_Auth.Size(m) +} +func (m *Auth) XXX_DiscardUnknown() { + xxx_messageInfo_Auth.DiscardUnknown(m) +} + +var xxx_messageInfo_Auth proto.InternalMessageInfo + +func (m *Auth) GetLeaseOptions() *LeaseOptions { + if m != nil { + return m.LeaseOptions + } + return nil +} + +func (m *Auth) GetInternalData() string { + if m != nil { + return m.InternalData + } + return "" +} + +func (m *Auth) GetDisplayName() string { + if m != nil { + return m.DisplayName + } + return "" +} + +func (m *Auth) GetPolicies() []string { + if m != nil { + return m.Policies + } + return nil +} + +func (m *Auth) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *Auth) GetClientToken() string { + if m != nil { + return m.ClientToken + } + return "" +} + +func (m *Auth) GetAccessor() string { + if m != nil { + return m.Accessor + } + return "" +} + +func (m *Auth) GetPeriod() int64 { + if m != nil { + return m.Period + } + return 0 +} + +func (m *Auth) GetNumUses() int64 { + if m != nil { + return m.NumUses + } + return 0 +} + +func (m *Auth) GetEntityID() string { + if m != nil { + return m.EntityID + } + return "" +} + +func (m *Auth) GetAlias() *logical.Alias { + if m != nil { + return m.Alias + } + return nil +} + +func (m *Auth) GetGroupAliases() []*logical.Alias { + if m != nil { + return m.GroupAliases + } + return nil +} + +func (m *Auth) GetBoundCidrs() []string { + if m != nil { + return m.BoundCidrs + } + return nil +} + +type LeaseOptions struct { + TTL int64 `sentinel:"" protobuf:"varint,1,opt,name=TTL" json:"TTL,omitempty"` + Renewable bool `sentinel:"" protobuf:"varint,2,opt,name=renewable" json:"renewable,omitempty"` + Increment int64 `sentinel:"" protobuf:"varint,3,opt,name=increment" json:"increment,omitempty"` + IssueTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,4,opt,name=issue_time,json=issueTime" json:"issue_time,omitempty"` + MaxTTL int64 `sentinel:"" protobuf:"varint,5,opt,name=MaxTTL" json:"MaxTTL,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LeaseOptions) Reset() { *m = LeaseOptions{} } +func (m *LeaseOptions) String() string { return proto.CompactTextString(m) } +func (*LeaseOptions) ProtoMessage() {} +func (*LeaseOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{6} +} +func (m *LeaseOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LeaseOptions.Unmarshal(m, b) +} +func (m *LeaseOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LeaseOptions.Marshal(b, m, deterministic) +} +func (dst *LeaseOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_LeaseOptions.Merge(dst, src) +} +func (m *LeaseOptions) XXX_Size() int { + return xxx_messageInfo_LeaseOptions.Size(m) +} +func (m *LeaseOptions) XXX_DiscardUnknown() { + xxx_messageInfo_LeaseOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_LeaseOptions proto.InternalMessageInfo + +func (m *LeaseOptions) GetTTL() int64 { + if m != nil { + return m.TTL + } + return 0 +} + +func (m *LeaseOptions) GetRenewable() bool { + if m != nil { + return m.Renewable + } + return false +} + +func (m *LeaseOptions) GetIncrement() int64 { + if m != nil { + return m.Increment + } + return 0 +} + +func (m *LeaseOptions) GetIssueTime() *timestamp.Timestamp { + if m != nil { + return m.IssueTime + } + return nil +} + +func (m *LeaseOptions) GetMaxTTL() int64 { + if m != nil { + return m.MaxTTL + } + return 0 +} + +type Secret struct { + LeaseOptions *LeaseOptions `sentinel:"" protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions" json:"lease_options,omitempty"` + // InternalData is a JSON object that is stored with the secret. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + InternalData string `sentinel:"" protobuf:"bytes,2,opt,name=internal_data,json=internalData" json:"internal_data,omitempty"` + // LeaseID is the ID returned to the user to manage this secret. + // This is generated by Vault core. Any set value will be ignored. + // For requests, this will always be blank. + LeaseID string `sentinel:"" protobuf:"bytes,3,opt,name=lease_id,json=leaseId" json:"lease_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Secret) Reset() { *m = Secret{} } +func (m *Secret) String() string { return proto.CompactTextString(m) } +func (*Secret) ProtoMessage() {} +func (*Secret) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{7} +} +func (m *Secret) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Secret.Unmarshal(m, b) +} +func (m *Secret) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Secret.Marshal(b, m, deterministic) +} +func (dst *Secret) XXX_Merge(src proto.Message) { + xxx_messageInfo_Secret.Merge(dst, src) +} +func (m *Secret) XXX_Size() int { + return xxx_messageInfo_Secret.Size(m) +} +func (m *Secret) XXX_DiscardUnknown() { + xxx_messageInfo_Secret.DiscardUnknown(m) +} + +var xxx_messageInfo_Secret proto.InternalMessageInfo + +func (m *Secret) GetLeaseOptions() *LeaseOptions { + if m != nil { + return m.LeaseOptions + } + return nil +} + +func (m *Secret) GetInternalData() string { + if m != nil { + return m.InternalData + } + return "" +} + +func (m *Secret) GetLeaseID() string { + if m != nil { + return m.LeaseID + } + return "" +} + +type Response struct { + // Secret, if not nil, denotes that this response represents a secret. + Secret *Secret `sentinel:"" protobuf:"bytes,1,opt,name=secret" json:"secret,omitempty"` + // Auth, if not nil, contains the authentication information for + // this response. This is only checked and means something for + // credential backends. + Auth *Auth `sentinel:"" protobuf:"bytes,2,opt,name=auth" json:"auth,omitempty"` + // Response data is a JSON object that must have string keys. For + // secrets, this data is sent down to the user as-is. To store internal + // data that you don't want the user to see, store it in + // Secret.InternalData. + Data string `sentinel:"" protobuf:"bytes,3,opt,name=data" json:"data,omitempty"` + // Redirect is an HTTP URL to redirect to for further authentication. + // This is only valid for credential backends. This will be blanked + // for any logical backend and ignored. + Redirect string `sentinel:"" protobuf:"bytes,4,opt,name=redirect" json:"redirect,omitempty"` + // Warnings allow operations or backends to return warnings in response + // to user actions without failing the action outright. + Warnings []string `sentinel:"" protobuf:"bytes,5,rep,name=warnings" json:"warnings,omitempty"` + // Information for wrapping the response in a cubbyhole + WrapInfo *ResponseWrapInfo `sentinel:"" protobuf:"bytes,6,opt,name=wrap_info,json=wrapInfo" json:"wrap_info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{8} +} +func (m *Response) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Response.Unmarshal(m, b) +} +func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Response.Marshal(b, m, deterministic) +} +func (dst *Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_Response.Merge(dst, src) +} +func (m *Response) XXX_Size() int { + return xxx_messageInfo_Response.Size(m) +} +func (m *Response) XXX_DiscardUnknown() { + xxx_messageInfo_Response.DiscardUnknown(m) +} + +var xxx_messageInfo_Response proto.InternalMessageInfo + +func (m *Response) GetSecret() *Secret { + if m != nil { + return m.Secret + } + return nil +} + +func (m *Response) GetAuth() *Auth { + if m != nil { + return m.Auth + } + return nil +} + +func (m *Response) GetData() string { + if m != nil { + return m.Data + } + return "" +} + +func (m *Response) GetRedirect() string { + if m != nil { + return m.Redirect + } + return "" +} + +func (m *Response) GetWarnings() []string { + if m != nil { + return m.Warnings + } + return nil +} + +func (m *Response) GetWrapInfo() *ResponseWrapInfo { + if m != nil { + return m.WrapInfo + } + return nil +} + +type ResponseWrapInfo struct { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + TTL int64 `sentinel:"" protobuf:"varint,1,opt,name=TTL" json:"TTL,omitempty"` + // The token containing the wrapped response + Token string `sentinel:"" protobuf:"bytes,2,opt,name=token" json:"token,omitempty"` + // The token accessor for the wrapped response token + Accessor string `sentinel:"" protobuf:"bytes,3,opt,name=accessor" json:"accessor,omitempty"` + // The creation time. This can be used with the TTL to figure out an + // expected expiration. + CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,4,opt,name=creation_time,json=creationTime" json:"creation_time,omitempty"` + // If the contained response is the output of a token creation call, the + // created token's accessor will be accessible here + WrappedAccessor string `sentinel:"" protobuf:"bytes,5,opt,name=wrapped_accessor,json=wrappedAccessor" json:"wrapped_accessor,omitempty"` + // WrappedEntityID is the entity identifier of the caller who initiated the + // wrapping request + WrappedEntityID string `sentinel:"" protobuf:"bytes,6,opt,name=wrapped_entity_id,json=wrappedEntityID" json:"wrapped_entity_id,omitempty"` + // The format to use. This doesn't get returned, it's only internal. + Format string `sentinel:"" protobuf:"bytes,7,opt,name=format" json:"format,omitempty"` + // CreationPath is the original request path that was used to create + // the wrapped response. + CreationPath string `sentinel:"" protobuf:"bytes,8,opt,name=creation_path,json=creationPath" json:"creation_path,omitempty"` + // Controls seal wrapping behavior downstream for specific use cases + SealWrap bool `sentinel:"" protobuf:"varint,9,opt,name=seal_wrap,json=sealWrap" json:"seal_wrap,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseWrapInfo) Reset() { *m = ResponseWrapInfo{} } +func (m *ResponseWrapInfo) String() string { return proto.CompactTextString(m) } +func (*ResponseWrapInfo) ProtoMessage() {} +func (*ResponseWrapInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{9} +} +func (m *ResponseWrapInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseWrapInfo.Unmarshal(m, b) +} +func (m *ResponseWrapInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseWrapInfo.Marshal(b, m, deterministic) +} +func (dst *ResponseWrapInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseWrapInfo.Merge(dst, src) +} +func (m *ResponseWrapInfo) XXX_Size() int { + return xxx_messageInfo_ResponseWrapInfo.Size(m) +} +func (m *ResponseWrapInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseWrapInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseWrapInfo proto.InternalMessageInfo + +func (m *ResponseWrapInfo) GetTTL() int64 { + if m != nil { + return m.TTL + } + return 0 +} + +func (m *ResponseWrapInfo) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *ResponseWrapInfo) GetAccessor() string { + if m != nil { + return m.Accessor + } + return "" +} + +func (m *ResponseWrapInfo) GetCreationTime() *timestamp.Timestamp { + if m != nil { + return m.CreationTime + } + return nil +} + +func (m *ResponseWrapInfo) GetWrappedAccessor() string { + if m != nil { + return m.WrappedAccessor + } + return "" +} + +func (m *ResponseWrapInfo) GetWrappedEntityID() string { + if m != nil { + return m.WrappedEntityID + } + return "" +} + +func (m *ResponseWrapInfo) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *ResponseWrapInfo) GetCreationPath() string { + if m != nil { + return m.CreationPath + } + return "" +} + +func (m *ResponseWrapInfo) GetSealWrap() bool { + if m != nil { + return m.SealWrap + } + return false +} + +type RequestWrapInfo struct { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + TTL int64 `sentinel:"" protobuf:"varint,1,opt,name=TTL" json:"TTL,omitempty"` + // The format to use for the wrapped response; if not specified it's a bare + // token + Format string `sentinel:"" protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + // A flag to conforming backends that data for a given request should be + // seal wrapped + SealWrap bool `sentinel:"" protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap" json:"seal_wrap,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RequestWrapInfo) Reset() { *m = RequestWrapInfo{} } +func (m *RequestWrapInfo) String() string { return proto.CompactTextString(m) } +func (*RequestWrapInfo) ProtoMessage() {} +func (*RequestWrapInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{10} +} +func (m *RequestWrapInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RequestWrapInfo.Unmarshal(m, b) +} +func (m *RequestWrapInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RequestWrapInfo.Marshal(b, m, deterministic) +} +func (dst *RequestWrapInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestWrapInfo.Merge(dst, src) +} +func (m *RequestWrapInfo) XXX_Size() int { + return xxx_messageInfo_RequestWrapInfo.Size(m) +} +func (m *RequestWrapInfo) XXX_DiscardUnknown() { + xxx_messageInfo_RequestWrapInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestWrapInfo proto.InternalMessageInfo + +func (m *RequestWrapInfo) GetTTL() int64 { + if m != nil { + return m.TTL + } + return 0 +} + +func (m *RequestWrapInfo) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *RequestWrapInfo) GetSealWrap() bool { + if m != nil { + return m.SealWrap + } + return false +} + +// HandleRequestArgs is the args for HandleRequest method. +type HandleRequestArgs struct { + StorageID uint32 `sentinel:"" protobuf:"varint,1,opt,name=storage_id,json=storageId" json:"storage_id,omitempty"` + Request *Request `sentinel:"" protobuf:"bytes,2,opt,name=request" json:"request,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HandleRequestArgs) Reset() { *m = HandleRequestArgs{} } +func (m *HandleRequestArgs) String() string { return proto.CompactTextString(m) } +func (*HandleRequestArgs) ProtoMessage() {} +func (*HandleRequestArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{11} +} +func (m *HandleRequestArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HandleRequestArgs.Unmarshal(m, b) +} +func (m *HandleRequestArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HandleRequestArgs.Marshal(b, m, deterministic) +} +func (dst *HandleRequestArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_HandleRequestArgs.Merge(dst, src) +} +func (m *HandleRequestArgs) XXX_Size() int { + return xxx_messageInfo_HandleRequestArgs.Size(m) +} +func (m *HandleRequestArgs) XXX_DiscardUnknown() { + xxx_messageInfo_HandleRequestArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_HandleRequestArgs proto.InternalMessageInfo + +func (m *HandleRequestArgs) GetStorageID() uint32 { + if m != nil { + return m.StorageID + } + return 0 +} + +func (m *HandleRequestArgs) GetRequest() *Request { + if m != nil { + return m.Request + } + return nil +} + +// HandleRequestReply is the reply for HandleRequest method. +type HandleRequestReply struct { + Response *Response `sentinel:"" protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + Err *ProtoError `sentinel:"" protobuf:"bytes,2,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HandleRequestReply) Reset() { *m = HandleRequestReply{} } +func (m *HandleRequestReply) String() string { return proto.CompactTextString(m) } +func (*HandleRequestReply) ProtoMessage() {} +func (*HandleRequestReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{12} +} +func (m *HandleRequestReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HandleRequestReply.Unmarshal(m, b) +} +func (m *HandleRequestReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HandleRequestReply.Marshal(b, m, deterministic) +} +func (dst *HandleRequestReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_HandleRequestReply.Merge(dst, src) +} +func (m *HandleRequestReply) XXX_Size() int { + return xxx_messageInfo_HandleRequestReply.Size(m) +} +func (m *HandleRequestReply) XXX_DiscardUnknown() { + xxx_messageInfo_HandleRequestReply.DiscardUnknown(m) +} + +var xxx_messageInfo_HandleRequestReply proto.InternalMessageInfo + +func (m *HandleRequestReply) GetResponse() *Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *HandleRequestReply) GetErr() *ProtoError { + if m != nil { + return m.Err + } + return nil +} + +// SpecialPathsReply is the reply for SpecialPaths method. +type SpecialPathsReply struct { + Paths *Paths `sentinel:"" protobuf:"bytes,1,opt,name=paths" json:"paths,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SpecialPathsReply) Reset() { *m = SpecialPathsReply{} } +func (m *SpecialPathsReply) String() string { return proto.CompactTextString(m) } +func (*SpecialPathsReply) ProtoMessage() {} +func (*SpecialPathsReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{13} +} +func (m *SpecialPathsReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SpecialPathsReply.Unmarshal(m, b) +} +func (m *SpecialPathsReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SpecialPathsReply.Marshal(b, m, deterministic) +} +func (dst *SpecialPathsReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SpecialPathsReply.Merge(dst, src) +} +func (m *SpecialPathsReply) XXX_Size() int { + return xxx_messageInfo_SpecialPathsReply.Size(m) +} +func (m *SpecialPathsReply) XXX_DiscardUnknown() { + xxx_messageInfo_SpecialPathsReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SpecialPathsReply proto.InternalMessageInfo + +func (m *SpecialPathsReply) GetPaths() *Paths { + if m != nil { + return m.Paths + } + return nil +} + +// HandleExistenceCheckArgs is the args for HandleExistenceCheck method. +type HandleExistenceCheckArgs struct { + StorageID uint32 `sentinel:"" protobuf:"varint,1,opt,name=storage_id,json=storageId" json:"storage_id,omitempty"` + Request *Request `sentinel:"" protobuf:"bytes,2,opt,name=request" json:"request,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HandleExistenceCheckArgs) Reset() { *m = HandleExistenceCheckArgs{} } +func (m *HandleExistenceCheckArgs) String() string { return proto.CompactTextString(m) } +func (*HandleExistenceCheckArgs) ProtoMessage() {} +func (*HandleExistenceCheckArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{14} +} +func (m *HandleExistenceCheckArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HandleExistenceCheckArgs.Unmarshal(m, b) +} +func (m *HandleExistenceCheckArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HandleExistenceCheckArgs.Marshal(b, m, deterministic) +} +func (dst *HandleExistenceCheckArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_HandleExistenceCheckArgs.Merge(dst, src) +} +func (m *HandleExistenceCheckArgs) XXX_Size() int { + return xxx_messageInfo_HandleExistenceCheckArgs.Size(m) +} +func (m *HandleExistenceCheckArgs) XXX_DiscardUnknown() { + xxx_messageInfo_HandleExistenceCheckArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_HandleExistenceCheckArgs proto.InternalMessageInfo + +func (m *HandleExistenceCheckArgs) GetStorageID() uint32 { + if m != nil { + return m.StorageID + } + return 0 +} + +func (m *HandleExistenceCheckArgs) GetRequest() *Request { + if m != nil { + return m.Request + } + return nil +} + +// HandleExistenceCheckReply is the reply for HandleExistenceCheck method. +type HandleExistenceCheckReply struct { + CheckFound bool `sentinel:"" protobuf:"varint,1,opt,name=check_found,json=checkFound" json:"check_found,omitempty"` + Exists bool `sentinel:"" protobuf:"varint,2,opt,name=exists" json:"exists,omitempty"` + Err *ProtoError `sentinel:"" protobuf:"bytes,3,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HandleExistenceCheckReply) Reset() { *m = HandleExistenceCheckReply{} } +func (m *HandleExistenceCheckReply) String() string { return proto.CompactTextString(m) } +func (*HandleExistenceCheckReply) ProtoMessage() {} +func (*HandleExistenceCheckReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{15} +} +func (m *HandleExistenceCheckReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HandleExistenceCheckReply.Unmarshal(m, b) +} +func (m *HandleExistenceCheckReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HandleExistenceCheckReply.Marshal(b, m, deterministic) +} +func (dst *HandleExistenceCheckReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_HandleExistenceCheckReply.Merge(dst, src) +} +func (m *HandleExistenceCheckReply) XXX_Size() int { + return xxx_messageInfo_HandleExistenceCheckReply.Size(m) +} +func (m *HandleExistenceCheckReply) XXX_DiscardUnknown() { + xxx_messageInfo_HandleExistenceCheckReply.DiscardUnknown(m) +} + +var xxx_messageInfo_HandleExistenceCheckReply proto.InternalMessageInfo + +func (m *HandleExistenceCheckReply) GetCheckFound() bool { + if m != nil { + return m.CheckFound + } + return false +} + +func (m *HandleExistenceCheckReply) GetExists() bool { + if m != nil { + return m.Exists + } + return false +} + +func (m *HandleExistenceCheckReply) GetErr() *ProtoError { + if m != nil { + return m.Err + } + return nil +} + +// SetupArgs is the args for Setup method. +type SetupArgs struct { + BrokerID uint32 `sentinel:"" protobuf:"varint,1,opt,name=broker_id,json=brokerId" json:"broker_id,omitempty"` + Config map[string]string `sentinel:"" protobuf:"bytes,2,rep,name=Config" json:"Config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + BackendUUID string `sentinel:"" protobuf:"bytes,3,opt,name=backendUUID" json:"backendUUID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetupArgs) Reset() { *m = SetupArgs{} } +func (m *SetupArgs) String() string { return proto.CompactTextString(m) } +func (*SetupArgs) ProtoMessage() {} +func (*SetupArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{16} +} +func (m *SetupArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetupArgs.Unmarshal(m, b) +} +func (m *SetupArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetupArgs.Marshal(b, m, deterministic) +} +func (dst *SetupArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetupArgs.Merge(dst, src) +} +func (m *SetupArgs) XXX_Size() int { + return xxx_messageInfo_SetupArgs.Size(m) +} +func (m *SetupArgs) XXX_DiscardUnknown() { + xxx_messageInfo_SetupArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_SetupArgs proto.InternalMessageInfo + +func (m *SetupArgs) GetBrokerID() uint32 { + if m != nil { + return m.BrokerID + } + return 0 +} + +func (m *SetupArgs) GetConfig() map[string]string { + if m != nil { + return m.Config + } + return nil +} + +func (m *SetupArgs) GetBackendUUID() string { + if m != nil { + return m.BackendUUID + } + return "" +} + +// SetupReply is the reply for Setup method. +type SetupReply struct { + Err string `sentinel:"" protobuf:"bytes,1,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetupReply) Reset() { *m = SetupReply{} } +func (m *SetupReply) String() string { return proto.CompactTextString(m) } +func (*SetupReply) ProtoMessage() {} +func (*SetupReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{17} +} +func (m *SetupReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetupReply.Unmarshal(m, b) +} +func (m *SetupReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetupReply.Marshal(b, m, deterministic) +} +func (dst *SetupReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetupReply.Merge(dst, src) +} +func (m *SetupReply) XXX_Size() int { + return xxx_messageInfo_SetupReply.Size(m) +} +func (m *SetupReply) XXX_DiscardUnknown() { + xxx_messageInfo_SetupReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SetupReply proto.InternalMessageInfo + +func (m *SetupReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +// TypeReply is the reply for the Type method. +type TypeReply struct { + Type uint32 `sentinel:"" protobuf:"varint,1,opt,name=type" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TypeReply) Reset() { *m = TypeReply{} } +func (m *TypeReply) String() string { return proto.CompactTextString(m) } +func (*TypeReply) ProtoMessage() {} +func (*TypeReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{18} +} +func (m *TypeReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TypeReply.Unmarshal(m, b) +} +func (m *TypeReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TypeReply.Marshal(b, m, deterministic) +} +func (dst *TypeReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_TypeReply.Merge(dst, src) +} +func (m *TypeReply) XXX_Size() int { + return xxx_messageInfo_TypeReply.Size(m) +} +func (m *TypeReply) XXX_DiscardUnknown() { + xxx_messageInfo_TypeReply.DiscardUnknown(m) +} + +var xxx_messageInfo_TypeReply proto.InternalMessageInfo + +func (m *TypeReply) GetType() uint32 { + if m != nil { + return m.Type + } + return 0 +} + +type InvalidateKeyArgs struct { + Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InvalidateKeyArgs) Reset() { *m = InvalidateKeyArgs{} } +func (m *InvalidateKeyArgs) String() string { return proto.CompactTextString(m) } +func (*InvalidateKeyArgs) ProtoMessage() {} +func (*InvalidateKeyArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{19} +} +func (m *InvalidateKeyArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InvalidateKeyArgs.Unmarshal(m, b) +} +func (m *InvalidateKeyArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InvalidateKeyArgs.Marshal(b, m, deterministic) +} +func (dst *InvalidateKeyArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_InvalidateKeyArgs.Merge(dst, src) +} +func (m *InvalidateKeyArgs) XXX_Size() int { + return xxx_messageInfo_InvalidateKeyArgs.Size(m) +} +func (m *InvalidateKeyArgs) XXX_DiscardUnknown() { + xxx_messageInfo_InvalidateKeyArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_InvalidateKeyArgs proto.InternalMessageInfo + +func (m *InvalidateKeyArgs) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type StorageEntry struct { + Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value []byte `sentinel:"" protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + SealWrap bool `sentinel:"" protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap" json:"seal_wrap,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageEntry) Reset() { *m = StorageEntry{} } +func (m *StorageEntry) String() string { return proto.CompactTextString(m) } +func (*StorageEntry) ProtoMessage() {} +func (*StorageEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{20} +} +func (m *StorageEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageEntry.Unmarshal(m, b) +} +func (m *StorageEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageEntry.Marshal(b, m, deterministic) +} +func (dst *StorageEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageEntry.Merge(dst, src) +} +func (m *StorageEntry) XXX_Size() int { + return xxx_messageInfo_StorageEntry.Size(m) +} +func (m *StorageEntry) XXX_DiscardUnknown() { + xxx_messageInfo_StorageEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageEntry proto.InternalMessageInfo + +func (m *StorageEntry) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *StorageEntry) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *StorageEntry) GetSealWrap() bool { + if m != nil { + return m.SealWrap + } + return false +} + +type StorageListArgs struct { + Prefix string `sentinel:"" protobuf:"bytes,1,opt,name=prefix" json:"prefix,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageListArgs) Reset() { *m = StorageListArgs{} } +func (m *StorageListArgs) String() string { return proto.CompactTextString(m) } +func (*StorageListArgs) ProtoMessage() {} +func (*StorageListArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{21} +} +func (m *StorageListArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageListArgs.Unmarshal(m, b) +} +func (m *StorageListArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageListArgs.Marshal(b, m, deterministic) +} +func (dst *StorageListArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageListArgs.Merge(dst, src) +} +func (m *StorageListArgs) XXX_Size() int { + return xxx_messageInfo_StorageListArgs.Size(m) +} +func (m *StorageListArgs) XXX_DiscardUnknown() { + xxx_messageInfo_StorageListArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageListArgs proto.InternalMessageInfo + +func (m *StorageListArgs) GetPrefix() string { + if m != nil { + return m.Prefix + } + return "" +} + +type StorageListReply struct { + Keys []string `sentinel:"" protobuf:"bytes,1,rep,name=keys" json:"keys,omitempty"` + Err string `sentinel:"" protobuf:"bytes,2,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageListReply) Reset() { *m = StorageListReply{} } +func (m *StorageListReply) String() string { return proto.CompactTextString(m) } +func (*StorageListReply) ProtoMessage() {} +func (*StorageListReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{22} +} +func (m *StorageListReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageListReply.Unmarshal(m, b) +} +func (m *StorageListReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageListReply.Marshal(b, m, deterministic) +} +func (dst *StorageListReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageListReply.Merge(dst, src) +} +func (m *StorageListReply) XXX_Size() int { + return xxx_messageInfo_StorageListReply.Size(m) +} +func (m *StorageListReply) XXX_DiscardUnknown() { + xxx_messageInfo_StorageListReply.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageListReply proto.InternalMessageInfo + +func (m *StorageListReply) GetKeys() []string { + if m != nil { + return m.Keys + } + return nil +} + +func (m *StorageListReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type StorageGetArgs struct { + Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageGetArgs) Reset() { *m = StorageGetArgs{} } +func (m *StorageGetArgs) String() string { return proto.CompactTextString(m) } +func (*StorageGetArgs) ProtoMessage() {} +func (*StorageGetArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{23} +} +func (m *StorageGetArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageGetArgs.Unmarshal(m, b) +} +func (m *StorageGetArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageGetArgs.Marshal(b, m, deterministic) +} +func (dst *StorageGetArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageGetArgs.Merge(dst, src) +} +func (m *StorageGetArgs) XXX_Size() int { + return xxx_messageInfo_StorageGetArgs.Size(m) +} +func (m *StorageGetArgs) XXX_DiscardUnknown() { + xxx_messageInfo_StorageGetArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageGetArgs proto.InternalMessageInfo + +func (m *StorageGetArgs) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type StorageGetReply struct { + Entry *StorageEntry `sentinel:"" protobuf:"bytes,1,opt,name=entry" json:"entry,omitempty"` + Err string `sentinel:"" protobuf:"bytes,2,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageGetReply) Reset() { *m = StorageGetReply{} } +func (m *StorageGetReply) String() string { return proto.CompactTextString(m) } +func (*StorageGetReply) ProtoMessage() {} +func (*StorageGetReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{24} +} +func (m *StorageGetReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageGetReply.Unmarshal(m, b) +} +func (m *StorageGetReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageGetReply.Marshal(b, m, deterministic) +} +func (dst *StorageGetReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageGetReply.Merge(dst, src) +} +func (m *StorageGetReply) XXX_Size() int { + return xxx_messageInfo_StorageGetReply.Size(m) +} +func (m *StorageGetReply) XXX_DiscardUnknown() { + xxx_messageInfo_StorageGetReply.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageGetReply proto.InternalMessageInfo + +func (m *StorageGetReply) GetEntry() *StorageEntry { + if m != nil { + return m.Entry + } + return nil +} + +func (m *StorageGetReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type StoragePutArgs struct { + Entry *StorageEntry `sentinel:"" protobuf:"bytes,1,opt,name=entry" json:"entry,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StoragePutArgs) Reset() { *m = StoragePutArgs{} } +func (m *StoragePutArgs) String() string { return proto.CompactTextString(m) } +func (*StoragePutArgs) ProtoMessage() {} +func (*StoragePutArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{25} +} +func (m *StoragePutArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StoragePutArgs.Unmarshal(m, b) +} +func (m *StoragePutArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StoragePutArgs.Marshal(b, m, deterministic) +} +func (dst *StoragePutArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoragePutArgs.Merge(dst, src) +} +func (m *StoragePutArgs) XXX_Size() int { + return xxx_messageInfo_StoragePutArgs.Size(m) +} +func (m *StoragePutArgs) XXX_DiscardUnknown() { + xxx_messageInfo_StoragePutArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_StoragePutArgs proto.InternalMessageInfo + +func (m *StoragePutArgs) GetEntry() *StorageEntry { + if m != nil { + return m.Entry + } + return nil +} + +type StoragePutReply struct { + Err string `sentinel:"" protobuf:"bytes,1,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StoragePutReply) Reset() { *m = StoragePutReply{} } +func (m *StoragePutReply) String() string { return proto.CompactTextString(m) } +func (*StoragePutReply) ProtoMessage() {} +func (*StoragePutReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{26} +} +func (m *StoragePutReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StoragePutReply.Unmarshal(m, b) +} +func (m *StoragePutReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StoragePutReply.Marshal(b, m, deterministic) +} +func (dst *StoragePutReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoragePutReply.Merge(dst, src) +} +func (m *StoragePutReply) XXX_Size() int { + return xxx_messageInfo_StoragePutReply.Size(m) +} +func (m *StoragePutReply) XXX_DiscardUnknown() { + xxx_messageInfo_StoragePutReply.DiscardUnknown(m) +} + +var xxx_messageInfo_StoragePutReply proto.InternalMessageInfo + +func (m *StoragePutReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type StorageDeleteArgs struct { + Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageDeleteArgs) Reset() { *m = StorageDeleteArgs{} } +func (m *StorageDeleteArgs) String() string { return proto.CompactTextString(m) } +func (*StorageDeleteArgs) ProtoMessage() {} +func (*StorageDeleteArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{27} +} +func (m *StorageDeleteArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageDeleteArgs.Unmarshal(m, b) +} +func (m *StorageDeleteArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageDeleteArgs.Marshal(b, m, deterministic) +} +func (dst *StorageDeleteArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageDeleteArgs.Merge(dst, src) +} +func (m *StorageDeleteArgs) XXX_Size() int { + return xxx_messageInfo_StorageDeleteArgs.Size(m) +} +func (m *StorageDeleteArgs) XXX_DiscardUnknown() { + xxx_messageInfo_StorageDeleteArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageDeleteArgs proto.InternalMessageInfo + +func (m *StorageDeleteArgs) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type StorageDeleteReply struct { + Err string `sentinel:"" protobuf:"bytes,1,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageDeleteReply) Reset() { *m = StorageDeleteReply{} } +func (m *StorageDeleteReply) String() string { return proto.CompactTextString(m) } +func (*StorageDeleteReply) ProtoMessage() {} +func (*StorageDeleteReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{28} +} +func (m *StorageDeleteReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageDeleteReply.Unmarshal(m, b) +} +func (m *StorageDeleteReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageDeleteReply.Marshal(b, m, deterministic) +} +func (dst *StorageDeleteReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageDeleteReply.Merge(dst, src) +} +func (m *StorageDeleteReply) XXX_Size() int { + return xxx_messageInfo_StorageDeleteReply.Size(m) +} +func (m *StorageDeleteReply) XXX_DiscardUnknown() { + xxx_messageInfo_StorageDeleteReply.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageDeleteReply proto.InternalMessageInfo + +func (m *StorageDeleteReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type TTLReply struct { + TTL int64 `sentinel:"" protobuf:"varint,1,opt,name=TTL" json:"TTL,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TTLReply) Reset() { *m = TTLReply{} } +func (m *TTLReply) String() string { return proto.CompactTextString(m) } +func (*TTLReply) ProtoMessage() {} +func (*TTLReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{29} +} +func (m *TTLReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TTLReply.Unmarshal(m, b) +} +func (m *TTLReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TTLReply.Marshal(b, m, deterministic) +} +func (dst *TTLReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_TTLReply.Merge(dst, src) +} +func (m *TTLReply) XXX_Size() int { + return xxx_messageInfo_TTLReply.Size(m) +} +func (m *TTLReply) XXX_DiscardUnknown() { + xxx_messageInfo_TTLReply.DiscardUnknown(m) +} + +var xxx_messageInfo_TTLReply proto.InternalMessageInfo + +func (m *TTLReply) GetTTL() int64 { + if m != nil { + return m.TTL + } + return 0 +} + +type SudoPrivilegeArgs struct { + Path string `sentinel:"" protobuf:"bytes,1,opt,name=path" json:"path,omitempty"` + Token string `sentinel:"" protobuf:"bytes,2,opt,name=token" json:"token,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SudoPrivilegeArgs) Reset() { *m = SudoPrivilegeArgs{} } +func (m *SudoPrivilegeArgs) String() string { return proto.CompactTextString(m) } +func (*SudoPrivilegeArgs) ProtoMessage() {} +func (*SudoPrivilegeArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{30} +} +func (m *SudoPrivilegeArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SudoPrivilegeArgs.Unmarshal(m, b) +} +func (m *SudoPrivilegeArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SudoPrivilegeArgs.Marshal(b, m, deterministic) +} +func (dst *SudoPrivilegeArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_SudoPrivilegeArgs.Merge(dst, src) +} +func (m *SudoPrivilegeArgs) XXX_Size() int { + return xxx_messageInfo_SudoPrivilegeArgs.Size(m) +} +func (m *SudoPrivilegeArgs) XXX_DiscardUnknown() { + xxx_messageInfo_SudoPrivilegeArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_SudoPrivilegeArgs proto.InternalMessageInfo + +func (m *SudoPrivilegeArgs) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *SudoPrivilegeArgs) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +type SudoPrivilegeReply struct { + Sudo bool `sentinel:"" protobuf:"varint,1,opt,name=sudo" json:"sudo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SudoPrivilegeReply) Reset() { *m = SudoPrivilegeReply{} } +func (m *SudoPrivilegeReply) String() string { return proto.CompactTextString(m) } +func (*SudoPrivilegeReply) ProtoMessage() {} +func (*SudoPrivilegeReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{31} +} +func (m *SudoPrivilegeReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SudoPrivilegeReply.Unmarshal(m, b) +} +func (m *SudoPrivilegeReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SudoPrivilegeReply.Marshal(b, m, deterministic) +} +func (dst *SudoPrivilegeReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SudoPrivilegeReply.Merge(dst, src) +} +func (m *SudoPrivilegeReply) XXX_Size() int { + return xxx_messageInfo_SudoPrivilegeReply.Size(m) +} +func (m *SudoPrivilegeReply) XXX_DiscardUnknown() { + xxx_messageInfo_SudoPrivilegeReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SudoPrivilegeReply proto.InternalMessageInfo + +func (m *SudoPrivilegeReply) GetSudo() bool { + if m != nil { + return m.Sudo + } + return false +} + +type TaintedReply struct { + Tainted bool `sentinel:"" protobuf:"varint,1,opt,name=tainted" json:"tainted,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaintedReply) Reset() { *m = TaintedReply{} } +func (m *TaintedReply) String() string { return proto.CompactTextString(m) } +func (*TaintedReply) ProtoMessage() {} +func (*TaintedReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{32} +} +func (m *TaintedReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TaintedReply.Unmarshal(m, b) +} +func (m *TaintedReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TaintedReply.Marshal(b, m, deterministic) +} +func (dst *TaintedReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaintedReply.Merge(dst, src) +} +func (m *TaintedReply) XXX_Size() int { + return xxx_messageInfo_TaintedReply.Size(m) +} +func (m *TaintedReply) XXX_DiscardUnknown() { + xxx_messageInfo_TaintedReply.DiscardUnknown(m) +} + +var xxx_messageInfo_TaintedReply proto.InternalMessageInfo + +func (m *TaintedReply) GetTainted() bool { + if m != nil { + return m.Tainted + } + return false +} + +type CachingDisabledReply struct { + Disabled bool `sentinel:"" protobuf:"varint,1,opt,name=disabled" json:"disabled,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CachingDisabledReply) Reset() { *m = CachingDisabledReply{} } +func (m *CachingDisabledReply) String() string { return proto.CompactTextString(m) } +func (*CachingDisabledReply) ProtoMessage() {} +func (*CachingDisabledReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{33} +} +func (m *CachingDisabledReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CachingDisabledReply.Unmarshal(m, b) +} +func (m *CachingDisabledReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CachingDisabledReply.Marshal(b, m, deterministic) +} +func (dst *CachingDisabledReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_CachingDisabledReply.Merge(dst, src) +} +func (m *CachingDisabledReply) XXX_Size() int { + return xxx_messageInfo_CachingDisabledReply.Size(m) +} +func (m *CachingDisabledReply) XXX_DiscardUnknown() { + xxx_messageInfo_CachingDisabledReply.DiscardUnknown(m) +} + +var xxx_messageInfo_CachingDisabledReply proto.InternalMessageInfo + +func (m *CachingDisabledReply) GetDisabled() bool { + if m != nil { + return m.Disabled + } + return false +} + +type ReplicationStateReply struct { + State int32 `sentinel:"" protobuf:"varint,1,opt,name=state" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReplicationStateReply) Reset() { *m = ReplicationStateReply{} } +func (m *ReplicationStateReply) String() string { return proto.CompactTextString(m) } +func (*ReplicationStateReply) ProtoMessage() {} +func (*ReplicationStateReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{34} +} +func (m *ReplicationStateReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReplicationStateReply.Unmarshal(m, b) +} +func (m *ReplicationStateReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReplicationStateReply.Marshal(b, m, deterministic) +} +func (dst *ReplicationStateReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReplicationStateReply.Merge(dst, src) +} +func (m *ReplicationStateReply) XXX_Size() int { + return xxx_messageInfo_ReplicationStateReply.Size(m) +} +func (m *ReplicationStateReply) XXX_DiscardUnknown() { + xxx_messageInfo_ReplicationStateReply.DiscardUnknown(m) +} + +var xxx_messageInfo_ReplicationStateReply proto.InternalMessageInfo + +func (m *ReplicationStateReply) GetState() int32 { + if m != nil { + return m.State + } + return 0 +} + +type ResponseWrapDataArgs struct { + Data string `sentinel:"" protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` + TTL int64 `sentinel:"" protobuf:"varint,2,opt,name=TTL" json:"TTL,omitempty"` + JWT bool `sentinel:"" protobuf:"varint,3,opt,name=JWT" json:"JWT,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseWrapDataArgs) Reset() { *m = ResponseWrapDataArgs{} } +func (m *ResponseWrapDataArgs) String() string { return proto.CompactTextString(m) } +func (*ResponseWrapDataArgs) ProtoMessage() {} +func (*ResponseWrapDataArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{35} +} +func (m *ResponseWrapDataArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseWrapDataArgs.Unmarshal(m, b) +} +func (m *ResponseWrapDataArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseWrapDataArgs.Marshal(b, m, deterministic) +} +func (dst *ResponseWrapDataArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseWrapDataArgs.Merge(dst, src) +} +func (m *ResponseWrapDataArgs) XXX_Size() int { + return xxx_messageInfo_ResponseWrapDataArgs.Size(m) +} +func (m *ResponseWrapDataArgs) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseWrapDataArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseWrapDataArgs proto.InternalMessageInfo + +func (m *ResponseWrapDataArgs) GetData() string { + if m != nil { + return m.Data + } + return "" +} + +func (m *ResponseWrapDataArgs) GetTTL() int64 { + if m != nil { + return m.TTL + } + return 0 +} + +func (m *ResponseWrapDataArgs) GetJWT() bool { + if m != nil { + return m.JWT + } + return false +} + +type ResponseWrapDataReply struct { + WrapInfo *ResponseWrapInfo `sentinel:"" protobuf:"bytes,1,opt,name=wrap_info,json=wrapInfo" json:"wrap_info,omitempty"` + Err string `sentinel:"" protobuf:"bytes,2,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseWrapDataReply) Reset() { *m = ResponseWrapDataReply{} } +func (m *ResponseWrapDataReply) String() string { return proto.CompactTextString(m) } +func (*ResponseWrapDataReply) ProtoMessage() {} +func (*ResponseWrapDataReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{36} +} +func (m *ResponseWrapDataReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseWrapDataReply.Unmarshal(m, b) +} +func (m *ResponseWrapDataReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseWrapDataReply.Marshal(b, m, deterministic) +} +func (dst *ResponseWrapDataReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseWrapDataReply.Merge(dst, src) +} +func (m *ResponseWrapDataReply) XXX_Size() int { + return xxx_messageInfo_ResponseWrapDataReply.Size(m) +} +func (m *ResponseWrapDataReply) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseWrapDataReply.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseWrapDataReply proto.InternalMessageInfo + +func (m *ResponseWrapDataReply) GetWrapInfo() *ResponseWrapInfo { + if m != nil { + return m.WrapInfo + } + return nil +} + +func (m *ResponseWrapDataReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type MlockEnabledReply struct { + Enabled bool `sentinel:"" protobuf:"varint,1,opt,name=enabled" json:"enabled,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MlockEnabledReply) Reset() { *m = MlockEnabledReply{} } +func (m *MlockEnabledReply) String() string { return proto.CompactTextString(m) } +func (*MlockEnabledReply) ProtoMessage() {} +func (*MlockEnabledReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{37} +} +func (m *MlockEnabledReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MlockEnabledReply.Unmarshal(m, b) +} +func (m *MlockEnabledReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MlockEnabledReply.Marshal(b, m, deterministic) +} +func (dst *MlockEnabledReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_MlockEnabledReply.Merge(dst, src) +} +func (m *MlockEnabledReply) XXX_Size() int { + return xxx_messageInfo_MlockEnabledReply.Size(m) +} +func (m *MlockEnabledReply) XXX_DiscardUnknown() { + xxx_messageInfo_MlockEnabledReply.DiscardUnknown(m) +} + +var xxx_messageInfo_MlockEnabledReply proto.InternalMessageInfo + +func (m *MlockEnabledReply) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +type LocalMountReply struct { + Local bool `sentinel:"" protobuf:"varint,1,opt,name=local" json:"local,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LocalMountReply) Reset() { *m = LocalMountReply{} } +func (m *LocalMountReply) String() string { return proto.CompactTextString(m) } +func (*LocalMountReply) ProtoMessage() {} +func (*LocalMountReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{38} +} +func (m *LocalMountReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LocalMountReply.Unmarshal(m, b) +} +func (m *LocalMountReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LocalMountReply.Marshal(b, m, deterministic) +} +func (dst *LocalMountReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_LocalMountReply.Merge(dst, src) +} +func (m *LocalMountReply) XXX_Size() int { + return xxx_messageInfo_LocalMountReply.Size(m) +} +func (m *LocalMountReply) XXX_DiscardUnknown() { + xxx_messageInfo_LocalMountReply.DiscardUnknown(m) +} + +var xxx_messageInfo_LocalMountReply proto.InternalMessageInfo + +func (m *LocalMountReply) GetLocal() bool { + if m != nil { + return m.Local + } + return false +} + +type EntityInfoArgs struct { + EntityID string `sentinel:"" protobuf:"bytes,1,opt,name=entity_id,json=entityId" json:"entity_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EntityInfoArgs) Reset() { *m = EntityInfoArgs{} } +func (m *EntityInfoArgs) String() string { return proto.CompactTextString(m) } +func (*EntityInfoArgs) ProtoMessage() {} +func (*EntityInfoArgs) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{39} +} +func (m *EntityInfoArgs) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EntityInfoArgs.Unmarshal(m, b) +} +func (m *EntityInfoArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EntityInfoArgs.Marshal(b, m, deterministic) +} +func (dst *EntityInfoArgs) XXX_Merge(src proto.Message) { + xxx_messageInfo_EntityInfoArgs.Merge(dst, src) +} +func (m *EntityInfoArgs) XXX_Size() int { + return xxx_messageInfo_EntityInfoArgs.Size(m) +} +func (m *EntityInfoArgs) XXX_DiscardUnknown() { + xxx_messageInfo_EntityInfoArgs.DiscardUnknown(m) +} + +var xxx_messageInfo_EntityInfoArgs proto.InternalMessageInfo + +func (m *EntityInfoArgs) GetEntityID() string { + if m != nil { + return m.EntityID + } + return "" +} + +type EntityInfoReply struct { + Entity *logical.Entity `sentinel:"" protobuf:"bytes,1,opt,name=entity" json:"entity,omitempty"` + Err string `sentinel:"" protobuf:"bytes,2,opt,name=err" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EntityInfoReply) Reset() { *m = EntityInfoReply{} } +func (m *EntityInfoReply) String() string { return proto.CompactTextString(m) } +func (*EntityInfoReply) ProtoMessage() {} +func (*EntityInfoReply) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{40} +} +func (m *EntityInfoReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EntityInfoReply.Unmarshal(m, b) +} +func (m *EntityInfoReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EntityInfoReply.Marshal(b, m, deterministic) +} +func (dst *EntityInfoReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_EntityInfoReply.Merge(dst, src) +} +func (m *EntityInfoReply) XXX_Size() int { + return xxx_messageInfo_EntityInfoReply.Size(m) +} +func (m *EntityInfoReply) XXX_DiscardUnknown() { + xxx_messageInfo_EntityInfoReply.DiscardUnknown(m) +} + +var xxx_messageInfo_EntityInfoReply proto.InternalMessageInfo + +func (m *EntityInfoReply) GetEntity() *logical.Entity { + if m != nil { + return m.Entity + } + return nil +} + +func (m *EntityInfoReply) GetErr() string { + if m != nil { + return m.Err + } + return "" +} + +type Connection struct { + // RemoteAddr is the network address that sent the request. + RemoteAddr string `sentinel:"" protobuf:"bytes,1,opt,name=remote_addr,json=remoteAddr" json:"remote_addr,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Connection) Reset() { *m = Connection{} } +func (m *Connection) String() string { return proto.CompactTextString(m) } +func (*Connection) ProtoMessage() {} +func (*Connection) Descriptor() ([]byte, []int) { + return fileDescriptor_backend_b95a338e744ea757, []int{41} +} +func (m *Connection) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Connection.Unmarshal(m, b) +} +func (m *Connection) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Connection.Marshal(b, m, deterministic) +} +func (dst *Connection) XXX_Merge(src proto.Message) { + xxx_messageInfo_Connection.Merge(dst, src) +} +func (m *Connection) XXX_Size() int { + return xxx_messageInfo_Connection.Size(m) +} +func (m *Connection) XXX_DiscardUnknown() { + xxx_messageInfo_Connection.DiscardUnknown(m) +} + +var xxx_messageInfo_Connection proto.InternalMessageInfo + +func (m *Connection) GetRemoteAddr() string { + if m != nil { + return m.RemoteAddr + } + return "" +} + +func init() { + proto.RegisterType((*Empty)(nil), "pb.Empty") + proto.RegisterType((*Header)(nil), "pb.Header") + proto.RegisterType((*ProtoError)(nil), "pb.ProtoError") + proto.RegisterType((*Paths)(nil), "pb.Paths") + proto.RegisterType((*Request)(nil), "pb.Request") + proto.RegisterMapType((map[string]*Header)(nil), "pb.Request.HeadersEntry") + proto.RegisterType((*Auth)(nil), "pb.Auth") + proto.RegisterMapType((map[string]string)(nil), "pb.Auth.MetadataEntry") + proto.RegisterType((*LeaseOptions)(nil), "pb.LeaseOptions") + proto.RegisterType((*Secret)(nil), "pb.Secret") + proto.RegisterType((*Response)(nil), "pb.Response") + proto.RegisterType((*ResponseWrapInfo)(nil), "pb.ResponseWrapInfo") + proto.RegisterType((*RequestWrapInfo)(nil), "pb.RequestWrapInfo") + proto.RegisterType((*HandleRequestArgs)(nil), "pb.HandleRequestArgs") + proto.RegisterType((*HandleRequestReply)(nil), "pb.HandleRequestReply") + proto.RegisterType((*SpecialPathsReply)(nil), "pb.SpecialPathsReply") + proto.RegisterType((*HandleExistenceCheckArgs)(nil), "pb.HandleExistenceCheckArgs") + proto.RegisterType((*HandleExistenceCheckReply)(nil), "pb.HandleExistenceCheckReply") + proto.RegisterType((*SetupArgs)(nil), "pb.SetupArgs") + proto.RegisterMapType((map[string]string)(nil), "pb.SetupArgs.ConfigEntry") + proto.RegisterType((*SetupReply)(nil), "pb.SetupReply") + proto.RegisterType((*TypeReply)(nil), "pb.TypeReply") + proto.RegisterType((*InvalidateKeyArgs)(nil), "pb.InvalidateKeyArgs") + proto.RegisterType((*StorageEntry)(nil), "pb.StorageEntry") + proto.RegisterType((*StorageListArgs)(nil), "pb.StorageListArgs") + proto.RegisterType((*StorageListReply)(nil), "pb.StorageListReply") + proto.RegisterType((*StorageGetArgs)(nil), "pb.StorageGetArgs") + proto.RegisterType((*StorageGetReply)(nil), "pb.StorageGetReply") + proto.RegisterType((*StoragePutArgs)(nil), "pb.StoragePutArgs") + proto.RegisterType((*StoragePutReply)(nil), "pb.StoragePutReply") + proto.RegisterType((*StorageDeleteArgs)(nil), "pb.StorageDeleteArgs") + proto.RegisterType((*StorageDeleteReply)(nil), "pb.StorageDeleteReply") + proto.RegisterType((*TTLReply)(nil), "pb.TTLReply") + proto.RegisterType((*SudoPrivilegeArgs)(nil), "pb.SudoPrivilegeArgs") + proto.RegisterType((*SudoPrivilegeReply)(nil), "pb.SudoPrivilegeReply") + proto.RegisterType((*TaintedReply)(nil), "pb.TaintedReply") + proto.RegisterType((*CachingDisabledReply)(nil), "pb.CachingDisabledReply") + proto.RegisterType((*ReplicationStateReply)(nil), "pb.ReplicationStateReply") + proto.RegisterType((*ResponseWrapDataArgs)(nil), "pb.ResponseWrapDataArgs") + proto.RegisterType((*ResponseWrapDataReply)(nil), "pb.ResponseWrapDataReply") + proto.RegisterType((*MlockEnabledReply)(nil), "pb.MlockEnabledReply") + proto.RegisterType((*LocalMountReply)(nil), "pb.LocalMountReply") + proto.RegisterType((*EntityInfoArgs)(nil), "pb.EntityInfoArgs") + proto.RegisterType((*EntityInfoReply)(nil), "pb.EntityInfoReply") + proto.RegisterType((*Connection)(nil), "pb.Connection") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// BackendClient is the client API for Backend service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type BackendClient interface { + // HandleRequest is used to handle a request and generate a response. + // The plugins must check the operation type and handle appropriately. + HandleRequest(ctx context.Context, in *HandleRequestArgs, opts ...grpc.CallOption) (*HandleRequestReply, error) + // SpecialPaths is a list of paths that are special in some way. + // See PathType for the types of special paths. The key is the type + // of the special path, and the value is a list of paths for this type. + // This is not a regular expression but is an exact match. If the path + // ends in '*' then it is a prefix-based match. The '*' can only appear + // at the end. + SpecialPaths(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SpecialPathsReply, error) + // HandleExistenceCheck is used to handle a request and generate a response + // indicating whether the given path exists or not; this is used to + // understand whether the request must have a Create or Update capability + // ACL applied. The first bool indicates whether an existence check + // function was found for the backend; the second indicates whether, if an + // existence check function was found, the item exists or not. + HandleExistenceCheck(ctx context.Context, in *HandleExistenceCheckArgs, opts ...grpc.CallOption) (*HandleExistenceCheckReply, error) + // Cleanup is invoked during an unmount of a backend to allow it to + // handle any cleanup like connection closing or releasing of file handles. + // Cleanup is called right before Vault closes the plugin process. + Cleanup(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + // InvalidateKey may be invoked when an object is modified that belongs + // to the backend. The backend can use this to clear any caches or reset + // internal state as needed. + InvalidateKey(ctx context.Context, in *InvalidateKeyArgs, opts ...grpc.CallOption) (*Empty, error) + // Setup is used to set up the backend based on the provided backend + // configuration. The plugin's setup implementation should use the provided + // broker_id to create a connection back to Vault for use with the Storage + // and SystemView clients. + Setup(ctx context.Context, in *SetupArgs, opts ...grpc.CallOption) (*SetupReply, error) + // Type returns the BackendType for the particular backend + Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error) +} + +type backendClient struct { + cc *grpc.ClientConn +} + +func NewBackendClient(cc *grpc.ClientConn) BackendClient { + return &backendClient{cc} +} + +func (c *backendClient) HandleRequest(ctx context.Context, in *HandleRequestArgs, opts ...grpc.CallOption) (*HandleRequestReply, error) { + out := new(HandleRequestReply) + err := c.cc.Invoke(ctx, "/pb.Backend/HandleRequest", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) SpecialPaths(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SpecialPathsReply, error) { + out := new(SpecialPathsReply) + err := c.cc.Invoke(ctx, "/pb.Backend/SpecialPaths", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) HandleExistenceCheck(ctx context.Context, in *HandleExistenceCheckArgs, opts ...grpc.CallOption) (*HandleExistenceCheckReply, error) { + out := new(HandleExistenceCheckReply) + err := c.cc.Invoke(ctx, "/pb.Backend/HandleExistenceCheck", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) Cleanup(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/pb.Backend/Cleanup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) InvalidateKey(ctx context.Context, in *InvalidateKeyArgs, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/pb.Backend/InvalidateKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) Setup(ctx context.Context, in *SetupArgs, opts ...grpc.CallOption) (*SetupReply, error) { + out := new(SetupReply) + err := c.cc.Invoke(ctx, "/pb.Backend/Setup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *backendClient) Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error) { + out := new(TypeReply) + err := c.cc.Invoke(ctx, "/pb.Backend/Type", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BackendServer is the server API for Backend service. +type BackendServer interface { + // HandleRequest is used to handle a request and generate a response. + // The plugins must check the operation type and handle appropriately. + HandleRequest(context.Context, *HandleRequestArgs) (*HandleRequestReply, error) + // SpecialPaths is a list of paths that are special in some way. + // See PathType for the types of special paths. The key is the type + // of the special path, and the value is a list of paths for this type. + // This is not a regular expression but is an exact match. If the path + // ends in '*' then it is a prefix-based match. The '*' can only appear + // at the end. + SpecialPaths(context.Context, *Empty) (*SpecialPathsReply, error) + // HandleExistenceCheck is used to handle a request and generate a response + // indicating whether the given path exists or not; this is used to + // understand whether the request must have a Create or Update capability + // ACL applied. The first bool indicates whether an existence check + // function was found for the backend; the second indicates whether, if an + // existence check function was found, the item exists or not. + HandleExistenceCheck(context.Context, *HandleExistenceCheckArgs) (*HandleExistenceCheckReply, error) + // Cleanup is invoked during an unmount of a backend to allow it to + // handle any cleanup like connection closing or releasing of file handles. + // Cleanup is called right before Vault closes the plugin process. + Cleanup(context.Context, *Empty) (*Empty, error) + // InvalidateKey may be invoked when an object is modified that belongs + // to the backend. The backend can use this to clear any caches or reset + // internal state as needed. + InvalidateKey(context.Context, *InvalidateKeyArgs) (*Empty, error) + // Setup is used to set up the backend based on the provided backend + // configuration. The plugin's setup implementation should use the provided + // broker_id to create a connection back to Vault for use with the Storage + // and SystemView clients. + Setup(context.Context, *SetupArgs) (*SetupReply, error) + // Type returns the BackendType for the particular backend + Type(context.Context, *Empty) (*TypeReply, error) +} + +func RegisterBackendServer(s *grpc.Server, srv BackendServer) { + s.RegisterService(&_Backend_serviceDesc, srv) +} + +func _Backend_HandleRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HandleRequestArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).HandleRequest(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/HandleRequest", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).HandleRequest(ctx, req.(*HandleRequestArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_SpecialPaths_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).SpecialPaths(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/SpecialPaths", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).SpecialPaths(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_HandleExistenceCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HandleExistenceCheckArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).HandleExistenceCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/HandleExistenceCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).HandleExistenceCheck(ctx, req.(*HandleExistenceCheckArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_Cleanup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).Cleanup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/Cleanup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).Cleanup(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_InvalidateKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InvalidateKeyArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).InvalidateKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/InvalidateKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).InvalidateKey(ctx, req.(*InvalidateKeyArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_Setup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetupArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).Setup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/Setup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).Setup(ctx, req.(*SetupArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Backend_Type_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BackendServer).Type(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Backend/Type", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BackendServer).Type(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +var _Backend_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pb.Backend", + HandlerType: (*BackendServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "HandleRequest", + Handler: _Backend_HandleRequest_Handler, + }, + { + MethodName: "SpecialPaths", + Handler: _Backend_SpecialPaths_Handler, + }, + { + MethodName: "HandleExistenceCheck", + Handler: _Backend_HandleExistenceCheck_Handler, + }, + { + MethodName: "Cleanup", + Handler: _Backend_Cleanup_Handler, + }, + { + MethodName: "InvalidateKey", + Handler: _Backend_InvalidateKey_Handler, + }, + { + MethodName: "Setup", + Handler: _Backend_Setup_Handler, + }, + { + MethodName: "Type", + Handler: _Backend_Type_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "logical/plugin/pb/backend.proto", +} + +// StorageClient is the client API for Storage service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type StorageClient interface { + List(ctx context.Context, in *StorageListArgs, opts ...grpc.CallOption) (*StorageListReply, error) + Get(ctx context.Context, in *StorageGetArgs, opts ...grpc.CallOption) (*StorageGetReply, error) + Put(ctx context.Context, in *StoragePutArgs, opts ...grpc.CallOption) (*StoragePutReply, error) + Delete(ctx context.Context, in *StorageDeleteArgs, opts ...grpc.CallOption) (*StorageDeleteReply, error) +} + +type storageClient struct { + cc *grpc.ClientConn +} + +func NewStorageClient(cc *grpc.ClientConn) StorageClient { + return &storageClient{cc} +} + +func (c *storageClient) List(ctx context.Context, in *StorageListArgs, opts ...grpc.CallOption) (*StorageListReply, error) { + out := new(StorageListReply) + err := c.cc.Invoke(ctx, "/pb.Storage/List", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) Get(ctx context.Context, in *StorageGetArgs, opts ...grpc.CallOption) (*StorageGetReply, error) { + out := new(StorageGetReply) + err := c.cc.Invoke(ctx, "/pb.Storage/Get", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) Put(ctx context.Context, in *StoragePutArgs, opts ...grpc.CallOption) (*StoragePutReply, error) { + out := new(StoragePutReply) + err := c.cc.Invoke(ctx, "/pb.Storage/Put", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) Delete(ctx context.Context, in *StorageDeleteArgs, opts ...grpc.CallOption) (*StorageDeleteReply, error) { + out := new(StorageDeleteReply) + err := c.cc.Invoke(ctx, "/pb.Storage/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StorageServer is the server API for Storage service. +type StorageServer interface { + List(context.Context, *StorageListArgs) (*StorageListReply, error) + Get(context.Context, *StorageGetArgs) (*StorageGetReply, error) + Put(context.Context, *StoragePutArgs) (*StoragePutReply, error) + Delete(context.Context, *StorageDeleteArgs) (*StorageDeleteReply, error) +} + +func RegisterStorageServer(s *grpc.Server, srv StorageServer) { + s.RegisterService(&_Storage_serviceDesc, srv) +} + +func _Storage_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StorageListArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Storage/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).List(ctx, req.(*StorageListArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StorageGetArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).Get(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Storage/Get", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).Get(ctx, req.(*StorageGetArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_Put_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StoragePutArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).Put(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Storage/Put", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).Put(ctx, req.(*StoragePutArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StorageDeleteArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.Storage/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).Delete(ctx, req.(*StorageDeleteArgs)) + } + return interceptor(ctx, in, info, handler) +} + +var _Storage_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pb.Storage", + HandlerType: (*StorageServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "List", + Handler: _Storage_List_Handler, + }, + { + MethodName: "Get", + Handler: _Storage_Get_Handler, + }, + { + MethodName: "Put", + Handler: _Storage_Put_Handler, + }, + { + MethodName: "Delete", + Handler: _Storage_Delete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "logical/plugin/pb/backend.proto", +} + +// SystemViewClient is the client API for SystemView service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SystemViewClient interface { + // DefaultLeaseTTL returns the default lease TTL set in Vault configuration + DefaultLeaseTTL(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TTLReply, error) + // MaxLeaseTTL returns the max lease TTL set in Vault configuration; backend + // authors should take care not to issue credentials that last longer than + // this value, as Vault will revoke them + MaxLeaseTTL(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TTLReply, error) + // SudoPrivilege returns true if given path has sudo privileges + // for the given client token + SudoPrivilege(ctx context.Context, in *SudoPrivilegeArgs, opts ...grpc.CallOption) (*SudoPrivilegeReply, error) + // Tainted, returns true if the mount is tainted. A mount is tainted if it is in the + // process of being unmounted. This should only be used in special + // circumstances; a primary use-case is as a guard in revocation functions. + // If revocation of a backend's leases fails it can keep the unmounting + // process from being successful. If the reason for this failure is not + // relevant when the mount is tainted (for instance, saving a CRL to disk + // when the stored CRL will be removed during the unmounting process + // anyways), we can ignore the errors to allow unmounting to complete. + Tainted(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TaintedReply, error) + // CachingDisabled returns true if caching is disabled. If true, no caches + // should be used, despite known slowdowns. + CachingDisabled(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*CachingDisabledReply, error) + // ReplicationState indicates the state of cluster replication + ReplicationState(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ReplicationStateReply, error) + // ResponseWrapData wraps the given data in a cubbyhole and returns the + // token used to unwrap. + ResponseWrapData(ctx context.Context, in *ResponseWrapDataArgs, opts ...grpc.CallOption) (*ResponseWrapDataReply, error) + // MlockEnabled returns the configuration setting for enabling mlock on + // plugins. + MlockEnabled(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*MlockEnabledReply, error) + // LocalMount, when run from a system view attached to a request, indicates + // whether the request is affecting a local mount or not + LocalMount(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*LocalMountReply, error) + // EntityInfo returns the basic entity information for the given entity id + EntityInfo(ctx context.Context, in *EntityInfoArgs, opts ...grpc.CallOption) (*EntityInfoReply, error) +} + +type systemViewClient struct { + cc *grpc.ClientConn +} + +func NewSystemViewClient(cc *grpc.ClientConn) SystemViewClient { + return &systemViewClient{cc} +} + +func (c *systemViewClient) DefaultLeaseTTL(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TTLReply, error) { + out := new(TTLReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/DefaultLeaseTTL", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) MaxLeaseTTL(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TTLReply, error) { + out := new(TTLReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/MaxLeaseTTL", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) SudoPrivilege(ctx context.Context, in *SudoPrivilegeArgs, opts ...grpc.CallOption) (*SudoPrivilegeReply, error) { + out := new(SudoPrivilegeReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/SudoPrivilege", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) Tainted(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TaintedReply, error) { + out := new(TaintedReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/Tainted", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) CachingDisabled(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*CachingDisabledReply, error) { + out := new(CachingDisabledReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/CachingDisabled", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) ReplicationState(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ReplicationStateReply, error) { + out := new(ReplicationStateReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/ReplicationState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) ResponseWrapData(ctx context.Context, in *ResponseWrapDataArgs, opts ...grpc.CallOption) (*ResponseWrapDataReply, error) { + out := new(ResponseWrapDataReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/ResponseWrapData", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) MlockEnabled(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*MlockEnabledReply, error) { + out := new(MlockEnabledReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/MlockEnabled", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) LocalMount(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*LocalMountReply, error) { + out := new(LocalMountReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/LocalMount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) EntityInfo(ctx context.Context, in *EntityInfoArgs, opts ...grpc.CallOption) (*EntityInfoReply, error) { + out := new(EntityInfoReply) + err := c.cc.Invoke(ctx, "/pb.SystemView/EntityInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SystemViewServer is the server API for SystemView service. +type SystemViewServer interface { + // DefaultLeaseTTL returns the default lease TTL set in Vault configuration + DefaultLeaseTTL(context.Context, *Empty) (*TTLReply, error) + // MaxLeaseTTL returns the max lease TTL set in Vault configuration; backend + // authors should take care not to issue credentials that last longer than + // this value, as Vault will revoke them + MaxLeaseTTL(context.Context, *Empty) (*TTLReply, error) + // SudoPrivilege returns true if given path has sudo privileges + // for the given client token + SudoPrivilege(context.Context, *SudoPrivilegeArgs) (*SudoPrivilegeReply, error) + // Tainted, returns true if the mount is tainted. A mount is tainted if it is in the + // process of being unmounted. This should only be used in special + // circumstances; a primary use-case is as a guard in revocation functions. + // If revocation of a backend's leases fails it can keep the unmounting + // process from being successful. If the reason for this failure is not + // relevant when the mount is tainted (for instance, saving a CRL to disk + // when the stored CRL will be removed during the unmounting process + // anyways), we can ignore the errors to allow unmounting to complete. + Tainted(context.Context, *Empty) (*TaintedReply, error) + // CachingDisabled returns true if caching is disabled. If true, no caches + // should be used, despite known slowdowns. + CachingDisabled(context.Context, *Empty) (*CachingDisabledReply, error) + // ReplicationState indicates the state of cluster replication + ReplicationState(context.Context, *Empty) (*ReplicationStateReply, error) + // ResponseWrapData wraps the given data in a cubbyhole and returns the + // token used to unwrap. + ResponseWrapData(context.Context, *ResponseWrapDataArgs) (*ResponseWrapDataReply, error) + // MlockEnabled returns the configuration setting for enabling mlock on + // plugins. + MlockEnabled(context.Context, *Empty) (*MlockEnabledReply, error) + // LocalMount, when run from a system view attached to a request, indicates + // whether the request is affecting a local mount or not + LocalMount(context.Context, *Empty) (*LocalMountReply, error) + // EntityInfo returns the basic entity information for the given entity id + EntityInfo(context.Context, *EntityInfoArgs) (*EntityInfoReply, error) +} + +func RegisterSystemViewServer(s *grpc.Server, srv SystemViewServer) { + s.RegisterService(&_SystemView_serviceDesc, srv) +} + +func _SystemView_DefaultLeaseTTL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).DefaultLeaseTTL(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/DefaultLeaseTTL", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).DefaultLeaseTTL(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_MaxLeaseTTL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).MaxLeaseTTL(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/MaxLeaseTTL", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).MaxLeaseTTL(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_SudoPrivilege_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SudoPrivilegeArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).SudoPrivilege(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/SudoPrivilege", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).SudoPrivilege(ctx, req.(*SudoPrivilegeArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_Tainted_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).Tainted(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/Tainted", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).Tainted(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_CachingDisabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).CachingDisabled(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/CachingDisabled", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).CachingDisabled(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_ReplicationState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).ReplicationState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/ReplicationState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).ReplicationState(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_ResponseWrapData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResponseWrapDataArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).ResponseWrapData(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/ResponseWrapData", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).ResponseWrapData(ctx, req.(*ResponseWrapDataArgs)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_MlockEnabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).MlockEnabled(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/MlockEnabled", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).MlockEnabled(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_LocalMount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).LocalMount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/LocalMount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).LocalMount(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_EntityInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EntityInfoArgs) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).EntityInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.SystemView/EntityInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).EntityInfo(ctx, req.(*EntityInfoArgs)) + } + return interceptor(ctx, in, info, handler) +} + +var _SystemView_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pb.SystemView", + HandlerType: (*SystemViewServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DefaultLeaseTTL", + Handler: _SystemView_DefaultLeaseTTL_Handler, + }, + { + MethodName: "MaxLeaseTTL", + Handler: _SystemView_MaxLeaseTTL_Handler, + }, + { + MethodName: "SudoPrivilege", + Handler: _SystemView_SudoPrivilege_Handler, + }, + { + MethodName: "Tainted", + Handler: _SystemView_Tainted_Handler, + }, + { + MethodName: "CachingDisabled", + Handler: _SystemView_CachingDisabled_Handler, + }, + { + MethodName: "ReplicationState", + Handler: _SystemView_ReplicationState_Handler, + }, + { + MethodName: "ResponseWrapData", + Handler: _SystemView_ResponseWrapData_Handler, + }, + { + MethodName: "MlockEnabled", + Handler: _SystemView_MlockEnabled_Handler, + }, + { + MethodName: "LocalMount", + Handler: _SystemView_LocalMount_Handler, + }, + { + MethodName: "EntityInfo", + Handler: _SystemView_EntityInfo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "logical/plugin/pb/backend.proto", +} + +func init() { + proto.RegisterFile("logical/plugin/pb/backend.proto", fileDescriptor_backend_b95a338e744ea757) +} + +var fileDescriptor_backend_b95a338e744ea757 = []byte{ + // 2201 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5f, 0x73, 0xdb, 0xc6, + 0x11, 0x1f, 0xfe, 0x07, 0x97, 0xa4, 0x28, 0x9d, 0x15, 0x17, 0xa6, 0x9d, 0x9a, 0x45, 0x6a, 0x9b, + 0xf1, 0xc4, 0x94, 0xcd, 0x34, 0xad, 0xd3, 0x4e, 0xd2, 0x51, 0x24, 0xc5, 0x51, 0x23, 0x25, 0x1a, + 0x48, 0x6e, 0xfa, 0x6f, 0x86, 0x39, 0x02, 0x2b, 0x12, 0x23, 0x10, 0x40, 0x0f, 0x07, 0xc9, 0x7c, + 0xea, 0xb7, 0xe8, 0x43, 0x67, 0xfa, 0x19, 0xfa, 0xda, 0xb7, 0xbe, 0x76, 0xa6, 0xcf, 0xfd, 0x1a, + 0xfd, 0x0c, 0x9d, 0xfb, 0x03, 0x10, 0x20, 0xa9, 0xc6, 0x9d, 0x69, 0xdf, 0x6e, 0xff, 0xdd, 0xde, + 0x2e, 0x76, 0x7f, 0x7b, 0x07, 0x78, 0xe8, 0x87, 0x53, 0xcf, 0xa1, 0xfe, 0x5e, 0xe4, 0x27, 0x53, + 0x2f, 0xd8, 0x8b, 0x26, 0x7b, 0x13, 0xea, 0x5c, 0x61, 0xe0, 0x0e, 0x23, 0x16, 0xf2, 0x90, 0x94, + 0xa3, 0x49, 0xef, 0xe1, 0x34, 0x0c, 0xa7, 0x3e, 0xee, 0x49, 0xce, 0x24, 0xb9, 0xdc, 0xe3, 0xde, + 0x1c, 0x63, 0x4e, 0xe7, 0x91, 0x52, 0xea, 0xdd, 0x4d, 0x77, 0xf1, 0x5c, 0x0c, 0xb8, 0xc7, 0x17, + 0x8a, 0x6f, 0x35, 0xa0, 0x76, 0x34, 0x8f, 0xf8, 0xc2, 0xea, 0x43, 0xfd, 0x0b, 0xa4, 0x2e, 0x32, + 0x72, 0x17, 0xea, 0x33, 0xb9, 0x32, 0x4b, 0xfd, 0xca, 0xa0, 0x69, 0x6b, 0xca, 0xfa, 0x2d, 0xc0, + 0x99, 0xb0, 0x39, 0x62, 0x2c, 0x64, 0xe4, 0x1e, 0x18, 0xc8, 0xd8, 0x98, 0x2f, 0x22, 0x34, 0x4b, + 0xfd, 0xd2, 0xa0, 0x63, 0x37, 0x90, 0xb1, 0x8b, 0x45, 0x84, 0xe4, 0x7b, 0x20, 0x96, 0xe3, 0x79, + 0x3c, 0x35, 0xcb, 0xfd, 0x92, 0xd8, 0x01, 0x19, 0x3b, 0x8d, 0xa7, 0xa9, 0x8d, 0x13, 0xba, 0x68, + 0x56, 0xfa, 0xa5, 0x41, 0x45, 0xda, 0x1c, 0x84, 0x2e, 0x5a, 0x7f, 0x2c, 0x41, 0xed, 0x8c, 0xf2, + 0x59, 0x4c, 0x08, 0x54, 0x59, 0x18, 0x72, 0xed, 0x5c, 0xae, 0xc9, 0x00, 0xba, 0x49, 0x40, 0x13, + 0x3e, 0x13, 0x67, 0x77, 0x28, 0x47, 0xd7, 0x2c, 0x4b, 0xf1, 0x2a, 0x9b, 0xbc, 0x07, 0x1d, 0x3f, + 0x74, 0xa8, 0x3f, 0x8e, 0x79, 0xc8, 0xe8, 0x54, 0xf8, 0x11, 0x7a, 0x6d, 0xc9, 0x3c, 0x57, 0x3c, + 0xf2, 0x14, 0x76, 0x62, 0xa4, 0xfe, 0xf8, 0x86, 0xd1, 0x28, 0x53, 0xac, 0xaa, 0x0d, 0x85, 0xe0, + 0x1b, 0x46, 0x23, 0xad, 0x6b, 0xfd, 0xad, 0x0e, 0x0d, 0x1b, 0x7f, 0x9f, 0x60, 0xcc, 0xc9, 0x16, + 0x94, 0x3d, 0x57, 0x46, 0xdb, 0xb4, 0xcb, 0x9e, 0x4b, 0x86, 0x40, 0x6c, 0x8c, 0x7c, 0xe1, 0xda, + 0x0b, 0x83, 0x03, 0x3f, 0x89, 0x39, 0x32, 0x1d, 0xf3, 0x06, 0x09, 0x79, 0x00, 0xcd, 0x30, 0x42, + 0x26, 0x79, 0x32, 0x01, 0x4d, 0x7b, 0xc9, 0x10, 0x81, 0x47, 0x94, 0xcf, 0xcc, 0xaa, 0x14, 0xc8, + 0xb5, 0xe0, 0xb9, 0x94, 0x53, 0xb3, 0xa6, 0x78, 0x62, 0x4d, 0x2c, 0xa8, 0xc7, 0xe8, 0x30, 0xe4, + 0x66, 0xbd, 0x5f, 0x1a, 0xb4, 0x46, 0x30, 0x8c, 0x26, 0xc3, 0x73, 0xc9, 0xb1, 0xb5, 0x84, 0x3c, + 0x80, 0xaa, 0xc8, 0x8b, 0xd9, 0x90, 0x1a, 0x86, 0xd0, 0xd8, 0x4f, 0xf8, 0xcc, 0x96, 0x5c, 0x32, + 0x82, 0x86, 0xfa, 0xa6, 0xb1, 0x69, 0xf4, 0x2b, 0x83, 0xd6, 0xc8, 0x14, 0x0a, 0x3a, 0xca, 0xa1, + 0x2a, 0x83, 0xf8, 0x28, 0xe0, 0x6c, 0x61, 0xa7, 0x8a, 0xe4, 0x07, 0xd0, 0x76, 0x7c, 0x0f, 0x03, + 0x3e, 0xe6, 0xe1, 0x15, 0x06, 0x66, 0x53, 0x9e, 0xa8, 0xa5, 0x78, 0x17, 0x82, 0x45, 0x46, 0xf0, + 0x4e, 0x5e, 0x65, 0x4c, 0x1d, 0x07, 0xe3, 0x38, 0x64, 0x26, 0x48, 0xdd, 0x3b, 0x39, 0xdd, 0x7d, + 0x2d, 0x12, 0xdb, 0xba, 0x5e, 0x1c, 0xf9, 0x74, 0x31, 0x0e, 0xe8, 0x1c, 0xcd, 0x96, 0xda, 0x56, + 0xf3, 0xbe, 0xa2, 0x73, 0x24, 0x0f, 0xa1, 0x35, 0x0f, 0x93, 0x80, 0x8f, 0xa3, 0xd0, 0x0b, 0xb8, + 0xd9, 0x96, 0x1a, 0x20, 0x59, 0x67, 0x82, 0x43, 0xde, 0x05, 0x45, 0xa9, 0x62, 0xec, 0xa8, 0xbc, + 0x4a, 0x8e, 0x2c, 0xc7, 0x47, 0xb0, 0xa5, 0xc4, 0xd9, 0x79, 0xb6, 0xa4, 0x4a, 0x47, 0x72, 0xb3, + 0x93, 0x3c, 0x87, 0xa6, 0xac, 0x07, 0x2f, 0xb8, 0x0c, 0xcd, 0xae, 0xcc, 0xdb, 0x9d, 0x5c, 0x5a, + 0x44, 0x4d, 0x1c, 0x07, 0x97, 0xa1, 0x6d, 0xdc, 0xe8, 0x15, 0xf9, 0x04, 0xee, 0x17, 0xe2, 0x65, + 0x38, 0xa7, 0x5e, 0xe0, 0x05, 0xd3, 0x71, 0x12, 0x63, 0x6c, 0x6e, 0xcb, 0x0a, 0x37, 0x73, 0x51, + 0xdb, 0xa9, 0xc2, 0xeb, 0x18, 0x63, 0x72, 0x1f, 0x9a, 0xaa, 0x15, 0xc7, 0x9e, 0x6b, 0xee, 0xc8, + 0x23, 0x19, 0x8a, 0x71, 0xec, 0x92, 0x27, 0xd0, 0x8d, 0x42, 0xdf, 0x73, 0x16, 0xe3, 0xf0, 0x1a, + 0x19, 0xf3, 0x5c, 0x34, 0x49, 0xbf, 0x34, 0x30, 0xec, 0x2d, 0xc5, 0xfe, 0x5a, 0x73, 0x37, 0xb5, + 0xc6, 0x1d, 0xa9, 0xb8, 0xd6, 0x1a, 0x43, 0x00, 0x27, 0x0c, 0x02, 0x74, 0x64, 0xf9, 0xed, 0xca, + 0x08, 0xb7, 0x44, 0x84, 0x07, 0x19, 0xd7, 0xce, 0x69, 0xf4, 0x3e, 0x87, 0x76, 0xbe, 0x14, 0xc8, + 0x36, 0x54, 0xae, 0x70, 0xa1, 0xcb, 0x5f, 0x2c, 0x49, 0x1f, 0x6a, 0xd7, 0xd4, 0x4f, 0x50, 0x96, + 0xbc, 0x2e, 0x44, 0x65, 0x62, 0x2b, 0xc1, 0x4f, 0xcb, 0x2f, 0x4b, 0xd6, 0x9f, 0xab, 0x50, 0x15, + 0xc5, 0x47, 0x3e, 0x82, 0x8e, 0x8f, 0x34, 0xc6, 0x71, 0x18, 0x09, 0x07, 0xb1, 0xdc, 0xaa, 0x35, + 0xda, 0x16, 0x66, 0x27, 0x42, 0xf0, 0xb5, 0xe2, 0xdb, 0x6d, 0x3f, 0x47, 0x89, 0x96, 0xf6, 0x02, + 0x8e, 0x2c, 0xa0, 0xfe, 0x58, 0x36, 0x83, 0x6a, 0xb0, 0x76, 0xca, 0x3c, 0x14, 0x4d, 0xb1, 0x5a, + 0x47, 0x95, 0xf5, 0x3a, 0xea, 0x81, 0x21, 0x73, 0xe7, 0x61, 0xac, 0x9b, 0x3d, 0xa3, 0xc9, 0x08, + 0x8c, 0x39, 0x72, 0xaa, 0x7b, 0x4d, 0xb4, 0xc4, 0xdd, 0xb4, 0x67, 0x86, 0xa7, 0x5a, 0xa0, 0x1a, + 0x22, 0xd3, 0x5b, 0xeb, 0x88, 0xfa, 0x7a, 0x47, 0xf4, 0xc0, 0xc8, 0x8a, 0xae, 0xa1, 0xbe, 0x70, + 0x4a, 0x0b, 0x98, 0x8d, 0x90, 0x79, 0xa1, 0x6b, 0x1a, 0xb2, 0x50, 0x34, 0x25, 0x40, 0x32, 0x48, + 0xe6, 0xaa, 0x84, 0x9a, 0x0a, 0x24, 0x83, 0x64, 0xbe, 0x5e, 0x31, 0xb0, 0x52, 0x31, 0x3f, 0x84, + 0x1a, 0xf5, 0x3d, 0x1a, 0xcb, 0x16, 0x12, 0x5f, 0x56, 0x23, 0xfe, 0x70, 0x5f, 0x70, 0x6d, 0x25, + 0x24, 0x1f, 0x42, 0x67, 0xca, 0xc2, 0x24, 0x1a, 0x4b, 0x12, 0x63, 0xb3, 0x2d, 0xa3, 0x5d, 0xd5, + 0x6e, 0x4b, 0xa5, 0x7d, 0xa5, 0x23, 0x3a, 0x70, 0x12, 0x26, 0x81, 0x3b, 0x76, 0x3c, 0x97, 0xc5, + 0x66, 0x47, 0x26, 0x0f, 0x24, 0xeb, 0x40, 0x70, 0x7a, 0x3f, 0x83, 0x4e, 0x21, 0x4b, 0x1b, 0x6a, + 0x65, 0x37, 0x5f, 0x2b, 0xcd, 0x7c, 0x7d, 0xfc, 0xa5, 0x04, 0xed, 0xfc, 0xe7, 0x17, 0xc6, 0x17, + 0x17, 0x27, 0xd2, 0xb8, 0x62, 0x8b, 0xa5, 0x00, 0x4e, 0x86, 0x01, 0xde, 0xd0, 0x89, 0xaf, 0x36, + 0x30, 0xec, 0x25, 0x43, 0x48, 0xbd, 0xc0, 0x61, 0x38, 0xc7, 0x80, 0xeb, 0xb9, 0xb2, 0x64, 0x90, + 0x8f, 0x01, 0xbc, 0x38, 0x4e, 0x70, 0x2c, 0x46, 0xa2, 0x04, 0xd7, 0xd6, 0xa8, 0x37, 0x54, 0xf3, + 0x72, 0x98, 0xce, 0xcb, 0xe1, 0x45, 0x3a, 0x2f, 0xed, 0xa6, 0xd4, 0x16, 0xb4, 0xf8, 0x44, 0xa7, + 0xf4, 0x8d, 0x38, 0x4b, 0x4d, 0x7d, 0x22, 0x45, 0x59, 0x7f, 0x80, 0xba, 0xc2, 0xdb, 0xff, 0x6b, + 0x49, 0xdf, 0x03, 0x43, 0xed, 0xed, 0xb9, 0xba, 0x9c, 0x1b, 0x92, 0x3e, 0x76, 0xad, 0x7f, 0x94, + 0xc0, 0xb0, 0x31, 0x8e, 0xc2, 0x20, 0xc6, 0xdc, 0x3c, 0x28, 0x7d, 0xe7, 0x3c, 0x28, 0x6f, 0x9c, + 0x07, 0xe9, 0x94, 0xa9, 0xe4, 0xa6, 0x4c, 0x0f, 0x0c, 0x86, 0xae, 0xc7, 0xd0, 0xe1, 0x7a, 0x22, + 0x65, 0xb4, 0x90, 0xdd, 0x50, 0x26, 0x80, 0x2c, 0x96, 0xdd, 0xd2, 0xb4, 0x33, 0x9a, 0xbc, 0xc8, + 0xc3, 0xa8, 0x1a, 0x50, 0xbb, 0x0a, 0x46, 0xd5, 0x71, 0xd7, 0x71, 0xd4, 0xfa, 0x7b, 0x19, 0xb6, + 0x57, 0xc5, 0x1b, 0x8a, 0x60, 0x17, 0x6a, 0xaa, 0xd1, 0x74, 0x05, 0xf1, 0xb5, 0x16, 0xab, 0xac, + 0xb4, 0xd8, 0xcf, 0xa1, 0xe3, 0x30, 0x94, 0xd3, 0xf5, 0x6d, 0xbf, 0x7e, 0x3b, 0x35, 0x90, 0x05, + 0xf0, 0x3e, 0x6c, 0x8b, 0x53, 0x46, 0xe8, 0x2e, 0x87, 0x87, 0x1a, 0xc5, 0x5d, 0xcd, 0xcf, 0xc6, + 0xc7, 0x53, 0xd8, 0x49, 0x55, 0x97, 0x3d, 0x5a, 0x2f, 0xe8, 0x1e, 0xa5, 0xad, 0x7a, 0x17, 0xea, + 0x97, 0x21, 0x9b, 0x53, 0xae, 0x41, 0x41, 0x53, 0xa2, 0x2c, 0xb2, 0xf3, 0xca, 0xab, 0x80, 0xa1, + 0xca, 0x22, 0x65, 0x8a, 0x0b, 0x92, 0x00, 0x81, 0xec, 0xf2, 0x22, 0x01, 0xc2, 0xb0, 0x8d, 0xf4, + 0xd2, 0x62, 0xfd, 0x0a, 0xba, 0x2b, 0xf3, 0x6a, 0x43, 0x22, 0x97, 0xee, 0xcb, 0x05, 0xf7, 0x85, + 0x9d, 0x2b, 0x2b, 0x3b, 0xff, 0x1a, 0x76, 0xbe, 0xa0, 0x81, 0xeb, 0xa3, 0xde, 0x7f, 0x9f, 0x4d, + 0x63, 0x31, 0x79, 0xf5, 0xf5, 0x69, 0xac, 0x2f, 0x46, 0x1d, 0xbb, 0xa9, 0x39, 0xc7, 0x2e, 0x79, + 0x04, 0x0d, 0xa6, 0xb4, 0x75, 0xe1, 0xb5, 0x72, 0x03, 0xd5, 0x4e, 0x65, 0xd6, 0xb7, 0x40, 0x0a, + 0x5b, 0x8b, 0x9b, 0xd3, 0x82, 0x0c, 0x44, 0x01, 0xaa, 0xa2, 0xd0, 0x85, 0xdd, 0xce, 0xd7, 0x91, + 0x9d, 0x49, 0x49, 0x1f, 0x2a, 0xc8, 0x98, 0x76, 0x21, 0x27, 0xda, 0xf2, 0x9e, 0x6a, 0x0b, 0x91, + 0xf5, 0x23, 0xd8, 0x39, 0x8f, 0xd0, 0xf1, 0xa8, 0x2f, 0xef, 0x98, 0xca, 0xc1, 0x43, 0xa8, 0x89, + 0x24, 0xa7, 0x3d, 0xdb, 0x94, 0x86, 0x52, 0xac, 0xf8, 0xd6, 0xb7, 0x60, 0xaa, 0x73, 0x1d, 0xbd, + 0xf1, 0x62, 0x8e, 0x81, 0x83, 0x07, 0x33, 0x74, 0xae, 0xfe, 0x87, 0x91, 0x5f, 0xc3, 0xbd, 0x4d, + 0x1e, 0xd2, 0xf3, 0xb5, 0x1c, 0x41, 0x8d, 0x2f, 0x05, 0xd0, 0x4a, 0x1f, 0x86, 0x0d, 0x92, 0xf5, + 0xb9, 0xe0, 0x88, 0xef, 0x88, 0xc2, 0x2e, 0xd6, 0x90, 0xa8, 0xa9, 0x34, 0x1f, 0x95, 0xdb, 0xf3, + 0xf1, 0xd7, 0x12, 0x34, 0xcf, 0x91, 0x27, 0x91, 0x8c, 0xe5, 0x3e, 0x34, 0x27, 0x2c, 0xbc, 0x42, + 0xb6, 0x0c, 0xc5, 0x50, 0x8c, 0x63, 0x97, 0xbc, 0x80, 0xfa, 0x41, 0x18, 0x5c, 0x7a, 0x53, 0x79, + 0xe3, 0x6e, 0x8d, 0xee, 0x29, 0x74, 0xd1, 0xb6, 0x43, 0x25, 0x53, 0xa3, 0x51, 0x2b, 0x92, 0x3e, + 0xb4, 0xf4, 0x0b, 0xe5, 0xf5, 0xeb, 0xe3, 0xc3, 0x74, 0x14, 0xe7, 0x58, 0xbd, 0x8f, 0xa1, 0x95, + 0x33, 0xfc, 0xaf, 0xa6, 0xc5, 0xf7, 0x01, 0xa4, 0x77, 0x95, 0xa3, 0x6d, 0x15, 0xaa, 0xb6, 0x14, + 0xa1, 0x3d, 0x84, 0xa6, 0xb8, 0xf5, 0x29, 0x31, 0x81, 0x6a, 0xee, 0x81, 0x22, 0xd7, 0xd6, 0x23, + 0xd8, 0x39, 0x0e, 0xae, 0xa9, 0xef, 0xb9, 0x94, 0xe3, 0x97, 0xb8, 0x90, 0x29, 0x58, 0x3b, 0x81, + 0x75, 0x0e, 0x6d, 0xfd, 0x04, 0x78, 0xab, 0x33, 0xb6, 0xf5, 0x19, 0xff, 0x73, 0x13, 0xbd, 0x0f, + 0x5d, 0xbd, 0xe9, 0x89, 0xa7, 0x5b, 0x48, 0x5c, 0x03, 0x18, 0x5e, 0x7a, 0x6f, 0xf4, 0xd6, 0x9a, + 0xb2, 0x5e, 0xc2, 0x76, 0x4e, 0x35, 0x0b, 0xe7, 0x0a, 0x17, 0x71, 0xfa, 0x34, 0x12, 0xeb, 0x34, + 0x03, 0xe5, 0x65, 0x06, 0x2c, 0xd8, 0xd2, 0x96, 0xaf, 0x90, 0xdf, 0x12, 0xdd, 0x97, 0xd9, 0x41, + 0x5e, 0xa1, 0xde, 0xfc, 0x31, 0xd4, 0x50, 0x44, 0x9a, 0x1f, 0x61, 0xf9, 0x0c, 0xd8, 0x4a, 0xbc, + 0xc1, 0xe1, 0xcb, 0xcc, 0xe1, 0x59, 0xa2, 0x1c, 0xbe, 0xe5, 0x5e, 0xd6, 0x7b, 0xd9, 0x31, 0xce, + 0x12, 0x7e, 0xdb, 0x17, 0x7d, 0x04, 0x3b, 0x5a, 0xe9, 0x10, 0x7d, 0xe4, 0x78, 0x4b, 0x48, 0x8f, + 0x81, 0x14, 0xd4, 0x6e, 0xdb, 0xee, 0x01, 0x18, 0x17, 0x17, 0x27, 0x99, 0xb4, 0x88, 0x8d, 0xd6, + 0x27, 0xb0, 0x73, 0x9e, 0xb8, 0xe1, 0x19, 0xf3, 0xae, 0x3d, 0x1f, 0xa7, 0xca, 0x59, 0xfa, 0x32, + 0x2b, 0xe5, 0x5e, 0x66, 0x1b, 0xa7, 0x91, 0x35, 0x00, 0x52, 0x30, 0xcf, 0xbe, 0x5b, 0x9c, 0xb8, + 0xa1, 0x6e, 0x61, 0xb9, 0xb6, 0x06, 0xd0, 0xbe, 0xa0, 0x62, 0xde, 0xbb, 0x4a, 0xc7, 0x84, 0x06, + 0x57, 0xb4, 0x56, 0x4b, 0x49, 0x6b, 0x04, 0xbb, 0x07, 0xd4, 0x99, 0x79, 0xc1, 0xf4, 0xd0, 0x8b, + 0xc5, 0x85, 0x47, 0x5b, 0xf4, 0xc0, 0x70, 0x35, 0x43, 0x9b, 0x64, 0xb4, 0xf5, 0x0c, 0xde, 0xc9, + 0xbd, 0x3f, 0xcf, 0x39, 0x4d, 0xf3, 0xb1, 0x0b, 0xb5, 0x58, 0x50, 0xd2, 0xa2, 0x66, 0x2b, 0xc2, + 0xfa, 0x0a, 0x76, 0xf3, 0x03, 0x58, 0x5c, 0x3f, 0xd2, 0xc0, 0xe5, 0xc5, 0xa0, 0x94, 0xbb, 0x18, + 0xe8, 0x9c, 0x95, 0x97, 0xf3, 0x64, 0x1b, 0x2a, 0xbf, 0xf8, 0xe6, 0x42, 0x17, 0xbb, 0x58, 0x5a, + 0xbf, 0x13, 0xee, 0x8b, 0xfb, 0x29, 0xf7, 0x85, 0xdb, 0x41, 0xe9, 0x6d, 0x6e, 0x07, 0x1b, 0xea, + 0xed, 0x19, 0xec, 0x9c, 0xfa, 0xa1, 0x73, 0x75, 0x14, 0xe4, 0xb2, 0x61, 0x42, 0x03, 0x83, 0x7c, + 0x32, 0x52, 0xd2, 0x7a, 0x02, 0xdd, 0x13, 0xf1, 0xfa, 0x3f, 0x15, 0xcf, 0xbd, 0x2c, 0x0b, 0xf2, + 0x87, 0x80, 0x56, 0x55, 0x84, 0xf5, 0x0c, 0xb6, 0xf4, 0x88, 0x0e, 0x2e, 0xc3, 0x14, 0x19, 0x97, + 0xc3, 0xbc, 0x54, 0xbc, 0x70, 0x5b, 0x27, 0xd0, 0x5d, 0xaa, 0xab, 0x7d, 0x9f, 0x40, 0x5d, 0x89, + 0x75, 0x6c, 0xdd, 0xec, 0x5a, 0xad, 0x34, 0x6d, 0x2d, 0xde, 0x18, 0x14, 0x2c, 0xdf, 0x61, 0x02, + 0xfb, 0x19, 0xce, 0x43, 0x8e, 0x63, 0xea, 0xba, 0x69, 0xf9, 0x82, 0x62, 0xed, 0xbb, 0x2e, 0x1b, + 0xfd, 0xab, 0x0c, 0x8d, 0xcf, 0x14, 0xa2, 0x92, 0x4f, 0xa1, 0x53, 0x98, 0x9f, 0xe4, 0x1d, 0xf9, + 0x10, 0x5b, 0x9d, 0xd6, 0xbd, 0xbb, 0x6b, 0x6c, 0x75, 0xea, 0xe7, 0xd0, 0xce, 0x4f, 0x47, 0x22, + 0x27, 0xa1, 0xfc, 0x2b, 0xd4, 0x93, 0x3b, 0xad, 0x8f, 0xce, 0x73, 0xd8, 0xdd, 0x34, 0xb7, 0xc8, + 0x83, 0xa5, 0x87, 0xf5, 0x99, 0xd9, 0x7b, 0xf7, 0x36, 0x69, 0x3a, 0xef, 0x1a, 0x07, 0x3e, 0xd2, + 0x20, 0x89, 0xf2, 0x27, 0x58, 0x2e, 0xc9, 0x0b, 0xe8, 0x14, 0x90, 0x5b, 0xc5, 0xb9, 0x06, 0xe6, + 0x79, 0x93, 0xc7, 0x50, 0x93, 0xd3, 0x82, 0x74, 0x0a, 0x63, 0xab, 0xb7, 0x95, 0x91, 0xca, 0x77, + 0x1f, 0xaa, 0xf2, 0x5f, 0x41, 0xce, 0xb1, 0xb4, 0xc8, 0x46, 0xc9, 0xe8, 0x9f, 0x25, 0x68, 0xa4, + 0xff, 0x8f, 0x5e, 0x40, 0x55, 0x80, 0x32, 0xb9, 0x93, 0xc3, 0xb5, 0x14, 0xd0, 0x7b, 0xbb, 0x2b, + 0x4c, 0xe5, 0x60, 0x08, 0x95, 0x57, 0xc8, 0x09, 0xc9, 0x09, 0x35, 0x3a, 0xf7, 0xee, 0x14, 0x79, + 0x99, 0xfe, 0x59, 0x52, 0xd4, 0xd7, 0xe0, 0x5a, 0xd0, 0xcf, 0x60, 0xf3, 0x27, 0x50, 0x57, 0xb0, + 0xa7, 0x92, 0xb2, 0x06, 0x98, 0xea, 0xe3, 0xaf, 0x03, 0xe4, 0xe8, 0x4f, 0x55, 0x80, 0xf3, 0x45, + 0xcc, 0x71, 0xfe, 0x4b, 0x0f, 0x6f, 0xc8, 0x53, 0xe8, 0x1e, 0xe2, 0x25, 0x4d, 0x7c, 0x2e, 0x9f, + 0x2f, 0xa2, 0xbd, 0x73, 0x39, 0x91, 0x37, 0xb0, 0x0c, 0x3d, 0x1f, 0x43, 0xeb, 0x94, 0xbe, 0xf9, + 0x6e, 0xbd, 0x4f, 0xa1, 0x53, 0x00, 0x45, 0x7d, 0xc4, 0x55, 0x98, 0xd5, 0x47, 0x5c, 0x87, 0xcf, + 0xc7, 0xd0, 0xd0, 0x50, 0x99, 0xf7, 0x21, 0x87, 0x4a, 0x01, 0x42, 0x7f, 0x0c, 0xdd, 0x15, 0xa0, + 0xcc, 0xeb, 0xcb, 0x7f, 0x5c, 0x1b, 0x81, 0xf4, 0xa5, 0x78, 0x7e, 0x14, 0xc1, 0x32, 0x6f, 0x78, + 0x4f, 0x01, 0xd4, 0x26, 0x34, 0x7d, 0x55, 0x7c, 0xb8, 0xc8, 0x67, 0x9b, 0xb9, 0x8a, 0x67, 0x29, + 0x9a, 0xa6, 0x1b, 0x6d, 0xc2, 0xc5, 0xe7, 0xd0, 0xce, 0x43, 0xda, 0x5a, 0x0b, 0xae, 0xe3, 0xdd, + 0x07, 0x00, 0x4b, 0x54, 0xcb, 0xeb, 0xcb, 0xf2, 0x58, 0x05, 0xbc, 0x8f, 0x00, 0x96, 0x58, 0xa5, + 0xaa, 0xaa, 0x08, 0x75, 0xca, 0x6c, 0x05, 0xcf, 0x3e, 0x1b, 0xfe, 0xe6, 0x83, 0xa9, 0xc7, 0x67, + 0xc9, 0x64, 0xe8, 0x84, 0xf3, 0xbd, 0x19, 0x8d, 0x67, 0x9e, 0x13, 0xb2, 0x68, 0xef, 0x5a, 0x14, + 0xc8, 0xde, 0xda, 0x8f, 0xe9, 0x49, 0x5d, 0xbe, 0xa8, 0x3e, 0xfc, 0x77, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x6e, 0x84, 0x57, 0xb3, 0xb4, 0x16, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.proto b/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.proto new file mode 100644 index 0000000..db0815f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/pb/backend.proto @@ -0,0 +1,552 @@ +syntax = "proto3"; +package pb; + +option go_package = "github.com/hashicorp/vault/logical/plugin/pb"; + +import "google/protobuf/timestamp.proto"; +import "logical/identity.proto"; + +message Empty {} + +message Header { + repeated string header = 1; +} + +message ProtoError { + // Error type can be one of: + // ErrTypeUnknown uint32 = iota + // ErrTypeUserError + // ErrTypeInternalError + // ErrTypeCodedError + // ErrTypeStatusBadRequest + // ErrTypeUnsupportedOperation + // ErrTypeUnsupportedPath + // ErrTypeInvalidRequest + // ErrTypePermissionDenied + // ErrTypeMultiAuthzPending + uint32 err_type = 1; + string err_msg = 2; + int64 err_code = 3; +} + +// Paths is the structure of special paths that is used for SpecialPaths. +message Paths { + // Root are the paths that require a root token to access + repeated string root = 1; + + // Unauthenticated are the paths that can be accessed without any auth. + repeated string unauthenticated = 2; + + // LocalStorage are paths (prefixes) that are local to this instance; this + // indicates that these paths should not be replicated + repeated string local_storage = 3; + + // SealWrapStorage are storage paths that, when using a capable seal, + // should be seal wrapped with extra encryption. It is exact matching + // unless it ends with '/' in which case it will be treated as a prefix. + repeated string seal_wrap_storage = 4; +} + +message Request { + // Id is the uuid associated with each request + string id = 1; + + // If set, the name given to the replication secondary where this request + // originated + string ReplicationCluster = 2; + + // Operation is the requested operation type + string operation = 3; + + // Path is the part of the request path not consumed by the + // routing. As an example, if the original request path is "prod/aws/foo" + // and the AWS logical backend is mounted at "prod/aws/", then the + // final path is "foo" since the mount prefix is trimmed. + string path = 4; + + // Request data is a JSON object that must have keys with string type. + string data = 5; + + // Secret will be non-nil only for Revoke and Renew operations + // to represent the secret that was returned prior. + Secret secret = 6; + + // Auth will be non-nil only for Renew operations + // to represent the auth that was returned prior. + Auth auth = 7; + + // Headers will contain the http headers from the request. This value will + // be used in the audit broker to ensure we are auditing only the allowed + // headers. + map headers = 8; + + // ClientToken is provided to the core so that the identity + // can be verified and ACLs applied. This value is passed + // through to the logical backends but after being salted and + // hashed. + string client_token = 9; + + // ClientTokenAccessor is provided to the core so that the it can get + // logged as part of request audit logging. + string client_token_accessor = 10; + + // DisplayName is provided to the logical backend to help associate + // dynamic secrets with the source entity. This is not a sensitive + // name, but is useful for operators. + string display_name = 11; + + // MountPoint is provided so that a logical backend can generate + // paths relative to itself. The `Path` is effectively the client + // request path with the MountPoint trimmed off. + string mount_point = 12; + + // MountType is provided so that a logical backend can make decisions + // based on the specific mount type (e.g., if a mount type has different + // aliases, generating different defaults depending on the alias) + string mount_type = 13; + + // MountAccessor is provided so that identities returned by the authentication + // backends can be tied to the mount it belongs to. + string mount_accessor = 14; + + // WrapInfo contains requested response wrapping parameters + RequestWrapInfo wrap_info = 15; + + // ClientTokenRemainingUses represents the allowed number of uses left on the + // token supplied + int64 client_token_remaining_uses = 16; + + // EntityID is the identity of the caller extracted out of the token used + // to make this request + string entity_id = 17; + + // PolicyOverride indicates that the requestor wishes to override + // soft-mandatory Sentinel policies + bool policy_override = 18; + + // Whether the request is unauthenticated, as in, had no client token + // attached. Useful in some situations where the client token is not made + // accessible. + bool unauthenticated = 19; + + // Connection will be non-nil only for credential providers to + // inspect the connection information and potentially use it for + // authentication/protection. + Connection connection = 20; +} + +message Auth { + LeaseOptions lease_options = 1; + + // InternalData is a JSON object that is stored with the auth struct. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + string internal_data = 2; + + // DisplayName is a non-security sensitive identifier that is + // applicable to this Auth. It is used for logging and prefixing + // of dynamic secrets. For example, DisplayName may be "armon" for + // the github credential backend. If the client token is used to + // generate a SQL credential, the user may be "github-armon-uuid". + // This is to help identify the source without using audit tables. + string display_name = 3; + + // Policies is the list of policies that the authenticated user + // is associated with. + repeated string policies = 4; + + // Metadata is used to attach arbitrary string-type metadata to + // an authenticated user. This metadata will be outputted into the + // audit log. + map metadata = 5; + + // ClientToken is the token that is generated for the authentication. + // This will be filled in by Vault core when an auth structure is + // returned. Setting this manually will have no effect. + string client_token = 6; + + // Accessor is the identifier for the ClientToken. This can be used + // to perform management functionalities (especially revocation) when + // ClientToken in the audit logs are obfuscated. Accessor can be used + // to revoke a ClientToken and to lookup the capabilities of the ClientToken, + // both without actually knowing the ClientToken. + string accessor = 7; + + // Period indicates that the token generated using this Auth object + // should never expire. The token should be renewed within the duration + // specified by this period. + int64 period = 8; + + // Number of allowed uses of the issued token + int64 num_uses = 9; + + // EntityID is the identifier of the entity in identity store to which the + // identity of the authenticating client belongs to. + string entity_id = 10; + + // Alias is the information about the authenticated client returned by + // the auth backend + logical.Alias alias = 11; + + // GroupAliases are the informational mappings of external groups which an + // authenticated user belongs to. This is used to check if there are + // mappings groups for the group aliases in identity store. For all the + // matching groups, the entity ID of the user will be added. + repeated logical.Alias group_aliases = 12; + + // If set, restricts usage of the certificates to client IPs falling within + // the range of the specified CIDR(s). + repeated string bound_cidrs = 13; +} + +message LeaseOptions { + int64 TTL = 1; + + bool renewable = 2; + + int64 increment = 3; + + google.protobuf.Timestamp issue_time = 4; + + int64 MaxTTL = 5; +} + +message Secret { + LeaseOptions lease_options = 1; + + // InternalData is a JSON object that is stored with the secret. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + string internal_data = 2; + + // LeaseID is the ID returned to the user to manage this secret. + // This is generated by Vault core. Any set value will be ignored. + // For requests, this will always be blank. + string lease_id = 3; +} + +message Response { + // Secret, if not nil, denotes that this response represents a secret. + Secret secret = 1; + + // Auth, if not nil, contains the authentication information for + // this response. This is only checked and means something for + // credential backends. + Auth auth = 2; + + // Response data is a JSON object that must have string keys. For + // secrets, this data is sent down to the user as-is. To store internal + // data that you don't want the user to see, store it in + // Secret.InternalData. + string data = 3; + + // Redirect is an HTTP URL to redirect to for further authentication. + // This is only valid for credential backends. This will be blanked + // for any logical backend and ignored. + string redirect = 4; + + // Warnings allow operations or backends to return warnings in response + // to user actions without failing the action outright. + repeated string warnings = 5; + + // Information for wrapping the response in a cubbyhole + ResponseWrapInfo wrap_info = 6; +} + +message ResponseWrapInfo { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + int64 TTL = 1; + + // The token containing the wrapped response + string token = 2; + + // The token accessor for the wrapped response token + string accessor = 3; + + // The creation time. This can be used with the TTL to figure out an + // expected expiration. + google.protobuf.Timestamp creation_time = 4; + + // If the contained response is the output of a token creation call, the + // created token's accessor will be accessible here + string wrapped_accessor = 5; + + // WrappedEntityID is the entity identifier of the caller who initiated the + // wrapping request + string wrapped_entity_id = 6; + + // The format to use. This doesn't get returned, it's only internal. + string format = 7; + + // CreationPath is the original request path that was used to create + // the wrapped response. + string creation_path = 8; + + // Controls seal wrapping behavior downstream for specific use cases + bool seal_wrap = 9; +} + +message RequestWrapInfo { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + int64 TTL = 1; + + // The format to use for the wrapped response; if not specified it's a bare + // token + string format = 2; + + // A flag to conforming backends that data for a given request should be + // seal wrapped + bool seal_wrap = 3; +} + +// HandleRequestArgs is the args for HandleRequest method. +message HandleRequestArgs { + uint32 storage_id = 1; + Request request = 2; +} + +// HandleRequestReply is the reply for HandleRequest method. +message HandleRequestReply { + Response response = 1; + ProtoError err = 2; +} + +// SpecialPathsReply is the reply for SpecialPaths method. +message SpecialPathsReply { + Paths paths = 1; +} + +// HandleExistenceCheckArgs is the args for HandleExistenceCheck method. +message HandleExistenceCheckArgs { + uint32 storage_id = 1; + Request request = 2; +} + +// HandleExistenceCheckReply is the reply for HandleExistenceCheck method. +message HandleExistenceCheckReply { + bool check_found = 1; + bool exists = 2; + ProtoError err = 3; +} + +// SetupArgs is the args for Setup method. +message SetupArgs { + uint32 broker_id = 1; + map Config = 2; + string backendUUID = 3; +} + +// SetupReply is the reply for Setup method. +message SetupReply { + string err = 1; +} + +// TypeReply is the reply for the Type method. +message TypeReply { + uint32 type = 1; +} + +message InvalidateKeyArgs { + string key = 1; +} + +// Backend is the interface that plugins must satisfy. The plugin should +// implement the server for this service. Requests will first run the +// HandleExistenceCheck rpc then run the HandleRequests rpc. +service Backend { + // HandleRequest is used to handle a request and generate a response. + // The plugins must check the operation type and handle appropriately. + rpc HandleRequest(HandleRequestArgs) returns (HandleRequestReply); + + // SpecialPaths is a list of paths that are special in some way. + // See PathType for the types of special paths. The key is the type + // of the special path, and the value is a list of paths for this type. + // This is not a regular expression but is an exact match. If the path + // ends in '*' then it is a prefix-based match. The '*' can only appear + // at the end. + rpc SpecialPaths(Empty) returns (SpecialPathsReply); + + // HandleExistenceCheck is used to handle a request and generate a response + // indicating whether the given path exists or not; this is used to + // understand whether the request must have a Create or Update capability + // ACL applied. The first bool indicates whether an existence check + // function was found for the backend; the second indicates whether, if an + // existence check function was found, the item exists or not. + rpc HandleExistenceCheck(HandleExistenceCheckArgs) returns (HandleExistenceCheckReply); + + // Cleanup is invoked during an unmount of a backend to allow it to + // handle any cleanup like connection closing or releasing of file handles. + // Cleanup is called right before Vault closes the plugin process. + rpc Cleanup(Empty) returns (Empty); + + // InvalidateKey may be invoked when an object is modified that belongs + // to the backend. The backend can use this to clear any caches or reset + // internal state as needed. + rpc InvalidateKey(InvalidateKeyArgs) returns (Empty); + + // Setup is used to set up the backend based on the provided backend + // configuration. The plugin's setup implementation should use the provided + // broker_id to create a connection back to Vault for use with the Storage + // and SystemView clients. + rpc Setup(SetupArgs) returns (SetupReply); + + // Type returns the BackendType for the particular backend + rpc Type(Empty) returns (TypeReply); +} + +message StorageEntry { + string key = 1; + bytes value = 2; + bool seal_wrap = 3; +} + +message StorageListArgs { + string prefix = 1; +} + +message StorageListReply { + repeated string keys = 1; + string err = 2; +} + +message StorageGetArgs { + string key = 1; +} + +message StorageGetReply { + StorageEntry entry = 1; + string err = 2; +} + +message StoragePutArgs { + StorageEntry entry = 1; +} + +message StoragePutReply { + string err = 1; +} + +message StorageDeleteArgs { + string key = 1; +} + +message StorageDeleteReply { + string err = 1; +} + +// Storage is the way that plugins are able read/write data. Plugins should +// implement the client for this service. +service Storage { + rpc List(StorageListArgs) returns (StorageListReply); + rpc Get(StorageGetArgs) returns (StorageGetReply); + rpc Put(StoragePutArgs) returns (StoragePutReply); + rpc Delete(StorageDeleteArgs) returns (StorageDeleteReply); +} + +message TTLReply { + int64 TTL = 1; +} + +message SudoPrivilegeArgs { + string path = 1; + string token = 2; +} + +message SudoPrivilegeReply { + bool sudo = 1; +} + +message TaintedReply { + bool tainted = 1; +} + +message CachingDisabledReply { + bool disabled = 1; +} + +message ReplicationStateReply { + int32 state = 1; +} + +message ResponseWrapDataArgs { + string data = 1; + int64 TTL = 2; + bool JWT = 3; +} + +message ResponseWrapDataReply { + ResponseWrapInfo wrap_info = 1; + string err = 2; +} + +message MlockEnabledReply { + bool enabled = 1; +} + +message LocalMountReply { + bool local = 1; +} + +message EntityInfoArgs { + string entity_id = 1; +} + +message EntityInfoReply { + logical.Entity entity = 1; + string err = 2; +} + +// SystemView exposes system configuration information in a safe way for plugins +// to consume. Plugins should implement the client for this service. +service SystemView { + // DefaultLeaseTTL returns the default lease TTL set in Vault configuration + rpc DefaultLeaseTTL(Empty) returns (TTLReply); + + // MaxLeaseTTL returns the max lease TTL set in Vault configuration; backend + // authors should take care not to issue credentials that last longer than + // this value, as Vault will revoke them + rpc MaxLeaseTTL(Empty) returns (TTLReply); + + // SudoPrivilege returns true if given path has sudo privileges + // for the given client token + rpc SudoPrivilege(SudoPrivilegeArgs) returns (SudoPrivilegeReply); + + // Tainted, returns true if the mount is tainted. A mount is tainted if it is in the + // process of being unmounted. This should only be used in special + // circumstances; a primary use-case is as a guard in revocation functions. + // If revocation of a backend's leases fails it can keep the unmounting + // process from being successful. If the reason for this failure is not + // relevant when the mount is tainted (for instance, saving a CRL to disk + // when the stored CRL will be removed during the unmounting process + // anyways), we can ignore the errors to allow unmounting to complete. + rpc Tainted(Empty) returns (TaintedReply); + + // CachingDisabled returns true if caching is disabled. If true, no caches + // should be used, despite known slowdowns. + rpc CachingDisabled(Empty) returns (CachingDisabledReply); + + // ReplicationState indicates the state of cluster replication + rpc ReplicationState(Empty) returns (ReplicationStateReply); + + // ResponseWrapData wraps the given data in a cubbyhole and returns the + // token used to unwrap. + rpc ResponseWrapData(ResponseWrapDataArgs) returns (ResponseWrapDataReply); + + // MlockEnabled returns the configuration setting for enabling mlock on + // plugins. + rpc MlockEnabled(Empty) returns (MlockEnabledReply); + + // LocalMount, when run from a system view attached to a request, indicates + // whether the request is affecting a local mount or not + rpc LocalMount(Empty) returns (LocalMountReply); + + // EntityInfo returns the basic entity information for the given entity id + rpc EntityInfo(EntityInfoArgs) returns (EntityInfoReply); +} + +message Connection { + // RemoteAddr is the network address that sent the request. + string remote_addr = 1; +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/pb/translation.go b/vendor/github.com/hashicorp/vault/logical/plugin/pb/translation.go new file mode 100644 index 0000000..d0d220e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/pb/translation.go @@ -0,0 +1,545 @@ +package pb + +import ( + "encoding/json" + "errors" + "time" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" +) + +const ( + ErrTypeUnknown uint32 = iota + ErrTypeUserError + ErrTypeInternalError + ErrTypeCodedError + ErrTypeStatusBadRequest + ErrTypeUnsupportedOperation + ErrTypeUnsupportedPath + ErrTypeInvalidRequest + ErrTypePermissionDenied + ErrTypeMultiAuthzPending +) + +func ProtoErrToErr(e *ProtoError) error { + if e == nil { + return nil + } + + var err error + switch e.ErrType { + case ErrTypeUnknown: + err = errors.New(e.ErrMsg) + case ErrTypeUserError: + err = errutil.UserError{Err: e.ErrMsg} + case ErrTypeInternalError: + err = errutil.InternalError{Err: e.ErrMsg} + case ErrTypeCodedError: + err = logical.CodedError(int(e.ErrCode), e.ErrMsg) + case ErrTypeStatusBadRequest: + err = &logical.StatusBadRequest{Err: e.ErrMsg} + case ErrTypeUnsupportedOperation: + err = logical.ErrUnsupportedOperation + case ErrTypeUnsupportedPath: + err = logical.ErrUnsupportedPath + case ErrTypeInvalidRequest: + err = logical.ErrInvalidRequest + case ErrTypePermissionDenied: + err = logical.ErrPermissionDenied + case ErrTypeMultiAuthzPending: + err = logical.ErrMultiAuthzPending + } + + return err +} + +func ErrToProtoErr(e error) *ProtoError { + if e == nil { + return nil + } + pbErr := &ProtoError{ + ErrMsg: e.Error(), + ErrType: ErrTypeUnknown, + } + + switch e.(type) { + case errutil.UserError: + pbErr.ErrType = ErrTypeUserError + case errutil.InternalError: + pbErr.ErrType = ErrTypeInternalError + case logical.HTTPCodedError: + pbErr.ErrType = ErrTypeCodedError + pbErr.ErrCode = int64(e.(logical.HTTPCodedError).Code()) + case *logical.StatusBadRequest: + pbErr.ErrType = ErrTypeStatusBadRequest + } + + switch { + case e == logical.ErrUnsupportedOperation: + pbErr.ErrType = ErrTypeUnsupportedOperation + case e == logical.ErrUnsupportedPath: + pbErr.ErrType = ErrTypeUnsupportedPath + case e == logical.ErrInvalidRequest: + pbErr.ErrType = ErrTypeInvalidRequest + case e == logical.ErrPermissionDenied: + pbErr.ErrType = ErrTypePermissionDenied + case e == logical.ErrMultiAuthzPending: + pbErr.ErrType = ErrTypeMultiAuthzPending + } + + return pbErr +} + +func ErrToString(e error) string { + if e == nil { + return "" + } + + return e.Error() +} + +func LogicalStorageEntryToProtoStorageEntry(e *logical.StorageEntry) *StorageEntry { + if e == nil { + return nil + } + + return &StorageEntry{ + Key: e.Key, + Value: e.Value, + SealWrap: e.SealWrap, + } +} + +func ProtoStorageEntryToLogicalStorageEntry(e *StorageEntry) *logical.StorageEntry { + if e == nil { + return nil + } + + return &logical.StorageEntry{ + Key: e.Key, + Value: e.Value, + SealWrap: e.SealWrap, + } +} + +func ProtoLeaseOptionsToLogicalLeaseOptions(l *LeaseOptions) (logical.LeaseOptions, error) { + if l == nil { + return logical.LeaseOptions{}, nil + } + + t, err := ptypes.Timestamp(l.IssueTime) + return logical.LeaseOptions{ + TTL: time.Duration(l.TTL), + Renewable: l.Renewable, + Increment: time.Duration(l.Increment), + IssueTime: t, + MaxTTL: time.Duration(l.MaxTTL), + }, err +} + +func LogicalLeaseOptionsToProtoLeaseOptions(l logical.LeaseOptions) (*LeaseOptions, error) { + t, err := ptypes.TimestampProto(l.IssueTime) + if err != nil { + return nil, err + } + + return &LeaseOptions{ + TTL: int64(l.TTL), + Renewable: l.Renewable, + Increment: int64(l.Increment), + IssueTime: t, + MaxTTL: int64(l.MaxTTL), + }, err +} + +func ProtoSecretToLogicalSecret(s *Secret) (*logical.Secret, error) { + if s == nil { + return nil, nil + } + + data := map[string]interface{}{} + err := json.Unmarshal([]byte(s.InternalData), &data) + if err != nil { + return nil, err + } + + lease, err := ProtoLeaseOptionsToLogicalLeaseOptions(s.LeaseOptions) + if err != nil { + return nil, err + } + + return &logical.Secret{ + LeaseOptions: lease, + InternalData: data, + LeaseID: s.LeaseID, + }, nil +} + +func LogicalSecretToProtoSecret(s *logical.Secret) (*Secret, error) { + if s == nil { + return nil, nil + } + + buf, err := json.Marshal(s.InternalData) + if err != nil { + return nil, err + } + + lease, err := LogicalLeaseOptionsToProtoLeaseOptions(s.LeaseOptions) + if err != nil { + return nil, err + } + + return &Secret{ + LeaseOptions: lease, + InternalData: string(buf[:]), + LeaseID: s.LeaseID, + }, err +} + +func LogicalRequestToProtoRequest(r *logical.Request) (*Request, error) { + if r == nil { + return nil, nil + } + + buf, err := json.Marshal(r.Data) + if err != nil { + return nil, err + } + + secret, err := LogicalSecretToProtoSecret(r.Secret) + if err != nil { + return nil, err + } + + auth, err := LogicalAuthToProtoAuth(r.Auth) + if err != nil { + return nil, err + } + + headers := map[string]*Header{} + for k, v := range r.Headers { + headers[k] = &Header{Header: v} + } + + return &Request{ + ID: r.ID, + ReplicationCluster: r.ReplicationCluster, + Operation: string(r.Operation), + Path: r.Path, + Data: string(buf[:]), + Secret: secret, + Auth: auth, + Headers: headers, + ClientToken: r.ClientToken, + ClientTokenAccessor: r.ClientTokenAccessor, + DisplayName: r.DisplayName, + MountPoint: r.MountPoint, + MountType: r.MountType, + MountAccessor: r.MountAccessor, + WrapInfo: LogicalRequestWrapInfoToProtoRequestWrapInfo(r.WrapInfo), + ClientTokenRemainingUses: int64(r.ClientTokenRemainingUses), + Connection: LogicalConnectionToProtoConnection(r.Connection), + EntityID: r.EntityID, + PolicyOverride: r.PolicyOverride, + Unauthenticated: r.Unauthenticated, + }, nil +} + +func ProtoRequestToLogicalRequest(r *Request) (*logical.Request, error) { + if r == nil { + return nil, nil + } + + data := map[string]interface{}{} + err := json.Unmarshal([]byte(r.Data), &data) + if err != nil { + return nil, err + } + + secret, err := ProtoSecretToLogicalSecret(r.Secret) + if err != nil { + return nil, err + } + + auth, err := ProtoAuthToLogicalAuth(r.Auth) + if err != nil { + return nil, err + } + + var headers map[string][]string + if len(r.Headers) > 0 { + headers = make(map[string][]string, len(r.Headers)) + for k, v := range r.Headers { + headers[k] = v.Header + } + } + + return &logical.Request{ + ID: r.ID, + ReplicationCluster: r.ReplicationCluster, + Operation: logical.Operation(r.Operation), + Path: r.Path, + Data: data, + Secret: secret, + Auth: auth, + Headers: headers, + ClientToken: r.ClientToken, + ClientTokenAccessor: r.ClientTokenAccessor, + DisplayName: r.DisplayName, + MountPoint: r.MountPoint, + MountType: r.MountType, + MountAccessor: r.MountAccessor, + WrapInfo: ProtoRequestWrapInfoToLogicalRequestWrapInfo(r.WrapInfo), + ClientTokenRemainingUses: int(r.ClientTokenRemainingUses), + Connection: ProtoConnectionToLogicalConnection(r.Connection), + EntityID: r.EntityID, + PolicyOverride: r.PolicyOverride, + Unauthenticated: r.Unauthenticated, + }, nil +} + +func LogicalConnectionToProtoConnection(c *logical.Connection) *Connection { + if c == nil { + return nil + } + + return &Connection{ + RemoteAddr: c.RemoteAddr, + } +} + +func ProtoConnectionToLogicalConnection(c *Connection) *logical.Connection { + if c == nil { + return nil + } + + return &logical.Connection{ + RemoteAddr: c.RemoteAddr, + } +} + +func LogicalRequestWrapInfoToProtoRequestWrapInfo(i *logical.RequestWrapInfo) *RequestWrapInfo { + if i == nil { + return nil + } + + return &RequestWrapInfo{ + TTL: int64(i.TTL), + Format: i.Format, + SealWrap: i.SealWrap, + } +} + +func ProtoRequestWrapInfoToLogicalRequestWrapInfo(i *RequestWrapInfo) *logical.RequestWrapInfo { + if i == nil { + return nil + } + + return &logical.RequestWrapInfo{ + TTL: time.Duration(i.TTL), + Format: i.Format, + SealWrap: i.SealWrap, + } +} + +func ProtoResponseToLogicalResponse(r *Response) (*logical.Response, error) { + if r == nil { + return nil, nil + } + + secret, err := ProtoSecretToLogicalSecret(r.Secret) + if err != nil { + return nil, err + } + + auth, err := ProtoAuthToLogicalAuth(r.Auth) + if err != nil { + return nil, err + } + + data := map[string]interface{}{} + err = json.Unmarshal([]byte(r.Data), &data) + if err != nil { + return nil, err + } + + wrapInfo, err := ProtoResponseWrapInfoToLogicalResponseWrapInfo(r.WrapInfo) + if err != nil { + return nil, err + } + + return &logical.Response{ + Secret: secret, + Auth: auth, + Data: data, + Redirect: r.Redirect, + Warnings: r.Warnings, + WrapInfo: wrapInfo, + }, nil +} + +func ProtoResponseWrapInfoToLogicalResponseWrapInfo(i *ResponseWrapInfo) (*wrapping.ResponseWrapInfo, error) { + if i == nil { + return nil, nil + } + + t, err := ptypes.Timestamp(i.CreationTime) + if err != nil { + return nil, err + } + + return &wrapping.ResponseWrapInfo{ + TTL: time.Duration(i.TTL), + Token: i.Token, + Accessor: i.Accessor, + CreationTime: t, + WrappedAccessor: i.WrappedAccessor, + WrappedEntityID: i.WrappedEntityID, + Format: i.Format, + CreationPath: i.CreationPath, + SealWrap: i.SealWrap, + }, nil +} + +func LogicalResponseWrapInfoToProtoResponseWrapInfo(i *wrapping.ResponseWrapInfo) (*ResponseWrapInfo, error) { + if i == nil { + return nil, nil + } + + t, err := ptypes.TimestampProto(i.CreationTime) + if err != nil { + return nil, err + } + + return &ResponseWrapInfo{ + TTL: int64(i.TTL), + Token: i.Token, + Accessor: i.Accessor, + CreationTime: t, + WrappedAccessor: i.WrappedAccessor, + WrappedEntityID: i.WrappedEntityID, + Format: i.Format, + CreationPath: i.CreationPath, + SealWrap: i.SealWrap, + }, nil +} + +func LogicalResponseToProtoResponse(r *logical.Response) (*Response, error) { + if r == nil { + return nil, nil + } + + secret, err := LogicalSecretToProtoSecret(r.Secret) + if err != nil { + return nil, err + } + + auth, err := LogicalAuthToProtoAuth(r.Auth) + if err != nil { + return nil, err + } + + buf, err := json.Marshal(r.Data) + if err != nil { + return nil, err + } + + wrapInfo, err := LogicalResponseWrapInfoToProtoResponseWrapInfo(r.WrapInfo) + if err != nil { + return nil, err + } + + return &Response{ + Secret: secret, + Auth: auth, + Data: string(buf[:]), + Redirect: r.Redirect, + Warnings: r.Warnings, + WrapInfo: wrapInfo, + }, nil +} + +func LogicalAuthToProtoAuth(a *logical.Auth) (*Auth, error) { + if a == nil { + return nil, nil + } + + buf, err := json.Marshal(a.InternalData) + if err != nil { + return nil, err + } + + lo, err := LogicalLeaseOptionsToProtoLeaseOptions(a.LeaseOptions) + if err != nil { + return nil, err + } + + boundCIDRs := make([]string, len(a.BoundCIDRs)) + for i, cidr := range a.BoundCIDRs { + boundCIDRs[i] = cidr.String() + } + + return &Auth{ + LeaseOptions: lo, + InternalData: string(buf[:]), + DisplayName: a.DisplayName, + Policies: a.Policies, + Metadata: a.Metadata, + ClientToken: a.ClientToken, + Accessor: a.Accessor, + Period: int64(a.Period), + NumUses: int64(a.NumUses), + EntityID: a.EntityID, + Alias: a.Alias, + GroupAliases: a.GroupAliases, + BoundCidrs: boundCIDRs, + }, nil +} + +func ProtoAuthToLogicalAuth(a *Auth) (*logical.Auth, error) { + if a == nil { + return nil, nil + } + + data := map[string]interface{}{} + err := json.Unmarshal([]byte(a.InternalData), &data) + if err != nil { + return nil, err + } + + lo, err := ProtoLeaseOptionsToLogicalLeaseOptions(a.LeaseOptions) + if err != nil { + return nil, err + } + + boundCIDRs, err := parseutil.ParseAddrs(a.BoundCidrs) + if err != nil { + return nil, err + } + if len(boundCIDRs) == 0 { + // On inbound auths, if auth.BoundCIDRs is empty, it will be nil. + // Let's match that behavior outbound. + boundCIDRs = nil + } + + return &logical.Auth{ + LeaseOptions: lo, + InternalData: data, + DisplayName: a.DisplayName, + Policies: a.Policies, + Metadata: a.Metadata, + ClientToken: a.ClientToken, + Accessor: a.Accessor, + Period: time.Duration(a.Period), + NumUses: int(a.NumUses), + EntityID: a.EntityID, + Alias: a.Alias, + GroupAliases: a.GroupAliases, + BoundCIDRs: boundCIDRs, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/plugin.go b/vendor/github.com/hashicorp/vault/logical/plugin/plugin.go new file mode 100644 index 0000000..754494b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/plugin.go @@ -0,0 +1,176 @@ +package plugin + +import ( + "context" + "crypto/ecdsa" + "crypto/rsa" + "encoding/gob" + "errors" + "fmt" + "time" + + "sync" + + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" +) + +// init registers basic structs with gob which will be used to transport complex +// types through the plugin server and client. +func init() { + // Common basic structs + gob.Register([]interface{}{}) + gob.Register(map[string]interface{}{}) + gob.Register(map[string]string{}) + gob.Register(map[string]int{}) + + // Register these types since we have to serialize and de-serialize + // tls.ConnectionState over the wire as part of logical.Request.Connection. + gob.Register(rsa.PublicKey{}) + gob.Register(ecdsa.PublicKey{}) + gob.Register(time.Duration(0)) + + // Custom common error types for requests. If you add something here, you must + // also add it to the switch statement in `wrapError`! + gob.Register(&plugin.BasicError{}) + gob.Register(logical.CodedError(0, "")) + gob.Register(&logical.StatusBadRequest{}) +} + +// BackendPluginClient is a wrapper around backendPluginClient +// that also contains its plugin.Client instance. It's primarily +// used to cleanly kill the client on Cleanup() +type BackendPluginClient struct { + client *plugin.Client + sync.Mutex + + logical.Backend +} + +// Cleanup calls the RPC client's Cleanup() func and also calls +// the go-plugin's client Kill() func +func (b *BackendPluginClient) Cleanup(ctx context.Context) { + b.Backend.Cleanup(ctx) + b.client.Kill() +} + +// NewBackend will return an instance of an RPC-based client implementation of the backend for +// external plugins, or a concrete implementation of the backend if it is a builtin backend. +// The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether +// the plugin should run in metadata mode. +func NewBackend(ctx context.Context, pluginName string, sys pluginutil.LookRunnerUtil, logger log.Logger, isMetadataMode bool) (logical.Backend, error) { + // Look for plugin in the plugin catalog + pluginRunner, err := sys.LookupPlugin(ctx, pluginName) + if err != nil { + return nil, err + } + + var backend logical.Backend + if pluginRunner.Builtin { + // Plugin is builtin so we can retrieve an instance of the interface + // from the pluginRunner. Then cast it to logical.Backend. + backendRaw, err := pluginRunner.BuiltinFactory() + if err != nil { + return nil, errwrap.Wrapf("error getting plugin type: {{err}}", err) + } + + var ok bool + backend, ok = backendRaw.(logical.Backend) + if !ok { + return nil, fmt.Errorf("unsupported backend type: %q", pluginName) + } + + } else { + // create a backendPluginClient instance + backend, err = newPluginClient(ctx, sys, pluginRunner, logger, isMetadataMode) + if err != nil { + return nil, err + } + } + + return backend, nil +} + +func newPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (logical.Backend, error) { + // pluginMap is the map of plugins we can dispense. + pluginMap := map[string]plugin.Plugin{ + "backend": &BackendPlugin{ + metadataMode: isMetadataMode, + }, + } + + namedLogger := logger.Named(pluginRunner.Name) + + var client *plugin.Client + var err error + if isMetadataMode { + client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginMap, handshakeConfig, []string{}, namedLogger) + } else { + client, err = pluginRunner.Run(ctx, sys, pluginMap, handshakeConfig, []string{}, namedLogger) + } + if err != nil { + return nil, err + } + + // Connect via RPC + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + // Request the plugin + raw, err := rpcClient.Dispense("backend") + if err != nil { + return nil, err + } + + var backend logical.Backend + var transport string + // We should have a logical backend type now. This feels like a normal interface + // implementation but is in fact over an RPC connection. + switch raw.(type) { + case *backendPluginClient: + backend = raw.(*backendPluginClient) + transport = "netRPC" + case *backendGRPCPluginClient: + backend = raw.(*backendGRPCPluginClient) + transport = "gRPC" + default: + return nil, errors.New("unsupported plugin client type") + } + + // Wrap the backend in a tracing middleware + if namedLogger.IsTrace() { + backend = &backendTracingMiddleware{ + logger: namedLogger.With("transport", transport), + next: backend, + } + } + + return &BackendPluginClient{ + client: client, + Backend: backend, + }, nil +} + +// wrapError takes a generic error type and makes it usable with the plugin +// interface. Only errors which have exported fields and have been registered +// with gob can be unwrapped and transported. This checks error types and, if +// none match, wrap the error in a plugin.BasicError. +func wrapError(err error) error { + if err == nil { + return nil + } + + switch err.(type) { + case *plugin.BasicError, + logical.HTTPCodedError, + *logical.StatusBadRequest: + return err + } + + return plugin.NewBasicError(err) +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/serve.go b/vendor/github.com/hashicorp/vault/logical/plugin/serve.go new file mode 100644 index 0000000..d7dc867 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/serve.go @@ -0,0 +1,78 @@ +package plugin + +import ( + "crypto/tls" + "os" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" +) + +// BackendPluginName is the name of the plugin that can be +// dispensed rom the plugin server. +const BackendPluginName = "backend" + +type TLSProviderFunc func() (*tls.Config, error) + +type ServeOpts struct { + BackendFactoryFunc logical.Factory + TLSProviderFunc TLSProviderFunc + Logger log.Logger +} + +// Serve is a helper function used to serve a backend plugin. This +// should be ran on the plugin's main process. +func Serve(opts *ServeOpts) error { + logger := opts.Logger + if logger == nil { + logger = log.New(&log.LoggerOptions{ + Level: log.Trace, + Output: os.Stderr, + JSONFormat: true, + }) + } + + // pluginMap is the map of plugins we can dispense. + var pluginMap = map[string]plugin.Plugin{ + "backend": &BackendPlugin{ + Factory: opts.BackendFactoryFunc, + Logger: logger, + }, + } + + err := pluginutil.OptionallyEnableMlock() + if err != nil { + return err + } + + serveOpts := &plugin.ServeConfig{ + HandshakeConfig: handshakeConfig, + Plugins: pluginMap, + TLSProvider: opts.TLSProviderFunc, + Logger: logger, + + // A non-nil value here enables gRPC serving for this plugin... + GRPCServer: plugin.DefaultGRPCServer, + } + + if !pluginutil.GRPCSupport() { + serveOpts.GRPCServer = nil + } + + // If FetchMetadata is true, run without TLSProvider + plugin.Serve(serveOpts) + + return nil +} + +// handshakeConfigs are used to just do a basic handshake between +// a plugin and host. If the handshake fails, a user friendly error is shown. +// This prevents users from executing bad plugins or executing a plugin +// directory. It is a UX feature, not a security feature. +var handshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 3, + MagicCookieKey: "VAULT_BACKEND_PLUGIN", + MagicCookieValue: "6669da05-b1c8-4f49-97d9-c8e5bed98e20", +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/storage.go b/vendor/github.com/hashicorp/vault/logical/plugin/storage.go new file mode 100644 index 0000000..75cda55 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/storage.go @@ -0,0 +1,139 @@ +package plugin + +import ( + "context" + "net/rpc" + + "github.com/hashicorp/vault/logical" +) + +// StorageClient is an implementation of logical.Storage that communicates +// over RPC. +type StorageClient struct { + client *rpc.Client +} + +func (s *StorageClient) List(_ context.Context, prefix string) ([]string, error) { + var reply StorageListReply + err := s.client.Call("Plugin.List", prefix, &reply) + if err != nil { + return reply.Keys, err + } + if reply.Error != nil { + return reply.Keys, reply.Error + } + return reply.Keys, nil +} + +func (s *StorageClient) Get(_ context.Context, key string) (*logical.StorageEntry, error) { + var reply StorageGetReply + err := s.client.Call("Plugin.Get", key, &reply) + if err != nil { + return nil, err + } + if reply.Error != nil { + return nil, reply.Error + } + return reply.StorageEntry, nil +} + +func (s *StorageClient) Put(_ context.Context, entry *logical.StorageEntry) error { + var reply StoragePutReply + err := s.client.Call("Plugin.Put", entry, &reply) + if err != nil { + return err + } + if reply.Error != nil { + return reply.Error + } + return nil +} + +func (s *StorageClient) Delete(_ context.Context, key string) error { + var reply StorageDeleteReply + err := s.client.Call("Plugin.Delete", key, &reply) + if err != nil { + return err + } + if reply.Error != nil { + return reply.Error + } + return nil +} + +// StorageServer is a net/rpc compatible structure for serving +type StorageServer struct { + impl logical.Storage +} + +func (s *StorageServer) List(prefix string, reply *StorageListReply) error { + keys, err := s.impl.List(context.Background(), prefix) + *reply = StorageListReply{ + Keys: keys, + Error: wrapError(err), + } + return nil +} + +func (s *StorageServer) Get(key string, reply *StorageGetReply) error { + storageEntry, err := s.impl.Get(context.Background(), key) + *reply = StorageGetReply{ + StorageEntry: storageEntry, + Error: wrapError(err), + } + return nil +} + +func (s *StorageServer) Put(entry *logical.StorageEntry, reply *StoragePutReply) error { + err := s.impl.Put(context.Background(), entry) + *reply = StoragePutReply{ + Error: wrapError(err), + } + return nil +} + +func (s *StorageServer) Delete(key string, reply *StorageDeleteReply) error { + err := s.impl.Delete(context.Background(), key) + *reply = StorageDeleteReply{ + Error: wrapError(err), + } + return nil +} + +type StorageListReply struct { + Keys []string + Error error +} + +type StorageGetReply struct { + StorageEntry *logical.StorageEntry + Error error +} + +type StoragePutReply struct { + Error error +} + +type StorageDeleteReply struct { + Error error +} + +// NOOPStorage is used to deny access to the storage interface while running a +// backend plugin in metadata mode. +type NOOPStorage struct{} + +func (s *NOOPStorage) List(_ context.Context, prefix string) ([]string, error) { + return []string{}, nil +} + +func (s *NOOPStorage) Get(_ context.Context, key string) (*logical.StorageEntry, error) { + return nil, nil +} + +func (s *NOOPStorage) Put(_ context.Context, entry *logical.StorageEntry) error { + return nil +} + +func (s *NOOPStorage) Delete(_ context.Context, key string) error { + return nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/plugin/system.go b/vendor/github.com/hashicorp/vault/logical/plugin/system.go new file mode 100644 index 0000000..08402de --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/plugin/system.go @@ -0,0 +1,311 @@ +package plugin + +import ( + "context" + "net/rpc" + "time" + + "fmt" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" +) + +type SystemViewClient struct { + client *rpc.Client +} + +func (s *SystemViewClient) DefaultLeaseTTL() time.Duration { + var reply DefaultLeaseTTLReply + err := s.client.Call("Plugin.DefaultLeaseTTL", new(interface{}), &reply) + if err != nil { + return 0 + } + + return reply.DefaultLeaseTTL +} + +func (s *SystemViewClient) MaxLeaseTTL() time.Duration { + var reply MaxLeaseTTLReply + err := s.client.Call("Plugin.MaxLeaseTTL", new(interface{}), &reply) + if err != nil { + return 0 + } + + return reply.MaxLeaseTTL +} + +func (s *SystemViewClient) SudoPrivilege(ctx context.Context, path string, token string) bool { + var reply SudoPrivilegeReply + args := &SudoPrivilegeArgs{ + Path: path, + Token: token, + } + + err := s.client.Call("Plugin.SudoPrivilege", args, &reply) + if err != nil { + return false + } + + return reply.Sudo +} + +func (s *SystemViewClient) Tainted() bool { + var reply TaintedReply + + err := s.client.Call("Plugin.Tainted", new(interface{}), &reply) + if err != nil { + return false + } + + return reply.Tainted +} + +func (s *SystemViewClient) CachingDisabled() bool { + var reply CachingDisabledReply + + err := s.client.Call("Plugin.CachingDisabled", new(interface{}), &reply) + if err != nil { + return false + } + + return reply.CachingDisabled +} + +func (s *SystemViewClient) ReplicationState() consts.ReplicationState { + var reply ReplicationStateReply + + err := s.client.Call("Plugin.ReplicationState", new(interface{}), &reply) + if err != nil { + return consts.ReplicationUnknown + } + + return reply.ReplicationState +} + +func (s *SystemViewClient) ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) { + var reply ResponseWrapDataReply + // Do not allow JWTs to be returned + args := &ResponseWrapDataArgs{ + Data: data, + TTL: ttl, + JWT: false, + } + + err := s.client.Call("Plugin.ResponseWrapData", args, &reply) + if err != nil { + return nil, err + } + if reply.Error != nil { + return nil, reply.Error + } + + return reply.ResponseWrapInfo, nil +} + +func (s *SystemViewClient) LookupPlugin(ctx context.Context, name string) (*pluginutil.PluginRunner, error) { + return nil, fmt.Errorf("cannot call LookupPlugin from a plugin backend") +} + +func (s *SystemViewClient) MlockEnabled() bool { + var reply MlockEnabledReply + err := s.client.Call("Plugin.MlockEnabled", new(interface{}), &reply) + if err != nil { + return false + } + + return reply.MlockEnabled +} + +func (s *SystemViewClient) LocalMount() bool { + var reply LocalMountReply + err := s.client.Call("Plugin.LocalMount", new(interface{}), &reply) + if err != nil { + return false + } + + return reply.Local +} + +func (s *SystemViewClient) EntityInfo(entityID string) (*logical.Entity, error) { + var reply EntityInfoReply + args := &EntityInfoArgs{ + EntityID: entityID, + } + + err := s.client.Call("Plugin.EntityInfo", args, &reply) + if err != nil { + return nil, err + } + if reply.Error != nil { + return nil, reply.Error + } + + return reply.Entity, nil +} + +type SystemViewServer struct { + impl logical.SystemView +} + +func (s *SystemViewServer) DefaultLeaseTTL(_ interface{}, reply *DefaultLeaseTTLReply) error { + ttl := s.impl.DefaultLeaseTTL() + *reply = DefaultLeaseTTLReply{ + DefaultLeaseTTL: ttl, + } + + return nil +} + +func (s *SystemViewServer) MaxLeaseTTL(_ interface{}, reply *MaxLeaseTTLReply) error { + ttl := s.impl.MaxLeaseTTL() + *reply = MaxLeaseTTLReply{ + MaxLeaseTTL: ttl, + } + + return nil +} + +func (s *SystemViewServer) SudoPrivilege(args *SudoPrivilegeArgs, reply *SudoPrivilegeReply) error { + sudo := s.impl.SudoPrivilege(context.Background(), args.Path, args.Token) + *reply = SudoPrivilegeReply{ + Sudo: sudo, + } + + return nil +} + +func (s *SystemViewServer) Tainted(_ interface{}, reply *TaintedReply) error { + tainted := s.impl.Tainted() + *reply = TaintedReply{ + Tainted: tainted, + } + + return nil +} + +func (s *SystemViewServer) CachingDisabled(_ interface{}, reply *CachingDisabledReply) error { + cachingDisabled := s.impl.CachingDisabled() + *reply = CachingDisabledReply{ + CachingDisabled: cachingDisabled, + } + + return nil +} + +func (s *SystemViewServer) ReplicationState(_ interface{}, reply *ReplicationStateReply) error { + replicationState := s.impl.ReplicationState() + *reply = ReplicationStateReply{ + ReplicationState: replicationState, + } + + return nil +} + +func (s *SystemViewServer) ResponseWrapData(args *ResponseWrapDataArgs, reply *ResponseWrapDataReply) error { + // Do not allow JWTs to be returned + info, err := s.impl.ResponseWrapData(context.Background(), args.Data, args.TTL, false) + if err != nil { + *reply = ResponseWrapDataReply{ + Error: wrapError(err), + } + return nil + } + *reply = ResponseWrapDataReply{ + ResponseWrapInfo: info, + } + + return nil +} + +func (s *SystemViewServer) MlockEnabled(_ interface{}, reply *MlockEnabledReply) error { + enabled := s.impl.MlockEnabled() + *reply = MlockEnabledReply{ + MlockEnabled: enabled, + } + + return nil +} + +func (s *SystemViewServer) LocalMount(_ interface{}, reply *LocalMountReply) error { + local := s.impl.LocalMount() + *reply = LocalMountReply{ + Local: local, + } + + return nil +} + +func (s *SystemViewServer) EntityInfo(args *EntityInfoArgs, reply *EntityInfoReply) error { + entity, err := s.impl.EntityInfo(args.EntityID) + if err != nil { + *reply = EntityInfoReply{ + Error: wrapError(err), + } + return nil + } + *reply = EntityInfoReply{ + Entity: entity, + } + + return nil +} + +type DefaultLeaseTTLReply struct { + DefaultLeaseTTL time.Duration +} + +type MaxLeaseTTLReply struct { + MaxLeaseTTL time.Duration +} + +type SudoPrivilegeArgs struct { + Path string + Token string +} + +type SudoPrivilegeReply struct { + Sudo bool +} + +type TaintedReply struct { + Tainted bool +} + +type CachingDisabledReply struct { + CachingDisabled bool +} + +type ReplicationStateReply struct { + ReplicationState consts.ReplicationState +} + +type ResponseWrapDataArgs struct { + Data map[string]interface{} + TTL time.Duration + JWT bool +} + +type ResponseWrapDataReply struct { + ResponseWrapInfo *wrapping.ResponseWrapInfo + Error error +} + +type MlockEnabledReply struct { + MlockEnabled bool +} + +type LocalMountReply struct { + Local bool +} + +type EntityInfoArgs struct { + EntityID string +} + +type EntityInfoReply struct { + Entity *logical.Entity + Error error +} diff --git a/vendor/github.com/hashicorp/vault/logical/request.go b/vendor/github.com/hashicorp/vault/logical/request.go new file mode 100644 index 0000000..7bff6f0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/request.go @@ -0,0 +1,279 @@ +package logical + +import ( + "errors" + "fmt" + "strings" + "time" +) + +// RequestWrapInfo is a struct that stores information about desired response +// and seal wrapping behavior +type RequestWrapInfo struct { + // Setting to non-zero specifies that the response should be wrapped. + // Specifies the desired TTL of the wrapping token. + TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl" sentinel:""` + + // The format to use for the wrapped response; if not specified it's a bare + // token + Format string `json:"format" structs:"format" mapstructure:"format" sentinel:""` + + // A flag to conforming backends that data for a given request should be + // seal wrapped + SealWrap bool `json:"seal_wrap" structs:"seal_wrap" mapstructure:"seal_wrap" sentinel:""` +} + +func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) { + if r == nil { + return nil, nil + } + switch key { + case "ttl": + return r.TTL, nil + case "ttl_seconds": + return int64(r.TTL.Seconds()), nil + } + + return nil, nil +} + +func (r *RequestWrapInfo) SentinelKeys() []string { + return []string{ + "ttl", + "ttl_seconds", + } +} + +// Request is a struct that stores the parameters and context of a request +// being made to Vault. It is used to abstract the details of the higher level +// request protocol from the handlers. +// +// Note: Many of these have Sentinel disabled because they are values populated +// by the router after policy checks; the token namespace would be the right +// place to access them via Sentinel +type Request struct { + // Id is the uuid associated with each request + ID string `json:"id" structs:"id" mapstructure:"id" sentinel:""` + + // If set, the name given to the replication secondary where this request + // originated + ReplicationCluster string `json:"replication_cluster" structs:"replication_cluster" mapstructure:"replication_cluster" sentinel:""` + + // Operation is the requested operation type + Operation Operation `json:"operation" structs:"operation" mapstructure:"operation"` + + // Path is the part of the request path not consumed by the + // routing. As an example, if the original request path is "prod/aws/foo" + // and the AWS logical backend is mounted at "prod/aws/", then the + // final path is "foo" since the mount prefix is trimmed. + Path string `json:"path" structs:"path" mapstructure:"path" sentinel:""` + + // Request data is an opaque map that must have string keys. + Data map[string]interface{} `json:"map" structs:"data" mapstructure:"data"` + + // Storage can be used to durably store and retrieve state. + Storage Storage `json:"-" sentinel:""` + + // Secret will be non-nil only for Revoke and Renew operations + // to represent the secret that was returned prior. + Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret" sentinel:""` + + // Auth will be non-nil only for Renew operations + // to represent the auth that was returned prior. + Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth" sentinel:""` + + // Headers will contain the http headers from the request. This value will + // be used in the audit broker to ensure we are auditing only the allowed + // headers. + Headers map[string][]string `json:"headers" structs:"headers" mapstructure:"headers" sentinel:""` + + // Connection will be non-nil only for credential providers to + // inspect the connection information and potentially use it for + // authentication/protection. + Connection *Connection `json:"connection" structs:"connection" mapstructure:"connection"` + + // ClientToken is provided to the core so that the identity + // can be verified and ACLs applied. This value is passed + // through to the logical backends but after being salted and + // hashed. + ClientToken string `json:"client_token" structs:"client_token" mapstructure:"client_token" sentinel:""` + + // ClientTokenAccessor is provided to the core so that the it can get + // logged as part of request audit logging. + ClientTokenAccessor string `json:"client_token_accessor" structs:"client_token_accessor" mapstructure:"client_token_accessor" sentinel:""` + + // DisplayName is provided to the logical backend to help associate + // dynamic secrets with the source entity. This is not a sensitive + // name, but is useful for operators. + DisplayName string `json:"display_name" structs:"display_name" mapstructure:"display_name" sentinel:""` + + // MountPoint is provided so that a logical backend can generate + // paths relative to itself. The `Path` is effectively the client + // request path with the MountPoint trimmed off. + MountPoint string `json:"mount_point" structs:"mount_point" mapstructure:"mount_point" sentinel:""` + + // MountType is provided so that a logical backend can make decisions + // based on the specific mount type (e.g., if a mount type has different + // aliases, generating different defaults depending on the alias) + MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type" sentinel:""` + + // MountAccessor is provided so that identities returned by the authentication + // backends can be tied to the mount it belongs to. + MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor" sentinel:""` + + // WrapInfo contains requested response wrapping parameters + WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info" sentinel:""` + + // ClientTokenRemainingUses represents the allowed number of uses left on the + // token supplied + ClientTokenRemainingUses int `json:"client_token_remaining_uses" structs:"client_token_remaining_uses" mapstructure:"client_token_remaining_uses"` + + // EntityID is the identity of the caller extracted out of the token used + // to make this request + EntityID string `json:"entity_id" structs:"entity_id" mapstructure:"entity_id" sentinel:""` + + // PolicyOverride indicates that the requestor wishes to override + // soft-mandatory Sentinel policies + PolicyOverride bool `json:"policy_override" structs:"policy_override" mapstructure:"policy_override"` + + // Whether the request is unauthenticated, as in, had no client token + // attached. Useful in some situations where the client token is not made + // accessible. + Unauthenticated bool `json:"unauthenticated" structs:"unauthenticated" mapstructure:"unauthenticated"` + + // For replication, contains the last WAL on the remote side after handling + // the request, used for best-effort avoidance of stale read-after-write + lastRemoteWAL uint64 +} + +// Get returns a data field and guards for nil Data +func (r *Request) Get(key string) interface{} { + if r.Data == nil { + return nil + } + return r.Data[key] +} + +// GetString returns a data field as a string +func (r *Request) GetString(key string) string { + raw := r.Get(key) + s, _ := raw.(string) + return s +} + +func (r *Request) GoString() string { + return fmt.Sprintf("*%#v", *r) +} + +func (r *Request) SentinelGet(key string) (interface{}, error) { + switch key { + case "path": + // Sanitize it here so that it's consistent in policies + return strings.TrimPrefix(r.Path, "/"), nil + + case "wrapping", "wrap_info": + // If the pointer is nil accessing the wrap info is considered + // "undefined" so this allows us to instead discover a TTL of zero + if r.WrapInfo == nil { + return &RequestWrapInfo{}, nil + } + return r.WrapInfo, nil + } + + return nil, nil +} + +func (r *Request) SentinelKeys() []string { + return []string{ + "path", + "wrapping", + "wrap_info", + } +} + +func (r *Request) LastRemoteWAL() uint64 { + return r.lastRemoteWAL +} + +func (r *Request) SetLastRemoteWAL(last uint64) { + r.lastRemoteWAL = last +} + +// RenewRequest creates the structure of the renew request. +func RenewRequest(path string, secret *Secret, data map[string]interface{}) *Request { + return &Request{ + Operation: RenewOperation, + Path: path, + Data: data, + Secret: secret, + } +} + +// RenewAuthRequest creates the structure of the renew request for an auth. +func RenewAuthRequest(path string, auth *Auth, data map[string]interface{}) *Request { + return &Request{ + Operation: RenewOperation, + Path: path, + Data: data, + Auth: auth, + } +} + +// RevokeRequest creates the structure of the revoke request. +func RevokeRequest(path string, secret *Secret, data map[string]interface{}) *Request { + return &Request{ + Operation: RevokeOperation, + Path: path, + Data: data, + Secret: secret, + } +} + +// RollbackRequest creates the structure of the revoke request. +func RollbackRequest(path string) *Request { + return &Request{ + Operation: RollbackOperation, + Path: path, + Data: make(map[string]interface{}), + } +} + +// Operation is an enum that is used to specify the type +// of request being made +type Operation string + +const ( + // The operations below are called per path + CreateOperation Operation = "create" + ReadOperation = "read" + UpdateOperation = "update" + DeleteOperation = "delete" + ListOperation = "list" + HelpOperation = "help" + AliasLookaheadOperation = "alias-lookahead" + + // The operations below are called globally, the path is less relevant. + RevokeOperation Operation = "revoke" + RenewOperation = "renew" + RollbackOperation = "rollback" +) + +var ( + // ErrUnsupportedOperation is returned if the operation is not supported + // by the logical backend. + ErrUnsupportedOperation = errors.New("unsupported operation") + + // ErrUnsupportedPath is returned if the path is not supported + // by the logical backend. + ErrUnsupportedPath = errors.New("unsupported path") + + // ErrInvalidRequest is returned if the request is invalid + ErrInvalidRequest = errors.New("invalid request") + + // ErrPermissionDenied is returned if the client is not authorized + ErrPermissionDenied = errors.New("permission denied") + + // ErrMultiAuthzPending is returned if the the request needs more + // authorizations + ErrMultiAuthzPending = errors.New("request needs further approval") +) diff --git a/vendor/github.com/hashicorp/vault/logical/response.go b/vendor/github.com/hashicorp/vault/logical/response.go new file mode 100644 index 0000000..723f88e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/response.go @@ -0,0 +1,162 @@ +package logical + +import ( + "encoding/json" + "errors" + + "github.com/hashicorp/vault/helper/wrapping" +) + +const ( + // HTTPContentType can be specified in the Data field of a Response + // so that the HTTP front end can specify a custom Content-Type associated + // with the HTTPRawBody. This can only be used for non-secrets, and should + // be avoided unless absolutely necessary, such as implementing a specification. + // The value must be a string. + HTTPContentType = "http_content_type" + + // HTTPRawBody is the raw content of the HTTP body that goes with the HTTPContentType. + // This can only be specified for non-secrets, and should should be similarly + // avoided like the HTTPContentType. The value must be a byte slice. + HTTPRawBody = "http_raw_body" + + // HTTPStatusCode is the response code of the HTTP body that goes with the HTTPContentType. + // This can only be specified for non-secrets, and should should be similarly + // avoided like the HTTPContentType. The value must be an integer. + HTTPStatusCode = "http_status_code" + + // For unwrapping we may need to know whether the value contained in the + // raw body is already JSON-unmarshaled. The presence of this key indicates + // that it has already been unmarshaled. That way we don't need to simply + // ignore errors. + HTTPRawBodyAlreadyJSONDecoded = "http_raw_body_already_json_decoded" +) + +// Response is a struct that stores the response of a request. +// It is used to abstract the details of the higher level request protocol. +type Response struct { + // Secret, if not nil, denotes that this response represents a secret. + Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret"` + + // Auth, if not nil, contains the authentication information for + // this response. This is only checked and means something for + // credential backends. + Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth"` + + // Response data is an opaque map that must have string keys. For + // secrets, this data is sent down to the user as-is. To store internal + // data that you don't want the user to see, store it in + // Secret.InternalData. + Data map[string]interface{} `json:"data" structs:"data" mapstructure:"data"` + + // Redirect is an HTTP URL to redirect to for further authentication. + // This is only valid for credential backends. This will be blanked + // for any logical backend and ignored. + Redirect string `json:"redirect" structs:"redirect" mapstructure:"redirect"` + + // Warnings allow operations or backends to return warnings in response + // to user actions without failing the action outright. + Warnings []string `json:"warnings" structs:"warnings" mapstructure:"warnings"` + + // Information for wrapping the response in a cubbyhole + WrapInfo *wrapping.ResponseWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info"` +} + +// AddWarning adds a warning into the response's warning list +func (r *Response) AddWarning(warning string) { + if r.Warnings == nil { + r.Warnings = make([]string, 0, 1) + } + r.Warnings = append(r.Warnings, warning) +} + +// IsError returns true if this response seems to indicate an error. +func (r *Response) IsError() bool { + return r != nil && r.Data != nil && len(r.Data) == 1 && r.Data["error"] != nil +} + +func (r *Response) Error() error { + if !r.IsError() { + return nil + } + switch r.Data["error"].(type) { + case string: + return errors.New(r.Data["error"].(string)) + case error: + return r.Data["error"].(error) + } + return nil +} + +// HelpResponse is used to format a help response +func HelpResponse(text string, seeAlso []string) *Response { + return &Response{ + Data: map[string]interface{}{ + "help": text, + "see_also": seeAlso, + }, + } +} + +// ErrorResponse is used to format an error response +func ErrorResponse(text string) *Response { + return &Response{ + Data: map[string]interface{}{ + "error": text, + }, + } +} + +// ListResponse is used to format a response to a list operation. +func ListResponse(keys []string) *Response { + resp := &Response{ + Data: map[string]interface{}{}, + } + if len(keys) != 0 { + resp.Data["keys"] = keys + } + return resp +} + +// ListResponseWithInfo is used to format a response to a list operation and +// return the keys as well as a map with corresponding key info. +func ListResponseWithInfo(keys []string, keyInfo map[string]interface{}) *Response { + resp := ListResponse(keys) + + keyInfoData := make(map[string]interface{}) + for _, key := range keys { + val, ok := keyInfo[key] + if ok { + keyInfoData[key] = val + } + } + + if len(keyInfoData) > 0 { + resp.Data["key_info"] = keyInfoData + } + + return resp +} + +// RespondWithStatusCode takes a response and converts it to a raw response with +// the provided Status Code. +func RespondWithStatusCode(resp *Response, req *Request, code int) (*Response, error) { + httpResp := LogicalResponseToHTTPResponse(resp) + httpResp.RequestID = req.ID + + body, err := json.Marshal(httpResp) + if err != nil { + return nil, err + } + + return &Response{ + Data: map[string]interface{}{ + HTTPContentType: "application/json", + // We default to string here so that the value is HMAC'd via audit. + // Since this function is always marshaling to JSON, this is + // appropriate. + HTTPRawBody: string(body), + HTTPStatusCode: code, + }, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/response_util.go b/vendor/github.com/hashicorp/vault/logical/response_util.go new file mode 100644 index 0000000..803ae9f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/response_util.go @@ -0,0 +1,136 @@ +package logical + +import ( + "errors" + "fmt" + "net/http" + + "github.com/hashicorp/errwrap" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/helper/consts" +) + +// RespondErrorCommon pulls most of the functionality from http's +// respondErrorCommon and some of http's handleLogical and makes it available +// to both the http package and elsewhere. +func RespondErrorCommon(req *Request, resp *Response, err error) (int, error) { + if err == nil && (resp == nil || !resp.IsError()) { + switch { + case req.Operation == ReadOperation: + if resp == nil { + return http.StatusNotFound, nil + } + + // Basically: if we have empty "keys" or no keys at all, 404. This + // provides consistency with GET. + case req.Operation == ListOperation && resp.WrapInfo == nil: + if resp == nil { + return http.StatusNotFound, nil + } + if len(resp.Data) == 0 { + if len(resp.Warnings) > 0 { + return 0, nil + } + return http.StatusNotFound, nil + } + keysRaw, ok := resp.Data["keys"] + if !ok || keysRaw == nil { + // If we don't have keys but have other data, return as-is + if len(resp.Data) > 0 || len(resp.Warnings) > 0 { + return 0, nil + } + return http.StatusNotFound, nil + } + + var keys []string + switch keysRaw.(type) { + case []interface{}: + keys = make([]string, len(keysRaw.([]interface{}))) + for i, el := range keysRaw.([]interface{}) { + s, ok := el.(string) + if !ok { + return http.StatusInternalServerError, nil + } + keys[i] = s + } + + case []string: + keys = keysRaw.([]string) + default: + return http.StatusInternalServerError, nil + } + + if len(keys) == 0 { + return http.StatusNotFound, nil + } + } + + return 0, nil + } + + if errwrap.ContainsType(err, new(ReplicationCodedError)) { + var allErrors error + codedErr := errwrap.GetType(err, new(ReplicationCodedError)).(*ReplicationCodedError) + errwrap.Walk(err, func(inErr error) { + newErr, ok := inErr.(*ReplicationCodedError) + if !ok { + allErrors = multierror.Append(allErrors, newErr) + } + }) + if allErrors != nil { + return codedErr.Code, multierror.Append(errors.New(fmt.Sprintf("errors from both primary and secondary; primary error was %v; secondary errors follow", codedErr.Msg)), allErrors) + } + return codedErr.Code, errors.New(codedErr.Msg) + } + + // Start out with internal server error since in most of these cases there + // won't be a response so this won't be overridden + statusCode := http.StatusInternalServerError + // If we actually have a response, start out with bad request + if resp != nil { + statusCode = http.StatusBadRequest + } + + // Now, check the error itself; if it has a specific logical error, set the + // appropriate code + if err != nil { + switch { + case errwrap.ContainsType(err, new(StatusBadRequest)): + statusCode = http.StatusBadRequest + case errwrap.Contains(err, ErrPermissionDenied.Error()): + statusCode = http.StatusForbidden + case errwrap.Contains(err, ErrUnsupportedOperation.Error()): + statusCode = http.StatusMethodNotAllowed + case errwrap.Contains(err, ErrUnsupportedPath.Error()): + statusCode = http.StatusNotFound + case errwrap.Contains(err, ErrInvalidRequest.Error()): + statusCode = http.StatusBadRequest + } + } + + if resp != nil && resp.IsError() { + err = fmt.Errorf("%s", resp.Data["error"].(string)) + } + + return statusCode, err +} + +// AdjustErrorStatusCode adjusts the status that will be sent in error +// conditions in a way that can be shared across http's respondError and other +// locations. +func AdjustErrorStatusCode(status *int, err error) { + // Adjust status code when sealed + if errwrap.Contains(err, consts.ErrSealed.Error()) { + *status = http.StatusServiceUnavailable + } + + // Adjust status code on + if errwrap.Contains(err, "http: request body too large") { + *status = http.StatusRequestEntityTooLarge + } + + // Allow HTTPCoded error passthrough to specify a code + if t, ok := err.(HTTPCodedError); ok { + *status = t.Code() + } +} diff --git a/vendor/github.com/hashicorp/vault/logical/secret.go b/vendor/github.com/hashicorp/vault/logical/secret.go new file mode 100644 index 0000000..a2128d8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/secret.go @@ -0,0 +1,30 @@ +package logical + +import "fmt" + +// Secret represents the secret part of a response. +type Secret struct { + LeaseOptions + + // InternalData is JSON-encodable data that is stored with the secret. + // This will be sent back during a Renew/Revoke for storing internal data + // used for those operations. + InternalData map[string]interface{} `json:"internal_data" sentinel:""` + + // LeaseID is the ID returned to the user to manage this secret. + // This is generated by Vault core. Any set value will be ignored. + // For requests, this will always be blank. + LeaseID string `sentinel:""` +} + +func (s *Secret) Validate() error { + if s.TTL < 0 { + return fmt.Errorf("ttl duration must not be less than zero") + } + + return nil +} + +func (s *Secret) GoString() string { + return fmt.Sprintf("*%#v", *s) +} diff --git a/vendor/github.com/hashicorp/vault/logical/storage.go b/vendor/github.com/hashicorp/vault/logical/storage.go new file mode 100644 index 0000000..116fd30 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/storage.go @@ -0,0 +1,121 @@ +package logical + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" +) + +// ErrReadOnly is returned when a backend does not support +// writing. This can be caused by a read-only replica or secondary +// cluster operation. +var ErrReadOnly = errors.New("cannot write to readonly storage") + +// ErrSetupReadOnly is returned when a write operation is attempted on a +// storage while the backend is still being setup. +var ErrSetupReadOnly = errors.New("cannot write to storage during setup") + +// Storage is the way that logical backends are able read/write data. +type Storage interface { + List(context.Context, string) ([]string, error) + Get(context.Context, string) (*StorageEntry, error) + Put(context.Context, *StorageEntry) error + Delete(context.Context, string) error +} + +// StorageEntry is the entry for an item in a Storage implementation. +type StorageEntry struct { + Key string + Value []byte + SealWrap bool +} + +// DecodeJSON decodes the 'Value' present in StorageEntry. +func (e *StorageEntry) DecodeJSON(out interface{}) error { + return jsonutil.DecodeJSON(e.Value, out) +} + +// StorageEntryJSON creates a StorageEntry with a JSON-encoded value. +func StorageEntryJSON(k string, v interface{}) (*StorageEntry, error) { + encodedBytes, err := jsonutil.EncodeJSON(v) + if err != nil { + return nil, errwrap.Wrapf("failed to encode storage entry: {{err}}", err) + } + + return &StorageEntry{ + Key: k, + Value: encodedBytes, + }, nil +} + +type ClearableView interface { + List(context.Context, string) ([]string, error) + Delete(context.Context, string) error +} + +// ScanView is used to scan all the keys in a view iteratively +func ScanView(ctx context.Context, view ClearableView, cb func(path string)) error { + frontier := []string{""} + for len(frontier) > 0 { + n := len(frontier) + current := frontier[n-1] + frontier = frontier[:n-1] + + // List the contents + contents, err := view.List(ctx, current) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("list failed at path %q: {{err}}", current), err) + } + + // Handle the contents in the directory + for _, c := range contents { + fullPath := current + c + if strings.HasSuffix(c, "/") { + frontier = append(frontier, fullPath) + } else { + cb(fullPath) + } + } + } + return nil +} + +// CollectKeys is used to collect all the keys in a view +func CollectKeys(ctx context.Context, view ClearableView) ([]string, error) { + // Accumulate the keys + var existing []string + cb := func(path string) { + existing = append(existing, path) + } + + // Scan for all the keys + if err := ScanView(ctx, view, cb); err != nil { + return nil, err + } + return existing, nil +} + +// ClearView is used to delete all the keys in a view +func ClearView(ctx context.Context, view ClearableView) error { + if view == nil { + return nil + } + + // Collect all the keys + keys, err := CollectKeys(ctx, view) + if err != nil { + return err + } + + // Delete all the keys + for _, key := range keys { + if err := view.Delete(ctx, key); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/storage_inmem.go b/vendor/github.com/hashicorp/vault/logical/storage_inmem.go new file mode 100644 index 0000000..e0ff75f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/storage_inmem.go @@ -0,0 +1,67 @@ +package logical + +import ( + "context" + "sync" + + "github.com/hashicorp/vault/physical" + "github.com/hashicorp/vault/physical/inmem" +) + +// InmemStorage implements Storage and stores all data in memory. It is +// basically a straight copy of physical.Inmem, but it prevents backends from +// having to load all of physical's dependencies (which are legion) just to +// have some testing storage. +type InmemStorage struct { + underlying physical.Backend + once sync.Once +} + +func (s *InmemStorage) Get(ctx context.Context, key string) (*StorageEntry, error) { + s.once.Do(s.init) + + entry, err := s.underlying.Get(ctx, key) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + return &StorageEntry{ + Key: entry.Key, + Value: entry.Value, + SealWrap: entry.SealWrap, + }, nil +} + +func (s *InmemStorage) Put(ctx context.Context, entry *StorageEntry) error { + s.once.Do(s.init) + + return s.underlying.Put(ctx, &physical.Entry{ + Key: entry.Key, + Value: entry.Value, + SealWrap: entry.SealWrap, + }) +} + +func (s *InmemStorage) Delete(ctx context.Context, key string) error { + s.once.Do(s.init) + + return s.underlying.Delete(ctx, key) +} + +func (s *InmemStorage) List(ctx context.Context, prefix string) ([]string, error) { + s.once.Do(s.init) + + return s.underlying.List(ctx, prefix) +} + +func (s *InmemStorage) Underlying() *inmem.InmemBackend { + s.once.Do(s.init) + + return s.underlying.(*inmem.InmemBackend) +} + +func (s *InmemStorage) init() { + s.underlying, _ = inmem.NewInmem(nil, nil) +} diff --git a/vendor/github.com/hashicorp/vault/logical/system_view.go b/vendor/github.com/hashicorp/vault/logical/system_view.go new file mode 100644 index 0000000..3fbcb67 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/system_view.go @@ -0,0 +1,121 @@ +package logical + +import ( + "context" + "errors" + "time" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/helper/wrapping" +) + +// SystemView exposes system configuration information in a safe way +// for logical backends to consume +type SystemView interface { + // DefaultLeaseTTL returns the default lease TTL set in Vault configuration + DefaultLeaseTTL() time.Duration + + // MaxLeaseTTL returns the max lease TTL set in Vault configuration; backend + // authors should take care not to issue credentials that last longer than + // this value, as Vault will revoke them + MaxLeaseTTL() time.Duration + + // SudoPrivilege returns true if given path has sudo privileges + // for the given client token + SudoPrivilege(ctx context.Context, path string, token string) bool + + // Returns true if the mount is tainted. A mount is tainted if it is in the + // process of being unmounted. This should only be used in special + // circumstances; a primary use-case is as a guard in revocation functions. + // If revocation of a backend's leases fails it can keep the unmounting + // process from being successful. If the reason for this failure is not + // relevant when the mount is tainted (for instance, saving a CRL to disk + // when the stored CRL will be removed during the unmounting process + // anyways), we can ignore the errors to allow unmounting to complete. + Tainted() bool + + // Returns true if caching is disabled. If true, no caches should be used, + // despite known slowdowns. + CachingDisabled() bool + + // When run from a system view attached to a request, indicates whether the + // request is affecting a local mount or not + LocalMount() bool + + // ReplicationState indicates the state of cluster replication + ReplicationState() consts.ReplicationState + + // ResponseWrapData wraps the given data in a cubbyhole and returns the + // token used to unwrap. + ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) + + // LookupPlugin looks into the plugin catalog for a plugin with the given + // name. Returns a PluginRunner or an error if a plugin can not be found. + LookupPlugin(context.Context, string) (*pluginutil.PluginRunner, error) + + // MlockEnabled returns the configuration setting for enabling mlock on + // plugins. + MlockEnabled() bool + + // EntityInfo returns a subset of information related to the identity entity + // for the given entity id + EntityInfo(entityID string) (*Entity, error) +} + +type StaticSystemView struct { + DefaultLeaseTTLVal time.Duration + MaxLeaseTTLVal time.Duration + SudoPrivilegeVal bool + TaintedVal bool + CachingDisabledVal bool + Primary bool + EnableMlock bool + LocalMountVal bool + ReplicationStateVal consts.ReplicationState + EntityVal *Entity +} + +func (d StaticSystemView) DefaultLeaseTTL() time.Duration { + return d.DefaultLeaseTTLVal +} + +func (d StaticSystemView) MaxLeaseTTL() time.Duration { + return d.MaxLeaseTTLVal +} + +func (d StaticSystemView) SudoPrivilege(_ context.Context, path string, token string) bool { + return d.SudoPrivilegeVal +} + +func (d StaticSystemView) Tainted() bool { + return d.TaintedVal +} + +func (d StaticSystemView) CachingDisabled() bool { + return d.CachingDisabledVal +} + +func (d StaticSystemView) LocalMount() bool { + return d.LocalMountVal +} + +func (d StaticSystemView) ReplicationState() consts.ReplicationState { + return d.ReplicationStateVal +} + +func (d StaticSystemView) ResponseWrapData(_ context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) { + return nil, errors.New("ResponseWrapData is not implemented in StaticSystemView") +} + +func (d StaticSystemView) LookupPlugin(_ context.Context, name string) (*pluginutil.PluginRunner, error) { + return nil, errors.New("LookupPlugin is not implemented in StaticSystemView") +} + +func (d StaticSystemView) MlockEnabled() bool { + return d.EnableMlock +} + +func (d StaticSystemView) EntityInfo(entityID string) (*Entity, error) { + return d.EntityVal, nil +} diff --git a/vendor/github.com/hashicorp/vault/logical/testing.go b/vendor/github.com/hashicorp/vault/logical/testing.go new file mode 100644 index 0000000..7c77389 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/testing.go @@ -0,0 +1,84 @@ +package logical + +import ( + "context" + "reflect" + "time" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/helper/logging" + "github.com/mitchellh/go-testing-interface" +) + +// TestRequest is a helper to create a purely in-memory Request struct. +func TestRequest(t testing.T, op Operation, path string) *Request { + return &Request{ + Operation: op, + Path: path, + Data: make(map[string]interface{}), + Storage: new(InmemStorage), + } +} + +// TestStorage is a helper that can be used from unit tests to verify +// the behavior of a Storage impl. +func TestStorage(t testing.T, s Storage) { + keys, err := s.List(context.Background(), "") + if err != nil { + t.Fatalf("list error: %s", err) + } + if len(keys) > 0 { + t.Fatalf("should have no keys to start: %#v", keys) + } + + entry := &StorageEntry{Key: "foo", Value: []byte("bar")} + if err := s.Put(context.Background(), entry); err != nil { + t.Fatalf("put error: %s", err) + } + + actual, err := s.Get(context.Background(), "foo") + if err != nil { + t.Fatalf("get error: %s", err) + } + if !reflect.DeepEqual(actual, entry) { + t.Fatalf("wrong value. Expected: %#v\nGot: %#v", entry, actual) + } + + keys, err = s.List(context.Background(), "") + if err != nil { + t.Fatalf("list error: %s", err) + } + if !reflect.DeepEqual(keys, []string{"foo"}) { + t.Fatalf("bad keys: %#v", keys) + } + + if err := s.Delete(context.Background(), "foo"); err != nil { + t.Fatalf("put error: %s", err) + } + + keys, err = s.List(context.Background(), "") + if err != nil { + t.Fatalf("list error: %s", err) + } + if len(keys) > 0 { + t.Fatalf("should have no keys to start: %#v", keys) + } +} + +func TestSystemView() *StaticSystemView { + defaultLeaseTTLVal := time.Hour * 24 + maxLeaseTTLVal := time.Hour * 24 * 2 + return &StaticSystemView{ + DefaultLeaseTTLVal: defaultLeaseTTLVal, + MaxLeaseTTLVal: maxLeaseTTLVal, + } +} + +func TestBackendConfig() *BackendConfig { + bc := &BackendConfig{ + Logger: logging.NewVaultLogger(log.Trace), + System: TestSystemView(), + } + + return bc +} diff --git a/vendor/github.com/hashicorp/vault/logical/translate_response.go b/vendor/github.com/hashicorp/vault/logical/translate_response.go new file mode 100644 index 0000000..4335301 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/translate_response.go @@ -0,0 +1,143 @@ +package logical + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +// This logic was pulled from the http package so that it can be used for +// encoding wrapped responses as well. It simply translates the logical +// response to an http response, with the values we want and omitting the +// values we don't. +func LogicalResponseToHTTPResponse(input *Response) *HTTPResponse { + httpResp := &HTTPResponse{ + Data: input.Data, + Warnings: input.Warnings, + } + + if input.Secret != nil { + httpResp.LeaseID = input.Secret.LeaseID + httpResp.Renewable = input.Secret.Renewable + httpResp.LeaseDuration = int(input.Secret.TTL.Seconds()) + } + + // If we have authentication information, then + // set up the result structure. + if input.Auth != nil { + httpResp.Auth = &HTTPAuth{ + ClientToken: input.Auth.ClientToken, + Accessor: input.Auth.Accessor, + Policies: input.Auth.Policies, + Metadata: input.Auth.Metadata, + LeaseDuration: int(input.Auth.TTL.Seconds()), + Renewable: input.Auth.Renewable, + EntityID: input.Auth.EntityID, + } + } + + return httpResp +} + +func HTTPResponseToLogicalResponse(input *HTTPResponse) *Response { + logicalResp := &Response{ + Data: input.Data, + Warnings: input.Warnings, + } + + if input.LeaseID != "" { + logicalResp.Secret = &Secret{ + LeaseID: input.LeaseID, + } + logicalResp.Secret.Renewable = input.Renewable + logicalResp.Secret.TTL = time.Second * time.Duration(input.LeaseDuration) + } + + if input.Auth != nil { + logicalResp.Auth = &Auth{ + ClientToken: input.Auth.ClientToken, + Accessor: input.Auth.Accessor, + Policies: input.Auth.Policies, + Metadata: input.Auth.Metadata, + EntityID: input.Auth.EntityID, + } + logicalResp.Auth.Renewable = input.Auth.Renewable + logicalResp.Auth.TTL = time.Second * time.Duration(input.Auth.LeaseDuration) + } + + return logicalResp +} + +type HTTPResponse struct { + RequestID string `json:"request_id"` + LeaseID string `json:"lease_id"` + Renewable bool `json:"renewable"` + LeaseDuration int `json:"lease_duration"` + Data map[string]interface{} `json:"data"` + WrapInfo *HTTPWrapInfo `json:"wrap_info"` + Warnings []string `json:"warnings"` + Auth *HTTPAuth `json:"auth"` +} + +type HTTPAuth struct { + ClientToken string `json:"client_token"` + Accessor string `json:"accessor"` + Policies []string `json:"policies"` + Metadata map[string]string `json:"metadata"` + LeaseDuration int `json:"lease_duration"` + Renewable bool `json:"renewable"` + EntityID string `json:"entity_id"` +} + +type HTTPWrapInfo struct { + Token string `json:"token"` + Accessor string `json:"accessor"` + TTL int `json:"ttl"` + CreationTime string `json:"creation_time"` + CreationPath string `json:"creation_path"` + WrappedAccessor string `json:"wrapped_accessor,omitempty"` +} + +type HTTPSysInjector struct { + Response *HTTPResponse +} + +func (h HTTPSysInjector) MarshalJSON() ([]byte, error) { + j, err := json.Marshal(h.Response) + if err != nil { + return nil, err + } + + // Fast path no data or empty data + if h.Response.Data == nil || len(h.Response.Data) == 0 { + return j, nil + } + + // Marshaling a response will always be a JSON object, meaning it will + // always start with '{', so we hijack this to prepend necessary values + + // Make a guess at the capacity, and write the object opener + buf := bytes.NewBuffer(make([]byte, 0, len(j)*2)) + buf.WriteRune('{') + + for k, v := range h.Response.Data { + // Marshal each key/value individually + mk, err := json.Marshal(k) + if err != nil { + return nil, err + } + mv, err := json.Marshal(v) + if err != nil { + return nil, err + } + // Write into the final buffer. We'll never have a valid response + // without any fields so we can unconditionally add a comma after each. + buf.WriteString(fmt.Sprintf("%s: %s, ", mk, mv)) + } + + // Add the rest, without the first '{' + buf.Write(j[1:]) + + return buf.Bytes(), nil +} diff --git a/vendor/github.com/hashicorp/vault/physical/cache.go b/vendor/github.com/hashicorp/vault/physical/cache.go new file mode 100644 index 0000000..4e2e5a5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/cache.go @@ -0,0 +1,220 @@ +package physical + +import ( + "context" + "sync/atomic" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/golang-lru" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/pathmanager" +) + +const ( + // DefaultCacheSize is used if no cache size is specified for NewCache + DefaultCacheSize = 128 * 1024 +) + +// These paths don't need to be cached by the LRU cache. This should +// particularly help memory pressure when unsealing. +var cacheExceptionsPaths = []string{ + "wal/logs/", + "index/pages/", + "index-dr/pages/", + "sys/expire/", +} + +// Cache is used to wrap an underlying physical backend +// and provide an LRU cache layer on top. Most of the reads done by +// Vault are for policy objects so there is a large read reduction +// by using a simple write-through cache. +type Cache struct { + backend Backend + lru *lru.TwoQueueCache + locks []*locksutil.LockEntry + logger log.Logger + enabled *uint32 + cacheExceptions *pathmanager.PathManager +} + +// TransactionalCache is a Cache that wraps the physical that is transactional +type TransactionalCache struct { + *Cache + Transactional +} + +// Verify Cache satisfies the correct interfaces +var _ ToggleablePurgemonster = (*Cache)(nil) +var _ ToggleablePurgemonster = (*TransactionalCache)(nil) +var _ Backend = (*Cache)(nil) +var _ Transactional = (*TransactionalCache)(nil) + +// NewCache returns a physical cache of the given size. +// If no size is provided, the default size is used. +func NewCache(b Backend, size int, logger log.Logger) *Cache { + if logger.IsDebug() { + logger.Debug("creating LRU cache", "size", size) + } + if size <= 0 { + size = DefaultCacheSize + } + + pm := pathmanager.New() + pm.AddPaths(cacheExceptionsPaths) + + cache, _ := lru.New2Q(size) + c := &Cache{ + backend: b, + lru: cache, + locks: locksutil.CreateLocks(), + logger: logger, + // This fails safe. + enabled: new(uint32), + cacheExceptions: pm, + } + return c +} + +func NewTransactionalCache(b Backend, size int, logger log.Logger) *TransactionalCache { + c := &TransactionalCache{ + Cache: NewCache(b, size, logger), + Transactional: b.(Transactional), + } + return c +} + +func (c *Cache) shouldCache(key string) bool { + if atomic.LoadUint32(c.enabled) == 0 { + return false + } + + return !c.cacheExceptions.HasPath(key) +} + +// SetEnabled is used to toggle whether the cache is on or off. It must be +// called with true to actually activate the cache after creation. +func (c *Cache) SetEnabled(enabled bool) { + if enabled { + atomic.StoreUint32(c.enabled, 1) + return + } + atomic.StoreUint32(c.enabled, 0) +} + +// Purge is used to clear the cache +func (c *Cache) Purge(ctx context.Context) { + // Lock the world + for _, lock := range c.locks { + lock.Lock() + defer lock.Unlock() + } + + c.lru.Purge() +} + +func (c *Cache) Put(ctx context.Context, entry *Entry) error { + if entry != nil && !c.shouldCache(entry.Key) { + return c.backend.Put(ctx, entry) + } + + lock := locksutil.LockForKey(c.locks, entry.Key) + lock.Lock() + defer lock.Unlock() + + err := c.backend.Put(ctx, entry) + if err == nil { + c.lru.Add(entry.Key, entry) + } + return err +} + +func (c *Cache) Get(ctx context.Context, key string) (*Entry, error) { + if !c.shouldCache(key) { + return c.backend.Get(ctx, key) + } + + lock := locksutil.LockForKey(c.locks, key) + lock.RLock() + defer lock.RUnlock() + + // Check the LRU first + if raw, ok := c.lru.Get(key); ok { + if raw == nil { + return nil, nil + } + return raw.(*Entry), nil + } + + // Read from the underlying backend + ent, err := c.backend.Get(ctx, key) + if err != nil { + return nil, err + } + + // Cache the result + if ent != nil { + c.lru.Add(key, ent) + } + + return ent, nil +} + +func (c *Cache) Delete(ctx context.Context, key string) error { + if !c.shouldCache(key) { + return c.backend.Delete(ctx, key) + } + + lock := locksutil.LockForKey(c.locks, key) + lock.Lock() + defer lock.Unlock() + + err := c.backend.Delete(ctx, key) + if err == nil { + c.lru.Remove(key) + } + return err +} + +func (c *Cache) List(ctx context.Context, prefix string) ([]string, error) { + // Always pass-through as this would be difficult to cache. For the same + // reason we don't lock as we can't reasonably know which locks to readlock + // ahead of time. + return c.backend.List(ctx, prefix) +} + +func (c *TransactionalCache) Transaction(ctx context.Context, txns []*TxnEntry) error { + // Bypass the locking below + if atomic.LoadUint32(c.enabled) == 0 { + return c.Transactional.Transaction(ctx, txns) + } + + // Collect keys that need to be locked + var keys []string + for _, curr := range txns { + keys = append(keys, curr.Entry.Key) + } + // Lock the keys + for _, l := range locksutil.LocksForKeys(c.locks, keys) { + l.Lock() + defer l.Unlock() + } + + if err := c.Transactional.Transaction(ctx, txns); err != nil { + return err + } + + for _, txn := range txns { + if !c.shouldCache(txn.Entry.Key) { + continue + } + + switch txn.Operation { + case PutOperation: + c.lru.Add(txn.Entry.Key, txn.Entry) + case DeleteOperation: + c.lru.Remove(txn.Entry.Key) + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/physical/inmem/inmem.go b/vendor/github.com/hashicorp/vault/physical/inmem/inmem.go new file mode 100644 index 0000000..139671c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/inmem/inmem.go @@ -0,0 +1,216 @@ +package inmem + +import ( + "context" + "errors" + "strings" + "sync" + "sync/atomic" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/physical" + + "github.com/armon/go-radix" +) + +// Verify interfaces are satisfied +var _ physical.Backend = (*InmemBackend)(nil) +var _ physical.HABackend = (*InmemHABackend)(nil) +var _ physical.HABackend = (*TransactionalInmemHABackend)(nil) +var _ physical.Lock = (*InmemLock)(nil) +var _ physical.Transactional = (*TransactionalInmemBackend)(nil) +var _ physical.Transactional = (*TransactionalInmemHABackend)(nil) + +var ( + PutDisabledError = errors.New("put operations disabled in inmem backend") + GetDisabledError = errors.New("get operations disabled in inmem backend") + DeleteDisabledError = errors.New("delete operations disabled in inmem backend") + ListDisabledError = errors.New("list operations disabled in inmem backend") +) + +// InmemBackend is an in-memory only physical backend. It is useful +// for testing and development situations where the data is not +// expected to be durable. +type InmemBackend struct { + sync.RWMutex + root *radix.Tree + permitPool *physical.PermitPool + logger log.Logger + failGet uint32 + failPut uint32 + failDelete uint32 + failList uint32 +} + +type TransactionalInmemBackend struct { + InmemBackend +} + +// NewInmem constructs a new in-memory backend +func NewInmem(_ map[string]string, logger log.Logger) (physical.Backend, error) { + in := &InmemBackend{ + root: radix.New(), + permitPool: physical.NewPermitPool(physical.DefaultParallelOperations), + logger: logger, + } + return in, nil +} + +// Basically for now just creates a permit pool of size 1 so only one operation +// can run at a time +func NewTransactionalInmem(_ map[string]string, logger log.Logger) (physical.Backend, error) { + in := &TransactionalInmemBackend{ + InmemBackend: InmemBackend{ + root: radix.New(), + permitPool: physical.NewPermitPool(1), + logger: logger, + }, + } + return in, nil +} + +// Put is used to insert or update an entry +func (i *InmemBackend) Put(ctx context.Context, entry *physical.Entry) error { + i.permitPool.Acquire() + defer i.permitPool.Release() + + i.Lock() + defer i.Unlock() + + return i.PutInternal(ctx, entry) +} + +func (i *InmemBackend) PutInternal(ctx context.Context, entry *physical.Entry) error { + if atomic.LoadUint32(&i.failPut) != 0 { + return PutDisabledError + } + + i.root.Insert(entry.Key, entry.Value) + return nil +} + +func (i *InmemBackend) FailPut(fail bool) { + var val uint32 + if fail { + val = 1 + } + atomic.StoreUint32(&i.failPut, val) +} + +// Get is used to fetch an entry +func (i *InmemBackend) Get(ctx context.Context, key string) (*physical.Entry, error) { + i.permitPool.Acquire() + defer i.permitPool.Release() + + i.RLock() + defer i.RUnlock() + + return i.GetInternal(ctx, key) +} + +func (i *InmemBackend) GetInternal(ctx context.Context, key string) (*physical.Entry, error) { + if atomic.LoadUint32(&i.failGet) != 0 { + return nil, GetDisabledError + } + + if raw, ok := i.root.Get(key); ok { + return &physical.Entry{ + Key: key, + Value: raw.([]byte), + }, nil + } + return nil, nil +} + +func (i *InmemBackend) FailGet(fail bool) { + var val uint32 + if fail { + val = 1 + } + atomic.StoreUint32(&i.failGet, val) +} + +// Delete is used to permanently delete an entry +func (i *InmemBackend) Delete(ctx context.Context, key string) error { + i.permitPool.Acquire() + defer i.permitPool.Release() + + i.Lock() + defer i.Unlock() + + return i.DeleteInternal(ctx, key) +} + +func (i *InmemBackend) DeleteInternal(ctx context.Context, key string) error { + if atomic.LoadUint32(&i.failDelete) != 0 { + return DeleteDisabledError + } + + i.root.Delete(key) + return nil +} + +func (i *InmemBackend) FailDelete(fail bool) { + var val uint32 + if fail { + val = 1 + } + atomic.StoreUint32(&i.failDelete, val) +} + +// List is used ot list all the keys under a given +// prefix, up to the next prefix. +func (i *InmemBackend) List(ctx context.Context, prefix string) ([]string, error) { + i.permitPool.Acquire() + defer i.permitPool.Release() + + i.RLock() + defer i.RUnlock() + + return i.ListInternal(prefix) +} + +func (i *InmemBackend) ListInternal(prefix string) ([]string, error) { + if atomic.LoadUint32(&i.failList) != 0 { + return nil, ListDisabledError + } + + var out []string + seen := make(map[string]interface{}) + walkFn := func(s string, v interface{}) bool { + trimmed := strings.TrimPrefix(s, prefix) + sep := strings.Index(trimmed, "/") + if sep == -1 { + out = append(out, trimmed) + } else { + trimmed = trimmed[:sep+1] + if _, ok := seen[trimmed]; !ok { + out = append(out, trimmed) + seen[trimmed] = struct{}{} + } + } + return false + } + i.root.WalkPrefix(prefix, walkFn) + + return out, nil +} + +func (i *InmemBackend) FailList(fail bool) { + var val uint32 + if fail { + val = 1 + } + atomic.StoreUint32(&i.failList, val) +} + +// Implements the transaction interface +func (t *TransactionalInmemBackend) Transaction(ctx context.Context, txns []*physical.TxnEntry) error { + t.permitPool.Acquire() + defer t.permitPool.Release() + + t.Lock() + defer t.Unlock() + + return physical.GenericTransactionHandler(ctx, t, txns) +} diff --git a/vendor/github.com/hashicorp/vault/physical/inmem/inmem_ha.go b/vendor/github.com/hashicorp/vault/physical/inmem/inmem_ha.go new file mode 100644 index 0000000..6755100 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/inmem/inmem_ha.go @@ -0,0 +1,167 @@ +package inmem + +import ( + "fmt" + "sync" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/physical" +) + +type InmemHABackend struct { + physical.Backend + locks map[string]string + l *sync.Mutex + cond *sync.Cond + logger log.Logger +} + +type TransactionalInmemHABackend struct { + physical.Transactional + InmemHABackend +} + +// NewInmemHA constructs a new in-memory HA backend. This is only for testing. +func NewInmemHA(_ map[string]string, logger log.Logger) (physical.Backend, error) { + be, err := NewInmem(nil, logger) + if err != nil { + return nil, err + } + + in := &InmemHABackend{ + Backend: be, + locks: make(map[string]string), + logger: logger, + l: new(sync.Mutex), + } + in.cond = sync.NewCond(in.l) + return in, nil +} + +func NewTransactionalInmemHA(_ map[string]string, logger log.Logger) (physical.Backend, error) { + transInmem, err := NewTransactionalInmem(nil, logger) + if err != nil { + return nil, err + } + inmemHA := InmemHABackend{ + Backend: transInmem, + locks: make(map[string]string), + logger: logger, + l: new(sync.Mutex), + } + + in := &TransactionalInmemHABackend{ + InmemHABackend: inmemHA, + Transactional: transInmem.(physical.Transactional), + } + in.cond = sync.NewCond(in.l) + return in, nil +} + +// LockWith is used for mutual exclusion based on the given key. +func (i *InmemHABackend) LockWith(key, value string) (physical.Lock, error) { + l := &InmemLock{ + in: i, + key: key, + value: value, + } + return l, nil +} + +// LockMapSize is used in some tests to determine whether this backend has ever +// been used for HA purposes rather than simply for storage +func (i *InmemHABackend) LockMapSize() int { + return len(i.locks) +} + +// HAEnabled indicates whether the HA functionality should be exposed. +// Currently always returns true. +func (i *InmemHABackend) HAEnabled() bool { + return true +} + +// InmemLock is an in-memory Lock implementation for the HABackend +type InmemLock struct { + in *InmemHABackend + key string + value string + + held bool + leaderCh chan struct{} + l sync.Mutex +} + +func (i *InmemLock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) { + i.l.Lock() + defer i.l.Unlock() + if i.held { + return nil, fmt.Errorf("lock already held") + } + + // Attempt an async acquisition + didLock := make(chan struct{}) + releaseCh := make(chan bool, 1) + go func() { + // Wait to acquire the lock + i.in.l.Lock() + _, ok := i.in.locks[i.key] + for ok { + i.in.cond.Wait() + _, ok = i.in.locks[i.key] + } + i.in.locks[i.key] = i.value + i.in.l.Unlock() + + // Signal that lock is held + close(didLock) + + // Handle an early abort + release := <-releaseCh + if release { + i.in.l.Lock() + delete(i.in.locks, i.key) + i.in.l.Unlock() + i.in.cond.Broadcast() + } + }() + + // Wait for lock acquisition or shutdown + select { + case <-didLock: + releaseCh <- false + case <-stopCh: + releaseCh <- true + return nil, nil + } + + // Create the leader channel + i.held = true + i.leaderCh = make(chan struct{}) + return i.leaderCh, nil +} + +func (i *InmemLock) Unlock() error { + i.l.Lock() + defer i.l.Unlock() + + if !i.held { + return nil + } + + close(i.leaderCh) + i.leaderCh = nil + i.held = false + + i.in.l.Lock() + delete(i.in.locks, i.key) + i.in.l.Unlock() + i.in.cond.Broadcast() + return nil +} + +func (i *InmemLock) Value() (bool, string, error) { + i.in.l.Lock() + val, ok := i.in.locks[i.key] + i.in.l.Unlock() + return ok, val, nil +} diff --git a/vendor/github.com/hashicorp/vault/physical/latency.go b/vendor/github.com/hashicorp/vault/physical/latency.go new file mode 100644 index 0000000..7aa9fab --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/latency.go @@ -0,0 +1,95 @@ +package physical + +import ( + "context" + "math/rand" + "time" + + log "github.com/hashicorp/go-hclog" +) + +const ( + // DefaultJitterPercent is used if no cache size is specified for NewCache + DefaultJitterPercent = 20 +) + +// LatencyInjector is used to add latency into underlying physical requests +type LatencyInjector struct { + backend Backend + latency time.Duration + jitterPercent int + random *rand.Rand +} + +// TransactionalLatencyInjector is the transactional version of the latency +// injector +type TransactionalLatencyInjector struct { + *LatencyInjector + Transactional +} + +// Verify LatencyInjector satisfies the correct interfaces +var _ Backend = (*LatencyInjector)(nil) +var _ Transactional = (*TransactionalLatencyInjector)(nil) + +// NewLatencyInjector returns a wrapped physical backend to simulate latency +func NewLatencyInjector(b Backend, latency time.Duration, jitter int, logger log.Logger) *LatencyInjector { + if jitter < 0 || jitter > 100 { + jitter = DefaultJitterPercent + } + logger.Info("creating latency injector") + + return &LatencyInjector{ + backend: b, + latency: latency, + jitterPercent: jitter, + random: rand.New(rand.NewSource(int64(time.Now().Nanosecond()))), + } +} + +// NewTransactionalLatencyInjector creates a new transactional LatencyInjector +func NewTransactionalLatencyInjector(b Backend, latency time.Duration, jitter int, logger log.Logger) *TransactionalLatencyInjector { + return &TransactionalLatencyInjector{ + LatencyInjector: NewLatencyInjector(b, latency, jitter, logger), + Transactional: b.(Transactional), + } +} + +func (l *LatencyInjector) addLatency() { + // Calculate a value between 1 +- jitter% + min := 100 - l.jitterPercent + max := 100 + l.jitterPercent + percent := l.random.Intn(max-min) + min + latencyDuration := time.Duration(int(l.latency) * percent / 100) + time.Sleep(latencyDuration) +} + +// Put is a latent put request +func (l *LatencyInjector) Put(ctx context.Context, entry *Entry) error { + l.addLatency() + return l.backend.Put(ctx, entry) +} + +// Get is a latent get request +func (l *LatencyInjector) Get(ctx context.Context, key string) (*Entry, error) { + l.addLatency() + return l.backend.Get(ctx, key) +} + +// Delete is a latent delete request +func (l *LatencyInjector) Delete(ctx context.Context, key string) error { + l.addLatency() + return l.backend.Delete(ctx, key) +} + +// List is a latent list request +func (l *LatencyInjector) List(ctx context.Context, prefix string) ([]string, error) { + l.addLatency() + return l.backend.List(ctx, prefix) +} + +// Transaction is a latent transaction request +func (l *TransactionalLatencyInjector) Transaction(ctx context.Context, txns []*TxnEntry) error { + l.addLatency() + return l.Transactional.Transaction(ctx, txns) +} diff --git a/vendor/github.com/hashicorp/vault/physical/physical.go b/vendor/github.com/hashicorp/vault/physical/physical.go new file mode 100644 index 0000000..c7a37fc --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/physical.go @@ -0,0 +1,158 @@ +package physical + +import ( + "context" + "strings" + "sync" + + log "github.com/hashicorp/go-hclog" +) + +const DefaultParallelOperations = 128 + +// The operation type +type Operation string + +const ( + DeleteOperation Operation = "delete" + GetOperation = "get" + ListOperation = "list" + PutOperation = "put" +) + +// ShutdownSignal +type ShutdownChannel chan struct{} + +// Backend is the interface required for a physical +// backend. A physical backend is used to durably store +// data outside of Vault. As such, it is completely untrusted, +// and is only accessed via a security barrier. The backends +// must represent keys in a hierarchical manner. All methods +// are expected to be thread safe. +type Backend interface { + // Put is used to insert or update an entry + Put(ctx context.Context, entry *Entry) error + + // Get is used to fetch an entry + Get(ctx context.Context, key string) (*Entry, error) + + // Delete is used to permanently delete an entry + Delete(ctx context.Context, key string) error + + // List is used ot list all the keys under a given + // prefix, up to the next prefix. + List(ctx context.Context, prefix string) ([]string, error) +} + +// HABackend is an extensions to the standard physical +// backend to support high-availability. Vault only expects to +// use mutual exclusion to allow multiple instances to act as a +// hot standby for a leader that services all requests. +type HABackend interface { + // LockWith is used for mutual exclusion based on the given key. + LockWith(key, value string) (Lock, error) + + // Whether or not HA functionality is enabled + HAEnabled() bool +} + +// ToggleablePurgemonster is an interface for backends that can toggle on or +// off special functionality and/or support purging. This is only used for the +// cache, don't use it for other things. +type ToggleablePurgemonster interface { + Purge(ctx context.Context) + SetEnabled(bool) +} + +// RedirectDetect is an optional interface that an HABackend +// can implement. If they do, a redirect address can be automatically +// detected. +type RedirectDetect interface { + // DetectHostAddr is used to detect the host address + DetectHostAddr() (string, error) +} + +// Callback signatures for RunServiceDiscovery +type ActiveFunction func() bool +type SealedFunction func() bool + +// ServiceDiscovery is an optional interface that an HABackend can implement. +// If they do, the state of a backend is advertised to the service discovery +// network. +type ServiceDiscovery interface { + // NotifyActiveStateChange is used by Core to notify a backend + // capable of ServiceDiscovery that this Vault instance has changed + // its status to active or standby. + NotifyActiveStateChange() error + + // NotifySealedStateChange is used by Core to notify a backend + // capable of ServiceDiscovery that Vault has changed its Sealed + // status to sealed or unsealed. + NotifySealedStateChange() error + + // Run executes any background service discovery tasks until the + // shutdown channel is closed. + RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh ShutdownChannel, redirectAddr string, activeFunc ActiveFunction, sealedFunc SealedFunction) error +} + +type Lock interface { + // Lock is used to acquire the given lock + // The stopCh is optional and if closed should interrupt the lock + // acquisition attempt. The return struct should be closed when + // leadership is lost. + Lock(stopCh <-chan struct{}) (<-chan struct{}, error) + + // Unlock is used to release the lock + Unlock() error + + // Returns the value of the lock and if it is held + Value() (bool, string, error) +} + +// Entry is used to represent data stored by the physical backend +type Entry struct { + Key string + Value []byte + SealWrap bool `json:"seal_wrap,omitempty"` +} + +// Factory is the factory function to create a physical backend. +type Factory func(config map[string]string, logger log.Logger) (Backend, error) + +// PermitPool is used to limit maximum outstanding requests +type PermitPool struct { + sem chan int +} + +// NewPermitPool returns a new permit pool with the provided +// number of permits +func NewPermitPool(permits int) *PermitPool { + if permits < 1 { + permits = DefaultParallelOperations + } + return &PermitPool{ + sem: make(chan int, permits), + } +} + +// Acquire returns when a permit has been acquired +func (c *PermitPool) Acquire() { + c.sem <- 1 +} + +// Release returns a permit to the pool +func (c *PermitPool) Release() { + <-c.sem +} + +// Prefixes is a shared helper function returns all parent 'folders' for a +// given vault key. +// e.g. for 'foo/bar/baz', it returns ['foo', 'foo/bar'] +func Prefixes(s string) []string { + components := strings.Split(s, "/") + result := []string{} + for i := 1; i < len(components); i++ { + result = append(result, strings.Join(components[:i], "/")) + } + return result +} diff --git a/vendor/github.com/hashicorp/vault/physical/physical_access.go b/vendor/github.com/hashicorp/vault/physical/physical_access.go new file mode 100644 index 0000000..58ac973 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/physical_access.go @@ -0,0 +1,38 @@ +package physical + +import "context" + +// PhysicalAccess is a wrapper around physical.Backend that allows Core to +// expose its physical storage operations through PhysicalAccess() while +// restricting the ability to modify Core.physical itself. +type PhysicalAccess struct { + physical Backend +} + +var _ Backend = (*PhysicalAccess)(nil) + +func NewPhysicalAccess(physical Backend) *PhysicalAccess { + return &PhysicalAccess{physical: physical} +} + +func (p *PhysicalAccess) Put(ctx context.Context, entry *Entry) error { + return p.physical.Put(ctx, entry) +} + +func (p *PhysicalAccess) Get(ctx context.Context, key string) (*Entry, error) { + return p.physical.Get(ctx, key) +} + +func (p *PhysicalAccess) Delete(ctx context.Context, key string) error { + return p.physical.Delete(ctx, key) +} + +func (p *PhysicalAccess) List(ctx context.Context, prefix string) ([]string, error) { + return p.physical.List(ctx, prefix) +} + +func (p *PhysicalAccess) Purge(ctx context.Context) { + if purgeable, ok := p.physical.(ToggleablePurgemonster); ok { + purgeable.Purge(ctx) + } +} diff --git a/vendor/github.com/hashicorp/vault/physical/physical_view.go b/vendor/github.com/hashicorp/vault/physical/physical_view.go new file mode 100644 index 0000000..da505a4 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/physical_view.go @@ -0,0 +1,98 @@ +package physical + +import ( + "context" + "errors" + "strings" +) + +var ( + ErrRelativePath = errors.New("relative paths not supported") +) + +// View represents a prefixed view of a physical backend +type View struct { + backend Backend + prefix string +} + +// Verify View satisfies the correct interfaces +var _ Backend = (*View)(nil) + +// NewView takes an underlying physical backend and returns +// a view of it that can only operate with the given prefix. +func NewView(backend Backend, prefix string) *View { + return &View{ + backend: backend, + prefix: prefix, + } +} + +// List the contents of the prefixed view +func (v *View) List(ctx context.Context, prefix string) ([]string, error) { + if err := v.sanityCheck(prefix); err != nil { + return nil, err + } + return v.backend.List(ctx, v.expandKey(prefix)) +} + +// Get the key of the prefixed view +func (v *View) Get(ctx context.Context, key string) (*Entry, error) { + if err := v.sanityCheck(key); err != nil { + return nil, err + } + entry, err := v.backend.Get(ctx, v.expandKey(key)) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + if entry != nil { + entry.Key = v.truncateKey(entry.Key) + } + + return &Entry{ + Key: entry.Key, + Value: entry.Value, + }, nil +} + +// Put the entry into the prefix view +func (v *View) Put(ctx context.Context, entry *Entry) error { + if err := v.sanityCheck(entry.Key); err != nil { + return err + } + + nested := &Entry{ + Key: v.expandKey(entry.Key), + Value: entry.Value, + } + return v.backend.Put(ctx, nested) +} + +// Delete the entry from the prefix view +func (v *View) Delete(ctx context.Context, key string) error { + if err := v.sanityCheck(key); err != nil { + return err + } + return v.backend.Delete(ctx, v.expandKey(key)) +} + +// sanityCheck is used to perform a sanity check on a key +func (v *View) sanityCheck(key string) error { + if strings.Contains(key, "..") { + return ErrRelativePath + } + return nil +} + +// expandKey is used to expand to the full key path with the prefix +func (v *View) expandKey(suffix string) string { + return v.prefix + suffix +} + +// truncateKey is used to remove the prefix of the key +func (v *View) truncateKey(full string) string { + return strings.TrimPrefix(full, v.prefix) +} diff --git a/vendor/github.com/hashicorp/vault/physical/testing.go b/vendor/github.com/hashicorp/vault/physical/testing.go new file mode 100644 index 0000000..375d905 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/testing.go @@ -0,0 +1,488 @@ +package physical + +import ( + "context" + "reflect" + "sort" + "testing" + "time" +) + +func ExerciseBackend(t testing.TB, b Backend) { + t.Helper() + + // Should be empty + keys, err := b.List(context.Background(), "") + if err != nil { + t.Fatalf("initial list failed: %v", err) + } + if len(keys) != 0 { + t.Errorf("initial not empty: %v", keys) + } + + // Delete should work if it does not exist + err = b.Delete(context.Background(), "foo") + if err != nil { + t.Fatalf("idempotent delete: %v", err) + } + + // Get should not fail, but be nil + out, err := b.Get(context.Background(), "foo") + if err != nil { + t.Fatalf("initial get failed: %v", err) + } + if out != nil { + t.Errorf("initial get was not nil: %v", out) + } + + // Make an entry + e := &Entry{Key: "foo", Value: []byte("test")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("put failed: %v", err) + } + + // Get should work + out, err = b.Get(context.Background(), "foo") + if err != nil { + t.Fatalf("get failed: %v", err) + } + if !reflect.DeepEqual(out, e) { + t.Errorf("bad: %v expected: %v", out, e) + } + + // List should not be empty + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("list failed: %v", err) + } + if len(keys) != 1 || keys[0] != "foo" { + t.Errorf("keys[0] did not equal foo: %v", keys) + } + + // Delete should work + err = b.Delete(context.Background(), "foo") + if err != nil { + t.Fatalf("delete: %v", err) + } + + // Should be empty + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("list after delete: %v", err) + } + if len(keys) != 0 { + t.Errorf("list after delete not empty: %v", keys) + } + + // Get should fail + out, err = b.Get(context.Background(), "foo") + if err != nil { + t.Fatalf("get after delete: %v", err) + } + if out != nil { + t.Errorf("get after delete not nil: %v", out) + } + + // Multiple Puts should work; GH-189 + e = &Entry{Key: "foo", Value: []byte("test")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("multi put 1 failed: %v", err) + } + e = &Entry{Key: "foo", Value: []byte("test")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("multi put 2 failed: %v", err) + } + + // Make a nested entry + e = &Entry{Key: "foo/bar", Value: []byte("baz")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("nested put failed: %v", err) + } + + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("list multi failed: %v", err) + } + sort.Strings(keys) + if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" { + t.Errorf("expected 2 keys [foo, foo/]: %v", keys) + } + + // Delete with children should work + err = b.Delete(context.Background(), "foo") + if err != nil { + t.Fatalf("delete after multi: %v", err) + } + + // Get should return the child + out, err = b.Get(context.Background(), "foo/bar") + if err != nil { + t.Fatalf("get after multi delete: %v", err) + } + if out == nil { + t.Errorf("get after multi delete not nil: %v", out) + } + + // Removal of nested secret should not leave artifacts + e = &Entry{Key: "foo/nested1/nested2/nested3", Value: []byte("baz")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("deep nest: %v", err) + } + + err = b.Delete(context.Background(), "foo/nested1/nested2/nested3") + if err != nil { + t.Fatalf("failed to remove deep nest: %v", err) + } + + keys, err = b.List(context.Background(), "foo/") + if err != nil { + t.Fatalf("err: %v", err) + } + if len(keys) != 1 || keys[0] != "bar" { + t.Errorf("should be exactly 1 key == bar: %v", keys) + } + + // Make a second nested entry to test prefix removal + e = &Entry{Key: "foo/zip", Value: []byte("zap")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("failed to create second nested: %v", err) + } + + // Delete should not remove the prefix + err = b.Delete(context.Background(), "foo/bar") + if err != nil { + t.Fatalf("failed to delete nested prefix: %v", err) + } + + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("list nested prefix: %v", err) + } + if len(keys) != 1 || keys[0] != "foo/" { + t.Errorf("should be exactly 1 key == foo/: %v", keys) + } + + // Delete should remove the prefix + err = b.Delete(context.Background(), "foo/zip") + if err != nil { + t.Fatalf("failed to delete second prefix: %v", err) + } + + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("listing after second delete failed: %v", err) + } + if len(keys) != 0 { + t.Errorf("should be empty at end: %v", keys) + } + + // When the root path is empty, adding and removing deep nested values should not break listing + e = &Entry{Key: "foo/nested1/nested2/value1", Value: []byte("baz")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("deep nest: %v", err) + } + + e = &Entry{Key: "foo/nested1/nested2/value2", Value: []byte("baz")} + err = b.Put(context.Background(), e) + if err != nil { + t.Fatalf("deep nest: %v", err) + } + + err = b.Delete(context.Background(), "foo/nested1/nested2/value2") + if err != nil { + t.Fatalf("failed to remove deep nest: %v", err) + } + + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("listing of root failed after deletion: %v", err) + } + if len(keys) == 0 { + t.Errorf("root is returning empty after deleting a single nested value, expected nested1/: %v", keys) + keys, err = b.List(context.Background(), "foo/nested1") + if err != nil { + t.Fatalf("listing of expected nested path 'foo/nested1' failed: %v", err) + } + // prove that the root should not be empty and that foo/nested1 exists + if len(keys) != 0 { + t.Logf(" keys can still be listed from nested1/ so it's not empty, expected nested2/: %v", keys) + } + } + + // cleanup left over listing bug test value + err = b.Delete(context.Background(), "foo/nested1/nested2/value1") + if err != nil { + t.Fatalf("failed to remove deep nest: %v", err) + } + + keys, err = b.List(context.Background(), "") + if err != nil { + t.Fatalf("listing of root failed after delete of deep nest: %v", err) + } + if len(keys) != 0 { + t.Errorf("should be empty at end: %v", keys) + } +} + +func ExerciseBackend_ListPrefix(t testing.TB, b Backend) { + t.Helper() + + e1 := &Entry{Key: "foo", Value: []byte("test")} + e2 := &Entry{Key: "foo/bar", Value: []byte("test")} + e3 := &Entry{Key: "foo/bar/baz", Value: []byte("test")} + + defer func() { + b.Delete(context.Background(), "foo") + b.Delete(context.Background(), "foo/bar") + b.Delete(context.Background(), "foo/bar/baz") + }() + + err := b.Put(context.Background(), e1) + if err != nil { + t.Fatalf("failed to put entry 1: %v", err) + } + err = b.Put(context.Background(), e2) + if err != nil { + t.Fatalf("failed to put entry 2: %v", err) + } + err = b.Put(context.Background(), e3) + if err != nil { + t.Fatalf("failed to put entry 3: %v", err) + } + + // Scan the root + keys, err := b.List(context.Background(), "") + if err != nil { + t.Fatalf("list root: %v", err) + } + sort.Strings(keys) + if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" { + t.Errorf("root expected [foo foo/]: %v", keys) + } + + // Scan foo/ + keys, err = b.List(context.Background(), "foo/") + if err != nil { + t.Fatalf("list level 1: %v", err) + } + sort.Strings(keys) + if len(keys) != 2 || keys[0] != "bar" || keys[1] != "bar/" { + t.Errorf("level 1 expected [bar bar/]: %v", keys) + } + + // Scan foo/bar/ + keys, err = b.List(context.Background(), "foo/bar/") + if err != nil { + t.Fatalf("list level 2: %v", err) + } + sort.Strings(keys) + if len(keys) != 1 || keys[0] != "baz" { + t.Errorf("level 1 expected [baz]: %v", keys) + } +} + +func ExerciseHABackend(t testing.TB, b HABackend, b2 HABackend) { + t.Helper() + + // Get the lock + lock, err := b.LockWith("foo", "bar") + if err != nil { + t.Fatalf("initial lock: %v", err) + } + + // Attempt to lock + leaderCh, err := lock.Lock(nil) + if err != nil { + t.Fatalf("lock attempt 1: %v", err) + } + if leaderCh == nil { + t.Fatalf("missing leaderCh") + } + + // Check the value + held, val, err := lock.Value() + if err != nil { + t.Fatalf("err: %v", err) + } + if !held { + t.Errorf("should be held") + } + if val != "bar" { + t.Errorf("expected value bar: %v", err) + } + + // Second acquisition should fail + lock2, err := b2.LockWith("foo", "baz") + if err != nil { + t.Fatalf("lock 2: %v", err) + } + + // Cancel attempt in 50 msec + stopCh := make(chan struct{}) + time.AfterFunc(50*time.Millisecond, func() { + close(stopCh) + }) + + // Attempt to lock + leaderCh2, err := lock2.Lock(stopCh) + if err != nil { + t.Fatalf("stop lock 2: %v", err) + } + if leaderCh2 != nil { + t.Errorf("should not have gotten leaderCh: %v", leaderCh) + } + + // Release the first lock + lock.Unlock() + + // Attempt to lock should work + leaderCh2, err = lock2.Lock(nil) + if err != nil { + t.Fatalf("lock 2 lock: %v", err) + } + if leaderCh2 == nil { + t.Errorf("should get leaderCh") + } + + // Check the value + held, val, err = lock.Value() + if err != nil { + t.Fatalf("value: %v", err) + } + if !held { + t.Errorf("should still be held") + } + if val != "baz" { + t.Errorf("expected value baz: %v", err) + } + + // Cleanup + lock2.Unlock() +} + +func ExerciseTransactionalBackend(t testing.TB, b Backend) { + t.Helper() + tb, ok := b.(Transactional) + if !ok { + t.Fatal("Not a transactional backend") + } + + txns := SetupTestingTransactions(t, b) + + if err := tb.Transaction(context.Background(), txns); err != nil { + t.Fatal(err) + } + + keys, err := b.List(context.Background(), "") + if err != nil { + t.Fatal(err) + } + + expected := []string{"foo", "zip"} + + sort.Strings(keys) + sort.Strings(expected) + if !reflect.DeepEqual(keys, expected) { + t.Fatalf("mismatch: expected\n%#v\ngot\n%#v\n", expected, keys) + } + + entry, err := b.Get(context.Background(), "foo") + if err != nil { + t.Fatal(err) + } + if entry == nil { + t.Fatal("got nil entry") + } + if entry.Value == nil { + t.Fatal("got nil value") + } + if string(entry.Value) != "bar3" { + t.Fatal("updates did not apply correctly") + } + + entry, err = b.Get(context.Background(), "zip") + if err != nil { + t.Fatal(err) + } + if entry == nil { + t.Fatal("got nil entry") + } + if entry.Value == nil { + t.Fatal("got nil value") + } + if string(entry.Value) != "zap3" { + t.Fatal("updates did not apply correctly") + } +} + +func SetupTestingTransactions(t testing.TB, b Backend) []*TxnEntry { + t.Helper() + // Add a few keys so that we test rollback with deletion + if err := b.Put(context.Background(), &Entry{ + Key: "foo", + Value: []byte("bar"), + }); err != nil { + t.Fatal(err) + } + if err := b.Put(context.Background(), &Entry{ + Key: "zip", + Value: []byte("zap"), + }); err != nil { + t.Fatal(err) + } + if err := b.Put(context.Background(), &Entry{ + Key: "deleteme", + }); err != nil { + t.Fatal(err) + } + if err := b.Put(context.Background(), &Entry{ + Key: "deleteme2", + }); err != nil { + t.Fatal(err) + } + + txns := []*TxnEntry{ + &TxnEntry{ + Operation: PutOperation, + Entry: &Entry{ + Key: "foo", + Value: []byte("bar2"), + }, + }, + &TxnEntry{ + Operation: DeleteOperation, + Entry: &Entry{ + Key: "deleteme", + }, + }, + &TxnEntry{ + Operation: PutOperation, + Entry: &Entry{ + Key: "foo", + Value: []byte("bar3"), + }, + }, + &TxnEntry{ + Operation: DeleteOperation, + Entry: &Entry{ + Key: "deleteme2", + }, + }, + &TxnEntry{ + Operation: PutOperation, + Entry: &Entry{ + Key: "zip", + Value: []byte("zap3"), + }, + }, + } + + return txns +} diff --git a/vendor/github.com/hashicorp/vault/physical/transactions.go b/vendor/github.com/hashicorp/vault/physical/transactions.go new file mode 100644 index 0000000..5c43e57 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/transactions.go @@ -0,0 +1,126 @@ +package physical + +import ( + "context" + + multierror "github.com/hashicorp/go-multierror" +) + +// TxnEntry is an operation that takes atomically as part of +// a transactional update. Only supported by Transactional backends. +type TxnEntry struct { + Operation Operation + Entry *Entry +} + +// Transactional is an optional interface for backends that +// support doing transactional updates of multiple keys. This is +// required for some features such as replication. +type Transactional interface { + // The function to run a transaction + Transaction(context.Context, []*TxnEntry) error +} + +type PseudoTransactional interface { + // An internal function should do no locking or permit pool acquisition. + // Depending on the backend and if it natively supports transactions, these + // may simply chain to the normal backend functions. + GetInternal(context.Context, string) (*Entry, error) + PutInternal(context.Context, *Entry) error + DeleteInternal(context.Context, string) error +} + +// Implements the transaction interface +func GenericTransactionHandler(ctx context.Context, t PseudoTransactional, txns []*TxnEntry) (retErr error) { + rollbackStack := make([]*TxnEntry, 0, len(txns)) + var dirty bool + + // We walk the transactions in order; each successful operation goes into a + // LIFO for rollback if we hit an error along the way +TxnWalk: + for _, txn := range txns { + switch txn.Operation { + case DeleteOperation: + entry, err := t.GetInternal(ctx, txn.Entry.Key) + if err != nil { + retErr = multierror.Append(retErr, err) + dirty = true + break TxnWalk + } + if entry == nil { + // Nothing to delete or roll back + continue + } + rollbackEntry := &TxnEntry{ + Operation: PutOperation, + Entry: &Entry{ + Key: entry.Key, + Value: entry.Value, + }, + } + err = t.DeleteInternal(ctx, txn.Entry.Key) + if err != nil { + retErr = multierror.Append(retErr, err) + dirty = true + break TxnWalk + } + rollbackStack = append([]*TxnEntry{rollbackEntry}, rollbackStack...) + + case PutOperation: + entry, err := t.GetInternal(ctx, txn.Entry.Key) + if err != nil { + retErr = multierror.Append(retErr, err) + dirty = true + break TxnWalk + } + // Nothing existed so in fact rolling back requires a delete + var rollbackEntry *TxnEntry + if entry == nil { + rollbackEntry = &TxnEntry{ + Operation: DeleteOperation, + Entry: &Entry{ + Key: txn.Entry.Key, + }, + } + } else { + rollbackEntry = &TxnEntry{ + Operation: PutOperation, + Entry: &Entry{ + Key: entry.Key, + Value: entry.Value, + }, + } + } + + err = t.PutInternal(ctx, txn.Entry) + if err != nil { + retErr = multierror.Append(retErr, err) + dirty = true + break TxnWalk + } + rollbackStack = append([]*TxnEntry{rollbackEntry}, rollbackStack...) + } + } + + // Need to roll back because we hit an error along the way + if dirty { + // While traversing this, if we get an error, we continue anyways in + // best-effort fashion + for _, txn := range rollbackStack { + switch txn.Operation { + case DeleteOperation: + err := t.DeleteInternal(ctx, txn.Entry.Key) + if err != nil { + retErr = multierror.Append(retErr, err) + } + case PutOperation: + err := t.PutInternal(ctx, txn.Entry) + if err != nil { + retErr = multierror.Append(retErr, err) + } + } + } + } + + return +} diff --git a/vendor/github.com/hashicorp/vault/physical/types.pb.go b/vendor/github.com/hashicorp/vault/physical/types.pb.go new file mode 100644 index 0000000..c403cee --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/types.pb.go @@ -0,0 +1,102 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: physical/types.proto + +package physical // import "github.com/hashicorp/vault/physical" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type SealWrapEntry struct { + Ciphertext []byte `protobuf:"bytes,1,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` + IV []byte `protobuf:"bytes,2,opt,name=iv,proto3" json:"iv,omitempty"` + HMAC []byte `protobuf:"bytes,3,opt,name=hmac,proto3" json:"hmac,omitempty"` + Wrapped bool `protobuf:"varint,4,opt,name=wrapped" json:"wrapped,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SealWrapEntry) Reset() { *m = SealWrapEntry{} } +func (m *SealWrapEntry) String() string { return proto.CompactTextString(m) } +func (*SealWrapEntry) ProtoMessage() {} +func (*SealWrapEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_types_ce937ceb0910505a, []int{0} +} +func (m *SealWrapEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SealWrapEntry.Unmarshal(m, b) +} +func (m *SealWrapEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SealWrapEntry.Marshal(b, m, deterministic) +} +func (dst *SealWrapEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_SealWrapEntry.Merge(dst, src) +} +func (m *SealWrapEntry) XXX_Size() int { + return xxx_messageInfo_SealWrapEntry.Size(m) +} +func (m *SealWrapEntry) XXX_DiscardUnknown() { + xxx_messageInfo_SealWrapEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_SealWrapEntry proto.InternalMessageInfo + +func (m *SealWrapEntry) GetCiphertext() []byte { + if m != nil { + return m.Ciphertext + } + return nil +} + +func (m *SealWrapEntry) GetIV() []byte { + if m != nil { + return m.IV + } + return nil +} + +func (m *SealWrapEntry) GetHMAC() []byte { + if m != nil { + return m.HMAC + } + return nil +} + +func (m *SealWrapEntry) GetWrapped() bool { + if m != nil { + return m.Wrapped + } + return false +} + +func init() { + proto.RegisterType((*SealWrapEntry)(nil), "physical.SealWrapEntry") +} + +func init() { proto.RegisterFile("physical/types.proto", fileDescriptor_types_ce937ceb0910505a) } + +var fileDescriptor_types_ce937ceb0910505a = []byte{ + // 173 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0xce, 0xb1, 0x0a, 0xc2, 0x30, + 0x10, 0xc6, 0x71, 0x5a, 0x8b, 0x96, 0x43, 0x1d, 0x82, 0x43, 0x26, 0x29, 0x8a, 0xd0, 0xa9, 0x19, + 0x7c, 0x03, 0xc1, 0x17, 0xa8, 0x83, 0xe0, 0x76, 0x8d, 0xc1, 0x04, 0x5a, 0x73, 0xa4, 0xd7, 0x6a, + 0xdf, 0x5e, 0x08, 0x14, 0xdc, 0xbe, 0xef, 0x37, 0xfd, 0x61, 0x47, 0x76, 0xea, 0x9d, 0xc6, 0x56, + 0xf1, 0x44, 0xa6, 0xaf, 0x28, 0x78, 0xf6, 0x22, 0x9f, 0xf5, 0xd0, 0xc1, 0xe6, 0x66, 0xb0, 0xbd, + 0x07, 0xa4, 0xeb, 0x9b, 0xc3, 0x24, 0xf6, 0x00, 0xda, 0x91, 0x35, 0x81, 0xcd, 0x97, 0x65, 0x52, + 0x24, 0xe5, 0xba, 0xfe, 0x13, 0xb1, 0x85, 0xd4, 0x8d, 0x32, 0x8d, 0x9e, 0xba, 0x51, 0x08, 0xc8, + 0x6c, 0x87, 0x5a, 0x2e, 0xa2, 0xc4, 0x2d, 0x24, 0xac, 0x3e, 0x01, 0x89, 0xcc, 0x53, 0x66, 0x45, + 0x52, 0xe6, 0xf5, 0x7c, 0x2f, 0xa7, 0xc7, 0xf1, 0xe5, 0xd8, 0x0e, 0x4d, 0xa5, 0x7d, 0xa7, 0x2c, + 0xf6, 0xd6, 0x69, 0x1f, 0x48, 0x8d, 0x38, 0xb4, 0xac, 0xe6, 0xaa, 0x66, 0x19, 0x33, 0xcf, 0xbf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xe9, 0xa0, 0xf8, 0xbe, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/physical/types.proto b/vendor/github.com/hashicorp/vault/physical/types.proto new file mode 100644 index 0000000..2a4774d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/types.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/physical"; + +package physical; + +message SealWrapEntry { + bytes ciphertext = 1; + + bytes iv = 2; + + bytes hmac = 3; + + bool wrapped = 4; +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/cassandra/cassandra.go b/vendor/github.com/hashicorp/vault/plugins/database/cassandra/cassandra.go new file mode 100644 index 0000000..05ad662 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/cassandra/cassandra.go @@ -0,0 +1,242 @@ +package cassandra + +import ( + "context" + "strings" + "time" + + "github.com/gocql/gocql" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" +) + +const ( + defaultUserCreationCQL = `CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER;` + defaultUserDeletionCQL = `DROP USER '{{username}}';` + defaultRootCredentialRotationCQL = `ALTER USER {{username}} WITH PASSWORD '{{password}}';` + cassandraTypeName = "cassandra" +) + +var _ dbplugin.Database = &Cassandra{} + +// Cassandra is an implementation of Database interface +type Cassandra struct { + *cassandraConnectionProducer + credsutil.CredentialsProducer +} + +// New returns a new Cassandra instance +func New() (interface{}, error) { + db := new() + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.secretValues) + + return dbType, nil +} + +func new() *Cassandra { + connProducer := &cassandraConnectionProducer{} + connProducer.Type = cassandraTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: 15, + RoleNameLen: 15, + UsernameLen: 100, + Separator: "_", + } + + return &Cassandra{ + cassandraConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } +} + +// Run instantiates a Cassandra object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + dbType, err := New() + if err != nil { + return err + } + + plugins.Serve(dbType.(dbplugin.Database), apiTLSConfig) + + return nil +} + +// Type returns the TypeName for this backend +func (c *Cassandra) Type() (string, error) { + return cassandraTypeName, nil +} + +func (c *Cassandra) getConnection(ctx context.Context) (*gocql.Session, error) { + session, err := c.Connection(ctx) + if err != nil { + return nil, err + } + + return session.(*gocql.Session), nil +} + +// CreateUser generates the username/password on the underlying Cassandra secret backend as instructed by +// the CreationStatement provided. +func (c *Cassandra) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + // Grab the lock + c.Lock() + defer c.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get the connection + session, err := c.getConnection(ctx) + if err != nil { + return "", "", err + } + + creationCQL := statements.Creation + if len(creationCQL) == 0 { + creationCQL = []string{defaultUserCreationCQL} + } + + rollbackCQL := statements.Rollback + if len(rollbackCQL) == 0 { + rollbackCQL = []string{defaultUserDeletionCQL} + } + + username, err = c.GenerateUsername(usernameConfig) + username = strings.Replace(username, "-", "_", -1) + if err != nil { + return "", "", err + } + // Cassandra doesn't like the uppercase usernames + username = strings.ToLower(username) + + password, err = c.GeneratePassword() + if err != nil { + return "", "", err + } + + // Execute each query + for _, stmt := range creationCQL { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + err = session.Query(dbutil.QueryHelper(query, map[string]string{ + "username": username, + "password": password, + })).Exec() + if err != nil { + for _, stmt := range rollbackCQL { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + session.Query(dbutil.QueryHelper(query, map[string]string{ + "username": username, + })).Exec() + } + } + return "", "", err + } + } + } + + return username, password, nil +} + +// RenewUser is not supported on Cassandra, so this is a no-op. +func (c *Cassandra) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + // NOOP + return nil +} + +// RevokeUser attempts to drop the specified user. +func (c *Cassandra) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + // Grab the lock + c.Lock() + defer c.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + session, err := c.getConnection(ctx) + if err != nil { + return err + } + + revocationCQL := statements.Revocation + if len(revocationCQL) == 0 { + revocationCQL = []string{defaultUserDeletionCQL} + } + + var result *multierror.Error + for _, stmt := range revocationCQL { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + err := session.Query(dbutil.QueryHelper(query, map[string]string{ + "username": username, + })).Exec() + + result = multierror.Append(result, err) + } + } + + return result.ErrorOrNil() +} + +func (c *Cassandra) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + // Grab the lock + c.Lock() + defer c.Unlock() + + session, err := c.getConnection(ctx) + if err != nil { + return nil, err + } + + rotateCQL := statements + if len(rotateCQL) == 0 { + rotateCQL = []string{defaultRootCredentialRotationCQL} + } + + password, err := c.GeneratePassword() + if err != nil { + return nil, err + } + + var result *multierror.Error + for _, stmt := range rotateCQL { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + err := session.Query(dbutil.QueryHelper(query, map[string]string{ + "username": c.Username, + "password": password, + })).Exec() + + result = multierror.Append(result, err) + } + } + + err = result.ErrorOrNil() + if err != nil { + return nil, err + } + + c.rawConfig["password"] = password + return c.rawConfig, nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/cassandra/connection_producer.go b/vendor/github.com/hashicorp/vault/plugins/database/cassandra/connection_producer.go new file mode 100644 index 0000000..700f963 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/cassandra/connection_producer.go @@ -0,0 +1,255 @@ +package cassandra + +import ( + "context" + "crypto/tls" + "fmt" + "strings" + "sync" + "time" + + "github.com/mitchellh/mapstructure" + + "github.com/gocql/gocql" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/tlsutil" + "github.com/hashicorp/vault/plugins/helper/database/connutil" +) + +// cassandraConnectionProducer implements ConnectionProducer and provides an +// interface for cassandra databases to make connections. +type cassandraConnectionProducer struct { + Hosts string `json:"hosts" structs:"hosts" mapstructure:"hosts"` + Port int `json:"port" structs:"port" mapstructure:"port"` + Username string `json:"username" structs:"username" mapstructure:"username"` + Password string `json:"password" structs:"password" mapstructure:"password"` + TLS bool `json:"tls" structs:"tls" mapstructure:"tls"` + InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"` + ProtocolVersion int `json:"protocol_version" structs:"protocol_version" mapstructure:"protocol_version"` + ConnectTimeoutRaw interface{} `json:"connect_timeout" structs:"connect_timeout" mapstructure:"connect_timeout"` + TLSMinVersion string `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"` + Consistency string `json:"consistency" structs:"consistency" mapstructure:"consistency"` + PemBundle string `json:"pem_bundle" structs:"pem_bundle" mapstructure:"pem_bundle"` + PemJSON string `json:"pem_json" structs:"pem_json" mapstructure:"pem_json"` + + connectTimeout time.Duration + certificate string + privateKey string + issuingCA string + rawConfig map[string]interface{} + + Initialized bool + Type string + session *gocql.Session + sync.Mutex +} + +func (c *cassandraConnectionProducer) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := c.Init(ctx, conf, verifyConnection) + return err +} + +func (c *cassandraConnectionProducer) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (map[string]interface{}, error) { + c.Lock() + defer c.Unlock() + + c.rawConfig = conf + + err := mapstructure.WeakDecode(conf, c) + if err != nil { + return nil, err + } + + if c.ConnectTimeoutRaw == nil { + c.ConnectTimeoutRaw = "0s" + } + c.connectTimeout, err = parseutil.ParseDurationSecond(c.ConnectTimeoutRaw) + if err != nil { + return nil, errwrap.Wrapf("invalid connect_timeout: {{err}}", err) + } + + switch { + case len(c.Hosts) == 0: + return nil, fmt.Errorf("hosts cannot be empty") + case len(c.Username) == 0: + return nil, fmt.Errorf("username cannot be empty") + case len(c.Password) == 0: + return nil, fmt.Errorf("password cannot be empty") + } + + var certBundle *certutil.CertBundle + var parsedCertBundle *certutil.ParsedCertBundle + switch { + case len(c.PemJSON) != 0: + parsedCertBundle, err = certutil.ParsePKIJSON([]byte(c.PemJSON)) + if err != nil { + return nil, errwrap.Wrapf("could not parse given JSON; it must be in the format of the output of the PKI backend certificate issuing command: {{err}}", err) + } + certBundle, err = parsedCertBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("Error marshaling PEM information: {{err}}", err) + } + c.certificate = certBundle.Certificate + c.privateKey = certBundle.PrivateKey + c.issuingCA = certBundle.IssuingCA + c.TLS = true + + case len(c.PemBundle) != 0: + parsedCertBundle, err = certutil.ParsePEMBundle(c.PemBundle) + if err != nil { + return nil, errwrap.Wrapf("Error parsing the given PEM information: {{err}}", err) + } + certBundle, err = parsedCertBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("Error marshaling PEM information: {{err}}", err) + } + c.certificate = certBundle.Certificate + c.privateKey = certBundle.PrivateKey + c.issuingCA = certBundle.IssuingCA + c.TLS = true + } + + // Set initialized to true at this point since all fields are set, + // and the connection can be established at a later time. + c.Initialized = true + + if verifyConnection { + if _, err := c.Connection(ctx); err != nil { + return nil, errwrap.Wrapf("error verifying connection: {{err}}", err) + } + } + + return conf, nil +} + +func (c *cassandraConnectionProducer) Connection(_ context.Context) (interface{}, error) { + if !c.Initialized { + return nil, connutil.ErrNotInitialized + } + + // If we already have a DB, return it + if c.session != nil && !c.session.Closed() { + return c.session, nil + } + + session, err := c.createSession() + if err != nil { + return nil, err + } + + // Store the session in backend for reuse + c.session = session + + return session, nil +} + +func (c *cassandraConnectionProducer) Close() error { + // Grab the write lock + c.Lock() + defer c.Unlock() + + if c.session != nil { + c.session.Close() + } + + c.session = nil + + return nil +} + +func (c *cassandraConnectionProducer) createSession() (*gocql.Session, error) { + hosts := strings.Split(c.Hosts, ",") + clusterConfig := gocql.NewCluster(hosts...) + clusterConfig.Authenticator = gocql.PasswordAuthenticator{ + Username: c.Username, + Password: c.Password, + } + + if c.Port != 0 { + clusterConfig.Port = c.Port + } + + clusterConfig.ProtoVersion = c.ProtocolVersion + if clusterConfig.ProtoVersion == 0 { + clusterConfig.ProtoVersion = 2 + } + + clusterConfig.Timeout = c.connectTimeout + if c.TLS { + var tlsConfig *tls.Config + if len(c.certificate) > 0 || len(c.issuingCA) > 0 { + if len(c.certificate) > 0 && len(c.privateKey) == 0 { + return nil, fmt.Errorf("found certificate for TLS authentication but no private key") + } + + certBundle := &certutil.CertBundle{} + if len(c.certificate) > 0 { + certBundle.Certificate = c.certificate + certBundle.PrivateKey = c.privateKey + } + if len(c.issuingCA) > 0 { + certBundle.IssuingCA = c.issuingCA + } + + parsedCertBundle, err := certBundle.ToParsedCertBundle() + if err != nil { + return nil, errwrap.Wrapf("failed to parse certificate bundle: {{err}}", err) + } + + tlsConfig, err = parsedCertBundle.GetTLSConfig(certutil.TLSClient) + if err != nil || tlsConfig == nil { + return nil, errwrap.Wrapf(fmt.Sprintf("failed to get TLS configuration: tlsConfig:%#v err:{{err}}", tlsConfig), err) + } + tlsConfig.InsecureSkipVerify = c.InsecureTLS + + if c.TLSMinVersion != "" { + var ok bool + tlsConfig.MinVersion, ok = tlsutil.TLSLookup[c.TLSMinVersion] + if !ok { + return nil, fmt.Errorf("invalid 'tls_min_version' in config") + } + } else { + // MinVersion was not being set earlier. Reset it to + // zero to gracefully handle upgrades. + tlsConfig.MinVersion = 0 + } + } + + clusterConfig.SslOpts = &gocql.SslOptions{ + Config: tlsConfig, + } + } + + session, err := clusterConfig.CreateSession() + if err != nil { + return nil, errwrap.Wrapf("error creating session: {{err}}", err) + } + + // Set consistency + if c.Consistency != "" { + consistencyValue, err := gocql.ParseConsistencyWrapper(c.Consistency) + if err != nil { + return nil, err + } + + session.SetConsistency(consistencyValue) + } + + // Verify the info + err = session.Query(`LIST ALL`).Exec() + if err != nil { + return nil, errwrap.Wrapf("error validating connection info: {{err}}", err) + } + + return session, nil +} + +func (c *cassandraConnectionProducer) secretValues() map[string]interface{} { + return map[string]interface{}{ + c.Password: "[password]", + c.PemBundle: "[pem_bundle]", + c.PemJSON: "[pem_json]", + } +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/hana/hana.go b/vendor/github.com/hashicorp/vault/plugins/database/hana/hana.go new file mode 100644 index 0000000..62e739a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/hana/hana.go @@ -0,0 +1,296 @@ +package hana + +import ( + "context" + "database/sql" + "errors" + "fmt" + "strings" + "time" + + _ "github.com/SAP/go-hdb/driver" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/dbtxn" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/connutil" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" +) + +const ( + hanaTypeName = "hdb" +) + +// HANA is an implementation of Database interface +type HANA struct { + *connutil.SQLConnectionProducer + credsutil.CredentialsProducer +} + +var _ dbplugin.Database = &HANA{} + +// New implements builtinplugins.BuiltinFactory +func New() (interface{}, error) { + db := new() + // Wrap the plugin with middleware to sanitize errors + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.SecretValues) + + return dbType, nil +} + +func new() *HANA { + connProducer := &connutil.SQLConnectionProducer{} + connProducer.Type = hanaTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: 32, + RoleNameLen: 20, + UsernameLen: 128, + Separator: "_", + } + + return &HANA{ + SQLConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } +} + +// Run instantiates a HANA object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + dbType, err := New() + if err != nil { + return err + } + + plugins.Serve(dbType.(dbplugin.Database), apiTLSConfig) + + return nil +} + +// Type returns the TypeName for this backend +func (h *HANA) Type() (string, error) { + return hanaTypeName, nil +} + +func (h *HANA) getConnection(ctx context.Context) (*sql.DB, error) { + db, err := h.Connection(ctx) + if err != nil { + return nil, err + } + + return db.(*sql.DB), nil +} + +// CreateUser generates the username/password on the underlying HANA secret backend +// as instructed by the CreationStatement provided. +func (h *HANA) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + // Grab the lock + h.Lock() + defer h.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get the connection + db, err := h.getConnection(ctx) + if err != nil { + return "", "", err + } + + if len(statements.Creation) == 0 { + return "", "", dbutil.ErrEmptyCreationStatement + } + + // Generate username + username, err = h.GenerateUsername(usernameConfig) + if err != nil { + return "", "", err + } + + // HANA does not allow hyphens in usernames, and highly prefers capital letters + username = strings.Replace(username, "-", "_", -1) + username = strings.ToUpper(username) + + // Generate password + password, err = h.GeneratePassword() + if err != nil { + return "", "", err + } + // Most HANA configurations have password constraints + // Prefix with A1a to satisfy these constraints. User will be forced to change upon login + password = strings.Replace(password, "-", "_", -1) + password = "A1a" + password + + // If expiration is in the role SQL, HANA will deactivate the user when time is up, + // regardless of whether vault is alive to revoke lease + expirationStr, err := h.GenerateExpiration(expiration) + if err != nil { + return "", "", err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return "", "", err + } + defer tx.Rollback() + + // Execute each query + for _, stmt := range statements.Creation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + "password": password, + "expiration": expirationStr, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return "", "", err + } + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return "", "", err + } + + return username, password, nil +} + +// Renewing hana user just means altering user's valid until property +func (h *HANA) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get connection + db, err := h.getConnection(ctx) + if err != nil { + return err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer tx.Rollback() + + // If expiration is in the role SQL, HANA will deactivate the user when time is up, + // regardless of whether vault is alive to revoke lease + expirationStr, err := h.GenerateExpiration(expiration) + if err != nil { + return err + } + + // Renew user's valid until property field + stmt, err := tx.PrepareContext(ctx, "ALTER USER "+username+" VALID UNTIL "+"'"+expirationStr+"'") + if err != nil { + return err + } + defer stmt.Close() + if _, err := stmt.ExecContext(ctx); err != nil { + return err + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return err + } + + return nil +} + +// Revoking hana user will deactivate user and try to perform a soft drop +func (h *HANA) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + statements = dbutil.StatementCompatibilityHelper(statements) + + // default revoke will be a soft drop on user + if len(statements.Revocation) == 0 { + return h.revokeUserDefault(ctx, username) + } + + // Get connection + db, err := h.getConnection(ctx) + if err != nil { + return err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer tx.Rollback() + + // Execute each query + for _, stmt := range statements.Revocation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return err + } + } + } + + return tx.Commit() +} + +func (h *HANA) revokeUserDefault(ctx context.Context, username string) error { + // Get connection + db, err := h.getConnection(ctx) + if err != nil { + return err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer tx.Rollback() + + // Disable server login for user + disableStmt, err := tx.PrepareContext(ctx, fmt.Sprintf("ALTER USER %s DEACTIVATE USER NOW", username)) + if err != nil { + return err + } + defer disableStmt.Close() + if _, err := disableStmt.ExecContext(ctx); err != nil { + return err + } + + // Invalidates current sessions and performs soft drop (drop if no dependencies) + // if hard drop is desired, custom revoke statements should be written for role + dropStmt, err := tx.PrepareContext(ctx, fmt.Sprintf("DROP USER %s RESTRICT", username)) + if err != nil { + return err + } + defer dropStmt.Close() + if _, err := dropStmt.ExecContext(ctx); err != nil { + return err + } + + // Commit transaction + if err := tx.Commit(); err != nil { + return err + } + + return nil +} + +// RotateRootCredentials is not currently supported on HANA +func (h *HANA) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + return nil, errors.New("root credentaion rotation is not currently implemented in this database secrets engine") +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/mongodb/connection_producer.go b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/connection_producer.go new file mode 100644 index 0000000..a4d394f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/connection_producer.go @@ -0,0 +1,228 @@ +package mongodb + +import ( + "context" + "crypto/tls" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "net" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/plugins/helper/database/connutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" + "github.com/mitchellh/mapstructure" + + "gopkg.in/mgo.v2" +) + +// mongoDBConnectionProducer implements ConnectionProducer and provides an +// interface for databases to make connections. +type mongoDBConnectionProducer struct { + ConnectionURL string `json:"connection_url" structs:"connection_url" mapstructure:"connection_url"` + WriteConcern string `json:"write_concern" structs:"write_concern" mapstructure:"write_concern"` + Username string `json:"username" structs:"username" mapstructure:"username"` + Password string `json:"password" structs:"password" mapstructure:"password"` + + Initialized bool + RawConfig map[string]interface{} + Type string + session *mgo.Session + safe *mgo.Safe + sync.Mutex +} + +func (c *mongoDBConnectionProducer) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := c.Init(ctx, conf, verifyConnection) + return err +} + +// Initialize parses connection configuration. +func (c *mongoDBConnectionProducer) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (map[string]interface{}, error) { + c.Lock() + defer c.Unlock() + + c.RawConfig = conf + + err := mapstructure.WeakDecode(conf, c) + if err != nil { + return nil, err + } + + if len(c.ConnectionURL) == 0 { + return nil, fmt.Errorf("connection_url cannot be empty") + } + + c.ConnectionURL = dbutil.QueryHelper(c.ConnectionURL, map[string]string{ + "username": c.Username, + "password": c.Password, + }) + + if c.WriteConcern != "" { + input := c.WriteConcern + + // Try to base64 decode the input. If successful, consider the decoded + // value as input. + inputBytes, err := base64.StdEncoding.DecodeString(input) + if err == nil { + input = string(inputBytes) + } + + concern := &mgo.Safe{} + err = json.Unmarshal([]byte(input), concern) + if err != nil { + return nil, errwrap.Wrapf("error mashalling write_concern: {{err}}", err) + } + + // Guard against empty, non-nil mgo.Safe object; we don't want to pass that + // into mgo.SetSafe in Connection(). + if (mgo.Safe{} == *concern) { + return nil, fmt.Errorf("provided write_concern values did not map to any mgo.Safe fields") + } + c.safe = concern + } + + // Set initialized to true at this point since all fields are set, + // and the connection can be established at a later time. + c.Initialized = true + + if verifyConnection { + if _, err := c.Connection(ctx); err != nil { + return nil, errwrap.Wrapf("error verifying connection: {{err}}", err) + } + + if err := c.session.Ping(); err != nil { + return nil, errwrap.Wrapf("error verifying connection: {{err}}", err) + } + } + + return conf, nil +} + +// Connection creates or returns an existing a database connection. If the session fails +// on a ping check, the session will be closed and then re-created. +func (c *mongoDBConnectionProducer) Connection(_ context.Context) (interface{}, error) { + if !c.Initialized { + return nil, connutil.ErrNotInitialized + } + + if c.session != nil { + if err := c.session.Ping(); err == nil { + return c.session, nil + } + c.session.Close() + } + + dialInfo, err := parseMongoURL(c.ConnectionURL) + if err != nil { + return nil, err + } + + c.session, err = mgo.DialWithInfo(dialInfo) + if err != nil { + return nil, err + } + + if c.safe != nil { + c.session.SetSafe(c.safe) + } + + c.session.SetSyncTimeout(1 * time.Minute) + c.session.SetSocketTimeout(1 * time.Minute) + + return c.session, nil +} + +// Close terminates the database connection. +func (c *mongoDBConnectionProducer) Close() error { + c.Lock() + defer c.Unlock() + + if c.session != nil { + c.session.Close() + } + + c.session = nil + + return nil +} + +func parseMongoURL(rawURL string) (*mgo.DialInfo, error) { + url, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + info := mgo.DialInfo{ + Addrs: strings.Split(url.Host, ","), + Database: strings.TrimPrefix(url.Path, "/"), + Timeout: 10 * time.Second, + } + + if url.User != nil { + info.Username = url.User.Username() + info.Password, _ = url.User.Password() + } + + query := url.Query() + for key, values := range query { + var value string + if len(values) > 0 { + value = values[0] + } + + switch key { + case "authSource": + info.Source = value + case "authMechanism": + info.Mechanism = value + case "gssapiServiceName": + info.Service = value + case "replicaSet": + info.ReplicaSetName = value + case "maxPoolSize": + poolLimit, err := strconv.Atoi(value) + if err != nil { + return nil, errors.New("bad value for maxPoolSize: " + value) + } + info.PoolLimit = poolLimit + case "ssl": + // Unfortunately, mgo doesn't support the ssl parameter in its MongoDB URI parsing logic, so we have to handle that + // ourselves. See https://github.com/go-mgo/mgo/issues/84 + ssl, err := strconv.ParseBool(value) + if err != nil { + return nil, errors.New("bad value for ssl: " + value) + } + if ssl { + info.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) { + return tls.Dial("tcp", addr.String(), &tls.Config{}) + } + } + case "connect": + if value == "direct" { + info.Direct = true + break + } + if value == "replicaSet" { + break + } + fallthrough + default: + return nil, errors.New("unsupported connection URL option: " + key + "=" + value) + } + } + + return &info, nil +} + +func (c *mongoDBConnectionProducer) secretValues() map[string]interface{} { + return map[string]interface{}{ + c.Password: "[password]", + } +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/mongodb/mongodb.go b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/mongodb.go new file mode 100644 index 0000000..61ca9c5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/mongodb.go @@ -0,0 +1,224 @@ +package mongodb + +import ( + "context" + "errors" + "io" + "strings" + "time" + + "encoding/json" + + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" + "gopkg.in/mgo.v2" +) + +const mongoDBTypeName = "mongodb" + +// MongoDB is an implementation of Database interface +type MongoDB struct { + *mongoDBConnectionProducer + credsutil.CredentialsProducer +} + +var _ dbplugin.Database = &MongoDB{} + +// New returns a new MongoDB instance +func New() (interface{}, error) { + db := new() + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.secretValues) + return dbType, nil +} + +func new() *MongoDB { + connProducer := &mongoDBConnectionProducer{} + connProducer.Type = mongoDBTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: 15, + RoleNameLen: 15, + UsernameLen: 100, + Separator: "-", + } + + return &MongoDB{ + mongoDBConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } +} + +// Run instantiates a MongoDB object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + dbType, err := New() + if err != nil { + return err + } + + plugins.Serve(dbType.(*MongoDB), apiTLSConfig) + + return nil +} + +// Type returns the TypeName for this backend +func (m *MongoDB) Type() (string, error) { + return mongoDBTypeName, nil +} + +func (m *MongoDB) getConnection(ctx context.Context) (*mgo.Session, error) { + session, err := m.Connection(ctx) + if err != nil { + return nil, err + } + + return session.(*mgo.Session), nil +} + +// CreateUser generates the username/password on the underlying secret backend as instructed by +// the CreationStatement provided. The creation statement is a JSON blob that has a db value, +// and an array of roles that accepts a role, and an optional db value pair. This array will +// be normalized the format specified in the mongoDB docs: +// https://docs.mongodb.com/manual/reference/command/createUser/#dbcmd.createUser +// +// JSON Example: +// { "db": "admin", "roles": [{ "role": "readWrite" }, {"role": "read", "db": "foo"}] } +func (m *MongoDB) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + // Grab the lock + m.Lock() + defer m.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + if len(statements.Creation) == 0 { + return "", "", dbutil.ErrEmptyCreationStatement + } + + session, err := m.getConnection(ctx) + if err != nil { + return "", "", err + } + + username, err = m.GenerateUsername(usernameConfig) + if err != nil { + return "", "", err + } + + password, err = m.GeneratePassword() + if err != nil { + return "", "", err + } + + // Unmarshal statements.CreationStatements into mongodbRoles + var mongoCS mongoDBStatement + err = json.Unmarshal([]byte(statements.Creation[0]), &mongoCS) + if err != nil { + return "", "", err + } + + // Default to "admin" if no db provided + if mongoCS.DB == "" { + mongoCS.DB = "admin" + } + + if len(mongoCS.Roles) == 0 { + return "", "", fmt.Errorf("roles array is required in creation statement") + } + + createUserCmd := createUserCommand{ + Username: username, + Password: password, + Roles: mongoCS.Roles.toStandardRolesArray(), + } + + err = session.DB(mongoCS.DB).Run(createUserCmd, nil) + switch { + case err == nil: + case err == io.EOF, strings.Contains(err.Error(), "EOF"): + // Call getConnection to reset and retry query if we get an EOF error on first attempt. + session, err := m.getConnection(ctx) + if err != nil { + return "", "", err + } + err = session.DB(mongoCS.DB).Run(createUserCmd, nil) + if err != nil { + return "", "", err + } + default: + return "", "", err + } + + return username, password, nil +} + +// RenewUser is not supported on MongoDB, so this is a no-op. +func (m *MongoDB) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + // NOOP + return nil +} + +// RevokeUser drops the specified user from the authentication database. If none is provided +// in the revocation statement, the default "admin" authentication database will be assumed. +func (m *MongoDB) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + statements = dbutil.StatementCompatibilityHelper(statements) + + session, err := m.getConnection(ctx) + if err != nil { + return err + } + + // If no revocation statements provided, pass in empty JSON + var revocationStatement string + switch len(statements.Revocation) { + case 0: + revocationStatement = `{}` + case 1: + revocationStatement = statements.Revocation[0] + default: + return fmt.Errorf("expected 0 or 1 revocation statements, got %d", len(statements.Revocation)) + } + + // Unmarshal revocation statements into mongodbRoles + var mongoCS mongoDBStatement + err = json.Unmarshal([]byte(revocationStatement), &mongoCS) + if err != nil { + return err + } + + db := mongoCS.DB + // If db is not specified, use the default authenticationDatabase "admin" + if db == "" { + db = "admin" + } + + err = session.DB(db).RemoveUser(username) + switch { + case err == nil, err == mgo.ErrNotFound: + case err == io.EOF, strings.Contains(err.Error(), "EOF"): + if err := m.Close(); err != nil { + return errwrap.Wrapf("error closing EOF'd mongo connection: {{err}}", err) + } + session, err := m.getConnection(ctx) + if err != nil { + return err + } + err = session.DB(db).RemoveUser(username) + if err != nil { + return err + } + default: + return err + } + + return nil +} + +// RotateRootCredentials is not currently supported on MongoDB +func (m *MongoDB) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + return nil, errors.New("root credentaion rotation is not currently implemented in this database secrets engine") +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/mongodb/util.go b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/util.go new file mode 100644 index 0000000..9004a3c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/mongodb/util.go @@ -0,0 +1,39 @@ +package mongodb + +type createUserCommand struct { + Username string `bson:"createUser"` + Password string `bson:"pwd"` + Roles []interface{} `bson:"roles"` +} +type mongodbRole struct { + Role string `json:"role" bson:"role"` + DB string `json:"db" bson:"db"` +} + +type mongodbRoles []mongodbRole + +type mongoDBStatement struct { + DB string `json:"db"` + Roles mongodbRoles `json:"roles"` +} + +// Convert array of role documents like: +// +// [ { "role": "readWrite" }, { "role": "readWrite", "db": "test" } ] +// +// into a "standard" MongoDB roles array containing both strings and role documents: +// +// [ "readWrite", { "role": "readWrite", "db": "test" } ] +// +// MongoDB's createUser command accepts the latter. +func (roles mongodbRoles) toStandardRolesArray() []interface{} { + var standardRolesArray []interface{} + for _, role := range roles { + if role.DB == "" { + standardRolesArray = append(standardRolesArray, role.Role) + } else { + standardRolesArray = append(standardRolesArray, role) + } + } + return standardRolesArray +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/mssql/mssql.go b/vendor/github.com/hashicorp/vault/plugins/database/mssql/mssql.go new file mode 100644 index 0000000..9b0a78c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/mssql/mssql.go @@ -0,0 +1,391 @@ +package mssql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "strings" + "time" + + _ "github.com/denisenkom/go-mssqldb" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/dbtxn" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/connutil" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" +) + +const msSQLTypeName = "mssql" + +var _ dbplugin.Database = &MSSQL{} + +// MSSQL is an implementation of Database interface +type MSSQL struct { + *connutil.SQLConnectionProducer + credsutil.CredentialsProducer +} + +func New() (interface{}, error) { + db := new() + // Wrap the plugin with middleware to sanitize errors + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.SecretValues) + + return dbType, nil +} + +func new() *MSSQL { + connProducer := &connutil.SQLConnectionProducer{} + connProducer.Type = msSQLTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: 20, + RoleNameLen: 20, + UsernameLen: 128, + Separator: "-", + } + + return &MSSQL{ + SQLConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } +} + +// Run instantiates a MSSQL object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + dbType, err := New() + if err != nil { + return err + } + + plugins.Serve(dbType.(dbplugin.Database), apiTLSConfig) + + return nil +} + +// Type returns the TypeName for this backend +func (m *MSSQL) Type() (string, error) { + return msSQLTypeName, nil +} + +func (m *MSSQL) getConnection(ctx context.Context) (*sql.DB, error) { + db, err := m.Connection(ctx) + if err != nil { + return nil, err + } + + return db.(*sql.DB), nil +} + +// CreateUser generates the username/password on the underlying MSSQL secret backend as instructed by +// the CreationStatement provided. +func (m *MSSQL) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + // Grab the lock + m.Lock() + defer m.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get the connection + db, err := m.getConnection(ctx) + if err != nil { + return "", "", err + } + + if len(statements.Creation) == 0 { + return "", "", dbutil.ErrEmptyCreationStatement + } + + username, err = m.GenerateUsername(usernameConfig) + if err != nil { + return "", "", err + } + + password, err = m.GeneratePassword() + if err != nil { + return "", "", err + } + + expirationStr, err := m.GenerateExpiration(expiration) + if err != nil { + return "", "", err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return "", "", err + } + defer tx.Rollback() + + // Execute each query + for _, stmt := range statements.Creation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + "password": password, + "expiration": expirationStr, + } + + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return "", "", err + } + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return "", "", err + } + + return username, password, nil +} + +// RenewUser is not supported on MSSQL, so this is a no-op. +func (m *MSSQL) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + // NOOP + return nil +} + +// RevokeUser attempts to drop the specified user. It will first attempt to disable login, +// then kill pending connections from that user, and finally drop the user and login from the +// database instance. +func (m *MSSQL) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + statements = dbutil.StatementCompatibilityHelper(statements) + + if len(statements.Revocation) == 0 { + return m.revokeUserDefault(ctx, username) + } + + // Get connection + db, err := m.getConnection(ctx) + if err != nil { + return err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer tx.Rollback() + + // Execute each query + for _, stmt := range statements.Revocation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return err + } + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return err + } + + return nil +} + +func (m *MSSQL) revokeUserDefault(ctx context.Context, username string) error { + // Get connection + db, err := m.getConnection(ctx) + if err != nil { + return err + } + + // First disable server login + disableStmt, err := db.PrepareContext(ctx, fmt.Sprintf("ALTER LOGIN [%s] DISABLE;", username)) + if err != nil { + return err + } + defer disableStmt.Close() + if _, err := disableStmt.ExecContext(ctx); err != nil { + return err + } + + // Query for sessions for the login so that we can kill any outstanding + // sessions. There cannot be any active sessions before we drop the logins + // This isn't done in a transaction because even if we fail along the way, + // we want to remove as much access as possible + sessionStmt, err := db.PrepareContext(ctx, fmt.Sprintf( + "SELECT session_id FROM sys.dm_exec_sessions WHERE login_name = '%s';", username)) + if err != nil { + return err + } + defer sessionStmt.Close() + + sessionRows, err := sessionStmt.QueryContext(ctx) + if err != nil { + return err + } + defer sessionRows.Close() + + var revokeStmts []string + for sessionRows.Next() { + var sessionID int + err = sessionRows.Scan(&sessionID) + if err != nil { + return err + } + revokeStmts = append(revokeStmts, fmt.Sprintf("KILL %d;", sessionID)) + } + + // Query for database users using undocumented stored procedure for now since + // it is the easiest way to get this information; + // we need to drop the database users before we can drop the login and the role + // This isn't done in a transaction because even if we fail along the way, + // we want to remove as much access as possible + stmt, err := db.PrepareContext(ctx, fmt.Sprintf("EXEC master.dbo.sp_msloginmappings '%s';", username)) + if err != nil { + return err + } + defer stmt.Close() + + rows, err := stmt.QueryContext(ctx) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var loginName, dbName, qUsername string + var aliasName sql.NullString + err = rows.Scan(&loginName, &dbName, &qUsername, &aliasName) + if err != nil { + return err + } + revokeStmts = append(revokeStmts, fmt.Sprintf(dropUserSQL, dbName, username, username)) + } + + // we do not stop on error, as we want to remove as + // many permissions as possible right now + var lastStmtError error + for _, query := range revokeStmts { + if err := dbtxn.ExecuteDBQuery(ctx, db, nil, query); err != nil { + lastStmtError = err + } + } + + // can't drop if not all database users are dropped + if rows.Err() != nil { + return errwrap.Wrapf("could not generate sql statements for all rows: {{err}}", rows.Err()) + } + if lastStmtError != nil { + return errwrap.Wrapf("could not perform all sql statements: {{err}}", lastStmtError) + } + + // Drop this login + stmt, err = db.PrepareContext(ctx, fmt.Sprintf(dropLoginSQL, username, username)) + if err != nil { + return err + } + defer stmt.Close() + if _, err := stmt.ExecContext(ctx); err != nil { + return err + } + + return nil +} + +func (m *MSSQL) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + m.Lock() + defer m.Unlock() + + if len(m.Username) == 0 || len(m.Password) == 0 { + return nil, errors.New("username and password are required to rotate") + } + + rotateStatents := statements + if len(rotateStatents) == 0 { + rotateStatents = []string{rotateRootCredentialsSQL} + } + + db, err := m.getConnection(ctx) + if err != nil { + return nil, err + } + + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer func() { + tx.Rollback() + }() + + password, err := m.GeneratePassword() + if err != nil { + return nil, err + } + + for _, stmt := range rotateStatents { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "username": m.Username, + "password": password, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return nil, err + } + } + } + + if err := tx.Commit(); err != nil { + return nil, err + } + + if err := db.Close(); err != nil { + return nil, err + } + + m.RawConfig["password"] = password + return m.RawConfig, nil +} + +const dropUserSQL = ` +USE [%s] +IF EXISTS + (SELECT name + FROM sys.database_principals + WHERE name = N'%s') +BEGIN + DROP USER [%s] +END +` + +const dropLoginSQL = ` +IF EXISTS + (SELECT name + FROM master.sys.server_principals + WHERE name = N'%s') +BEGIN + DROP LOGIN [%s] +END +` + +const rotateRootCredentialsSQL = ` +ALTER LOGIN [%s] WITH PASSWORD = '%s' +` diff --git a/vendor/github.com/hashicorp/vault/plugins/database/mysql/mysql.go b/vendor/github.com/hashicorp/vault/plugins/database/mysql/mysql.go new file mode 100644 index 0000000..a36f1a8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/mysql/mysql.go @@ -0,0 +1,317 @@ +package mysql + +import ( + "context" + "database/sql" + "errors" + "strings" + "time" + + stdmysql "github.com/go-sql-driver/mysql" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/dbtxn" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/connutil" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" +) + +const ( + defaultMysqlRevocationStmts = ` + REVOKE ALL PRIVILEGES, GRANT OPTION FROM '{{name}}'@'%'; + DROP USER '{{name}}'@'%' + ` + + defaultMySQLRotateRootCredentialsSQL = ` + ALTER USER '{{username}}'@'%' IDENTIFIED BY '{{password}}'; + ` + + mySQLTypeName = "mysql" +) + +var ( + MetadataLen int = 10 + LegacyMetadataLen int = 4 + UsernameLen int = 32 + LegacyUsernameLen int = 16 +) + +var _ dbplugin.Database = &MySQL{} + +type MySQL struct { + *connutil.SQLConnectionProducer + credsutil.CredentialsProducer +} + +// New implements builtinplugins.BuiltinFactory +func New(displayNameLen, roleNameLen, usernameLen int) func() (interface{}, error) { + return func() (interface{}, error) { + db := new(displayNameLen, roleNameLen, usernameLen) + // Wrap the plugin with middleware to sanitize errors + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.SecretValues) + + return dbType, nil + } +} + +func new(displayNameLen, roleNameLen, usernameLen int) *MySQL { + connProducer := &connutil.SQLConnectionProducer{} + connProducer.Type = mySQLTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: displayNameLen, + RoleNameLen: roleNameLen, + UsernameLen: usernameLen, + Separator: "-", + } + + return &MySQL{ + SQLConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } +} + +// Run instantiates a MySQL object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + return runCommon(false, apiTLSConfig) +} + +// Run instantiates a MySQL object, and runs the RPC server for the plugin +func RunLegacy(apiTLSConfig *api.TLSConfig) error { + return runCommon(true, apiTLSConfig) +} + +func runCommon(legacy bool, apiTLSConfig *api.TLSConfig) error { + var f func() (interface{}, error) + if legacy { + f = New(credsutil.NoneLength, LegacyMetadataLen, LegacyUsernameLen) + } else { + f = New(MetadataLen, MetadataLen, UsernameLen) + } + dbType, err := f() + if err != nil { + return err + } + + plugins.Serve(dbType.(dbplugin.Database), apiTLSConfig) + + return nil +} + +func (m *MySQL) Type() (string, error) { + return mySQLTypeName, nil +} + +func (m *MySQL) getConnection(ctx context.Context) (*sql.DB, error) { + db, err := m.Connection(ctx) + if err != nil { + return nil, err + } + + return db.(*sql.DB), nil +} + +func (m *MySQL) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + // Grab the lock + m.Lock() + defer m.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get the connection + db, err := m.getConnection(ctx) + if err != nil { + return "", "", err + } + + if len(statements.Creation) == 0 { + return "", "", dbutil.ErrEmptyCreationStatement + } + + username, err = m.GenerateUsername(usernameConfig) + if err != nil { + return "", "", err + } + + password, err = m.GeneratePassword() + if err != nil { + return "", "", err + } + + expirationStr, err := m.GenerateExpiration(expiration) + if err != nil { + return "", "", err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return "", "", err + } + defer tx.Rollback() + + // Execute each query + for _, stmt := range statements.Creation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + query = dbutil.QueryHelper(query, map[string]string{ + "name": username, + "password": password, + "expiration": expirationStr, + }) + + stmt, err := tx.PrepareContext(ctx, query) + if err != nil { + // If the error code we get back is Error 1295: This command is not + // supported in the prepared statement protocol yet, we will execute + // the statement without preparing it. This allows the caller to + // manually prepare statements, as well as run other not yet + // prepare supported commands. If there is no error when running we + // will continue to the next statement. + if e, ok := err.(*stdmysql.MySQLError); ok && e.Number == 1295 { + _, err = tx.ExecContext(ctx, query) + if err != nil { + return "", "", err + } + continue + } + + return "", "", err + } + if _, err := stmt.ExecContext(ctx); err != nil { + stmt.Close() + return "", "", err + } + stmt.Close() + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return "", "", err + } + + return username, password, nil +} + +// NOOP +func (m *MySQL) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + return nil +} + +func (m *MySQL) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + // Grab the read lock + m.Lock() + defer m.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + // Get the connection + db, err := m.getConnection(ctx) + if err != nil { + return err + } + + revocationStmts := statements.Revocation + // Use a default SQL statement for revocation if one cannot be fetched from the role + if len(revocationStmts) == 0 { + revocationStmts = []string{defaultMysqlRevocationStmts} + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer tx.Rollback() + + for _, stmt := range revocationStmts { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + // This is not a prepared statement because not all commands are supported + // 1295: This command is not supported in the prepared statement protocol yet + // Reference https://mariadb.com/kb/en/mariadb/prepare-statement/ + query = strings.Replace(query, "{{name}}", username, -1) + _, err = tx.ExecContext(ctx, query) + if err != nil { + return err + } + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return err + } + + return nil +} + +func (m *MySQL) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + m.Lock() + defer m.Unlock() + + if len(m.Username) == 0 || len(m.Password) == 0 { + return nil, errors.New("username and password are required to rotate") + } + + rotateStatents := statements + if len(rotateStatents) == 0 { + rotateStatents = []string{defaultMySQLRotateRootCredentialsSQL} + } + + db, err := m.getConnection(ctx) + if err != nil { + return nil, err + } + + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer func() { + tx.Rollback() + }() + + password, err := m.GeneratePassword() + if err != nil { + return nil, err + } + + for _, stmt := range rotateStatents { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "username": m.Username, + "password": password, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return nil, err + } + } + } + + if err := tx.Commit(); err != nil { + return nil, err + } + + if err := db.Close(); err != nil { + return nil, err + } + + m.RawConfig["password"] = password + return m.RawConfig, nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/database/postgresql/postgresql.go b/vendor/github.com/hashicorp/vault/plugins/database/postgresql/postgresql.go new file mode 100644 index 0000000..36dd003 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/database/postgresql/postgresql.go @@ -0,0 +1,427 @@ +package postgresql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/dbtxn" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/plugins" + "github.com/hashicorp/vault/plugins/helper/database/connutil" + "github.com/hashicorp/vault/plugins/helper/database/credsutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" + "github.com/lib/pq" +) + +const ( + postgreSQLTypeName = "postgres" + defaultPostgresRenewSQL = ` +ALTER ROLE "{{name}}" VALID UNTIL '{{expiration}}'; +` + defaultPostgresRotateRootCredentialsSQL = ` +ALTER ROLE "{{username}}" WITH PASSWORD '{{password}}'; +` +) + +var _ dbplugin.Database = &PostgreSQL{} + +// New implements builtinplugins.BuiltinFactory +func New() (interface{}, error) { + db := new() + // Wrap the plugin with middleware to sanitize errors + dbType := dbplugin.NewDatabaseErrorSanitizerMiddleware(db, db.SecretValues) + return dbType, nil +} + +func new() *PostgreSQL { + connProducer := &connutil.SQLConnectionProducer{} + connProducer.Type = postgreSQLTypeName + + credsProducer := &credsutil.SQLCredentialsProducer{ + DisplayNameLen: 8, + RoleNameLen: 8, + UsernameLen: 63, + Separator: "-", + } + + db := &PostgreSQL{ + SQLConnectionProducer: connProducer, + CredentialsProducer: credsProducer, + } + + return db +} + +// Run instantiates a PostgreSQL object, and runs the RPC server for the plugin +func Run(apiTLSConfig *api.TLSConfig) error { + dbType, err := New() + if err != nil { + return err + } + + plugins.Serve(dbType.(dbplugin.Database), apiTLSConfig) + + return nil +} + +type PostgreSQL struct { + *connutil.SQLConnectionProducer + credsutil.CredentialsProducer +} + +func (p *PostgreSQL) Type() (string, error) { + return postgreSQLTypeName, nil +} + +func (p *PostgreSQL) getConnection(ctx context.Context) (*sql.DB, error) { + db, err := p.Connection(ctx) + if err != nil { + return nil, err + } + + return db.(*sql.DB), nil +} + +func (p *PostgreSQL) CreateUser(ctx context.Context, statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) { + statements = dbutil.StatementCompatibilityHelper(statements) + + if len(statements.Creation) == 0 { + return "", "", dbutil.ErrEmptyCreationStatement + } + + // Grab the lock + p.Lock() + defer p.Unlock() + + username, err = p.GenerateUsername(usernameConfig) + if err != nil { + return "", "", err + } + + password, err = p.GeneratePassword() + if err != nil { + return "", "", err + } + + expirationStr, err := p.GenerateExpiration(expiration) + if err != nil { + return "", "", err + } + + // Get the connection + db, err := p.getConnection(ctx) + if err != nil { + return "", "", err + } + + // Start a transaction + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return "", "", err + + } + defer func() { + tx.Rollback() + }() + // Return the secret + + // Execute each query + for _, stmt := range statements.Creation { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + "password": password, + "expiration": expirationStr, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return "", "", err + } + } + } + + // Commit the transaction + if err := tx.Commit(); err != nil { + return "", "", err + } + + return username, password, nil +} + +func (p *PostgreSQL) RenewUser(ctx context.Context, statements dbplugin.Statements, username string, expiration time.Time) error { + p.Lock() + defer p.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + renewStmts := statements.Renewal + if len(renewStmts) == 0 { + renewStmts = []string{defaultPostgresRenewSQL} + } + + db, err := p.getConnection(ctx) + if err != nil { + return err + } + + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + expirationStr, err := p.GenerateExpiration(expiration) + if err != nil { + return err + } + + for _, stmt := range renewStmts { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + "expiration": expirationStr, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return err + } + } + } + + return tx.Commit() +} + +func (p *PostgreSQL) RevokeUser(ctx context.Context, statements dbplugin.Statements, username string) error { + // Grab the lock + p.Lock() + defer p.Unlock() + + statements = dbutil.StatementCompatibilityHelper(statements) + + if len(statements.Revocation) == 0 { + return p.defaultRevokeUser(ctx, username) + } + + return p.customRevokeUser(ctx, username, statements.Revocation) +} + +func (p *PostgreSQL) customRevokeUser(ctx context.Context, username string, revocationStmts []string) error { + db, err := p.getConnection(ctx) + if err != nil { + return err + } + + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + for _, stmt := range revocationStmts { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + + m := map[string]string{ + "name": username, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return err + } + } + } + + return tx.Commit() +} + +func (p *PostgreSQL) defaultRevokeUser(ctx context.Context, username string) error { + db, err := p.getConnection(ctx) + if err != nil { + return err + } + + // Check if the role exists + var exists bool + err = db.QueryRowContext(ctx, "SELECT exists (SELECT rolname FROM pg_roles WHERE rolname=$1);", username).Scan(&exists) + if err != nil && err != sql.ErrNoRows { + return err + } + + if exists == false { + return nil + } + + // Query for permissions; we need to revoke permissions before we can drop + // the role + // This isn't done in a transaction because even if we fail along the way, + // we want to remove as much access as possible + stmt, err := db.PrepareContext(ctx, "SELECT DISTINCT table_schema FROM information_schema.role_column_grants WHERE grantee=$1;") + if err != nil { + return err + } + defer stmt.Close() + + rows, err := stmt.QueryContext(ctx, username) + if err != nil { + return err + } + defer rows.Close() + + const initialNumRevocations = 16 + revocationStmts := make([]string, 0, initialNumRevocations) + for rows.Next() { + var schema string + err = rows.Scan(&schema) + if err != nil { + // keep going; remove as many permissions as possible right now + continue + } + revocationStmts = append(revocationStmts, fmt.Sprintf( + `REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA %s FROM %s;`, + pq.QuoteIdentifier(schema), + pq.QuoteIdentifier(username))) + + revocationStmts = append(revocationStmts, fmt.Sprintf( + `REVOKE USAGE ON SCHEMA %s FROM %s;`, + pq.QuoteIdentifier(schema), + pq.QuoteIdentifier(username))) + } + + // for good measure, revoke all privileges and usage on schema public + revocationStmts = append(revocationStmts, fmt.Sprintf( + `REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM %s;`, + pq.QuoteIdentifier(username))) + + revocationStmts = append(revocationStmts, fmt.Sprintf( + "REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM %s;", + pq.QuoteIdentifier(username))) + + revocationStmts = append(revocationStmts, fmt.Sprintf( + "REVOKE USAGE ON SCHEMA public FROM %s;", + pq.QuoteIdentifier(username))) + + // get the current database name so we can issue a REVOKE CONNECT for + // this username + var dbname sql.NullString + if err := db.QueryRowContext(ctx, "SELECT current_database();").Scan(&dbname); err != nil { + return err + } + + if dbname.Valid { + revocationStmts = append(revocationStmts, fmt.Sprintf( + `REVOKE CONNECT ON DATABASE %s FROM %s;`, + pq.QuoteIdentifier(dbname.String), + pq.QuoteIdentifier(username))) + } + + // again, here, we do not stop on error, as we want to remove as + // many permissions as possible right now + var lastStmtError error + for _, query := range revocationStmts { + if err := dbtxn.ExecuteDBQuery(ctx, db, nil, query); err != nil { + lastStmtError = err + } + } + + // can't drop if not all privileges are revoked + if rows.Err() != nil { + return errwrap.Wrapf("could not generate revocation statements for all rows: {{err}}", rows.Err()) + } + if lastStmtError != nil { + return errwrap.Wrapf("could not perform all revocation statements: {{err}}", lastStmtError) + } + + // Drop this user + stmt, err = db.PrepareContext(ctx, fmt.Sprintf( + `DROP ROLE IF EXISTS %s;`, pq.QuoteIdentifier(username))) + if err != nil { + return err + } + defer stmt.Close() + if _, err := stmt.ExecContext(ctx); err != nil { + return err + } + + return nil +} + +func (p *PostgreSQL) RotateRootCredentials(ctx context.Context, statements []string) (map[string]interface{}, error) { + p.Lock() + defer p.Unlock() + + if len(p.Username) == 0 || len(p.Password) == 0 { + return nil, errors.New("username and password are required to rotate") + } + + rotateStatents := statements + if len(rotateStatents) == 0 { + rotateStatents = []string{defaultPostgresRotateRootCredentialsSQL} + } + + db, err := p.getConnection(ctx) + if err != nil { + return nil, err + } + + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer func() { + tx.Rollback() + }() + + password, err := p.GeneratePassword() + if err != nil { + return nil, err + } + + for _, stmt := range rotateStatents { + for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { + query = strings.TrimSpace(query) + if len(query) == 0 { + continue + } + m := map[string]string{ + "username": p.Username, + "password": password, + } + if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil { + return nil, err + } + } + } + + if err := tx.Commit(); err != nil { + return nil, err + } + + // Close the database connection to ensure no new connections come in + if err := db.Close(); err != nil { + return nil, err + } + + p.RawConfig["password"] = password + return p.RawConfig, nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/connutil.go b/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/connutil.go new file mode 100644 index 0000000..45f6fa0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/connutil.go @@ -0,0 +1,25 @@ +package connutil + +import ( + "context" + "errors" + "sync" +) + +var ( + ErrNotInitialized = errors.New("connection has not been initalized") +) + +// ConnectionProducer can be used as an embeded interface in the Database +// definition. It implements the methods dealing with individual database +// connections and is used in all the builtin database types. +type ConnectionProducer interface { + Close() error + Init(context.Context, map[string]interface{}, bool) (map[string]interface{}, error) + Connection(context.Context) (interface{}, error) + + sync.Locker + + // DEPRECATED, will be removed in 0.12 + Initialize(context.Context, map[string]interface{}, bool) error +} diff --git a/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/sql.go b/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/sql.go new file mode 100644 index 0000000..38685d0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/sql.go @@ -0,0 +1,164 @@ +package connutil + +import ( + "context" + "database/sql" + "fmt" + "strings" + "sync" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/plugins/helper/database/dbutil" + "github.com/mitchellh/mapstructure" +) + +var _ ConnectionProducer = &SQLConnectionProducer{} + +// SQLConnectionProducer implements ConnectionProducer and provides a generic producer for most sql databases +type SQLConnectionProducer struct { + ConnectionURL string `json:"connection_url" mapstructure:"connection_url" structs:"connection_url"` + MaxOpenConnections int `json:"max_open_connections" mapstructure:"max_open_connections" structs:"max_open_connections"` + MaxIdleConnections int `json:"max_idle_connections" mapstructure:"max_idle_connections" structs:"max_idle_connections"` + MaxConnectionLifetimeRaw interface{} `json:"max_connection_lifetime" mapstructure:"max_connection_lifetime" structs:"max_connection_lifetime"` + Username string `json:"username" mapstructure:"username" structs:"username"` + Password string `json:"password" mapstructure:"password" structs:"password"` + + Type string + RawConfig map[string]interface{} + maxConnectionLifetime time.Duration + Initialized bool + db *sql.DB + sync.Mutex +} + +func (c *SQLConnectionProducer) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { + _, err := c.Init(ctx, conf, verifyConnection) + return err +} + +func (c *SQLConnectionProducer) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (map[string]interface{}, error) { + c.Lock() + defer c.Unlock() + + c.RawConfig = conf + + err := mapstructure.WeakDecode(conf, &c) + if err != nil { + return nil, err + } + + if len(c.ConnectionURL) == 0 { + return nil, fmt.Errorf("connection_url cannot be empty") + } + + c.ConnectionURL = dbutil.QueryHelper(c.ConnectionURL, map[string]string{ + "username": c.Username, + "password": c.Password, + }) + + if c.MaxOpenConnections == 0 { + c.MaxOpenConnections = 2 + } + + if c.MaxIdleConnections == 0 { + c.MaxIdleConnections = c.MaxOpenConnections + } + if c.MaxIdleConnections > c.MaxOpenConnections { + c.MaxIdleConnections = c.MaxOpenConnections + } + if c.MaxConnectionLifetimeRaw == nil { + c.MaxConnectionLifetimeRaw = "0s" + } + + c.maxConnectionLifetime, err = parseutil.ParseDurationSecond(c.MaxConnectionLifetimeRaw) + if err != nil { + return nil, errwrap.Wrapf("invalid max_connection_lifetime: {{err}}", err) + } + + // Set initialized to true at this point since all fields are set, + // and the connection can be established at a later time. + c.Initialized = true + + if verifyConnection { + if _, err := c.Connection(ctx); err != nil { + return nil, errwrap.Wrapf("error verifying connection: {{err}}", err) + } + + if err := c.db.PingContext(ctx); err != nil { + return nil, errwrap.Wrapf("error verifying connection: {{err}}", err) + } + } + + return c.RawConfig, nil +} + +func (c *SQLConnectionProducer) Connection(ctx context.Context) (interface{}, error) { + if !c.Initialized { + return nil, ErrNotInitialized + } + + // If we already have a DB, test it and return + if c.db != nil { + if err := c.db.PingContext(ctx); err == nil { + return c.db, nil + } + // If the ping was unsuccessful, close it and ignore errors as we'll be + // reestablishing anyways + c.db.Close() + } + + // For mssql backend, switch to sqlserver instead + dbType := c.Type + if c.Type == "mssql" { + dbType = "sqlserver" + } + + // Otherwise, attempt to make connection + conn := c.ConnectionURL + + // Ensure timezone is set to UTC for all the connections + if strings.HasPrefix(conn, "postgres://") || strings.HasPrefix(conn, "postgresql://") { + if strings.Contains(conn, "?") { + conn += "&timezone=utc" + } else { + conn += "?timezone=utc" + } + } + + var err error + c.db, err = sql.Open(dbType, conn) + if err != nil { + return nil, err + } + + // Set some connection pool settings. We don't need much of this, + // since the request rate shouldn't be high. + c.db.SetMaxOpenConns(c.MaxOpenConnections) + c.db.SetMaxIdleConns(c.MaxIdleConnections) + c.db.SetConnMaxLifetime(c.maxConnectionLifetime) + + return c.db, nil +} + +func (c *SQLConnectionProducer) SecretValues() map[string]interface{} { + return map[string]interface{}{ + c.Password: "[password]", + } +} + +// Close attempts to close the connection +func (c *SQLConnectionProducer) Close() error { + // Grab the write lock + c.Lock() + defer c.Unlock() + + if c.db != nil { + c.db.Close() + } + + c.db = nil + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/credsutil.go b/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/credsutil.go new file mode 100644 index 0000000..f186915 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/credsutil.go @@ -0,0 +1,49 @@ +package credsutil + +import ( + "time" + + "fmt" + + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/keysutil" +) + +// CredentialsProducer can be used as an embeded interface in the Database +// definition. It implements the methods for generating user information for a +// particular database type and is used in all the builtin database types. +type CredentialsProducer interface { + GenerateUsername(usernameConfig dbplugin.UsernameConfig) (string, error) + GeneratePassword() (string, error) + GenerateExpiration(ttl time.Time) (string, error) +} + +const ( + reqStr = `A1a-` + minStrLen = 10 +) + +// RandomAlphaNumeric returns a random string of characters [A-Za-z0-9-] +// of the provided length. The string generated takes up to 4 characters +// of space that are predefined and prepended to ensure password +// character requirements. It also requires a min length of 10 characters. +func RandomAlphaNumeric(length int, prependA1a bool) (string, error) { + if length < minStrLen { + return "", fmt.Errorf("minimum length of %d is required", minStrLen) + } + + var prefix string + if prependA1a { + prefix = reqStr + } + + buf, err := uuid.GenerateRandomBytes(length - len(prefix)) + if err != nil { + return "", err + } + + output := (prefix + keysutil.Base62Encode(buf))[:length] + + return output, nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/sql.go b/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/sql.go new file mode 100644 index 0000000..2f9cc7d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/sql.go @@ -0,0 +1,72 @@ +package credsutil + +import ( + "fmt" + "time" + + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" +) + +const ( + NoneLength int = -1 +) + +// SQLCredentialsProducer implements CredentialsProducer and provides a generic credentials producer for most sql database types. +type SQLCredentialsProducer struct { + DisplayNameLen int + RoleNameLen int + UsernameLen int + Separator string +} + +func (scp *SQLCredentialsProducer) GenerateUsername(config dbplugin.UsernameConfig) (string, error) { + username := "v" + + displayName := config.DisplayName + if scp.DisplayNameLen > 0 && len(displayName) > scp.DisplayNameLen { + displayName = displayName[:scp.DisplayNameLen] + } else if scp.DisplayNameLen == NoneLength { + displayName = "" + } + + if len(displayName) > 0 { + username = fmt.Sprintf("%s%s%s", username, scp.Separator, displayName) + } + + roleName := config.RoleName + if scp.RoleNameLen > 0 && len(roleName) > scp.RoleNameLen { + roleName = roleName[:scp.RoleNameLen] + } else if scp.RoleNameLen == NoneLength { + roleName = "" + } + + if len(roleName) > 0 { + username = fmt.Sprintf("%s%s%s", username, scp.Separator, roleName) + } + + userUUID, err := RandomAlphaNumeric(20, false) + if err != nil { + return "", err + } + + username = fmt.Sprintf("%s%s%s", username, scp.Separator, userUUID) + username = fmt.Sprintf("%s%s%s", username, scp.Separator, fmt.Sprint(time.Now().Unix())) + if scp.UsernameLen > 0 && len(username) > scp.UsernameLen { + username = username[:scp.UsernameLen] + } + + return username, nil +} + +func (scp *SQLCredentialsProducer) GeneratePassword() (string, error) { + password, err := RandomAlphaNumeric(20, true) + if err != nil { + return "", err + } + + return password, nil +} + +func (scp *SQLCredentialsProducer) GenerateExpiration(ttl time.Time) (string, error) { + return ttl.Format("2006-01-02 15:04:05-0700"), nil +} diff --git a/vendor/github.com/hashicorp/vault/plugins/helper/database/dbutil/dbutil.go b/vendor/github.com/hashicorp/vault/plugins/helper/database/dbutil/dbutil.go new file mode 100644 index 0000000..4225705 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/helper/database/dbutil/dbutil.go @@ -0,0 +1,52 @@ +package dbutil + +import ( + "errors" + "fmt" + "strings" + + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" +) + +var ( + ErrEmptyCreationStatement = errors.New("empty creation statements") +) + +// Query templates a query for us. +func QueryHelper(tpl string, data map[string]string) string { + for k, v := range data { + tpl = strings.Replace(tpl, fmt.Sprintf("{{%s}}", k), v, -1) + } + + return tpl +} + +// StatementCompatibilityHelper will populate the statements fields to support +// compatibility +func StatementCompatibilityHelper(statements dbplugin.Statements) dbplugin.Statements { + switch { + case len(statements.Creation) > 0 && len(statements.CreationStatements) == 0: + statements.CreationStatements = strings.Join(statements.Creation, ";") + case len(statements.CreationStatements) > 0: + statements.Creation = []string{statements.CreationStatements} + } + switch { + case len(statements.Revocation) > 0 && len(statements.RevocationStatements) == 0: + statements.RevocationStatements = strings.Join(statements.Revocation, ";") + case len(statements.RevocationStatements) > 0: + statements.Revocation = []string{statements.RevocationStatements} + } + switch { + case len(statements.Renewal) > 0 && len(statements.RenewStatements) == 0: + statements.RenewStatements = strings.Join(statements.Renewal, ";") + case len(statements.RenewStatements) > 0: + statements.Renewal = []string{statements.RenewStatements} + } + switch { + case len(statements.Rollback) > 0 && len(statements.RollbackStatements) == 0: + statements.RollbackStatements = strings.Join(statements.Rollback, ";") + case len(statements.RollbackStatements) > 0: + statements.Rollback = []string{statements.RollbackStatements} + } + return statements +} diff --git a/vendor/github.com/hashicorp/vault/plugins/serve.go b/vendor/github.com/hashicorp/vault/plugins/serve.go new file mode 100644 index 0000000..0bc3bc4 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/plugins/serve.go @@ -0,0 +1,31 @@ +package plugins + +import ( + "fmt" + + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/builtin/logical/database/dbplugin" + "github.com/hashicorp/vault/helper/pluginutil" +) + +// Serve is used to start a plugin's RPC server. It takes an interface that must +// implement a known plugin interface to vault and an optional api.TLSConfig for +// use during the inital unwrap request to vault. The api config is particularly +// useful when vault is setup to require client cert checking. +func Serve(plugin interface{}, tlsConfig *api.TLSConfig) { + tlsProvider := pluginutil.VaultPluginTLSProvider(tlsConfig) + + err := pluginutil.OptionallyEnableMlock() + if err != nil { + fmt.Println(err) + return + } + + switch p := plugin.(type) { + case dbplugin.Database: + dbplugin.Serve(p, tlsProvider) + default: + fmt.Println("Unsupported plugin type") + } + +} diff --git a/vendor/github.com/hashicorp/vault/shamir/shamir.go b/vendor/github.com/hashicorp/vault/shamir/shamir.go new file mode 100644 index 0000000..0465086 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/shamir/shamir.go @@ -0,0 +1,262 @@ +package shamir + +import ( + "crypto/rand" + "crypto/subtle" + "fmt" + mathrand "math/rand" + "time" + + "github.com/hashicorp/errwrap" +) + +const ( + // ShareOverhead is the byte size overhead of each share + // when using Split on a secret. This is caused by appending + // a one byte tag to the share. + ShareOverhead = 1 +) + +// polynomial represents a polynomial of arbitrary degree +type polynomial struct { + coefficients []uint8 +} + +// makePolynomial constructs a random polynomial of the given +// degree but with the provided intercept value. +func makePolynomial(intercept, degree uint8) (polynomial, error) { + // Create a wrapper + p := polynomial{ + coefficients: make([]byte, degree+1), + } + + // Ensure the intercept is set + p.coefficients[0] = intercept + + // Assign random co-efficients to the polynomial + if _, err := rand.Read(p.coefficients[1:]); err != nil { + return p, err + } + + return p, nil +} + +// evaluate returns the value of the polynomial for the given x +func (p *polynomial) evaluate(x uint8) uint8 { + // Special case the origin + if x == 0 { + return p.coefficients[0] + } + + // Compute the polynomial value using Horner's method. + degree := len(p.coefficients) - 1 + out := p.coefficients[degree] + for i := degree - 1; i >= 0; i-- { + coeff := p.coefficients[i] + out = add(mult(out, x), coeff) + } + return out +} + +// interpolatePolynomial takes N sample points and returns +// the value at a given x using a lagrange interpolation. +func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 { + limit := len(x_samples) + var result, basis uint8 + for i := 0; i < limit; i++ { + basis = 1 + for j := 0; j < limit; j++ { + if i == j { + continue + } + num := add(x, x_samples[j]) + denom := add(x_samples[i], x_samples[j]) + term := div(num, denom) + basis = mult(basis, term) + } + group := mult(y_samples[i], basis) + result = add(result, group) + } + return result +} + +// div divides two numbers in GF(2^8) +func div(a, b uint8) uint8 { + if b == 0 { + // leaks some timing information but we don't care anyways as this + // should never happen, hence the panic + panic("divide by zero") + } + + var goodVal, zero uint8 + log_a := logTable[a] + log_b := logTable[b] + diff := (int(log_a) - int(log_b)) % 255 + if diff < 0 { + diff += 255 + } + + ret := expTable[diff] + + // Ensure we return zero if a is zero but aren't subject to timing attacks + goodVal = ret + + if subtle.ConstantTimeByteEq(a, 0) == 1 { + ret = zero + } else { + ret = goodVal + } + + return ret +} + +// mult multiplies two numbers in GF(2^8) +func mult(a, b uint8) (out uint8) { + var goodVal, zero uint8 + log_a := logTable[a] + log_b := logTable[b] + sum := (int(log_a) + int(log_b)) % 255 + + ret := expTable[sum] + + // Ensure we return zero if either a or be are zero but aren't subject to + // timing attacks + goodVal = ret + + if subtle.ConstantTimeByteEq(a, 0) == 1 { + ret = zero + } else { + ret = goodVal + } + + if subtle.ConstantTimeByteEq(b, 0) == 1 { + ret = zero + } else { + // This operation does not do anything logically useful. It + // only ensures a constant number of assignments to thwart + // timing attacks. + goodVal = zero + } + + return ret +} + +// add combines two numbers in GF(2^8) +// This can also be used for subtraction since it is symmetric. +func add(a, b uint8) uint8 { + return a ^ b +} + +// Split takes an arbitrarily long secret and generates a `parts` +// number of shares, `threshold` of which are required to reconstruct +// the secret. The parts and threshold must be at least 2, and less +// than 256. The returned shares are each one byte longer than the secret +// as they attach a tag used to reconstruct the secret. +func Split(secret []byte, parts, threshold int) ([][]byte, error) { + // Sanity check the input + if parts < threshold { + return nil, fmt.Errorf("parts cannot be less than threshold") + } + if parts > 255 { + return nil, fmt.Errorf("parts cannot exceed 255") + } + if threshold < 2 { + return nil, fmt.Errorf("threshold must be at least 2") + } + if threshold > 255 { + return nil, fmt.Errorf("threshold cannot exceed 255") + } + if len(secret) == 0 { + return nil, fmt.Errorf("cannot split an empty secret") + } + + // Generate random list of x coordinates + mathrand.Seed(time.Now().UnixNano()) + xCoordinates := mathrand.Perm(255) + + // Allocate the output array, initialize the final byte + // of the output with the offset. The representation of each + // output is {y1, y2, .., yN, x}. + out := make([][]byte, parts) + for idx := range out { + out[idx] = make([]byte, len(secret)+1) + out[idx][len(secret)] = uint8(xCoordinates[idx]) + 1 + } + + // Construct a random polynomial for each byte of the secret. + // Because we are using a field of size 256, we can only represent + // a single byte as the intercept of the polynomial, so we must + // use a new polynomial for each byte. + for idx, val := range secret { + p, err := makePolynomial(val, uint8(threshold-1)) + if err != nil { + return nil, errwrap.Wrapf("failed to generate polynomial: {{err}}", err) + } + + // Generate a `parts` number of (x,y) pairs + // We cheat by encoding the x value once as the final index, + // so that it only needs to be stored once. + for i := 0; i < parts; i++ { + x := uint8(xCoordinates[i]) + 1 + y := p.evaluate(x) + out[i][idx] = y + } + } + + // Return the encoded secrets + return out, nil +} + +// Combine is used to reverse a Split and reconstruct a secret +// once a `threshold` number of parts are available. +func Combine(parts [][]byte) ([]byte, error) { + // Verify enough parts provided + if len(parts) < 2 { + return nil, fmt.Errorf("less than two parts cannot be used to reconstruct the secret") + } + + // Verify the parts are all the same length + firstPartLen := len(parts[0]) + if firstPartLen < 2 { + return nil, fmt.Errorf("parts must be at least two bytes") + } + for i := 1; i < len(parts); i++ { + if len(parts[i]) != firstPartLen { + return nil, fmt.Errorf("all parts must be the same length") + } + } + + // Create a buffer to store the reconstructed secret + secret := make([]byte, firstPartLen-1) + + // Buffer to store the samples + x_samples := make([]uint8, len(parts)) + y_samples := make([]uint8, len(parts)) + + // Set the x value for each sample and ensure no x_sample values are the same, + // otherwise div() can be unhappy + checkMap := map[byte]bool{} + for i, part := range parts { + samp := part[firstPartLen-1] + if exists := checkMap[samp]; exists { + return nil, fmt.Errorf("duplicate part detected") + } + checkMap[samp] = true + x_samples[i] = samp + } + + // Reconstruct each byte + for idx := range secret { + // Set the y value for each sample + for i, part := range parts { + y_samples[i] = part[idx] + } + + // Interpolate the polynomial and compute the value at 0 + val := interpolatePolynomial(x_samples, y_samples, 0) + + // Evaluate the 0th value to get the intercept + secret[idx] = val + } + return secret, nil +} diff --git a/vendor/github.com/hashicorp/vault/shamir/tables.go b/vendor/github.com/hashicorp/vault/shamir/tables.go new file mode 100644 index 0000000..76c245e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/shamir/tables.go @@ -0,0 +1,77 @@ +package shamir + +// Tables taken from http://www.samiam.org/galois.html +// They use 0xe5 (229) as the generator + +var ( + // logTable provides the log(X)/log(g) at each index X + logTable = [256]uint8{ + 0x00, 0xff, 0xc8, 0x08, 0x91, 0x10, 0xd0, 0x36, + 0x5a, 0x3e, 0xd8, 0x43, 0x99, 0x77, 0xfe, 0x18, + 0x23, 0x20, 0x07, 0x70, 0xa1, 0x6c, 0x0c, 0x7f, + 0x62, 0x8b, 0x40, 0x46, 0xc7, 0x4b, 0xe0, 0x0e, + 0xeb, 0x16, 0xe8, 0xad, 0xcf, 0xcd, 0x39, 0x53, + 0x6a, 0x27, 0x35, 0x93, 0xd4, 0x4e, 0x48, 0xc3, + 0x2b, 0x79, 0x54, 0x28, 0x09, 0x78, 0x0f, 0x21, + 0x90, 0x87, 0x14, 0x2a, 0xa9, 0x9c, 0xd6, 0x74, + 0xb4, 0x7c, 0xde, 0xed, 0xb1, 0x86, 0x76, 0xa4, + 0x98, 0xe2, 0x96, 0x8f, 0x02, 0x32, 0x1c, 0xc1, + 0x33, 0xee, 0xef, 0x81, 0xfd, 0x30, 0x5c, 0x13, + 0x9d, 0x29, 0x17, 0xc4, 0x11, 0x44, 0x8c, 0x80, + 0xf3, 0x73, 0x42, 0x1e, 0x1d, 0xb5, 0xf0, 0x12, + 0xd1, 0x5b, 0x41, 0xa2, 0xd7, 0x2c, 0xe9, 0xd5, + 0x59, 0xcb, 0x50, 0xa8, 0xdc, 0xfc, 0xf2, 0x56, + 0x72, 0xa6, 0x65, 0x2f, 0x9f, 0x9b, 0x3d, 0xba, + 0x7d, 0xc2, 0x45, 0x82, 0xa7, 0x57, 0xb6, 0xa3, + 0x7a, 0x75, 0x4f, 0xae, 0x3f, 0x37, 0x6d, 0x47, + 0x61, 0xbe, 0xab, 0xd3, 0x5f, 0xb0, 0x58, 0xaf, + 0xca, 0x5e, 0xfa, 0x85, 0xe4, 0x4d, 0x8a, 0x05, + 0xfb, 0x60, 0xb7, 0x7b, 0xb8, 0x26, 0x4a, 0x67, + 0xc6, 0x1a, 0xf8, 0x69, 0x25, 0xb3, 0xdb, 0xbd, + 0x66, 0xdd, 0xf1, 0xd2, 0xdf, 0x03, 0x8d, 0x34, + 0xd9, 0x92, 0x0d, 0x63, 0x55, 0xaa, 0x49, 0xec, + 0xbc, 0x95, 0x3c, 0x84, 0x0b, 0xf5, 0xe6, 0xe7, + 0xe5, 0xac, 0x7e, 0x6e, 0xb9, 0xf9, 0xda, 0x8e, + 0x9a, 0xc9, 0x24, 0xe1, 0x0a, 0x15, 0x6b, 0x3a, + 0xa0, 0x51, 0xf4, 0xea, 0xb2, 0x97, 0x9e, 0x5d, + 0x22, 0x88, 0x94, 0xce, 0x19, 0x01, 0x71, 0x4c, + 0xa5, 0xe3, 0xc5, 0x31, 0xbb, 0xcc, 0x1f, 0x2d, + 0x3b, 0x52, 0x6f, 0xf6, 0x2e, 0x89, 0xf7, 0xc0, + 0x68, 0x1b, 0x64, 0x04, 0x06, 0xbf, 0x83, 0x38} + + // expTable provides the anti-log or exponentiation value + // for the equivalent index + expTable = [256]uint8{ + 0x01, 0xe5, 0x4c, 0xb5, 0xfb, 0x9f, 0xfc, 0x12, + 0x03, 0x34, 0xd4, 0xc4, 0x16, 0xba, 0x1f, 0x36, + 0x05, 0x5c, 0x67, 0x57, 0x3a, 0xd5, 0x21, 0x5a, + 0x0f, 0xe4, 0xa9, 0xf9, 0x4e, 0x64, 0x63, 0xee, + 0x11, 0x37, 0xe0, 0x10, 0xd2, 0xac, 0xa5, 0x29, + 0x33, 0x59, 0x3b, 0x30, 0x6d, 0xef, 0xf4, 0x7b, + 0x55, 0xeb, 0x4d, 0x50, 0xb7, 0x2a, 0x07, 0x8d, + 0xff, 0x26, 0xd7, 0xf0, 0xc2, 0x7e, 0x09, 0x8c, + 0x1a, 0x6a, 0x62, 0x0b, 0x5d, 0x82, 0x1b, 0x8f, + 0x2e, 0xbe, 0xa6, 0x1d, 0xe7, 0x9d, 0x2d, 0x8a, + 0x72, 0xd9, 0xf1, 0x27, 0x32, 0xbc, 0x77, 0x85, + 0x96, 0x70, 0x08, 0x69, 0x56, 0xdf, 0x99, 0x94, + 0xa1, 0x90, 0x18, 0xbb, 0xfa, 0x7a, 0xb0, 0xa7, + 0xf8, 0xab, 0x28, 0xd6, 0x15, 0x8e, 0xcb, 0xf2, + 0x13, 0xe6, 0x78, 0x61, 0x3f, 0x89, 0x46, 0x0d, + 0x35, 0x31, 0x88, 0xa3, 0x41, 0x80, 0xca, 0x17, + 0x5f, 0x53, 0x83, 0xfe, 0xc3, 0x9b, 0x45, 0x39, + 0xe1, 0xf5, 0x9e, 0x19, 0x5e, 0xb6, 0xcf, 0x4b, + 0x38, 0x04, 0xb9, 0x2b, 0xe2, 0xc1, 0x4a, 0xdd, + 0x48, 0x0c, 0xd0, 0x7d, 0x3d, 0x58, 0xde, 0x7c, + 0xd8, 0x14, 0x6b, 0x87, 0x47, 0xe8, 0x79, 0x84, + 0x73, 0x3c, 0xbd, 0x92, 0xc9, 0x23, 0x8b, 0x97, + 0x95, 0x44, 0xdc, 0xad, 0x40, 0x65, 0x86, 0xa2, + 0xa4, 0xcc, 0x7f, 0xec, 0xc0, 0xaf, 0x91, 0xfd, + 0xf7, 0x4f, 0x81, 0x2f, 0x5b, 0xea, 0xa8, 0x1c, + 0x02, 0xd1, 0x98, 0x71, 0xed, 0x25, 0xe3, 0x24, + 0x06, 0x68, 0xb3, 0x93, 0x2c, 0x6f, 0x3e, 0x6c, + 0x0a, 0xb8, 0xce, 0xae, 0x74, 0xb1, 0x42, 0xb4, + 0x1e, 0xd3, 0x49, 0xe9, 0x9c, 0xc8, 0xc6, 0xc7, + 0x22, 0x6e, 0xdb, 0x20, 0xbf, 0x43, 0x51, 0x52, + 0x66, 0xb2, 0x76, 0x60, 0xda, 0xc5, 0xf3, 0xf6, + 0xaa, 0xcd, 0x9a, 0xa0, 0x75, 0x54, 0x0e, 0x01} +) diff --git a/vendor/github.com/hashicorp/vault/vault/acl.go b/vendor/github.com/hashicorp/vault/vault/acl.go new file mode 100644 index 0000000..e86e79e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/acl.go @@ -0,0 +1,460 @@ +package vault + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/armon/go-radix" + "github.com/hashicorp/errwrap" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" + "github.com/mitchellh/copystructure" +) + +// ACL is used to wrap a set of policies to provide +// an efficient interface for access control. +type ACL struct { + // exactRules contains the path policies that are exact + exactRules *radix.Tree + + // globRules contains the path policies that glob + globRules *radix.Tree + + // root is enabled if the "root" named policy is present. + root bool +} + +type PolicyCheckOpts struct { + RootPrivsRequired bool + Unauth bool +} + +type AuthResults struct { + ACLResults *ACLResults + Allowed bool + RootPrivs bool + Error *multierror.Error +} + +type ACLResults struct { + Allowed bool + RootPrivs bool + IsRoot bool + MFAMethods []string +} + +// New is used to construct a policy based ACL from a set of policies. +func NewACL(policies []*Policy) (*ACL, error) { + // Initialize + a := &ACL{ + exactRules: radix.New(), + globRules: radix.New(), + root: false, + } + + // Inject each policy + for _, policy := range policies { + // Ignore a nil policy object + if policy == nil { + continue + } + + switch policy.Type { + case PolicyTypeACL: + default: + return nil, fmt.Errorf("unable to parse policy (wrong type)") + } + + // Check if this is root + if policy.Name == "root" { + a.root = true + } + for _, pc := range policy.Paths { + // Check which tree to use + tree := a.exactRules + if pc.Glob { + tree = a.globRules + } + + // Check for an existing policy + raw, ok := tree.Get(pc.Prefix) + if !ok { + clonedPerms, err := pc.Permissions.Clone() + if err != nil { + return nil, errwrap.Wrapf("error cloning ACL permissions: {{err}}", err) + } + tree.Insert(pc.Prefix, clonedPerms) + continue + } + + // these are the ones already in the tree + existingPerms := raw.(*ACLPermissions) + + switch { + case existingPerms.CapabilitiesBitmap&DenyCapabilityInt > 0: + // If we are explicitly denied in the existing capability set, + // don't save anything else + continue + + case pc.Permissions.CapabilitiesBitmap&DenyCapabilityInt > 0: + // If this new policy explicitly denies, only save the deny value + existingPerms.CapabilitiesBitmap = DenyCapabilityInt + existingPerms.AllowedParameters = nil + existingPerms.DeniedParameters = nil + goto INSERT + + default: + // Insert the capabilities in this new policy into the existing + // value + existingPerms.CapabilitiesBitmap = existingPerms.CapabilitiesBitmap | pc.Permissions.CapabilitiesBitmap + } + + // Note: In these stanzas, we're preferring minimum lifetimes. So + // we take the lesser of two specified max values, or we take the + // lesser of two specified min values, the idea being, allowing + // token lifetime to be minimum possible. + // + // If we have an existing max, and we either don't have a current + // max, or the current is greater than the previous, use the + // existing. + if pc.Permissions.MaxWrappingTTL > 0 && + (existingPerms.MaxWrappingTTL == 0 || + pc.Permissions.MaxWrappingTTL < existingPerms.MaxWrappingTTL) { + existingPerms.MaxWrappingTTL = pc.Permissions.MaxWrappingTTL + } + // If we have an existing min, and we either don't have a current + // min, or the current is greater than the previous, use the + // existing + if pc.Permissions.MinWrappingTTL > 0 && + (existingPerms.MinWrappingTTL == 0 || + pc.Permissions.MinWrappingTTL < existingPerms.MinWrappingTTL) { + existingPerms.MinWrappingTTL = pc.Permissions.MinWrappingTTL + } + + if len(pc.Permissions.AllowedParameters) > 0 { + if existingPerms.AllowedParameters == nil { + clonedAllowed, err := copystructure.Copy(pc.Permissions.AllowedParameters) + if err != nil { + return nil, err + } + existingPerms.AllowedParameters = clonedAllowed.(map[string][]interface{}) + } else { + for key, value := range pc.Permissions.AllowedParameters { + pcValue, ok := existingPerms.AllowedParameters[key] + // If an empty array exist it should overwrite any other + // value. + if len(value) == 0 || (ok && len(pcValue) == 0) { + existingPerms.AllowedParameters[key] = []interface{}{} + } else { + // Merge the two maps, appending values on key conflict. + existingPerms.AllowedParameters[key] = append(value, existingPerms.AllowedParameters[key]...) + } + } + } + } + + if len(pc.Permissions.DeniedParameters) > 0 { + if existingPerms.DeniedParameters == nil { + clonedDenied, err := copystructure.Copy(pc.Permissions.DeniedParameters) + if err != nil { + return nil, err + } + existingPerms.DeniedParameters = clonedDenied.(map[string][]interface{}) + } else { + for key, value := range pc.Permissions.DeniedParameters { + pcValue, ok := existingPerms.DeniedParameters[key] + // If an empty array exist it should overwrite any other + // value. + if len(value) == 0 || (ok && len(pcValue) == 0) { + existingPerms.DeniedParameters[key] = []interface{}{} + } else { + // Merge the two maps, appending values on key conflict. + existingPerms.DeniedParameters[key] = append(value, existingPerms.DeniedParameters[key]...) + } + } + } + } + + if len(pc.Permissions.RequiredParameters) > 0 { + if len(existingPerms.RequiredParameters) == 0 { + existingPerms.RequiredParameters = pc.Permissions.RequiredParameters + } else { + for _, v := range pc.Permissions.RequiredParameters { + if !strutil.StrListContains(existingPerms.RequiredParameters, v) { + existingPerms.RequiredParameters = append(existingPerms.RequiredParameters, v) + } + } + } + } + + INSERT: + tree.Insert(pc.Prefix, existingPerms) + } + } + return a, nil +} + +func (a *ACL) Capabilities(path string) (pathCapabilities []string) { + // Fast-path root + if a.root { + return []string{RootCapability} + } + + // Find an exact matching rule, look for glob if no match + var capabilities uint32 + raw, ok := a.exactRules.Get(path) + + if ok { + perm := raw.(*ACLPermissions) + capabilities = perm.CapabilitiesBitmap + goto CHECK + } + + // Find a glob rule, default deny if no match + _, raw, ok = a.globRules.LongestPrefix(path) + if !ok { + return []string{DenyCapability} + } else { + perm := raw.(*ACLPermissions) + capabilities = perm.CapabilitiesBitmap + } + +CHECK: + if capabilities&SudoCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, SudoCapability) + } + if capabilities&ReadCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, ReadCapability) + } + if capabilities&ListCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, ListCapability) + } + if capabilities&UpdateCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, UpdateCapability) + } + if capabilities&DeleteCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, DeleteCapability) + } + if capabilities&CreateCapabilityInt > 0 { + pathCapabilities = append(pathCapabilities, CreateCapability) + } + + // If "deny" is explicitly set or if the path has no capabilities at all, + // set the path capabilities to "deny" + if capabilities&DenyCapabilityInt > 0 || len(pathCapabilities) == 0 { + pathCapabilities = []string{DenyCapability} + } + return +} + +// AllowOperation is used to check if the given operation is permitted. +func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) { + ret = new(ACLResults) + + // Fast-path root + if a.root { + ret.Allowed = true + ret.RootPrivs = true + ret.IsRoot = true + return + } + op := req.Operation + path := req.Path + + // Help is always allowed + if op == logical.HelpOperation { + ret.Allowed = true + return + } + + var permissions *ACLPermissions + + // Find an exact matching rule, look for glob if no match + var capabilities uint32 + raw, ok := a.exactRules.Get(path) + if ok { + permissions = raw.(*ACLPermissions) + capabilities = permissions.CapabilitiesBitmap + goto CHECK + } + + // Find a glob rule, default deny if no match + _, raw, ok = a.globRules.LongestPrefix(path) + if !ok { + return + } else { + permissions = raw.(*ACLPermissions) + capabilities = permissions.CapabilitiesBitmap + } + +CHECK: + // Check if the minimum permissions are met + // If "deny" has been explicitly set, only deny will be in the map, so we + // only need to check for the existence of other values + ret.RootPrivs = capabilities&SudoCapabilityInt > 0 + + operationAllowed := false + switch op { + case logical.ReadOperation: + operationAllowed = capabilities&ReadCapabilityInt > 0 + case logical.ListOperation: + operationAllowed = capabilities&ListCapabilityInt > 0 + case logical.UpdateOperation: + operationAllowed = capabilities&UpdateCapabilityInt > 0 + case logical.DeleteOperation: + operationAllowed = capabilities&DeleteCapabilityInt > 0 + case logical.CreateOperation: + operationAllowed = capabilities&CreateCapabilityInt > 0 + + // These three re-use UpdateCapabilityInt since that's the most appropriate + // capability/operation mapping + case logical.RevokeOperation, logical.RenewOperation, logical.RollbackOperation: + operationAllowed = capabilities&UpdateCapabilityInt > 0 + + default: + return + } + + if !operationAllowed { + return + } + + if permissions.MaxWrappingTTL > 0 { + if req.WrapInfo == nil || req.WrapInfo.TTL > permissions.MaxWrappingTTL { + return + } + } + if permissions.MinWrappingTTL > 0 { + if req.WrapInfo == nil || req.WrapInfo.TTL < permissions.MinWrappingTTL { + return + } + } + // This situation can happen because of merging, even though in a single + // path statement we check on ingress + if permissions.MinWrappingTTL != 0 && + permissions.MaxWrappingTTL != 0 && + permissions.MaxWrappingTTL < permissions.MinWrappingTTL { + return + } + + // Only check parameter permissions for operations that can modify + // parameters. + if op == logical.ReadOperation || op == logical.UpdateOperation || op == logical.CreateOperation { + for _, parameter := range permissions.RequiredParameters { + if _, ok := req.Data[strings.ToLower(parameter)]; !ok { + return + } + } + + // If there are no data fields, allow + if len(req.Data) == 0 { + ret.Allowed = true + return + } + + if len(permissions.DeniedParameters) == 0 { + goto ALLOWED_PARAMETERS + } + + // Check if all parameters have been denied + if _, ok := permissions.DeniedParameters["*"]; ok { + return + } + + for parameter, value := range req.Data { + // Check if parameter has been explicitly denied + if valueSlice, ok := permissions.DeniedParameters[strings.ToLower(parameter)]; ok { + // If the value exists in denied values slice, deny + if valueInParameterList(value, valueSlice) { + return + } + } + } + + ALLOWED_PARAMETERS: + // If we don't have any allowed parameters set, allow + if len(permissions.AllowedParameters) == 0 { + ret.Allowed = true + return + } + + _, allowedAll := permissions.AllowedParameters["*"] + if len(permissions.AllowedParameters) == 1 && allowedAll { + ret.Allowed = true + return + } + + for parameter, value := range req.Data { + valueSlice, ok := permissions.AllowedParameters[strings.ToLower(parameter)] + // Requested parameter is not in allowed list + if !ok && !allowedAll { + return + } + + // If the value doesn't exists in the allowed values slice, + // deny + if ok && !valueInParameterList(value, valueSlice) { + return + } + } + } + + ret.Allowed = true + return +} +func (c *Core) performPolicyChecks(ctx context.Context, acl *ACL, te *TokenEntry, req *logical.Request, inEntity *identity.Entity, opts *PolicyCheckOpts) (ret *AuthResults) { + ret = new(AuthResults) + + // First, perform normal ACL checks if requested. The only time no ACL + // should be applied is if we are only processing EGPs against a login + // path in which case opts.Unauth will be set. + if acl != nil && !opts.Unauth { + ret.ACLResults = acl.AllowOperation(req) + ret.RootPrivs = ret.ACLResults.RootPrivs + // Root is always allowed; skip Sentinel/MFA checks + if ret.ACLResults.IsRoot { + //c.logger.Warn("policy: token is root, skipping checks") + ret.Allowed = true + return + } + if !ret.ACLResults.Allowed { + return + } + if !ret.RootPrivs && opts.RootPrivsRequired { + return + } + } + + ret.Allowed = true + return +} + +func valueInParameterList(v interface{}, list []interface{}) bool { + // Empty list is equivalent to the item always existing in the list + if len(list) == 0 { + return true + } + + return valueInSlice(v, list) +} + +func valueInSlice(v interface{}, list []interface{}) bool { + for _, el := range list { + if reflect.TypeOf(el).String() == "string" && reflect.TypeOf(v).String() == "string" { + item := el.(string) + val := v.(string) + + if strutil.GlobbedStringsMatch(item, val) { + return true + } + } else if reflect.DeepEqual(el, v) { + return true + } + } + + return false +} diff --git a/vendor/github.com/hashicorp/vault/vault/audit.go b/vendor/github.com/hashicorp/vault/vault/audit.go new file mode 100644 index 0000000..9984148 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/audit.go @@ -0,0 +1,461 @@ +package vault + +import ( + "context" + "crypto/sha256" + "errors" + "fmt" + "strings" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" +) + +const ( + // coreAuditConfigPath is used to store the audit configuration. + // Audit configuration is protected within the Vault itself, which means it + // can only be viewed or modified after an unseal. + coreAuditConfigPath = "core/audit" + + // coreLocalAuditConfigPath is used to store audit information for local + // (non-replicated) mounts + coreLocalAuditConfigPath = "core/local-audit" + + // auditBarrierPrefix is the prefix to the UUID used in the + // barrier view for the audit backends. + auditBarrierPrefix = "audit/" + + // auditTableType is the value we expect to find for the audit table and + // corresponding entries + auditTableType = "audit" +) + +var ( + // loadAuditFailed if loading audit tables encounters an error + errLoadAuditFailed = errors.New("failed to setup audit table") +) + +// enableAudit is used to enable a new audit backend +func (c *Core) enableAudit(ctx context.Context, entry *MountEntry) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(entry.Path, "/") { + entry.Path += "/" + } + + // Ensure there is a name + if entry.Path == "/" { + return fmt.Errorf("backend path must be specified") + } + + // Update the audit table + c.auditLock.Lock() + defer c.auditLock.Unlock() + + // Look for matching name + for _, ent := range c.audit.Entries { + switch { + // Existing is sql/mysql/ new is sql/ or + // existing is sql/ and new is sql/mysql/ + case strings.HasPrefix(ent.Path, entry.Path): + fallthrough + case strings.HasPrefix(entry.Path, ent.Path): + return fmt.Errorf("path already in use") + } + } + + // Generate a new UUID and view + if entry.UUID == "" { + entryUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.UUID = entryUUID + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor("audit_" + entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + } + viewPath := auditBarrierPrefix + entry.UUID + "/" + view := NewBarrierView(c.barrier, viewPath) + + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + defer view.setReadOnlyErr(nil) + + // Lookup the new backend + backend, err := c.newAuditBackend(ctx, entry, view, entry.Options) + if err != nil { + return err + } + if backend == nil { + return fmt.Errorf("nil audit backend of type %q returned from factory", entry.Type) + } + + newTable := c.audit.shallowClone() + newTable.Entries = append(newTable.Entries, entry) + if err := c.persistAudit(ctx, newTable, entry.Local); err != nil { + return errors.New("failed to update audit table") + } + + c.audit = newTable + + // Register the backend + c.auditBroker.Register(entry.Path, backend, view) + if c.logger.IsInfo() { + c.logger.Info("enabled audit backend", "path", entry.Path, "type", entry.Type) + } + return nil +} + +// disableAudit is used to disable an existing audit backend +func (c *Core) disableAudit(ctx context.Context, path string) (bool, error) { + // Ensure we end the path in a slash + if !strings.HasSuffix(path, "/") { + path += "/" + } + + // Remove the entry from the mount table + c.auditLock.Lock() + defer c.auditLock.Unlock() + + newTable := c.audit.shallowClone() + entry := newTable.remove(path) + + // Ensure there was a match + if entry == nil { + return false, fmt.Errorf("no matching backend") + } + + c.removeAuditReloadFunc(entry) + + // When unmounting all entries the JSON code will load back up from storage + // as a nil slice, which kills tests...just set it nil explicitly + if len(newTable.Entries) == 0 { + newTable.Entries = nil + } + + // Update the audit table + if err := c.persistAudit(ctx, newTable, entry.Local); err != nil { + return true, errors.New("failed to update audit table") + } + + c.audit = newTable + + // Unmount the backend + c.auditBroker.Deregister(path) + if c.logger.IsInfo() { + c.logger.Info("disabled audit backend", "path", path) + } + + return true, nil +} + +// loadAudits is invoked as part of postUnseal to load the audit table +func (c *Core) loadAudits(ctx context.Context) error { + auditTable := &MountTable{} + localAuditTable := &MountTable{} + + // Load the existing audit table + raw, err := c.barrier.Get(ctx, coreAuditConfigPath) + if err != nil { + c.logger.Error("failed to read audit table", "error", err) + return errLoadAuditFailed + } + rawLocal, err := c.barrier.Get(ctx, coreLocalAuditConfigPath) + if err != nil { + c.logger.Error("failed to read local audit table", "error", err) + return errLoadAuditFailed + } + + c.auditLock.Lock() + defer c.auditLock.Unlock() + + if raw != nil { + if err := jsonutil.DecodeJSON(raw.Value, auditTable); err != nil { + c.logger.Error("failed to decode audit table", "error", err) + return errLoadAuditFailed + } + c.audit = auditTable + } + + var needPersist bool + if c.audit == nil { + c.audit = defaultAuditTable() + needPersist = true + } + + if rawLocal != nil { + if err := jsonutil.DecodeJSON(rawLocal.Value, localAuditTable); err != nil { + c.logger.Error("failed to decode local audit table", "error", err) + return errLoadAuditFailed + } + if localAuditTable != nil && len(localAuditTable.Entries) > 0 { + c.audit.Entries = append(c.audit.Entries, localAuditTable.Entries...) + } + } + + // Upgrade to typed auth table + if c.audit.Type == "" { + c.audit.Type = auditTableType + needPersist = true + } + + // Upgrade to table-scoped entries + for _, entry := range c.audit.Entries { + if entry.Table == "" { + entry.Table = c.audit.Type + needPersist = true + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor("audit_" + entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + needPersist = true + } + } + + if !needPersist { + return nil + } + + if err := c.persistAudit(ctx, c.audit, false); err != nil { + return errLoadAuditFailed + } + return nil +} + +// persistAudit is used to persist the audit table after modification +func (c *Core) persistAudit(ctx context.Context, table *MountTable, localOnly bool) error { + if table.Type != auditTableType { + c.logger.Error("given table to persist has wrong type", "actual_type", table.Type, "expected_type", auditTableType) + return fmt.Errorf("invalid table type given, not persisting") + } + + for _, entry := range table.Entries { + if entry.Table != table.Type { + c.logger.Error("given entry to persist in audit table has wrong table value", "path", entry.Path, "entry_table_type", entry.Table, "actual_type", table.Type) + return fmt.Errorf("invalid audit entry found, not persisting") + } + } + + nonLocalAudit := &MountTable{ + Type: auditTableType, + } + + localAudit := &MountTable{ + Type: auditTableType, + } + + for _, entry := range table.Entries { + if entry.Local { + localAudit.Entries = append(localAudit.Entries, entry) + } else { + nonLocalAudit.Entries = append(nonLocalAudit.Entries, entry) + } + } + + if !localOnly { + // Marshal the table + compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalAudit, nil) + if err != nil { + c.logger.Error("failed to encode and/or compress audit table", "error", err) + return err + } + + // Create an entry + entry := &Entry{ + Key: coreAuditConfigPath, + Value: compressedBytes, + } + + // Write to the physical backend + if err := c.barrier.Put(ctx, entry); err != nil { + c.logger.Error("failed to persist audit table", "error", err) + return err + } + } + + // Repeat with local audit + compressedBytes, err := jsonutil.EncodeJSONAndCompress(localAudit, nil) + if err != nil { + c.logger.Error("failed to encode and/or compress local audit table", "error", err) + return err + } + + entry := &Entry{ + Key: coreLocalAuditConfigPath, + Value: compressedBytes, + } + + if err := c.barrier.Put(ctx, entry); err != nil { + c.logger.Error("failed to persist local audit table", "error", err) + return err + } + + return nil +} + +// setupAudit is invoked after we've loaded the audit able to +// initialize the audit backends +func (c *Core) setupAudits(ctx context.Context) error { + broker := NewAuditBroker(c.logger.ResetNamed("audit")) + + c.auditLock.Lock() + defer c.auditLock.Unlock() + + var successCount int + + for _, entry := range c.audit.Entries { + // Create a barrier view using the UUID + viewPath := auditBarrierPrefix + entry.UUID + "/" + view := NewBarrierView(c.barrier, viewPath) + + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + c.postUnsealFuncs = append(c.postUnsealFuncs, func() { + view.setReadOnlyErr(nil) + }) + + // Initialize the backend + backend, err := c.newAuditBackend(ctx, entry, view, entry.Options) + if err != nil { + c.logger.Error("failed to create audit entry", "path", entry.Path, "error", err) + continue + } + if backend == nil { + c.logger.Error("created audit entry was nil", "path", entry.Path, "type", entry.Type) + continue + } + + // Mount the backend + broker.Register(entry.Path, backend, view) + + successCount += 1 + } + + if len(c.audit.Entries) > 0 && successCount == 0 { + return errLoadAuditFailed + } + + c.auditBroker = broker + return nil +} + +// teardownAudit is used before we seal the vault to reset the audit +// backends to their unloaded state. This is reversed by loadAudits. +func (c *Core) teardownAudits() error { + c.auditLock.Lock() + defer c.auditLock.Unlock() + + if c.audit != nil { + for _, entry := range c.audit.Entries { + c.removeAuditReloadFunc(entry) + } + } + + c.audit = nil + c.auditBroker = nil + return nil +} + +// removeAuditReloadFunc removes the reload func from the working set. The +// audit lock needs to be held before calling this. +func (c *Core) removeAuditReloadFunc(entry *MountEntry) { + switch entry.Type { + case "file": + key := "audit_file|" + entry.Path + c.reloadFuncsLock.Lock() + + if c.logger.IsDebug() { + c.logger.ResetNamed("audit").Debug("removing reload function", "path", entry.Path) + } + + delete(c.reloadFuncs, key) + + c.reloadFuncsLock.Unlock() + } +} + +// newAuditBackend is used to create and configure a new audit backend by name +func (c *Core) newAuditBackend(ctx context.Context, entry *MountEntry, view logical.Storage, conf map[string]string) (audit.Backend, error) { + f, ok := c.auditBackends[entry.Type] + if !ok { + return nil, fmt.Errorf("unknown backend type: %q", entry.Type) + } + saltConfig := &salt.Config{ + HMAC: sha256.New, + HMACType: "hmac-sha256", + Location: salt.DefaultLocation, + } + + be, err := f(ctx, &audit.BackendConfig{ + SaltView: view, + SaltConfig: saltConfig, + Config: conf, + }) + if err != nil { + return nil, err + } + if be == nil { + return nil, fmt.Errorf("nil backend returned from %q factory function", entry.Type) + } + + auditLogger := c.logger.ResetNamed("audit") + + switch entry.Type { + case "file": + key := "audit_file|" + entry.Path + + c.reloadFuncsLock.Lock() + + if auditLogger.IsDebug() { + auditLogger.Debug("adding reload function", "path", entry.Path) + if entry.Options != nil { + auditLogger.Debug("file backend options", "path", entry.Path, "file_path", entry.Options["file_path"]) + } + } + + c.reloadFuncs[key] = append(c.reloadFuncs[key], func(map[string]interface{}) error { + if auditLogger.IsInfo() { + auditLogger.Info("reloading file audit backend", "path", entry.Path) + } + return be.Reload(ctx) + }) + + c.reloadFuncsLock.Unlock() + case "socket": + if auditLogger.IsDebug() { + if entry.Options != nil { + auditLogger.Debug("socket backend options", "path", entry.Path, "address", entry.Options["address"], "socket type", entry.Options["socket_type"]) + } + } + case "syslog": + if auditLogger.IsDebug() { + if entry.Options != nil { + auditLogger.Debug("syslog backend options", "path", entry.Path, "facility", entry.Options["facility"], "tag", entry.Options["tag"]) + } + } + } + + return be, err +} + +// defaultAuditTable creates a default audit table +func defaultAuditTable() *MountTable { + table := &MountTable{ + Type: auditTableType, + } + return table +} diff --git a/vendor/github.com/hashicorp/vault/vault/audit_broker.go b/vendor/github.com/hashicorp/vault/vault/audit_broker.go new file mode 100644 index 0000000..ae6f48e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/audit_broker.go @@ -0,0 +1,200 @@ +package vault + +import ( + "context" + "fmt" + "sync" + "time" + + metrics "github.com/armon/go-metrics" + log "github.com/hashicorp/go-hclog" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/audit" +) + +type backendEntry struct { + backend audit.Backend + view *BarrierView +} + +// AuditBroker is used to provide a single ingest interface to auditable +// events given that multiple backends may be configured. +type AuditBroker struct { + sync.RWMutex + backends map[string]backendEntry + logger log.Logger +} + +// NewAuditBroker creates a new audit broker +func NewAuditBroker(log log.Logger) *AuditBroker { + b := &AuditBroker{ + backends: make(map[string]backendEntry), + logger: log, + } + return b +} + +// Register is used to add new audit backend to the broker +func (a *AuditBroker) Register(name string, b audit.Backend, v *BarrierView) { + a.Lock() + defer a.Unlock() + a.backends[name] = backendEntry{ + backend: b, + view: v, + } +} + +// Deregister is used to remove an audit backend from the broker +func (a *AuditBroker) Deregister(name string) { + a.Lock() + defer a.Unlock() + delete(a.backends, name) +} + +// IsRegistered is used to check if a given audit backend is registered +func (a *AuditBroker) IsRegistered(name string) bool { + a.RLock() + defer a.RUnlock() + _, ok := a.backends[name] + return ok +} + +// GetHash returns a hash using the salt of the given backend +func (a *AuditBroker) GetHash(ctx context.Context, name string, input string) (string, error) { + a.RLock() + defer a.RUnlock() + be, ok := a.backends[name] + if !ok { + return "", fmt.Errorf("unknown audit backend %q", name) + } + + return be.backend.GetHash(ctx, input) +} + +// LogRequest is used to ensure all the audit backends have an opportunity to +// log the given request and that *at least one* succeeds. +func (a *AuditBroker) LogRequest(ctx context.Context, in *audit.LogInput, headersConfig *AuditedHeadersConfig) (ret error) { + defer metrics.MeasureSince([]string{"audit", "log_request"}, time.Now()) + a.RLock() + defer a.RUnlock() + + var retErr *multierror.Error + + defer func() { + if r := recover(); r != nil { + a.logger.Error("panic during logging", "request_path", in.Request.Path, "error", r) + retErr = multierror.Append(retErr, fmt.Errorf("panic generating audit log")) + } + + ret = retErr.ErrorOrNil() + failure := float32(0.0) + if ret != nil { + failure = 1.0 + } + metrics.IncrCounter([]string{"audit", "log_request_failure"}, failure) + }() + + // All logged requests must have an identifier + //if req.ID == "" { + // a.logger.Error("missing identifier in request object", "request_path", req.Path) + // retErr = multierror.Append(retErr, fmt.Errorf("missing identifier in request object: %s", req.Path)) + // return + //} + + headers := in.Request.Headers + defer func() { + in.Request.Headers = headers + }() + + // Ensure at least one backend logs + anyLogged := false + for name, be := range a.backends { + in.Request.Headers = nil + transHeaders, thErr := headersConfig.ApplyConfig(ctx, headers, be.backend.GetHash) + if thErr != nil { + a.logger.Error("backend failed to include headers", "backend", name, "error", thErr) + continue + } + in.Request.Headers = transHeaders + + start := time.Now() + lrErr := be.backend.LogRequest(ctx, in) + metrics.MeasureSince([]string{"audit", name, "log_request"}, start) + if lrErr != nil { + a.logger.Error("backend failed to log request", "backend", name, "error", lrErr) + } else { + anyLogged = true + } + } + if !anyLogged && len(a.backends) > 0 { + retErr = multierror.Append(retErr, fmt.Errorf("no audit backend succeeded in logging the request")) + } + + return retErr.ErrorOrNil() +} + +// LogResponse is used to ensure all the audit backends have an opportunity to +// log the given response and that *at least one* succeeds. +func (a *AuditBroker) LogResponse(ctx context.Context, in *audit.LogInput, headersConfig *AuditedHeadersConfig) (ret error) { + defer metrics.MeasureSince([]string{"audit", "log_response"}, time.Now()) + a.RLock() + defer a.RUnlock() + + var retErr *multierror.Error + + defer func() { + if r := recover(); r != nil { + a.logger.Error("panic during logging", "request_path", in.Request.Path, "error", r) + retErr = multierror.Append(retErr, fmt.Errorf("panic generating audit log")) + } + + ret = retErr.ErrorOrNil() + + failure := float32(0.0) + if ret != nil { + failure = 1.0 + } + metrics.IncrCounter([]string{"audit", "log_response_failure"}, failure) + }() + + headers := in.Request.Headers + defer func() { + in.Request.Headers = headers + }() + + // Ensure at least one backend logs + anyLogged := false + for name, be := range a.backends { + in.Request.Headers = nil + transHeaders, thErr := headersConfig.ApplyConfig(ctx, headers, be.backend.GetHash) + if thErr != nil { + a.logger.Error("backend failed to include headers", "backend", name, "error", thErr) + continue + } + in.Request.Headers = transHeaders + + start := time.Now() + lrErr := be.backend.LogResponse(ctx, in) + metrics.MeasureSince([]string{"audit", name, "log_response"}, start) + if lrErr != nil { + a.logger.Error("backend failed to log response", "backend", name, "error", lrErr) + } else { + anyLogged = true + } + } + if !anyLogged && len(a.backends) > 0 { + retErr = multierror.Append(retErr, fmt.Errorf("no audit backend succeeded in logging the response")) + } + + return retErr.ErrorOrNil() +} + +func (a *AuditBroker) Invalidate(ctx context.Context, key string) { + // For now we ignore the key as this would only apply to salts. We just + // sort of brute force it on each one. + a.Lock() + defer a.Unlock() + for _, be := range a.backends { + be.backend.Invalidate(ctx) + } +} diff --git a/vendor/github.com/hashicorp/vault/vault/audited_headers.go b/vendor/github.com/hashicorp/vault/vault/audited_headers.go new file mode 100644 index 0000000..ca8383e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/audited_headers.go @@ -0,0 +1,162 @@ +package vault + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/logical" +) + +// N.B.: While we could use textproto to get the canonical mime header, HTTP/2 +// requires all headers to be converted to lower case, so we just do that. + +const ( + // Key used in the BarrierView to store and retrieve the header config + auditedHeadersEntry = "audited-headers" + // Path used to create a sub view off of BarrierView + auditedHeadersSubPath = "audited-headers-config/" +) + +type auditedHeaderSettings struct { + HMAC bool `json:"hmac"` +} + +// AuditedHeadersConfig is used by the Audit Broker to write only approved +// headers to the audit logs. It uses a BarrierView to persist the settings. +type AuditedHeadersConfig struct { + Headers map[string]*auditedHeaderSettings + + view *BarrierView + sync.RWMutex +} + +// add adds or overwrites a header in the config and updates the barrier view +func (a *AuditedHeadersConfig) add(ctx context.Context, header string, hmac bool) error { + if header == "" { + return fmt.Errorf("header value cannot be empty") + } + + // Grab a write lock + a.Lock() + defer a.Unlock() + + if a.Headers == nil { + a.Headers = make(map[string]*auditedHeaderSettings, 1) + } + + a.Headers[strings.ToLower(header)] = &auditedHeaderSettings{hmac} + entry, err := logical.StorageEntryJSON(auditedHeadersEntry, a.Headers) + if err != nil { + return errwrap.Wrapf("failed to persist audited headers config: {{err}}", err) + } + + if err := a.view.Put(ctx, entry); err != nil { + return errwrap.Wrapf("failed to persist audited headers config: {{err}}", err) + } + + return nil +} + +// remove deletes a header out of the header config and updates the barrier view +func (a *AuditedHeadersConfig) remove(ctx context.Context, header string) error { + if header == "" { + return fmt.Errorf("header value cannot be empty") + } + + // Grab a write lock + a.Lock() + defer a.Unlock() + + // Nothing to delete + if len(a.Headers) == 0 { + return nil + } + + delete(a.Headers, strings.ToLower(header)) + entry, err := logical.StorageEntryJSON(auditedHeadersEntry, a.Headers) + if err != nil { + return errwrap.Wrapf("failed to persist audited headers config: {{err}}", err) + } + + if err := a.view.Put(ctx, entry); err != nil { + return errwrap.Wrapf("failed to persist audited headers config: {{err}}", err) + } + + return nil +} + +// ApplyConfig returns a map of approved headers and their values, either +// hmac'ed or plaintext +func (a *AuditedHeadersConfig) ApplyConfig(ctx context.Context, headers map[string][]string, hashFunc func(context.Context, string) (string, error)) (result map[string][]string, retErr error) { + // Grab a read lock + a.RLock() + defer a.RUnlock() + + // Make a copy of the incoming headers with everything lower so we can + // case-insensitively compare + lowerHeaders := make(map[string][]string, len(headers)) + for k, v := range headers { + lowerHeaders[strings.ToLower(k)] = v + } + + result = make(map[string][]string, len(a.Headers)) + for key, settings := range a.Headers { + if val, ok := lowerHeaders[key]; ok { + // copy the header values so we don't overwrite them + hVals := make([]string, len(val)) + copy(hVals, val) + + // Optionally hmac the values + if settings.HMAC { + for i, el := range hVals { + hVal, err := hashFunc(ctx, el) + if err != nil { + return nil, err + } + hVals[i] = hVal + } + } + + result[key] = hVals + } + } + + return result, nil +} + +// Initialize the headers config by loading from the barrier view +func (c *Core) setupAuditedHeadersConfig(ctx context.Context) error { + // Create a sub-view + view := c.systemBarrierView.SubView(auditedHeadersSubPath) + + // Create the config + out, err := view.Get(ctx, auditedHeadersEntry) + if err != nil { + return errwrap.Wrapf("failed to read config: {{err}}", err) + } + + headers := make(map[string]*auditedHeaderSettings) + if out != nil { + err = out.DecodeJSON(&headers) + if err != nil { + return err + } + } + + // Ensure that we are able to case-sensitively access the headers; + // necessary for the upgrade case + lowerHeaders := make(map[string]*auditedHeaderSettings, len(headers)) + for k, v := range headers { + lowerHeaders[strings.ToLower(k)] = v + } + + c.auditedHeaders = &AuditedHeadersConfig{ + Headers: lowerHeaders, + view: view, + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/auth.go b/vendor/github.com/hashicorp/vault/vault/auth.go new file mode 100644 index 0000000..a50320d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/auth.go @@ -0,0 +1,625 @@ +package vault + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" +) + +const ( + // coreAuthConfigPath is used to store the auth configuration. + // Auth configuration is protected within the Vault itself, which means it + // can only be viewed or modified after an unseal. + coreAuthConfigPath = "core/auth" + + // coreLocalAuthConfigPath is used to store credential configuration for + // local (non-replicated) mounts + coreLocalAuthConfigPath = "core/local-auth" + + // credentialBarrierPrefix is the prefix to the UUID used in the + // barrier view for the credential backends. + credentialBarrierPrefix = "auth/" + + // credentialRoutePrefix is the mount prefix used for the router + credentialRoutePrefix = "auth/" + + // credentialTableType is the value we expect to find for the credential + // table and corresponding entries + credentialTableType = "auth" +) + +var ( + // errLoadAuthFailed if loadCredentials encounters an error + errLoadAuthFailed = errors.New("failed to setup auth table") + + // credentialAliases maps old backend names to new backend names, allowing us + // to move/rename backends but maintain backwards compatibility + credentialAliases = map[string]string{"aws-ec2": "aws"} +) + +// enableCredential is used to enable a new credential backend +func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(entry.Path, "/") { + entry.Path += "/" + } + + // Ensure there is a name + if entry.Path == "/" { + return fmt.Errorf("backend path must be specified") + } + + c.authLock.Lock() + defer c.authLock.Unlock() + + // Look for matching name + for _, ent := range c.auth.Entries { + switch { + // Existing is oauth/github/ new is oauth/ or + // existing is oauth/ and new is oauth/github/ + case strings.HasPrefix(ent.Path, entry.Path): + fallthrough + case strings.HasPrefix(entry.Path, ent.Path): + return logical.CodedError(409, "path is already in use") + } + } + + // Ensure the token backend is a singleton + if entry.Type == "token" { + return fmt.Errorf("token credential backend cannot be instantiated") + } + + if conflict := c.router.MountConflict(credentialRoutePrefix + entry.Path); conflict != "" { + return logical.CodedError(409, fmt.Sprintf("existing mount at %s", conflict)) + } + + // Generate a new UUID and view + if entry.UUID == "" { + entryUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.UUID = entryUUID + } + if entry.BackendAwareUUID == "" { + bUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.BackendAwareUUID = bUUID + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor("auth_" + entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + } + // Sync values to the cache + entry.SyncCache() + + viewPath := credentialBarrierPrefix + entry.UUID + "/" + view := NewBarrierView(c.barrier, viewPath) + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + defer view.setReadOnlyErr(nil) + + var err error + var backend logical.Backend + sysView := c.mountEntrySysView(entry) + + // Create the new backend + backend, err = c.newCredentialBackend(ctx, entry, sysView, view) + if err != nil { + return err + } + if backend == nil { + return fmt.Errorf("nil backend returned from %q factory", entry.Type) + } + + // Check for the correct backend type + backendType := backend.Type() + if entry.Type == "plugin" && backendType != logical.TypeCredential { + return fmt.Errorf("cannot mount %q of type %q as an auth method", entry.Config.PluginName, backendType) + } + + // Update the auth table + newTable := c.auth.shallowClone() + newTable.Entries = append(newTable.Entries, entry) + if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil { + return errors.New("failed to update auth table") + } + + c.auth = newTable + + path := credentialRoutePrefix + entry.Path + if err := c.router.Mount(backend, path, entry, view); err != nil { + return err + } + + if c.logger.IsInfo() { + c.logger.Info("enabled credential backend", "path", entry.Path, "type", entry.Type) + } + return nil +} + +// disableCredential is used to disable an existing credential backend; the +// boolean indicates if it existed +func (c *Core) disableCredential(ctx context.Context, path string) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(path, "/") { + path += "/" + } + + // Ensure the token backend is not affected + if path == "token/" { + return fmt.Errorf("token credential backend cannot be disabled") + } + + // Store the view for this backend + fullPath := credentialRoutePrefix + path + view := c.router.MatchingStorageByAPIPath(fullPath) + if view == nil { + return fmt.Errorf("no matching backend %q", fullPath) + } + + // Get the backend/mount entry for this path, used to remove ignored + // replication prefixes + backend := c.router.MatchingBackend(fullPath) + entry := c.router.MatchingMountEntry(fullPath) + + // Mark the entry as tainted + if err := c.taintCredEntry(ctx, path); err != nil { + return err + } + + // Taint the router path to prevent routing + if err := c.router.Taint(fullPath); err != nil { + return err + } + + if backend != nil { + // Revoke credentials from this path + if err := c.expiration.RevokePrefix(fullPath); err != nil { + return err + } + + // Call cleanup function if it exists + backend.Cleanup(ctx) + } + + // Unmount the backend + if err := c.router.Unmount(ctx, fullPath); err != nil { + return err + } + + switch { + case entry.Local, !c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary): + // Have writable storage, remove the whole thing + if err := logical.ClearView(ctx, view); err != nil { + c.logger.Error("failed to clear view for path being unmounted", "error", err, "path", path) + return err + } + + } + + // Remove the mount table entry + if err := c.removeCredEntry(ctx, path); err != nil { + return err + } + if c.logger.IsInfo() { + c.logger.Info("disabled credential backend", "path", path) + } + return nil +} + +// removeCredEntry is used to remove an entry in the auth table +func (c *Core) removeCredEntry(ctx context.Context, path string) error { + c.authLock.Lock() + defer c.authLock.Unlock() + + // Taint the entry from the auth table + newTable := c.auth.shallowClone() + entry := newTable.remove(path) + if entry == nil { + c.logger.Error("nil entry found removing entry in auth table", "path", path) + return logical.CodedError(500, "failed to remove entry in auth table") + } + + // Update the auth table + if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil { + return errors.New("failed to update auth table") + } + + c.auth = newTable + + return nil +} + +// remountCredEntryForce takes a copy of the mount entry for the path and fully +// unmounts and remounts the backend to pick up any changes, such as filtered +// paths +func (c *Core) remountCredEntryForce(ctx context.Context, path string) error { + fullPath := credentialRoutePrefix + path + me := c.router.MatchingMountEntry(fullPath) + if me == nil { + return fmt.Errorf("cannot find mount for path %q", path) + } + + me, err := me.Clone() + if err != nil { + return err + } + + if err := c.disableCredential(ctx, path); err != nil { + return err + } + return c.enableCredential(ctx, me) +} + +// taintCredEntry is used to mark an entry in the auth table as tainted +func (c *Core) taintCredEntry(ctx context.Context, path string) error { + c.authLock.Lock() + defer c.authLock.Unlock() + + // Taint the entry from the auth table + // We do this on the original since setting the taint operates + // on the entries which a shallow clone shares anyways + entry := c.auth.setTaint(path, true) + + // Ensure there was a match + if entry == nil { + return fmt.Errorf("no matching backend") + } + + // Update the auth table + if err := c.persistAuth(ctx, c.auth, &entry.Local); err != nil { + return errors.New("failed to update auth table") + } + + return nil +} + +// loadCredentials is invoked as part of postUnseal to load the auth table +func (c *Core) loadCredentials(ctx context.Context) error { + authTable := &MountTable{} + localAuthTable := &MountTable{} + + // Load the existing mount table + raw, err := c.barrier.Get(ctx, coreAuthConfigPath) + if err != nil { + c.logger.Error("failed to read auth table", "error", err) + return errLoadAuthFailed + } + rawLocal, err := c.barrier.Get(ctx, coreLocalAuthConfigPath) + if err != nil { + c.logger.Error("failed to read local auth table", "error", err) + return errLoadAuthFailed + } + + c.authLock.Lock() + defer c.authLock.Unlock() + + if raw != nil { + if err := jsonutil.DecodeJSON(raw.Value, authTable); err != nil { + c.logger.Error("failed to decode auth table", "error", err) + return errLoadAuthFailed + } + c.auth = authTable + } + + var needPersist bool + if c.auth == nil { + c.auth = c.defaultAuthTable() + needPersist = true + } + + if rawLocal != nil { + if err := jsonutil.DecodeJSON(rawLocal.Value, localAuthTable); err != nil { + c.logger.Error("failed to decode local auth table", "error", err) + return errLoadAuthFailed + } + if localAuthTable != nil && len(localAuthTable.Entries) > 0 { + c.auth.Entries = append(c.auth.Entries, localAuthTable.Entries...) + } + } + + // Upgrade to typed auth table + if c.auth.Type == "" { + c.auth.Type = credentialTableType + needPersist = true + } + + // Upgrade to table-scoped entries + for _, entry := range c.auth.Entries { + if entry.Table == "" { + entry.Table = c.auth.Type + needPersist = true + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor("auth_" + entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + needPersist = true + } + if entry.BackendAwareUUID == "" { + bUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.BackendAwareUUID = bUUID + needPersist = true + } + + // Sync values to the cache + entry.SyncCache() + } + + if !needPersist { + return nil + } + + if err := c.persistAuth(ctx, c.auth, nil); err != nil { + c.logger.Error("failed to persist auth table", "error", err) + return errLoadAuthFailed + } + return nil +} + +// persistAuth is used to persist the auth table after modification +func (c *Core) persistAuth(ctx context.Context, table *MountTable, local *bool) error { + if table.Type != credentialTableType { + c.logger.Error("given table to persist has wrong type", "actual_type", table.Type, "expected_type", credentialTableType) + return fmt.Errorf("invalid table type given, not persisting") + } + + for _, entry := range table.Entries { + if entry.Table != table.Type { + c.logger.Error("given entry to persist in auth table has wrong table value", "path", entry.Path, "entry_table_type", entry.Table, "actual_type", table.Type) + return fmt.Errorf("invalid auth entry found, not persisting") + } + } + + nonLocalAuth := &MountTable{ + Type: credentialTableType, + } + + localAuth := &MountTable{ + Type: credentialTableType, + } + + for _, entry := range table.Entries { + if entry.Local { + localAuth.Entries = append(localAuth.Entries, entry) + } else { + nonLocalAuth.Entries = append(nonLocalAuth.Entries, entry) + } + } + + writeTable := func(mt *MountTable, path string) error { + // Encode the mount table into JSON and compress it (lzw). + compressedBytes, err := jsonutil.EncodeJSONAndCompress(mt, nil) + if err != nil { + c.logger.Error("failed to encode or compress auth mount table", "error", err) + return err + } + + // Create an entry + entry := &Entry{ + Key: path, + Value: compressedBytes, + } + + // Write to the physical backend + if err := c.barrier.Put(ctx, entry); err != nil { + c.logger.Error("failed to persist auth mount table", "error", err) + return err + } + return nil + } + + var err error + switch { + case local == nil: + // Write non-local mounts + err := writeTable(nonLocalAuth, coreAuthConfigPath) + if err != nil { + return err + } + + // Write local mounts + err = writeTable(localAuth, coreLocalAuthConfigPath) + if err != nil { + return err + } + case *local: + err = writeTable(localAuth, coreLocalAuthConfigPath) + default: + err = writeTable(nonLocalAuth, coreAuthConfigPath) + } + + return err +} + +// setupCredentials is invoked after we've loaded the auth table to +// initialize the credential backends and setup the router +func (c *Core) setupCredentials(ctx context.Context) error { + var err error + var persistNeeded bool + var backendType logical.BackendType + + c.authLock.Lock() + defer c.authLock.Unlock() + + for _, entry := range c.auth.Entries { + var backend logical.Backend + + // Create a barrier view using the UUID + viewPath := credentialBarrierPrefix + entry.UUID + "/" + view := NewBarrierView(c.barrier, viewPath) + + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + if strutil.StrListContains(singletonMounts, entry.Type) { + defer view.setReadOnlyErr(nil) + } else { + c.postUnsealFuncs = append(c.postUnsealFuncs, func() { + view.setReadOnlyErr(nil) + }) + } + + // Initialize the backend + sysView := c.mountEntrySysView(entry) + + backend, err = c.newCredentialBackend(ctx, entry, sysView, view) + if err != nil { + c.logger.Error("failed to create credential entry", "path", entry.Path, "error", err) + if entry.Type == "plugin" { + // If we encounter an error instantiating the backend due to an error, + // skip backend initialization but register the entry to the mount table + // to preserve storage and path. + c.logger.Warn("skipping plugin-based credential entry", "path", entry.Path) + goto ROUTER_MOUNT + } + return errLoadAuthFailed + } + if backend == nil { + return fmt.Errorf("nil backend returned from %q factory", entry.Type) + } + + // Check for the correct backend type + backendType = backend.Type() + if entry.Type == "plugin" && backendType != logical.TypeCredential { + return fmt.Errorf("cannot mount %q of type %q as an auth backend", entry.Config.PluginName, backendType) + } + + ROUTER_MOUNT: + // Mount the backend + path := credentialRoutePrefix + entry.Path + err = c.router.Mount(backend, path, entry, view) + if err != nil { + c.logger.Error("failed to mount auth entry", "path", entry.Path, "error", err) + return errLoadAuthFailed + } + + // Ensure the path is tainted if set in the mount table + if entry.Tainted { + c.router.Taint(path) + } + + // Check if this is the token store + if entry.Type == "token" { + c.tokenStore = backend.(*TokenStore) + + // this is loaded *after* the normal mounts, including cubbyhole + c.router.tokenStoreSaltFunc = c.tokenStore.Salt + c.tokenStore.cubbyholeBackend = c.router.MatchingBackend("cubbyhole/").(*CubbyholeBackend) + } + } + + if persistNeeded { + return c.persistAuth(ctx, c.auth, nil) + } + + return nil +} + +// teardownCredentials is used before we seal the vault to reset the credential +// backends to their unloaded state. This is reversed by loadCredentials. +func (c *Core) teardownCredentials(ctx context.Context) error { + c.authLock.Lock() + defer c.authLock.Unlock() + + if c.auth != nil { + authTable := c.auth.shallowClone() + for _, e := range authTable.Entries { + backend := c.router.MatchingBackend(credentialRoutePrefix + e.Path) + if backend != nil { + backend.Cleanup(ctx) + } + } + } + + c.auth = nil + c.tokenStore = nil + return nil +} + +// newCredentialBackend is used to create and configure a new credential backend by name +func (c *Core) newCredentialBackend(ctx context.Context, entry *MountEntry, sysView logical.SystemView, view logical.Storage) (logical.Backend, error) { + t := entry.Type + if alias, ok := credentialAliases[t]; ok { + t = alias + } + f, ok := c.credentialBackends[t] + if !ok { + return nil, fmt.Errorf("unknown backend type: %q", t) + } + + // Set up conf to pass in plugin_name + conf := make(map[string]string, len(entry.Options)+1) + for k, v := range entry.Options { + conf[k] = v + } + if entry.Config.PluginName != "" { + conf["plugin_name"] = entry.Config.PluginName + } + + config := &logical.BackendConfig{ + StorageView: view, + Logger: c.logger.ResetNamed(fmt.Sprintf("auth.%s.%s", t, entry.Accessor)), + Config: conf, + System: sysView, + BackendUUID: entry.BackendAwareUUID, + } + + b, err := f(ctx, config) + if err != nil { + return nil, err + } + + return b, nil +} + +// defaultAuthTable creates a default auth table +func (c *Core) defaultAuthTable() *MountTable { + table := &MountTable{ + Type: credentialTableType, + } + tokenUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not generate UUID for default auth table token entry: %v", err)) + } + tokenAccessor, err := c.generateMountAccessor("auth_token") + if err != nil { + panic(fmt.Sprintf("could not generate accessor for default auth table token entry: %v", err)) + } + tokenBackendUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create identity backend UUID: %v", err)) + } + tokenAuth := &MountEntry{ + Table: credentialTableType, + Path: "token/", + Type: "token", + Description: "token based credentials", + UUID: tokenUUID, + Accessor: tokenAccessor, + BackendAwareUUID: tokenBackendUUID, + } + table.Entries = append(table.Entries, tokenAuth) + return table +} diff --git a/vendor/github.com/hashicorp/vault/vault/barrier.go b/vendor/github.com/hashicorp/vault/vault/barrier.go new file mode 100644 index 0000000..7f8a313 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier.go @@ -0,0 +1,183 @@ +package vault + +import ( + "context" + "errors" + "time" + + "github.com/hashicorp/vault/logical" +) + +var ( + // ErrBarrierSealed is returned if an operation is performed on + // a sealed barrier. No operation is expected to succeed before unsealing + ErrBarrierSealed = errors.New("Vault is sealed") + + // ErrBarrierAlreadyInit is returned if the barrier is already + // initialized. This prevents a re-initialization. + ErrBarrierAlreadyInit = errors.New("Vault is already initialized") + + // ErrBarrierNotInit is returned if a non-initialized barrier + // is attempted to be unsealed. + ErrBarrierNotInit = errors.New("Vault is not initialized") + + // ErrBarrierInvalidKey is returned if the Unseal key is invalid + ErrBarrierInvalidKey = errors.New("Unseal failed, invalid key") +) + +const ( + // barrierInitPath is the path used to store our init sentinel file + barrierInitPath = "barrier/init" + + // keyringPath is the location of the keyring data. This is encrypted + // by the master key. + keyringPath = "core/keyring" + keyringPrefix = "core/" + + // keyringUpgradePrefix is the path used to store keyring update entries. + // When running in HA mode, the active instance will install the new key + // and re-write the keyring. For standby instances, they need an upgrade + // path from key N to N+1. They cannot just use the master key because + // in the event of a rekey, that master key can no longer decrypt the keyring. + // When key N+1 is installed, we create an entry at "prefix/N" which uses + // encryption key N to provide the N+1 key. The standby instances scan + // for this periodically and refresh their keyring. The upgrade keys + // are deleted after a few minutes, but this provides enough time for the + // standby instances to upgrade without causing any disruption. + keyringUpgradePrefix = "core/upgrade/" + + // masterKeyPath is the location of the master key. This is encrypted + // by the latest key in the keyring. This is only used by standby instances + // to handle the case of a rekey. If the active instance does a rekey, + // the standby instances can no longer reload the keyring since they + // have the old master key. This key can be decrypted if you have the + // keyring to discover the new master key. The new master key is then + // used to reload the keyring itself. + masterKeyPath = "core/master" +) + +// SecurityBarrier is a critical component of Vault. It is used to wrap +// an untrusted physical backend and provide a single point of encryption, +// decryption and checksum verification. The goal is to ensure that any +// data written to the barrier is confidential and that integrity is preserved. +// As a real-world analogy, this is the steel and concrete wrapper around +// a Vault. The barrier should only be Unlockable given its key. +type SecurityBarrier interface { + // Initialized checks if the barrier has been initialized + // and has a master key set. + Initialized(ctx context.Context) (bool, error) + + // Initialize works only if the barrier has not been initialized + // and makes use of the given master key. + Initialize(context.Context, []byte) error + + // GenerateKey is used to generate a new key + GenerateKey() ([]byte, error) + + // KeyLength is used to sanity check a key + KeyLength() (int, int) + + // Sealed checks if the barrier has been unlocked yet. The Barrier + // is not expected to be able to perform any CRUD until it is unsealed. + Sealed() (bool, error) + + // Unseal is used to provide the master key which permits the barrier + // to be unsealed. If the key is not correct, the barrier remains sealed. + Unseal(ctx context.Context, key []byte) error + + // VerifyMaster is used to check if the given key matches the master key + VerifyMaster(key []byte) error + + // SetMasterKey is used to directly set a new master key. This is used in + // replicated scenarios due to the chicken and egg problem of reloading the + // keyring from disk before we have the master key to decrypt it. + SetMasterKey(key []byte) error + + // ReloadKeyring is used to re-read the underlying keyring. + // This is used for HA deployments to ensure the latest keyring + // is present in the leader. + ReloadKeyring(ctx context.Context) error + + // ReloadMasterKey is used to re-read the underlying masterkey. + // This is used for HA deployments to ensure the latest master key + // is available for keyring reloading. + ReloadMasterKey(ctx context.Context) error + + // Seal is used to re-seal the barrier. This requires the barrier to + // be unsealed again to perform any further operations. + Seal() error + + // Rotate is used to create a new encryption key. All future writes + // should use the new key, while old values should still be decryptable. + Rotate(ctx context.Context) (uint32, error) + + // CreateUpgrade creates an upgrade path key to the given term from the previous term + CreateUpgrade(ctx context.Context, term uint32) error + + // DestroyUpgrade destroys the upgrade path key to the given term + DestroyUpgrade(ctx context.Context, term uint32) error + + // CheckUpgrade looks for an upgrade to the current term and installs it + CheckUpgrade(ctx context.Context) (bool, uint32, error) + + // ActiveKeyInfo is used to inform details about the active key + ActiveKeyInfo() (*KeyInfo, error) + + // Rekey is used to change the master key used to protect the keyring + Rekey(context.Context, []byte) error + + // For replication we must send over the keyring, so this must be available + Keyring() (*Keyring, error) + + // SecurityBarrier must provide the storage APIs + BarrierStorage + + // SecurityBarrier must provide the encryption APIs + BarrierEncryptor +} + +// BarrierStorage is the storage only interface required for a Barrier. +type BarrierStorage interface { + // Put is used to insert or update an entry + Put(ctx context.Context, entry *Entry) error + + // Get is used to fetch an entry + Get(ctx context.Context, key string) (*Entry, error) + + // Delete is used to permanently delete an entry + Delete(ctx context.Context, key string) error + + // List is used ot list all the keys under a given + // prefix, up to the next prefix. + List(ctx context.Context, prefix string) ([]string, error) +} + +// BarrierEncryptor is the in memory only interface that does not actually +// use the underlying barrier. It is used for lower level modules like the +// Write-Ahead-Log and Merkle index to allow them to use the barrier. +type BarrierEncryptor interface { + Encrypt(ctx context.Context, key string, plaintext []byte) ([]byte, error) + Decrypt(ctx context.Context, key string, ciphertext []byte) ([]byte, error) +} + +// Entry is used to represent data stored by the security barrier +type Entry struct { + Key string + Value []byte + SealWrap bool +} + +// Logical turns the Entry into a logical storage entry. +func (e *Entry) Logical() *logical.StorageEntry { + return &logical.StorageEntry{ + Key: e.Key, + Value: e.Value, + SealWrap: e.SealWrap, + } +} + +// KeyInfo is used to convey information about the encryption key +type KeyInfo struct { + Term int + InstallTime time.Time +} diff --git a/vendor/github.com/hashicorp/vault/vault/barrier_access.go b/vendor/github.com/hashicorp/vault/vault/barrier_access.go new file mode 100644 index 0000000..84e6e74 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier_access.go @@ -0,0 +1,24 @@ +package vault + +import "context" + +// BarrierEncryptorAccess is a wrapper around BarrierEncryptor that allows Core +// to expose its barrier encrypt/decrypt operations through BarrierEncryptorAccess() +// while restricting the ability to modify Core.barrier itself. +type BarrierEncryptorAccess struct { + barrierEncryptor BarrierEncryptor +} + +var _ BarrierEncryptor = (*BarrierEncryptorAccess)(nil) + +func NewBarrierEncryptorAccess(barrierEncryptor BarrierEncryptor) *BarrierEncryptorAccess { + return &BarrierEncryptorAccess{barrierEncryptor: barrierEncryptor} +} + +func (b *BarrierEncryptorAccess) Encrypt(ctx context.Context, key string, plaintext []byte) ([]byte, error) { + return b.barrierEncryptor.Encrypt(ctx, key, plaintext) +} + +func (b *BarrierEncryptorAccess) Decrypt(ctx context.Context, key string, ciphertext []byte) ([]byte, error) { + return b.barrierEncryptor.Decrypt(ctx, key, ciphertext) +} diff --git a/vendor/github.com/hashicorp/vault/vault/barrier_aes_gcm.go b/vendor/github.com/hashicorp/vault/vault/barrier_aes_gcm.go new file mode 100644 index 0000000..2a6fd7d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier_aes_gcm.go @@ -0,0 +1,894 @@ +package vault + +import ( + "context" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/subtle" + "encoding/binary" + "fmt" + "strings" + "sync" + "time" + + "github.com/armon/go-metrics" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/physical" +) + +const ( + // initialKeyTerm is the hard coded initial key term. This is + // used only for values that are not encrypted with the keyring. + initialKeyTerm = 1 + + // termSize the number of bytes used for the key term. + termSize = 4 +) + +// Versions of the AESGCM storage methodology +const ( + AESGCMVersion1 = 0x1 + AESGCMVersion2 = 0x2 +) + +// barrierInit is the JSON encoded value stored +type barrierInit struct { + Version int // Version is the current format version + Key []byte // Key is the primary encryption key +} + +// Validate AESGCMBarrier satisfies SecurityBarrier interface +var _ SecurityBarrier = &AESGCMBarrier{} + +// AESGCMBarrier is a SecurityBarrier implementation that uses the AES +// cipher core and the Galois Counter Mode block mode. It defaults to +// the golang NONCE default value of 12 and a key size of 256 +// bit. AES-GCM is high performance, and provides both confidentiality +// and integrity. +type AESGCMBarrier struct { + backend physical.Backend + + l sync.RWMutex + sealed bool + + // keyring is used to maintain all of the encryption keys, including + // the active key used for encryption, but also prior keys to allow + // decryption of keys encrypted under previous terms. + keyring *Keyring + + // cache is used to reduce the number of AEAD constructions we do + cache map[uint32]cipher.AEAD + cacheLock sync.RWMutex + + // currentAESGCMVersionByte is prefixed to a message to allow for + // future versioning of barrier implementations. It's var instead + // of const to allow for testing + currentAESGCMVersionByte byte +} + +// NewAESGCMBarrier is used to construct a new barrier that uses +// the provided physical backend for storage. +func NewAESGCMBarrier(physical physical.Backend) (*AESGCMBarrier, error) { + b := &AESGCMBarrier{ + backend: physical, + sealed: true, + cache: make(map[uint32]cipher.AEAD), + currentAESGCMVersionByte: byte(AESGCMVersion2), + } + return b, nil +} + +// Initialized checks if the barrier has been initialized +// and has a master key set. +func (b *AESGCMBarrier) Initialized(ctx context.Context) (bool, error) { + // Read the keyring file + keys, err := b.backend.List(ctx, keyringPrefix) + if err != nil { + return false, errwrap.Wrapf("failed to check for initialization: {{err}}", err) + } + if strutil.StrListContains(keys, "keyring") { + return true, nil + } + + // Fallback, check for the old sentinel file + out, err := b.backend.Get(ctx, barrierInitPath) + if err != nil { + return false, errwrap.Wrapf("failed to check for initialization: {{err}}", err) + } + return out != nil, nil +} + +// Initialize works only if the barrier has not been initialized +// and makes use of the given master key. +func (b *AESGCMBarrier) Initialize(ctx context.Context, key []byte) error { + // Verify the key size + min, max := b.KeyLength() + if len(key) < min || len(key) > max { + return fmt.Errorf("key size must be %d or %d", min, max) + } + + // Check if already initialized + if alreadyInit, err := b.Initialized(ctx); err != nil { + return err + } else if alreadyInit { + return ErrBarrierAlreadyInit + } + + // Generate encryption key + encrypt, err := b.GenerateKey() + if err != nil { + return errwrap.Wrapf("failed to generate encryption key: {{err}}", err) + } + + // Create a new keyring, install the keys + keyring := NewKeyring() + keyring = keyring.SetMasterKey(key) + keyring, err = keyring.AddKey(&Key{ + Term: 1, + Version: 1, + Value: encrypt, + }) + if err != nil { + return errwrap.Wrapf("failed to create keyring: {{err}}", err) + } + return b.persistKeyring(ctx, keyring) +} + +// persistKeyring is used to write out the keyring using the +// master key to encrypt it. +func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) error { + // Create the keyring entry + keyringBuf, err := keyring.Serialize() + defer memzero(keyringBuf) + if err != nil { + return errwrap.Wrapf("failed to serialize keyring: {{err}}", err) + } + + // Create the AES-GCM + gcm, err := b.aeadFromKey(keyring.MasterKey()) + if err != nil { + return err + } + + // Encrypt the barrier init value + value := b.encrypt(keyringPath, initialKeyTerm, gcm, keyringBuf) + + // Create the keyring physical entry + pe := &physical.Entry{ + Key: keyringPath, + Value: value, + } + if err := b.backend.Put(ctx, pe); err != nil { + return errwrap.Wrapf("failed to persist keyring: {{err}}", err) + } + + // Serialize the master key value + key := &Key{ + Term: 1, + Version: 1, + Value: keyring.MasterKey(), + } + keyBuf, err := key.Serialize() + defer memzero(keyBuf) + if err != nil { + return errwrap.Wrapf("failed to serialize master key: {{err}}", err) + } + + // Encrypt the master key + activeKey := keyring.ActiveKey() + aead, err := b.aeadFromKey(activeKey.Value) + if err != nil { + return err + } + value = b.encrypt(masterKeyPath, activeKey.Term, aead, keyBuf) + + // Update the masterKeyPath for standby instances + pe = &physical.Entry{ + Key: masterKeyPath, + Value: value, + } + if err := b.backend.Put(ctx, pe); err != nil { + return errwrap.Wrapf("failed to persist master key: {{err}}", err) + } + return nil +} + +// GenerateKey is used to generate a new key +func (b *AESGCMBarrier) GenerateKey() ([]byte, error) { + // Generate a 256bit key + buf := make([]byte, 2*aes.BlockSize) + _, err := rand.Read(buf) + return buf, err +} + +// KeyLength is used to sanity check a key +func (b *AESGCMBarrier) KeyLength() (int, int) { + return aes.BlockSize, 2 * aes.BlockSize +} + +// Sealed checks if the barrier has been unlocked yet. The Barrier +// is not expected to be able to perform any CRUD until it is unsealed. +func (b *AESGCMBarrier) Sealed() (bool, error) { + b.l.RLock() + defer b.l.RUnlock() + return b.sealed, nil +} + +// VerifyMaster is used to check if the given key matches the master key +func (b *AESGCMBarrier) VerifyMaster(key []byte) error { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return ErrBarrierSealed + } + if subtle.ConstantTimeCompare(key, b.keyring.MasterKey()) != 1 { + return ErrBarrierInvalidKey + } + return nil +} + +// ReloadKeyring is used to re-read the underlying keyring. +// This is used for HA deployments to ensure the latest keyring +// is present in the leader. +func (b *AESGCMBarrier) ReloadKeyring(ctx context.Context) error { + b.l.Lock() + defer b.l.Unlock() + + // Create the AES-GCM + gcm, err := b.aeadFromKey(b.keyring.MasterKey()) + if err != nil { + return err + } + + // Read in the keyring + out, err := b.backend.Get(ctx, keyringPath) + if err != nil { + return errwrap.Wrapf("failed to check for keyring: {{err}}", err) + } + + // Ensure that the keyring exists. This should never happen, + // and indicates something really bad has happened. + if out == nil { + return fmt.Errorf("keyring unexpectedly missing") + } + + // Decrypt the barrier init key + plain, err := b.decrypt(keyringPath, gcm, out.Value) + defer memzero(plain) + if err != nil { + if strings.Contains(err.Error(), "message authentication failed") { + return ErrBarrierInvalidKey + } + return err + } + + // Recover the keyring + keyring, err := DeserializeKeyring(plain) + if err != nil { + return errwrap.Wrapf("keyring deserialization failed: {{err}}", err) + } + + // Setup the keyring and finish + b.keyring = keyring + return nil +} + +// ReloadMasterKey is used to re-read the underlying masterkey. +// This is used for HA deployments to ensure the latest master key +// is available for keyring reloading. +func (b *AESGCMBarrier) ReloadMasterKey(ctx context.Context) error { + // Read the masterKeyPath upgrade + out, err := b.Get(ctx, masterKeyPath) + if err != nil { + return errwrap.Wrapf("failed to read master key path: {{err}}", err) + } + + // The masterKeyPath could be missing (backwards incompatible), + // we can ignore this and attempt to make progress with the current + // master key. + if out == nil { + return nil + } + + defer memzero(out.Value) + + // Deserialize the master key + key, err := DeserializeKey(out.Value) + if err != nil { + return errwrap.Wrapf("failed to deserialize key: {{err}}", err) + } + + b.l.Lock() + defer b.l.Unlock() + + // Check if the master key is the same + if subtle.ConstantTimeCompare(b.keyring.MasterKey(), key.Value) == 1 { + return nil + } + + // Update the master key + oldKeyring := b.keyring + b.keyring = b.keyring.SetMasterKey(key.Value) + oldKeyring.Zeroize(false) + return nil +} + +// Unseal is used to provide the master key which permits the barrier +// to be unsealed. If the key is not correct, the barrier remains sealed. +func (b *AESGCMBarrier) Unseal(ctx context.Context, key []byte) error { + b.l.Lock() + defer b.l.Unlock() + + // Do nothing if already unsealed + if !b.sealed { + return nil + } + + // Create the AES-GCM + gcm, err := b.aeadFromKey(key) + if err != nil { + return err + } + + // Read in the keyring + out, err := b.backend.Get(ctx, keyringPath) + if err != nil { + return errwrap.Wrapf("failed to check for keyring: {{err}}", err) + } + if out != nil { + // Decrypt the barrier init key + plain, err := b.decrypt(keyringPath, gcm, out.Value) + defer memzero(plain) + if err != nil { + if strings.Contains(err.Error(), "message authentication failed") { + return ErrBarrierInvalidKey + } + return err + } + + // Recover the keyring + keyring, err := DeserializeKeyring(plain) + if err != nil { + return errwrap.Wrapf("keyring deserialization failed: {{err}}", err) + } + + // Setup the keyring and finish + b.keyring = keyring + b.sealed = false + return nil + } + + // Read the barrier initialization key + out, err = b.backend.Get(ctx, barrierInitPath) + if err != nil { + return errwrap.Wrapf("failed to check for initialization: {{err}}", err) + } + if out == nil { + return ErrBarrierNotInit + } + + // Decrypt the barrier init key + plain, err := b.decrypt(barrierInitPath, gcm, out.Value) + if err != nil { + if strings.Contains(err.Error(), "message authentication failed") { + return ErrBarrierInvalidKey + } + return err + } + defer memzero(plain) + + // Unmarshal the barrier init + var init barrierInit + if err := jsonutil.DecodeJSON(plain, &init); err != nil { + return fmt.Errorf("failed to unmarshal barrier init file") + } + + // Setup a new keyring, this is for backwards compatibility + keyringNew := NewKeyring() + keyring := keyringNew.SetMasterKey(key) + + // AddKey reuses the master, so we are only zeroizing after this call + defer keyringNew.Zeroize(false) + + keyring, err = keyring.AddKey(&Key{ + Term: 1, + Version: 1, + Value: init.Key, + }) + if err != nil { + return errwrap.Wrapf("failed to create keyring: {{err}}", err) + } + if err := b.persistKeyring(ctx, keyring); err != nil { + return err + } + + // Delete the old barrier entry + if err := b.backend.Delete(ctx, barrierInitPath); err != nil { + return errwrap.Wrapf("failed to delete barrier init file: {{err}}", err) + } + + // Set the vault as unsealed + b.keyring = keyring + b.sealed = false + return nil +} + +// Seal is used to re-seal the barrier. This requires the barrier to +// be unsealed again to perform any further operations. +func (b *AESGCMBarrier) Seal() error { + b.l.Lock() + defer b.l.Unlock() + + // Remove the primary key, and seal the vault + b.cache = make(map[uint32]cipher.AEAD) + b.keyring.Zeroize(true) + b.keyring = nil + b.sealed = true + return nil +} + +// Rotate is used to create a new encryption key. All future writes +// should use the new key, while old values should still be decryptable. +func (b *AESGCMBarrier) Rotate(ctx context.Context) (uint32, error) { + b.l.Lock() + defer b.l.Unlock() + if b.sealed { + return 0, ErrBarrierSealed + } + + // Generate a new key + encrypt, err := b.GenerateKey() + if err != nil { + return 0, errwrap.Wrapf("failed to generate encryption key: {{err}}", err) + } + + // Get the next term + term := b.keyring.ActiveTerm() + newTerm := term + 1 + + // Add a new encryption key + newKeyring, err := b.keyring.AddKey(&Key{ + Term: newTerm, + Version: 1, + Value: encrypt, + }) + if err != nil { + return 0, errwrap.Wrapf("failed to add new encryption key: {{err}}", err) + } + + // Persist the new keyring + if err := b.persistKeyring(ctx, newKeyring); err != nil { + return 0, err + } + + // Swap the keyrings + b.keyring = newKeyring + return newTerm, nil +} + +// CreateUpgrade creates an upgrade path key to the given term from the previous term +func (b *AESGCMBarrier) CreateUpgrade(ctx context.Context, term uint32) error { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return ErrBarrierSealed + } + + // Get the key for this term + termKey := b.keyring.TermKey(term) + buf, err := termKey.Serialize() + defer memzero(buf) + if err != nil { + return err + } + + // Get the AEAD for the previous term + prevTerm := term - 1 + primary, err := b.aeadForTerm(prevTerm) + if err != nil { + return err + } + + key := fmt.Sprintf("%s%d", keyringUpgradePrefix, prevTerm) + value := b.encrypt(key, prevTerm, primary, buf) + // Create upgrade key + pe := &physical.Entry{ + Key: key, + Value: value, + } + return b.backend.Put(ctx, pe) +} + +// DestroyUpgrade destroys the upgrade path key to the given term +func (b *AESGCMBarrier) DestroyUpgrade(ctx context.Context, term uint32) error { + path := fmt.Sprintf("%s%d", keyringUpgradePrefix, term-1) + return b.Delete(ctx, path) +} + +// CheckUpgrade looks for an upgrade to the current term and installs it +func (b *AESGCMBarrier) CheckUpgrade(ctx context.Context) (bool, uint32, error) { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return false, 0, ErrBarrierSealed + } + + // Get the current term + activeTerm := b.keyring.ActiveTerm() + + // Check for an upgrade key + upgrade := fmt.Sprintf("%s%d", keyringUpgradePrefix, activeTerm) + entry, err := b.Get(ctx, upgrade) + if err != nil { + return false, 0, err + } + + // Nothing to do if no upgrade + if entry == nil { + return false, 0, nil + } + + defer memzero(entry.Value) + + // Deserialize the key + key, err := DeserializeKey(entry.Value) + if err != nil { + return false, 0, err + } + + // Upgrade from read lock to write lock + b.l.RUnlock() + defer b.l.RLock() + b.l.Lock() + defer b.l.Unlock() + + // Update the keyring + newKeyring, err := b.keyring.AddKey(key) + if err != nil { + return false, 0, errwrap.Wrapf("failed to add new encryption key: {{err}}", err) + } + b.keyring = newKeyring + + // Done! + return true, key.Term, nil +} + +// ActiveKeyInfo is used to inform details about the active key +func (b *AESGCMBarrier) ActiveKeyInfo() (*KeyInfo, error) { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + // Determine the key install time + term := b.keyring.ActiveTerm() + key := b.keyring.TermKey(term) + + // Return the key info + info := &KeyInfo{ + Term: int(term), + InstallTime: key.InstallTime, + } + return info, nil +} + +// Rekey is used to change the master key used to protect the keyring +func (b *AESGCMBarrier) Rekey(ctx context.Context, key []byte) error { + b.l.Lock() + defer b.l.Unlock() + + newKeyring, err := b.updateMasterKeyCommon(key) + if err != nil { + return err + } + + // Persist the new keyring + if err := b.persistKeyring(ctx, newKeyring); err != nil { + return err + } + + // Swap the keyrings + oldKeyring := b.keyring + b.keyring = newKeyring + oldKeyring.Zeroize(false) + return nil +} + +// SetMasterKey updates the keyring's in-memory master key but does not persist +// anything to storage +func (b *AESGCMBarrier) SetMasterKey(key []byte) error { + b.l.Lock() + defer b.l.Unlock() + + newKeyring, err := b.updateMasterKeyCommon(key) + if err != nil { + return err + } + + // Swap the keyrings + oldKeyring := b.keyring + b.keyring = newKeyring + oldKeyring.Zeroize(false) + return nil +} + +// Performs common tasks related to updating the master key; note that the lock +// must be held before calling this function +func (b *AESGCMBarrier) updateMasterKeyCommon(key []byte) (*Keyring, error) { + if b.sealed { + return nil, ErrBarrierSealed + } + + // Verify the key size + min, max := b.KeyLength() + if len(key) < min || len(key) > max { + return nil, fmt.Errorf("key size must be %d or %d", min, max) + } + + return b.keyring.SetMasterKey(key), nil +} + +// Put is used to insert or update an entry +func (b *AESGCMBarrier) Put(ctx context.Context, entry *Entry) error { + defer metrics.MeasureSince([]string{"barrier", "put"}, time.Now()) + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return ErrBarrierSealed + } + + term := b.keyring.ActiveTerm() + primary, err := b.aeadForTerm(term) + if err != nil { + return err + } + + pe := &physical.Entry{ + Key: entry.Key, + Value: b.encrypt(entry.Key, term, primary, entry.Value), + SealWrap: entry.SealWrap, + } + return b.backend.Put(ctx, pe) +} + +// Get is used to fetch an entry +func (b *AESGCMBarrier) Get(ctx context.Context, key string) (*Entry, error) { + defer metrics.MeasureSince([]string{"barrier", "get"}, time.Now()) + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + // Read the key from the backend + pe, err := b.backend.Get(ctx, key) + if err != nil { + return nil, err + } else if pe == nil { + return nil, nil + } + + // Decrypt the ciphertext + plain, err := b.decryptKeyring(key, pe.Value) + if err != nil { + return nil, errwrap.Wrapf("decryption failed: {{err}}", err) + } + + // Wrap in a logical entry + entry := &Entry{ + Key: key, + Value: plain, + SealWrap: pe.SealWrap, + } + return entry, nil +} + +// Delete is used to permanently delete an entry +func (b *AESGCMBarrier) Delete(ctx context.Context, key string) error { + defer metrics.MeasureSince([]string{"barrier", "delete"}, time.Now()) + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return ErrBarrierSealed + } + + return b.backend.Delete(ctx, key) +} + +// List is used ot list all the keys under a given +// prefix, up to the next prefix. +func (b *AESGCMBarrier) List(ctx context.Context, prefix string) ([]string, error) { + defer metrics.MeasureSince([]string{"barrier", "list"}, time.Now()) + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + return b.backend.List(ctx, prefix) +} + +// aeadForTerm returns the AES-GCM AEAD for the given term +func (b *AESGCMBarrier) aeadForTerm(term uint32) (cipher.AEAD, error) { + // Check for the keyring + keyring := b.keyring + if keyring == nil { + return nil, nil + } + + // Check the cache for the aead + b.cacheLock.RLock() + aead, ok := b.cache[term] + b.cacheLock.RUnlock() + if ok { + return aead, nil + } + + // Read the underlying key + key := keyring.TermKey(term) + if key == nil { + return nil, nil + } + + // Create a new aead + aead, err := b.aeadFromKey(key.Value) + if err != nil { + return nil, err + } + + // Update the cache + b.cacheLock.Lock() + b.cache[term] = aead + b.cacheLock.Unlock() + return aead, nil +} + +// aeadFromKey returns an AES-GCM AEAD using the given key. +func (b *AESGCMBarrier) aeadFromKey(key []byte) (cipher.AEAD, error) { + // Create the AES cipher + aesCipher, err := aes.NewCipher(key) + if err != nil { + return nil, errwrap.Wrapf("failed to create cipher: {{err}}", err) + } + + // Create the GCM mode AEAD + gcm, err := cipher.NewGCM(aesCipher) + if err != nil { + return nil, fmt.Errorf("failed to initialize GCM mode") + } + return gcm, nil +} + +// encrypt is used to encrypt a value +func (b *AESGCMBarrier) encrypt(path string, term uint32, gcm cipher.AEAD, plain []byte) []byte { + // Allocate the output buffer with room for tern, version byte, + // nonce, GCM tag and the plaintext + capacity := termSize + 1 + gcm.NonceSize() + gcm.Overhead() + len(plain) + size := termSize + 1 + gcm.NonceSize() + out := make([]byte, size, capacity) + + // Set the key term + binary.BigEndian.PutUint32(out[:4], term) + + // Set the version byte + out[4] = b.currentAESGCMVersionByte + + // Generate a random nonce + nonce := out[5 : 5+gcm.NonceSize()] + rand.Read(nonce) + + // Seal the output + switch b.currentAESGCMVersionByte { + case AESGCMVersion1: + out = gcm.Seal(out, nonce, plain, nil) + case AESGCMVersion2: + out = gcm.Seal(out, nonce, plain, []byte(path)) + default: + panic("Unknown AESGCM version") + } + + return out +} + +// decrypt is used to decrypt a value +func (b *AESGCMBarrier) decrypt(path string, gcm cipher.AEAD, cipher []byte) ([]byte, error) { + // Verify the term is always just one + term := binary.BigEndian.Uint32(cipher[:4]) + if term != initialKeyTerm { + return nil, fmt.Errorf("term mis-match") + } + + // Capture the parts + nonce := cipher[5 : 5+gcm.NonceSize()] + raw := cipher[5+gcm.NonceSize():] + out := make([]byte, 0, len(raw)-gcm.NonceSize()) + + // Verify the cipher byte and attempt to open + switch cipher[4] { + case AESGCMVersion1: + return gcm.Open(out, nonce, raw, nil) + case AESGCMVersion2: + return gcm.Open(out, nonce, raw, []byte(path)) + default: + return nil, fmt.Errorf("version bytes mis-match") + } +} + +// decryptKeyring is used to decrypt a value using the keyring +func (b *AESGCMBarrier) decryptKeyring(path string, cipher []byte) ([]byte, error) { + // Verify the term + term := binary.BigEndian.Uint32(cipher[:4]) + + // Get the GCM by term + // It is expensive to do this first but it is not a + // normal case that this won't match + gcm, err := b.aeadForTerm(term) + if err != nil { + return nil, err + } + if gcm == nil { + return nil, fmt.Errorf("no decryption key available for term %d", term) + } + + nonce := cipher[5 : 5+gcm.NonceSize()] + raw := cipher[5+gcm.NonceSize():] + out := make([]byte, 0, len(raw)-gcm.NonceSize()) + + // Attempt to open + switch cipher[4] { + case AESGCMVersion1: + return gcm.Open(out, nonce, raw, nil) + case AESGCMVersion2: + return gcm.Open(out, nonce, raw, []byte(path)) + default: + return nil, fmt.Errorf("version bytes mis-match") + } +} + +// Encrypt is used to encrypt in-memory for the BarrierEncryptor interface +func (b *AESGCMBarrier) Encrypt(ctx context.Context, key string, plaintext []byte) ([]byte, error) { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + term := b.keyring.ActiveTerm() + primary, err := b.aeadForTerm(term) + if err != nil { + return nil, err + } + + ciphertext := b.encrypt(key, term, primary, plaintext) + return ciphertext, nil +} + +// Decrypt is used to decrypt in-memory for the BarrierEncryptor interface +func (b *AESGCMBarrier) Decrypt(ctx context.Context, key string, ciphertext []byte) ([]byte, error) { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + // Decrypt the ciphertext + plain, err := b.decryptKeyring(key, ciphertext) + if err != nil { + return nil, errwrap.Wrapf("decryption failed: {{err}}", err) + } + return plain, nil +} + +func (b *AESGCMBarrier) Keyring() (*Keyring, error) { + b.l.RLock() + defer b.l.RUnlock() + if b.sealed { + return nil, ErrBarrierSealed + } + + return b.keyring.Clone(), nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/barrier_view.go b/vendor/github.com/hashicorp/vault/vault/barrier_view.go new file mode 100644 index 0000000..a0f3108 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier_view.go @@ -0,0 +1,141 @@ +package vault + +import ( + "context" + "errors" + "strings" + "sync" + + "github.com/hashicorp/vault/logical" +) + +// BarrierView wraps a SecurityBarrier and ensures all access is automatically +// prefixed. This is used to prevent anyone with access to the view to access +// any data in the durable storage outside of their prefix. Conceptually this +// is like a "chroot" into the barrier. +// +// BarrierView implements logical.Storage so it can be passed in as the +// durable storage mechanism for logical views. +type BarrierView struct { + barrier BarrierStorage + prefix string + readOnlyErr error + readOnlyErrLock sync.RWMutex +} + +var ( + ErrRelativePath = errors.New("relative paths not supported") +) + +// NewBarrierView takes an underlying security barrier and returns +// a view of it that can only operate with the given prefix. +func NewBarrierView(barrier BarrierStorage, prefix string) *BarrierView { + return &BarrierView{ + barrier: barrier, + prefix: prefix, + } +} + +func (v *BarrierView) setReadOnlyErr(readOnlyErr error) { + v.readOnlyErrLock.Lock() + defer v.readOnlyErrLock.Unlock() + v.readOnlyErr = readOnlyErr +} + +func (v *BarrierView) getReadOnlyErr() error { + v.readOnlyErrLock.RLock() + defer v.readOnlyErrLock.RUnlock() + return v.readOnlyErr +} + +// sanityCheck is used to perform a sanity check on a key +func (v *BarrierView) sanityCheck(key string) error { + if strings.Contains(key, "..") { + return ErrRelativePath + } + return nil +} + +// logical.Storage impl. +func (v *BarrierView) List(ctx context.Context, prefix string) ([]string, error) { + if err := v.sanityCheck(prefix); err != nil { + return nil, err + } + return v.barrier.List(ctx, v.expandKey(prefix)) +} + +// logical.Storage impl. +func (v *BarrierView) Get(ctx context.Context, key string) (*logical.StorageEntry, error) { + if err := v.sanityCheck(key); err != nil { + return nil, err + } + entry, err := v.barrier.Get(ctx, v.expandKey(key)) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + if entry != nil { + entry.Key = v.truncateKey(entry.Key) + } + + return &logical.StorageEntry{ + Key: entry.Key, + Value: entry.Value, + SealWrap: entry.SealWrap, + }, nil +} + +// logical.Storage impl. +func (v *BarrierView) Put(ctx context.Context, entry *logical.StorageEntry) error { + if err := v.sanityCheck(entry.Key); err != nil { + return err + } + + expandedKey := v.expandKey(entry.Key) + + roErr := v.getReadOnlyErr() + if roErr != nil { + return roErr + } + + nested := &Entry{ + Key: expandedKey, + Value: entry.Value, + SealWrap: entry.SealWrap, + } + return v.barrier.Put(ctx, nested) +} + +// logical.Storage impl. +func (v *BarrierView) Delete(ctx context.Context, key string) error { + if err := v.sanityCheck(key); err != nil { + return err + } + + expandedKey := v.expandKey(key) + + roErr := v.getReadOnlyErr() + if roErr != nil { + return roErr + } + + return v.barrier.Delete(ctx, expandedKey) +} + +// SubView constructs a nested sub-view using the given prefix +func (v *BarrierView) SubView(prefix string) *BarrierView { + sub := v.expandKey(prefix) + return &BarrierView{barrier: v.barrier, prefix: sub, readOnlyErr: v.getReadOnlyErr()} +} + +// expandKey is used to expand to the full key path with the prefix +func (v *BarrierView) expandKey(suffix string) string { + return v.prefix + suffix +} + +// truncateKey is used to remove the prefix of the key +func (v *BarrierView) truncateKey(full string) string { + return strings.TrimPrefix(full, v.prefix) +} diff --git a/vendor/github.com/hashicorp/vault/vault/capabilities.go b/vendor/github.com/hashicorp/vault/vault/capabilities.go new file mode 100644 index 0000000..a2b9e3f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/capabilities.go @@ -0,0 +1,70 @@ +package vault + +import ( + "context" + "sort" + + "github.com/hashicorp/vault/logical" +) + +// Capabilities is used to fetch the capabilities of the given token on the given path +func (c *Core) Capabilities(ctx context.Context, token, path string) ([]string, error) { + if path == "" { + return nil, &logical.StatusBadRequest{Err: "missing path"} + } + + if token == "" { + return nil, &logical.StatusBadRequest{Err: "missing token"} + } + + te, err := c.tokenStore.Lookup(ctx, token) + if err != nil { + return nil, err + } + if te == nil { + return nil, &logical.StatusBadRequest{Err: "invalid token"} + } + + if te.Policies == nil { + return []string{DenyCapability}, nil + } + + var policies []*Policy + for _, tePolicy := range te.Policies { + policy, err := c.policyStore.GetPolicy(ctx, tePolicy, PolicyTypeToken) + if err != nil { + return nil, err + } + policies = append(policies, policy) + } + + entity, derivedPolicies, err := c.fetchEntityAndDerivedPolicies(te.EntityID) + if err != nil { + return nil, err + } + + if entity != nil && entity.Disabled { + return nil, logical.ErrPermissionDenied + } + + for _, item := range derivedPolicies { + policy, err := c.policyStore.GetPolicy(ctx, item, PolicyTypeToken) + if err != nil { + return nil, err + } + policies = append(policies, policy) + } + + if len(policies) == 0 { + return []string{DenyCapability}, nil + } + + acl, err := NewACL(policies) + if err != nil { + return nil, err + } + + capabilities := acl.Capabilities(path) + sort.Strings(capabilities) + return capabilities, nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/cluster.go b/vendor/github.com/hashicorp/vault/vault/cluster.go new file mode 100644 index 0000000..4919b0b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/cluster.go @@ -0,0 +1,458 @@ +package vault + +import ( + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "errors" + "fmt" + "math/big" + mathrand "math/rand" + "net" + "net/http" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/jsonutil" +) + +const ( + // Storage path where the local cluster name and identifier are stored + coreLocalClusterInfoPath = "core/cluster/local/info" + + corePrivateKeyTypeP521 = "p521" + corePrivateKeyTypeED25519 = "ed25519" + + // Internal so as not to log a trace message + IntNoForwardingHeaderName = "X-Vault-Internal-No-Request-Forwarding" +) + +var ( + ErrCannotForward = errors.New("cannot forward request; no connection or address not known") +) + +// This is used for enterprise replication information +type ReplicatedClusters struct { +} + +// This can be one of a few key types so the different params may or may not be filled +type clusterKeyParams struct { + Type string `json:"type" structs:"type" mapstructure:"type"` + X *big.Int `json:"x" structs:"x" mapstructure:"x"` + Y *big.Int `json:"y" structs:"y" mapstructure:"y"` + D *big.Int `json:"d" structs:"d" mapstructure:"d"` +} + +// Structure representing the storage entry that holds cluster information +type Cluster struct { + // Name of the cluster + Name string `json:"name" structs:"name" mapstructure:"name"` + + // Identifier of the cluster + ID string `json:"id" structs:"id" mapstructure:"id"` +} + +// Cluster fetches the details of the local cluster. This method errors out +// when Vault is sealed. +func (c *Core) Cluster(ctx context.Context) (*Cluster, error) { + var cluster Cluster + + // Fetch the storage entry. This call fails when Vault is sealed. + entry, err := c.barrier.Get(ctx, coreLocalClusterInfoPath) + if err != nil { + return nil, err + } + if entry == nil { + return &cluster, nil + } + + // Decode the cluster information + if err = jsonutil.DecodeJSON(entry.Value, &cluster); err != nil { + return nil, errwrap.Wrapf("failed to decode cluster details: {{err}}", err) + } + + // Set in config file + if c.clusterName != "" { + cluster.Name = c.clusterName + } + + return &cluster, nil +} + +// This sets our local cluster cert and private key based on the advertisement. +// It also ensures the cert is in our local cluster cert pool. +func (c *Core) loadLocalClusterTLS(adv activeAdvertisement) (retErr error) { + defer func() { + if retErr != nil { + c.localClusterCert.Store(([]byte)(nil)) + c.localClusterParsedCert.Store((*x509.Certificate)(nil)) + c.localClusterPrivateKey.Store((*ecdsa.PrivateKey)(nil)) + + c.requestForwardingConnectionLock.Lock() + c.clearForwardingClients() + c.requestForwardingConnectionLock.Unlock() + } + }() + + switch { + case adv.ClusterAddr == "": + // Clustering disabled on the server, don't try to look for params + return nil + + case adv.ClusterKeyParams == nil: + c.logger.Error("no key params found loading local cluster TLS information") + return fmt.Errorf("no local cluster key params found") + + case adv.ClusterKeyParams.X == nil, adv.ClusterKeyParams.Y == nil, adv.ClusterKeyParams.D == nil: + c.logger.Error("failed to parse local cluster key due to missing params") + return fmt.Errorf("failed to parse local cluster key") + + case adv.ClusterKeyParams.Type != corePrivateKeyTypeP521: + c.logger.Error("unknown local cluster key type", "key_type", adv.ClusterKeyParams.Type) + return fmt.Errorf("failed to find valid local cluster key type") + + case adv.ClusterCert == nil || len(adv.ClusterCert) == 0: + c.logger.Error("no local cluster cert found") + return fmt.Errorf("no local cluster cert found") + + } + + c.localClusterPrivateKey.Store(&ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: elliptic.P521(), + X: adv.ClusterKeyParams.X, + Y: adv.ClusterKeyParams.Y, + }, + D: adv.ClusterKeyParams.D, + }) + + locCert := make([]byte, len(adv.ClusterCert)) + copy(locCert, adv.ClusterCert) + c.localClusterCert.Store(locCert) + + cert, err := x509.ParseCertificate(adv.ClusterCert) + if err != nil { + c.logger.Error("failed parsing local cluster certificate", "error", err) + return errwrap.Wrapf("error parsing local cluster certificate: {{err}}", err) + } + + c.localClusterParsedCert.Store(cert) + + return nil +} + +// setupCluster creates storage entries for holding Vault cluster information. +// Entries will be created only if they are not already present. If clusterName +// is not supplied, this method will auto-generate it. +func (c *Core) setupCluster(ctx context.Context) error { + // Prevent data races with the TLS parameters + c.clusterParamsLock.Lock() + defer c.clusterParamsLock.Unlock() + + // Check if storage index is already present or not + cluster, err := c.Cluster(ctx) + if err != nil { + c.logger.Error("failed to get cluster details", "error", err) + return err + } + + var modified bool + + if cluster == nil { + cluster = &Cluster{} + } + + if cluster.Name == "" { + // If cluster name is not supplied, generate one + if c.clusterName == "" { + c.logger.Debug("cluster name not found/set, generating new") + clusterNameBytes, err := uuid.GenerateRandomBytes(4) + if err != nil { + c.logger.Error("failed to generate cluster name", "error", err) + return err + } + + c.clusterName = fmt.Sprintf("vault-cluster-%08x", clusterNameBytes) + } + + cluster.Name = c.clusterName + if c.logger.IsDebug() { + c.logger.Debug("cluster name set", "name", cluster.Name) + } + modified = true + } + + if cluster.ID == "" { + c.logger.Debug("cluster ID not found, generating new") + // Generate a clusterID + cluster.ID, err = uuid.GenerateUUID() + if err != nil { + c.logger.Error("failed to generate cluster identifier", "error", err) + return err + } + if c.logger.IsDebug() { + c.logger.Debug("cluster ID set", "id", cluster.ID) + } + modified = true + } + + // If we're using HA, generate server-to-server parameters + if c.ha != nil { + // Create a private key + if c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey) == nil { + c.logger.Trace("generating cluster private key") + key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + c.logger.Error("failed to generate local cluster key", "error", err) + return err + } + + c.localClusterPrivateKey.Store(key) + } + + // Create a certificate + if c.localClusterCert.Load().([]byte) == nil { + c.logger.Debug("generating local cluster certificate") + + host, err := uuid.GenerateUUID() + if err != nil { + return err + } + host = fmt.Sprintf("fw-%s", host) + template := &x509.Certificate{ + Subject: pkix.Name{ + CommonName: host, + }, + DNSNames: []string{host}, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign, + SerialNumber: big.NewInt(mathrand.Int63()), + NotBefore: time.Now().Add(-30 * time.Second), + // 30 years of single-active uptime ought to be enough for anybody + NotAfter: time.Now().Add(262980 * time.Hour), + BasicConstraintsValid: true, + IsCA: true, + } + + certBytes, err := x509.CreateCertificate(rand.Reader, template, template, c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey).Public(), c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey)) + if err != nil { + c.logger.Error("error generating self-signed cert", "error", err) + return errwrap.Wrapf("unable to generate local cluster certificate: {{err}}", err) + } + + parsedCert, err := x509.ParseCertificate(certBytes) + if err != nil { + c.logger.Error("error parsing self-signed cert", "error", err) + return errwrap.Wrapf("error parsing generated certificate: {{err}}", err) + } + + c.localClusterCert.Store(certBytes) + c.localClusterParsedCert.Store(parsedCert) + } + } + + if modified { + // Encode the cluster information into as a JSON string + rawCluster, err := json.Marshal(cluster) + if err != nil { + c.logger.Error("failed to encode cluster details", "error", err) + return err + } + + // Store it + err = c.barrier.Put(ctx, &Entry{ + Key: coreLocalClusterInfoPath, + Value: rawCluster, + }) + if err != nil { + c.logger.Error("failed to store cluster details", "error", err) + return err + } + } + + return nil +} + +// startClusterListener starts cluster request listeners during postunseal. It +// is assumed that the state lock is held while this is run. Right now this +// only starts forwarding listeners; it's TBD whether other request types will +// be built in the same mechanism or started independently. +func (c *Core) startClusterListener(ctx context.Context) error { + if c.clusterAddr == "" { + c.logger.Info("clustering disabled, not starting listeners") + return nil + } + + if c.clusterListenerAddrs == nil || len(c.clusterListenerAddrs) == 0 { + c.logger.Warn("clustering not disabled but no addresses to listen on") + return fmt.Errorf("cluster addresses not found") + } + + c.logger.Debug("starting cluster listeners") + + err := c.startForwarding(ctx) + if err != nil { + return err + } + + return nil +} + +// stopClusterListener stops any existing listeners during preseal. It is +// assumed that the state lock is held while this is run. +func (c *Core) stopClusterListener() { + if c.clusterAddr == "" { + + c.logger.Debug("clustering disabled, not stopping listeners") + return + } + + if !c.clusterListenersRunning { + c.logger.Info("cluster listeners not running") + return + } + c.logger.Info("stopping cluster listeners") + + // Tell the goroutine managing the listeners to perform the shutdown + // process + c.clusterListenerShutdownCh <- struct{}{} + + // The reason for this loop-de-loop is that we may be unsealing again + // quickly, and if the listeners are not yet closed, we will get socket + // bind errors. This ensures proper ordering. + + c.logger.Debug("waiting for success notification while stopping cluster listeners") + <-c.clusterListenerShutdownSuccessCh + c.clusterListenersRunning = false + + c.logger.Info("cluster listeners successfully shut down") +} + +// ClusterTLSConfig generates a TLS configuration based on the local/replicated +// cluster key and cert. +func (c *Core) ClusterTLSConfig(ctx context.Context, repClusters *ReplicatedClusters) (*tls.Config, error) { + // Using lookup functions allows just-in-time lookup of the current state + // of clustering as connections come and go + + serverLookup := func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { + switch { + default: + currCert := c.localClusterCert.Load().([]byte) + if len(currCert) == 0 { + return nil, fmt.Errorf("got forwarding connection but no local cert") + } + + localCert := make([]byte, len(currCert)) + copy(localCert, currCert) + + return &tls.Certificate{ + Certificate: [][]byte{localCert}, + PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey), + Leaf: c.localClusterParsedCert.Load().(*x509.Certificate), + }, nil + } + } + + clientLookup := func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) { + + if len(requestInfo.AcceptableCAs) != 1 { + return nil, fmt.Errorf("expected only a single acceptable CA") + } + + currCert := c.localClusterCert.Load().([]byte) + if len(currCert) == 0 { + return nil, fmt.Errorf("forwarding connection client but no local cert") + } + + localCert := make([]byte, len(currCert)) + copy(localCert, currCert) + + return &tls.Certificate{ + Certificate: [][]byte{localCert}, + PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey), + Leaf: c.localClusterParsedCert.Load().(*x509.Certificate), + }, nil + } + + serverConfigLookup := func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) { + + for _, v := range clientHello.SupportedProtos { + switch v { + case "h2", requestForwardingALPN: + default: + return nil, fmt.Errorf("unknown ALPN proto %s", v) + } + } + + caPool := x509.NewCertPool() + + ret := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + GetCertificate: serverLookup, + GetClientCertificate: clientLookup, + MinVersion: tls.VersionTLS12, + RootCAs: caPool, + ClientCAs: caPool, + NextProtos: clientHello.SupportedProtos, + CipherSuites: c.clusterCipherSuites, + } + + switch { + default: + parsedCert := c.localClusterParsedCert.Load().(*x509.Certificate) + + if parsedCert == nil { + return nil, fmt.Errorf("forwarding connection client but no local cert") + } + + caPool.AddCert(parsedCert) + } + + return ret, nil + } + + tlsConfig := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + GetCertificate: serverLookup, + GetClientCertificate: clientLookup, + GetConfigForClient: serverConfigLookup, + MinVersion: tls.VersionTLS12, + CipherSuites: c.clusterCipherSuites, + } + + parsedCert := c.localClusterParsedCert.Load().(*x509.Certificate) + currCert := c.localClusterCert.Load().([]byte) + localCert := make([]byte, len(currCert)) + copy(localCert, currCert) + + if parsedCert != nil { + tlsConfig.ServerName = parsedCert.Subject.CommonName + + pool := x509.NewCertPool() + pool.AddCert(parsedCert) + tlsConfig.RootCAs = pool + tlsConfig.ClientCAs = pool + } + + return tlsConfig, nil +} + +func (c *Core) SetClusterListenerAddrs(addrs []*net.TCPAddr) { + c.clusterListenerAddrs = addrs + if c.clusterAddr == "" && len(addrs) == 1 { + c.clusterAddr = fmt.Sprintf("https://%s", addrs[0].String()) + } +} + +func (c *Core) SetClusterHandler(handler http.Handler) { + c.clusterHandler = handler +} diff --git a/vendor/github.com/hashicorp/vault/vault/core.go b/vendor/github.com/hashicorp/vault/vault/core.go new file mode 100644 index 0000000..76107f9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/core.go @@ -0,0 +1,1424 @@ +package vault + +import ( + "context" + "crypto/ecdsa" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "net" + "net/http" + "net/url" + "path/filepath" + "sync" + "sync/atomic" + "time" + + "github.com/armon/go-metrics" + log "github.com/hashicorp/go-hclog" + + "google.golang.org/grpc" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/logging" + "github.com/hashicorp/vault/helper/mlock" + "github.com/hashicorp/vault/helper/reload" + "github.com/hashicorp/vault/helper/tlsutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/physical" + "github.com/hashicorp/vault/shamir" + cache "github.com/patrickmn/go-cache" +) + +const ( + // coreLockPath is the path used to acquire a coordinating lock + // for a highly-available deploy. + coreLockPath = "core/lock" + + // The poison pill is used as a check during certain scenarios to indicate + // to standby nodes that they should seal + poisonPillPath = "core/poison-pill" + + // coreLeaderPrefix is the prefix used for the UUID that contains + // the currently elected leader. + coreLeaderPrefix = "core/leader/" + + // knownPrimaryAddrsPrefix is used to store last-known cluster address + // information for primaries + knownPrimaryAddrsPrefix = "core/primary-addrs/" + + // lockRetryInterval is the interval we re-attempt to acquire the + // HA lock if an error is encountered + lockRetryInterval = 10 * time.Second + + // leaderCheckInterval is how often a standby checks for a new leader + leaderCheckInterval = 2500 * time.Millisecond + + // keyRotateCheckInterval is how often a standby checks for a key + // rotation taking place. + keyRotateCheckInterval = 30 * time.Second + + // keyRotateGracePeriod is how long we allow an upgrade path + // for standby instances before we delete the upgrade keys + keyRotateGracePeriod = 2 * time.Minute + + // leaderPrefixCleanDelay is how long to wait between deletions + // of orphaned leader keys, to prevent slamming the backend. + leaderPrefixCleanDelay = 200 * time.Millisecond + + // coreKeyringCanaryPath is used as a canary to indicate to replicated + // clusters that they need to perform a rekey operation synchronously; this + // isn't keyring-canary to avoid ignoring it when ignoring core/keyring + coreKeyringCanaryPath = "core/canary-keyring" +) + +var ( + // ErrAlreadyInit is returned if the core is already + // initialized. This prevents a re-initialization. + ErrAlreadyInit = errors.New("Vault is already initialized") + + // ErrNotInit is returned if a non-initialized barrier + // is attempted to be unsealed. + ErrNotInit = errors.New("Vault is not initialized") + + // ErrInternalError is returned when we don't want to leak + // any information about an internal error + ErrInternalError = errors.New("internal error") + + // ErrHANotEnabled is returned if the operation only makes sense + // in an HA setting + ErrHANotEnabled = errors.New("Vault is not configured for highly-available mode") + + // manualStepDownSleepPeriod is how long to sleep after a user-initiated + // step down of the active node, to prevent instantly regrabbing the lock. + // It's var not const so that tests can manipulate it. + manualStepDownSleepPeriod = 10 * time.Second + + // Functions only in the Enterprise version + enterprisePostUnseal = enterprisePostUnsealImpl + enterprisePreSeal = enterprisePreSealImpl + startReplication = startReplicationImpl + stopReplication = stopReplicationImpl + LastRemoteWAL = lastRemoteWALImpl +) + +// NonFatalError is an error that can be returned during NewCore that should be +// displayed but not cause a program exit +type NonFatalError struct { + Err error +} + +func (e *NonFatalError) WrappedErrors() []error { + return []error{e.Err} +} + +func (e *NonFatalError) Error() string { + return e.Err.Error() +} + +// ErrInvalidKey is returned if there is a user-based error with a provided +// unseal key. This will be shown to the user, so should not contain +// information that is sensitive. +type ErrInvalidKey struct { + Reason string +} + +func (e *ErrInvalidKey) Error() string { + return fmt.Sprintf("invalid key: %v", e.Reason) +} + +type activeAdvertisement struct { + RedirectAddr string `json:"redirect_addr"` + ClusterAddr string `json:"cluster_addr,omitempty"` + ClusterCert []byte `json:"cluster_cert,omitempty"` + ClusterKeyParams *clusterKeyParams `json:"cluster_key_params,omitempty"` +} + +type unlockInformation struct { + Parts [][]byte + Nonce string +} + +// Core is used as the central manager of Vault activity. It is the primary point of +// interface for API handlers and is responsible for managing the logical and physical +// backends, router, security barrier, and audit trails. +type Core struct { + // N.B.: This is used to populate a dev token down replication, as + // otherwise, after replication is started, a dev would have to go through + // the generate-root process simply to talk to the new follower cluster. + devToken string + + // HABackend may be available depending on the physical backend + ha physical.HABackend + + // redirectAddr is the address we advertise as leader if held + redirectAddr string + + // clusterAddr is the address we use for clustering + clusterAddr string + + // physical backend is the un-trusted backend with durable data + physical physical.Backend + + // Our Seal, for seal configuration information + seal Seal + + // barrier is the security barrier wrapping the physical backend + barrier SecurityBarrier + + // router is responsible for managing the mount points for logical backends. + router *Router + + // logicalBackends is the mapping of backends to use for this core + logicalBackends map[string]logical.Factory + + // credentialBackends is the mapping of backends to use for this core + credentialBackends map[string]logical.Factory + + // auditBackends is the mapping of backends to use for this core + auditBackends map[string]audit.Factory + + // stateLock protects mutable state + stateLock sync.RWMutex + sealed bool + + standby bool + standbyDoneCh chan struct{} + standbyStopCh chan struct{} + manualStepDownCh chan struct{} + keepHALockOnStepDown uint32 + heldHALock physical.Lock + + // unlockInfo has the keys provided to Unseal until the threshold number of parts is available, as well as the operation nonce + unlockInfo *unlockInformation + + // generateRootProgress holds the shares until we reach enough + // to verify the master key + generateRootConfig *GenerateRootConfig + generateRootProgress [][]byte + generateRootLock sync.Mutex + + // These variables holds the config and shares we have until we reach + // enough to verify the appropriate master key. Note that the same lock is + // used; this isn't time-critical so this shouldn't be a problem. + barrierRekeyConfig *SealConfig + recoveryRekeyConfig *SealConfig + rekeyLock sync.RWMutex + + // mounts is loaded after unseal since it is a protected + // configuration + mounts *MountTable + + // mountsLock is used to ensure that the mounts table does not + // change underneath a calling function + mountsLock sync.RWMutex + + // auth is loaded after unseal since it is a protected + // configuration + auth *MountTable + + // authLock is used to ensure that the auth table does not + // change underneath a calling function + authLock sync.RWMutex + + // audit is loaded after unseal since it is a protected + // configuration + audit *MountTable + + // auditLock is used to ensure that the audit table does not + // change underneath a calling function + auditLock sync.RWMutex + + // auditBroker is used to ingest the audit events and fan + // out into the configured audit backends + auditBroker *AuditBroker + + // auditedHeaders is used to configure which http headers + // can be output in the audit logs + auditedHeaders *AuditedHeadersConfig + + // systemBackend is the backend which is used to manage internal operations + systemBackend *SystemBackend + + // systemBarrierView is the barrier view for the system backend + systemBarrierView *BarrierView + + // expiration manager is used for managing LeaseIDs, + // renewal, expiration and revocation + expiration *ExpirationManager + + // rollback manager is used to run rollbacks periodically + rollback *RollbackManager + + // policy store is used to manage named ACL policies + policyStore *PolicyStore + + // token store is used to manage authentication tokens + tokenStore *TokenStore + + // identityStore is used to manage client entities + identityStore *IdentityStore + + // metricsCh is used to stop the metrics streaming + metricsCh chan struct{} + + // metricsMutex is used to prevent a race condition between + // metrics emission and sealing leading to a nil pointer + metricsMutex sync.Mutex + + defaultLeaseTTL time.Duration + maxLeaseTTL time.Duration + + logger log.Logger + + // cachingDisabled indicates whether caches are disabled + cachingDisabled bool + // Cache stores the actual cache; we always have this but may bypass it if + // disabled + physicalCache physical.ToggleablePurgemonster + + // reloadFuncs is a map containing reload functions + reloadFuncs map[string][]reload.ReloadFunc + + // reloadFuncsLock controls access to the funcs + reloadFuncsLock sync.RWMutex + + // wrappingJWTKey is the key used for generating JWTs containing response + // wrapping information + wrappingJWTKey *ecdsa.PrivateKey + + // + // Cluster information + // + // Name + clusterName string + // Specific cipher suites to use for clustering, if any + clusterCipherSuites []uint16 + // Used to modify cluster parameters + clusterParamsLock sync.RWMutex + // The private key stored in the barrier used for establishing + // mutually-authenticated connections between Vault cluster members + localClusterPrivateKey *atomic.Value + // The local cluster cert + localClusterCert *atomic.Value + // The parsed form of the local cluster cert + localClusterParsedCert *atomic.Value + // The TCP addresses we should use for clustering + clusterListenerAddrs []*net.TCPAddr + // The handler to use for request forwarding + clusterHandler http.Handler + // Tracks whether cluster listeners are running, e.g. it's safe to send a + // shutdown down the channel + clusterListenersRunning bool + // Shutdown channel for the cluster listeners + clusterListenerShutdownCh chan struct{} + // Shutdown success channel. We need this to be done serially to ensure + // that binds are removed before they might be reinstated. + clusterListenerShutdownSuccessCh chan struct{} + // Write lock used to ensure that we don't have multiple connections adjust + // this value at the same time + requestForwardingConnectionLock sync.RWMutex + // Most recent leader UUID. Used to avoid repeatedly JSON parsing the same + // values. + clusterLeaderUUID string + // Most recent leader redirect addr + clusterLeaderRedirectAddr string + // Most recent leader cluster addr + clusterLeaderClusterAddr string + // Lock for the cluster leader values + clusterLeaderParamsLock sync.RWMutex + // Info on cluster members + clusterPeerClusterAddrsCache *cache.Cache + // Stores whether we currently have a server running + rpcServerActive *uint32 + // The context for the client + rpcClientConnContext context.Context + // The function for canceling the client connection + rpcClientConnCancelFunc context.CancelFunc + // The grpc ClientConn for RPC calls + rpcClientConn *grpc.ClientConn + // The grpc forwarding client + rpcForwardingClient *forwardingClient + + // CORS Information + corsConfig *CORSConfig + + // The active set of upstream cluster addresses; stored via the Echo + // mechanism, loaded by the balancer + atomicPrimaryClusterAddrs *atomic.Value + + atomicPrimaryFailoverAddrs *atomic.Value + // replicationState keeps the current replication state cached for quick + // lookup; activeNodeReplicationState stores the active value on standbys + replicationState *uint32 + activeNodeReplicationState *uint32 + + // uiConfig contains UI configuration + uiConfig *UIConfig + + // rawEnabled indicates whether the Raw endpoint is enabled + rawEnabled bool + + // pluginDirectory is the location vault will look for plugin binaries + pluginDirectory string + + // pluginCatalog is used to manage plugin configurations + pluginCatalog *PluginCatalog + + enableMlock bool + + // This can be used to trigger operations to stop running when Vault is + // going to be shut down, stepped down, or sealed + activeContext context.Context + activeContextCancelFunc context.CancelFunc + + // Stores the sealunwrapper for downgrade needs + sealUnwrapper physical.Backend + + // Stores any funcs that should be run on successful postUnseal + postUnsealFuncs []func() +} + +// CoreConfig is used to parameterize a core +type CoreConfig struct { + DevToken string `json:"dev_token" structs:"dev_token" mapstructure:"dev_token"` + + LogicalBackends map[string]logical.Factory `json:"logical_backends" structs:"logical_backends" mapstructure:"logical_backends"` + + CredentialBackends map[string]logical.Factory `json:"credential_backends" structs:"credential_backends" mapstructure:"credential_backends"` + + AuditBackends map[string]audit.Factory `json:"audit_backends" structs:"audit_backends" mapstructure:"audit_backends"` + + Physical physical.Backend `json:"physical" structs:"physical" mapstructure:"physical"` + + // May be nil, which disables HA operations + HAPhysical physical.HABackend `json:"ha_physical" structs:"ha_physical" mapstructure:"ha_physical"` + + Seal Seal `json:"seal" structs:"seal" mapstructure:"seal"` + + Logger log.Logger `json:"logger" structs:"logger" mapstructure:"logger"` + + // Disables the LRU cache on the physical backend + DisableCache bool `json:"disable_cache" structs:"disable_cache" mapstructure:"disable_cache"` + + // Disables mlock syscall + DisableMlock bool `json:"disable_mlock" structs:"disable_mlock" mapstructure:"disable_mlock"` + + // Custom cache size for the LRU cache on the physical backend, or zero for default + CacheSize int `json:"cache_size" structs:"cache_size" mapstructure:"cache_size"` + + // Set as the leader address for HA + RedirectAddr string `json:"redirect_addr" structs:"redirect_addr" mapstructure:"redirect_addr"` + + // Set as the cluster address for HA + ClusterAddr string `json:"cluster_addr" structs:"cluster_addr" mapstructure:"cluster_addr"` + + DefaultLeaseTTL time.Duration `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` + + MaxLeaseTTL time.Duration `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` + + ClusterName string `json:"cluster_name" structs:"cluster_name" mapstructure:"cluster_name"` + + ClusterCipherSuites string `json:"cluster_cipher_suites" structs:"cluster_cipher_suites" mapstructure:"cluster_cipher_suites"` + + EnableUI bool `json:"ui" structs:"ui" mapstructure:"ui"` + + // Enable the raw endpoint + EnableRaw bool `json:"enable_raw" structs:"enable_raw" mapstructure:"enable_raw"` + + PluginDirectory string `json:"plugin_directory" structs:"plugin_directory" mapstructure:"plugin_directory"` + + ReloadFuncs *map[string][]reload.ReloadFunc + ReloadFuncsLock *sync.RWMutex +} + +// NewCore is used to construct a new core +func NewCore(conf *CoreConfig) (*Core, error) { + if conf.HAPhysical != nil && conf.HAPhysical.HAEnabled() { + if conf.RedirectAddr == "" { + return nil, fmt.Errorf("missing API address, please set in configuration or via environment") + } + } + + if conf.DefaultLeaseTTL == 0 { + conf.DefaultLeaseTTL = defaultLeaseTTL + } + if conf.MaxLeaseTTL == 0 { + conf.MaxLeaseTTL = maxLeaseTTL + } + if conf.DefaultLeaseTTL > conf.MaxLeaseTTL { + return nil, fmt.Errorf("cannot have DefaultLeaseTTL larger than MaxLeaseTTL") + } + + // Validate the advertise addr if its given to us + if conf.RedirectAddr != "" { + u, err := url.Parse(conf.RedirectAddr) + if err != nil { + return nil, errwrap.Wrapf("redirect address is not valid url: {{err}}", err) + } + + if u.Scheme == "" { + return nil, fmt.Errorf("redirect address must include scheme (ex. 'http')") + } + } + + // Make a default logger if not provided + if conf.Logger == nil { + conf.Logger = logging.NewVaultLogger(log.Trace) + } + + // Setup the core + c := &Core{ + devToken: conf.DevToken, + physical: conf.Physical, + redirectAddr: conf.RedirectAddr, + clusterAddr: conf.ClusterAddr, + seal: conf.Seal, + router: NewRouter(), + sealed: true, + standby: true, + logger: conf.Logger.Named("core"), + defaultLeaseTTL: conf.DefaultLeaseTTL, + maxLeaseTTL: conf.MaxLeaseTTL, + cachingDisabled: conf.DisableCache, + clusterName: conf.ClusterName, + clusterListenerShutdownCh: make(chan struct{}), + clusterListenerShutdownSuccessCh: make(chan struct{}), + clusterPeerClusterAddrsCache: cache.New(3*HeartbeatInterval, time.Second), + enableMlock: !conf.DisableMlock, + rawEnabled: conf.EnableRaw, + replicationState: new(uint32), + rpcServerActive: new(uint32), + atomicPrimaryClusterAddrs: new(atomic.Value), + atomicPrimaryFailoverAddrs: new(atomic.Value), + localClusterPrivateKey: new(atomic.Value), + localClusterCert: new(atomic.Value), + localClusterParsedCert: new(atomic.Value), + activeNodeReplicationState: new(uint32), + } + + atomic.StoreUint32(c.replicationState, uint32(consts.ReplicationDRDisabled|consts.ReplicationPerformanceDisabled)) + c.localClusterCert.Store(([]byte)(nil)) + c.localClusterParsedCert.Store((*x509.Certificate)(nil)) + c.localClusterPrivateKey.Store((*ecdsa.PrivateKey)(nil)) + + if conf.ClusterCipherSuites != "" { + suites, err := tlsutil.ParseCiphers(conf.ClusterCipherSuites) + if err != nil { + return nil, errwrap.Wrapf("error parsing cluster cipher suites: {{err}}", err) + } + c.clusterCipherSuites = suites + } + + // Load CORS config and provide a value for the core field. + c.corsConfig = &CORSConfig{core: c} + + phys := conf.Physical + _, txnOK := conf.Physical.(physical.Transactional) + if c.seal == nil { + c.seal = NewDefaultSeal() + } + c.seal.SetCore(c) + + c.sealUnwrapper = NewSealUnwrapper(phys, conf.Logger.ResetNamed("storage.sealunwrapper")) + + var ok bool + + // Wrap the physical backend in a cache layer if enabled + if txnOK { + c.physical = physical.NewTransactionalCache(c.sealUnwrapper, conf.CacheSize, conf.Logger.ResetNamed("storage.cache")) + } else { + c.physical = physical.NewCache(c.sealUnwrapper, conf.CacheSize, conf.Logger.ResetNamed("storage.cache")) + } + c.physicalCache = c.physical.(physical.ToggleablePurgemonster) + + if !conf.DisableMlock { + // Ensure our memory usage is locked into physical RAM + if err := mlock.LockMemory(); err != nil { + return nil, fmt.Errorf( + "Failed to lock memory: %v\n\n"+ + "This usually means that the mlock syscall is not available.\n"+ + "Vault uses mlock to prevent memory from being swapped to\n"+ + "disk. This requires root privileges as well as a machine\n"+ + "that supports mlock. Please enable mlock on your system or\n"+ + "disable Vault from using it. To disable Vault from using it,\n"+ + "set the `disable_mlock` configuration option in your configuration\n"+ + "file.", + err) + } + } + + var err error + if conf.PluginDirectory != "" { + c.pluginDirectory, err = filepath.Abs(conf.PluginDirectory) + if err != nil { + return nil, errwrap.Wrapf("core setup failed, could not verify plugin directory: {{err}}", err) + } + } + + // Construct a new AES-GCM barrier + c.barrier, err = NewAESGCMBarrier(c.physical) + if err != nil { + return nil, errwrap.Wrapf("barrier setup failed: {{err}}", err) + } + + if conf.HAPhysical != nil && conf.HAPhysical.HAEnabled() { + c.ha = conf.HAPhysical + } + + // We create the funcs here, then populate the given config with it so that + // the caller can share state + conf.ReloadFuncsLock = &c.reloadFuncsLock + c.reloadFuncsLock.Lock() + c.reloadFuncs = make(map[string][]reload.ReloadFunc) + c.reloadFuncsLock.Unlock() + conf.ReloadFuncs = &c.reloadFuncs + + // Setup the backends + logicalBackends := make(map[string]logical.Factory) + for k, f := range conf.LogicalBackends { + logicalBackends[k] = f + } + _, ok = logicalBackends["kv"] + if !ok { + logicalBackends["kv"] = PassthroughBackendFactory + } + logicalBackends["cubbyhole"] = CubbyholeBackendFactory + logicalBackends["system"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + b := NewSystemBackend(c, conf.Logger.Named("system")) + if err := b.Setup(ctx, config); err != nil { + return nil, err + } + return b, nil + } + + logicalBackends["identity"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + return NewIdentityStore(ctx, c, config, conf.Logger.Named("identity")) + } + + c.logicalBackends = logicalBackends + + credentialBackends := make(map[string]logical.Factory) + for k, f := range conf.CredentialBackends { + credentialBackends[k] = f + } + credentialBackends["token"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + return NewTokenStore(ctx, conf.Logger.Named("token"), c, config) + } + c.credentialBackends = credentialBackends + + auditBackends := make(map[string]audit.Factory) + for k, f := range conf.AuditBackends { + auditBackends[k] = f + } + c.auditBackends = auditBackends + + uiStoragePrefix := systemBarrierPrefix + "ui" + c.uiConfig = NewUIConfig(conf.EnableUI, physical.NewView(c.physical, uiStoragePrefix), NewBarrierView(c.barrier, uiStoragePrefix)) + + return c, nil +} + +// Shutdown is invoked when the Vault instance is about to be terminated. It +// should not be accessible as part of an API call as it will cause an availability +// problem. It is only used to gracefully quit in the case of HA so that failover +// happens as quickly as possible. +func (c *Core) Shutdown() error { + c.logger.Debug("shutdown called") + c.stateLock.RLock() + // Tell any requests that know about this to stop + if c.activeContextCancelFunc != nil { + c.activeContextCancelFunc() + } + c.stateLock.RUnlock() + + c.logger.Debug("shutdown initiating internal seal") + // Seal the Vault, causes a leader stepdown + c.stateLock.Lock() + defer c.stateLock.Unlock() + + c.logger.Debug("shutdown running internal seal") + return c.sealInternal(false) +} + +// CORSConfig returns the current CORS configuration +func (c *Core) CORSConfig() *CORSConfig { + return c.corsConfig +} + +func (c *Core) GetContext() (context.Context, context.CancelFunc) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + + return context.WithCancel(c.activeContext) +} + +// Sealed checks if the Vault is current sealed +func (c *Core) Sealed() (bool, error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + return c.sealed, nil +} + +// SecretProgress returns the number of keys provided so far +func (c *Core) SecretProgress() (int, string) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + switch c.unlockInfo { + case nil: + return 0, "" + default: + return len(c.unlockInfo.Parts), c.unlockInfo.Nonce + } +} + +// ResetUnsealProcess removes the current unlock parts from memory, to reset +// the unsealing process +func (c *Core) ResetUnsealProcess() { + c.stateLock.Lock() + defer c.stateLock.Unlock() + if !c.sealed { + return + } + c.unlockInfo = nil +} + +// Unseal is used to provide one of the key parts to unseal the Vault. +// +// They key given as a parameter will automatically be zerod after +// this method is done with it. If you want to keep the key around, a copy +// should be made. +func (c *Core) Unseal(key []byte) (bool, error) { + defer metrics.MeasureSince([]string{"core", "unseal"}, time.Now()) + + c.stateLock.Lock() + defer c.stateLock.Unlock() + + ctx := context.Background() + + // Explicitly check for init status. This also checks if the seal + // configuration is valid (i.e. non-nil). + init, err := c.Initialized(ctx) + if err != nil { + return false, err + } + if !init { + return false, ErrNotInit + } + + // Verify the key length + min, max := c.barrier.KeyLength() + max += shamir.ShareOverhead + if len(key) < min { + return false, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} + } + if len(key) > max { + return false, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} + } + + // Get the barrier seal configuration + config, err := c.seal.BarrierConfig(ctx) + if err != nil { + return false, err + } + + // Check if already unsealed + if !c.sealed { + return true, nil + } + + masterKey, err := c.unsealPart(ctx, config, key, false) + if err != nil { + return false, err + } + if masterKey != nil { + return c.unsealInternal(ctx, masterKey) + } + + return false, nil +} + +// UnsealWithRecoveryKeys is used to provide one of the recovery key shares to +// unseal the Vault. +func (c *Core) UnsealWithRecoveryKeys(ctx context.Context, key []byte) (bool, error) { + defer metrics.MeasureSince([]string{"core", "unseal_with_recovery_keys"}, time.Now()) + + c.stateLock.Lock() + defer c.stateLock.Unlock() + + // Explicitly check for init status + init, err := c.Initialized(ctx) + if err != nil { + return false, err + } + if !init { + return false, ErrNotInit + } + + var config *SealConfig + // If recovery keys are supported then use recovery seal config to unseal + if c.seal.RecoveryKeySupported() { + config, err = c.seal.RecoveryConfig(ctx) + if err != nil { + return false, err + } + } + + // Check if already unsealed + if !c.sealed { + return true, nil + } + + masterKey, err := c.unsealPart(ctx, config, key, true) + if err != nil { + return false, err + } + if masterKey != nil { + return c.unsealInternal(ctx, masterKey) + } + + return false, nil +} + +// unsealPart takes in a key share, and returns the master key if the threshold +// is met. If recovery keys are supported, recovery key shares may be provided. +func (c *Core) unsealPart(ctx context.Context, config *SealConfig, key []byte, useRecoveryKeys bool) ([]byte, error) { + // Check if we already have this piece + if c.unlockInfo != nil { + for _, existing := range c.unlockInfo.Parts { + if subtle.ConstantTimeCompare(existing, key) == 1 { + return nil, nil + } + } + } else { + uuid, err := uuid.GenerateUUID() + if err != nil { + return nil, err + } + c.unlockInfo = &unlockInformation{ + Nonce: uuid, + } + } + + // Store this key + c.unlockInfo.Parts = append(c.unlockInfo.Parts, key) + + // Check if we don't have enough keys to unlock, proceed through the rest of + // the call only if we have met the threshold + if len(c.unlockInfo.Parts) < config.SecretThreshold { + if c.logger.IsDebug() { + c.logger.Debug("cannot unseal, not enough keys", "keys", len(c.unlockInfo.Parts), "threshold", config.SecretThreshold, "nonce", c.unlockInfo.Nonce) + } + return nil, nil + } + + // Best-effort memzero of unlock parts once we're done with them + defer func() { + for i := range c.unlockInfo.Parts { + memzero(c.unlockInfo.Parts[i]) + } + c.unlockInfo = nil + }() + + // Recover the split key. recoveredKey is the shamir combined + // key, or the single provided key if the threshold is 1. + var recoveredKey []byte + var err error + if config.SecretThreshold == 1 { + recoveredKey = make([]byte, len(c.unlockInfo.Parts[0])) + copy(recoveredKey, c.unlockInfo.Parts[0]) + } else { + recoveredKey, err = shamir.Combine(c.unlockInfo.Parts) + if err != nil { + return nil, errwrap.Wrapf("failed to compute master key: {{err}}", err) + } + } + + if c.seal.RecoveryKeySupported() && useRecoveryKeys { + // Verify recovery key + if err := c.seal.VerifyRecoveryKey(ctx, recoveredKey); err != nil { + return nil, err + } + + // Get stored keys and shamir combine into single master key. Unsealing with + // recovery keys currently does not support: 1) mixed stored and non-stored + // keys setup, nor 2) seals that support recovery keys but not stored keys. + // If insufficient shares are provided, shamir.Combine will error, and if + // no stored keys are found it will return masterKey as nil. + var masterKey []byte + if c.seal.StoredKeysSupported() { + masterKeyShares, err := c.seal.GetStoredKeys(ctx) + if err != nil { + return nil, errwrap.Wrapf("unable to retrieve stored keys: {{err}}", err) + } + + if len(masterKeyShares) == 1 { + return masterKeyShares[0], nil + } + + masterKey, err = shamir.Combine(masterKeyShares) + if err != nil { + return nil, errwrap.Wrapf("failed to compute master key: {{err}}", err) + } + } + return masterKey, nil + } + + // If this is not a recovery key-supported seal, then the recovered key is + // the master key to be returned. + return recoveredKey, nil +} + +// unsealInternal takes in the master key and attempts to unseal the barrier. +// N.B.: This must be called with the state write lock held. +func (c *Core) unsealInternal(ctx context.Context, masterKey []byte) (bool, error) { + defer memzero(masterKey) + + // Attempt to unlock + if err := c.barrier.Unseal(ctx, masterKey); err != nil { + return false, err + } + if c.logger.IsInfo() { + c.logger.Info("vault is unsealed") + } + + // Do post-unseal setup if HA is not enabled + if c.ha == nil { + // We still need to set up cluster info even if it's not part of a + // cluster right now. This also populates the cached cluster object. + if err := c.setupCluster(ctx); err != nil { + c.logger.Error("cluster setup failed", "error", err) + c.barrier.Seal() + c.logger.Warn("vault is sealed") + return false, err + } + + if err := c.postUnseal(); err != nil { + c.logger.Error("post-unseal setup failed", "error", err) + c.barrier.Seal() + c.logger.Warn("vault is sealed") + return false, err + } + + c.standby = false + } else { + // Go to standby mode, wait until we are active to unseal + c.standbyDoneCh = make(chan struct{}) + c.manualStepDownCh = make(chan struct{}) + c.standbyStopCh = make(chan struct{}) + go c.runStandby(c.standbyDoneCh, c.manualStepDownCh, c.standbyStopCh) + } + + // Success! + c.sealed = false + + // Force a cache bust here, which will also run migration code + if c.seal.RecoveryKeySupported() { + c.seal.SetRecoveryConfig(ctx, nil) + } + + if c.ha != nil { + sd, ok := c.ha.(physical.ServiceDiscovery) + if ok { + if err := sd.NotifySealedStateChange(); err != nil { + if c.logger.IsWarn() { + c.logger.Warn("failed to notify unsealed status", "error", err) + } + } + } + } + return true, nil +} + +// SealWithRequest takes in a logical.Request, acquires the lock, and passes +// through to sealInternal +func (c *Core) SealWithRequest(req *logical.Request) error { + defer metrics.MeasureSince([]string{"core", "seal-with-request"}, time.Now()) + + c.stateLock.RLock() + + if c.sealed { + c.stateLock.RUnlock() + return nil + } + + // This will unlock the read lock + // We use background context since we may not be active + return c.sealInitCommon(context.Background(), req) +} + +// Seal takes in a token and creates a logical.Request, acquires the lock, and +// passes through to sealInternal +func (c *Core) Seal(token string) error { + defer metrics.MeasureSince([]string{"core", "seal"}, time.Now()) + + c.stateLock.RLock() + + if c.sealed { + c.stateLock.RUnlock() + return nil + } + + req := &logical.Request{ + Operation: logical.UpdateOperation, + Path: "sys/seal", + ClientToken: token, + } + + // This will unlock the read lock + // We use background context since we may not be active + return c.sealInitCommon(context.Background(), req) +} + +// sealInitCommon is common logic for Seal and SealWithRequest and is used to +// re-seal the Vault. This requires the Vault to be unsealed again to perform +// any further operations. Note: this function will read-unlock the state lock. +func (c *Core) sealInitCommon(ctx context.Context, req *logical.Request) (retErr error) { + defer metrics.MeasureSince([]string{"core", "seal-internal"}, time.Now()) + + if req == nil { + retErr = multierror.Append(retErr, errors.New("nil request to seal")) + c.stateLock.RUnlock() + return retErr + } + + // Since there is no token store in standby nodes, sealing cannot be done. + // Ideally, the request has to be forwarded to leader node for validation + // and the operation should be performed. But for now, just returning with + // an error and recommending a vault restart, which essentially does the + // same thing. + if c.standby { + c.logger.Error("vault cannot seal when in standby mode; please restart instead") + retErr = multierror.Append(retErr, errors.New("vault cannot seal when in standby mode; please restart instead")) + c.stateLock.RUnlock() + return retErr + } + + // Validate the token is a root token + acl, te, entity, err := c.fetchACLTokenEntryAndEntity(req) + if err != nil { + retErr = multierror.Append(retErr, err) + c.stateLock.RUnlock() + return retErr + } + + // Audit-log the request before going any further + auth := &logical.Auth{ + ClientToken: req.ClientToken, + } + if te != nil { + auth.Policies = te.Policies + auth.Metadata = te.Meta + auth.DisplayName = te.DisplayName + auth.EntityID = te.EntityID + } + + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + } + if err := c.auditBroker.LogRequest(ctx, logInput, c.auditedHeaders); err != nil { + c.logger.Error("failed to audit request", "request_path", req.Path, "error", err) + retErr = multierror.Append(retErr, errors.New("failed to audit request, cannot continue")) + c.stateLock.RUnlock() + return retErr + } + + if entity != nil && entity.Disabled { + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + + // Attempt to use the token (decrement num_uses) + // On error bail out; if the token has been revoked, bail out too + if te != nil { + te, err = c.tokenStore.UseToken(ctx, te) + if err != nil { + c.logger.Error("failed to use token", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + c.stateLock.RUnlock() + return retErr + } + if te == nil { + // Token is no longer valid + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + } + + // Verify that this operation is allowed + authResults := c.performPolicyChecks(ctx, acl, te, req, entity, &PolicyCheckOpts{ + RootPrivsRequired: true, + }) + if authResults.Error.ErrorOrNil() != nil { + retErr = multierror.Append(retErr, authResults.Error) + c.stateLock.RUnlock() + return retErr + } + if !authResults.Allowed { + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + + if te != nil && te.NumUses == tokenRevocationPending { + // Token needs to be revoked. We do this immediately here because + // we won't have a token store after sealing. + leaseID, err := c.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err == nil { + err = c.expiration.Revoke(leaseID) + } + if err != nil { + c.logger.Error("token needed revocation before seal but failed to revoke", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + } + } + + // Tell any requests that know about this to stop + if c.activeContextCancelFunc != nil { + c.activeContextCancelFunc() + } + + // Unlock from the request handling + c.stateLock.RUnlock() + + //Seal the Vault + c.stateLock.Lock() + defer c.stateLock.Unlock() + sealErr := c.sealInternal(false) + + if sealErr != nil { + retErr = multierror.Append(retErr, sealErr) + } + + return +} + +// UIEnabled returns if the UI is enabled +func (c *Core) UIEnabled() bool { + return c.uiConfig.Enabled() +} + +// UIHeaders returns configured UI headers +func (c *Core) UIHeaders() (http.Header, error) { + return c.uiConfig.Headers(context.Background()) +} + +// sealInternal is an internal method used to seal the vault. It does not do +// any authorization checking. The stateLock must be held prior to calling. +func (c *Core) sealInternal(keepLock bool) error { + if c.sealed { + return nil + } + + // Enable that we are sealed to prevent further transactions + c.sealed = true + + c.logger.Debug("marked as sealed") + + // Clear forwarding clients + c.requestForwardingConnectionLock.Lock() + c.clearForwardingClients() + c.requestForwardingConnectionLock.Unlock() + + // Do pre-seal teardown if HA is not enabled + if c.ha == nil { + // Even in a non-HA context we key off of this for some things + c.standby = true + if err := c.preSeal(); err != nil { + c.logger.Error("pre-seal teardown failed", "error", err) + return fmt.Errorf("internal error") + } + } else { + if keepLock { + atomic.StoreUint32(&c.keepHALockOnStepDown, 1) + } + // If we are trying to acquire the lock, force it to return with nil so + // runStandby will exit + // If we are active, signal the standby goroutine to shut down and wait + // for completion. We have the state lock here so nothing else should + // be toggling standby status. + close(c.standbyStopCh) + c.logger.Debug("finished triggering standbyStopCh for runStandby") + + // Wait for runStandby to stop + <-c.standbyDoneCh + atomic.StoreUint32(&c.keepHALockOnStepDown, 0) + c.logger.Debug("runStandby done") + } + + c.logger.Debug("sealing barrier") + if err := c.barrier.Seal(); err != nil { + c.logger.Error("error sealing barrier", "error", err) + return err + } + + if c.ha != nil { + sd, ok := c.ha.(physical.ServiceDiscovery) + if ok { + if err := sd.NotifySealedStateChange(); err != nil { + if c.logger.IsWarn() { + c.logger.Warn("failed to notify sealed status", "error", err) + } + } + } + } + + c.logger.Info("vault is sealed") + + return nil +} + +// postUnseal is invoked after the barrier is unsealed, but before +// allowing any user operations. This allows us to setup any state that +// requires the Vault to be unsealed such as mount tables, logical backends, +// credential stores, etc. +func (c *Core) postUnseal() (retErr error) { + defer metrics.MeasureSince([]string{"core", "post_unseal"}, time.Now()) + + // Clear any out + c.postUnsealFuncs = nil + + // Create a new request context + c.activeContext, c.activeContextCancelFunc = context.WithCancel(context.Background()) + + defer func() { + if retErr != nil { + c.activeContextCancelFunc() + c.preSeal() + } + }() + c.logger.Info("post-unseal setup starting") + + // Clear forwarding clients; we're active + c.requestForwardingConnectionLock.Lock() + c.clearForwardingClients() + c.requestForwardingConnectionLock.Unlock() + + // Enable the cache + c.physicalCache.Purge(c.activeContext) + if !c.cachingDisabled { + c.physicalCache.SetEnabled(true) + } + + switch c.sealUnwrapper.(type) { + case *sealUnwrapper: + c.sealUnwrapper.(*sealUnwrapper).runUnwraps() + case *transactionalSealUnwrapper: + c.sealUnwrapper.(*transactionalSealUnwrapper).runUnwraps() + } + + // Purge these for safety in case of a rekey + c.seal.SetBarrierConfig(c.activeContext, nil) + if c.seal.RecoveryKeySupported() { + c.seal.SetRecoveryConfig(c.activeContext, nil) + } + + if err := enterprisePostUnseal(c); err != nil { + return err + } + if err := c.ensureWrappingKey(c.activeContext); err != nil { + return err + } + if err := c.setupPluginCatalog(); err != nil { + return err + } + if err := c.loadMounts(c.activeContext); err != nil { + return err + } + if err := c.setupMounts(c.activeContext); err != nil { + return err + } + if err := c.setupPolicyStore(c.activeContext); err != nil { + return err + } + if err := c.loadCORSConfig(c.activeContext); err != nil { + return err + } + if err := c.loadCredentials(c.activeContext); err != nil { + return err + } + if err := c.setupCredentials(c.activeContext); err != nil { + return err + } + if err := c.startRollback(); err != nil { + return err + } + if err := c.setupExpiration(); err != nil { + return err + } + if err := c.loadAudits(c.activeContext); err != nil { + return err + } + if err := c.setupAudits(c.activeContext); err != nil { + return err + } + if err := c.loadIdentityStoreArtifacts(c.activeContext); err != nil { + return err + } + if err := c.setupAuditedHeadersConfig(c.activeContext); err != nil { + return err + } + + if c.ha != nil { + if err := c.startClusterListener(c.activeContext); err != nil { + return err + } + } + c.metricsCh = make(chan struct{}) + go c.emitMetrics(c.metricsCh) + + // This is intentionally the last block in this function. We want to allow + // writes just before allowing client requests, to ensure everything has + // been set up properly before any writes can have happened. + for _, v := range c.postUnsealFuncs { + v() + } + + c.logger.Info("post-unseal setup complete") + return nil +} + +// preSeal is invoked before the barrier is sealed, allowing +// for any state teardown required. +func (c *Core) preSeal() error { + defer metrics.MeasureSince([]string{"core", "pre_seal"}, time.Now()) + c.logger.Info("pre-seal teardown starting") + + // Clear any pending funcs + c.postUnsealFuncs = nil + + // Clear any rekey progress + c.barrierRekeyConfig = nil + c.recoveryRekeyConfig = nil + + if c.metricsCh != nil { + close(c.metricsCh) + c.metricsCh = nil + } + var result error + + c.stopClusterListener() + + if err := c.teardownAudits(); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error tearing down audits: {{err}}", err)) + } + if err := c.stopExpiration(); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error stopping expiration: {{err}}", err)) + } + if err := c.teardownCredentials(c.activeContext); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error tearing down credentials: {{err}}", err)) + } + if err := c.teardownPolicyStore(); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error tearing down policy store: {{err}}", err)) + } + if err := c.stopRollback(); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error stopping rollback: {{err}}", err)) + } + if err := c.unloadMounts(c.activeContext); err != nil { + result = multierror.Append(result, errwrap.Wrapf("error unloading mounts: {{err}}", err)) + } + if err := enterprisePreSeal(c); err != nil { + result = multierror.Append(result, err) + } + + switch c.sealUnwrapper.(type) { + case *sealUnwrapper: + c.sealUnwrapper.(*sealUnwrapper).stopUnwraps() + case *transactionalSealUnwrapper: + c.sealUnwrapper.(*transactionalSealUnwrapper).stopUnwraps() + } + + // Purge the cache + c.physicalCache.SetEnabled(false) + c.physicalCache.Purge(c.activeContext) + + c.logger.Info("pre-seal teardown complete") + return result +} + +func enterprisePostUnsealImpl(c *Core) error { + return nil +} + +func enterprisePreSealImpl(c *Core) error { + return nil +} + +func startReplicationImpl(c *Core) error { + return nil +} + +func stopReplicationImpl(c *Core) error { + return nil +} + +// emitMetrics is used to periodically expose metrics while running +func (c *Core) emitMetrics(stopCh chan struct{}) { + for { + select { + case <-time.After(time.Second): + c.metricsMutex.Lock() + if c.expiration != nil { + c.expiration.emitMetrics() + } + c.metricsMutex.Unlock() + case <-stopCh: + return + } + } +} + +func (c *Core) ReplicationState() consts.ReplicationState { + return consts.ReplicationState(atomic.LoadUint32(c.replicationState)) +} + +func (c *Core) ActiveNodeReplicationState() consts.ReplicationState { + return consts.ReplicationState(atomic.LoadUint32(c.activeNodeReplicationState)) +} + +func (c *Core) SealAccess() *SealAccess { + return NewSealAccess(c.seal) +} + +func (c *Core) Logger() log.Logger { + return c.logger +} + +func (c *Core) BarrierKeyLength() (min, max int) { + min, max = c.barrier.KeyLength() + max += shamir.ShareOverhead + return +} + +func (c *Core) AuditedHeadersConfig() *AuditedHeadersConfig { + return c.auditedHeaders +} + +func lastRemoteWALImpl(c *Core) uint64 { + return 0 +} + +func (c *Core) BarrierEncryptorAccess() *BarrierEncryptorAccess { + return NewBarrierEncryptorAccess(c.barrier) +} + +func (c *Core) PhysicalAccess() *physical.PhysicalAccess { + return physical.NewPhysicalAccess(c.physical) +} + +func (c *Core) RouterAccess() *RouterAccess { + return NewRouterAccess(c) +} + +// IsDRSecondary returns if the current cluster state is a DR secondary. +func (c *Core) IsDRSecondary() bool { + return c.ReplicationState().HasState(consts.ReplicationDRSecondary) +} diff --git a/vendor/github.com/hashicorp/vault/vault/cors.go b/vendor/github.com/hashicorp/vault/vault/cors.go new file mode 100644 index 0000000..6b0920a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/cors.go @@ -0,0 +1,155 @@ +package vault + +import ( + "context" + "errors" + "sync" + "sync/atomic" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" +) + +const ( + CORSDisabled uint32 = iota + CORSEnabled +) + +var StdAllowedHeaders = []string{ + "Content-Type", + "X-Requested-With", + "X-Vault-AWS-IAM-Server-ID", + "X-Vault-MFA", + "X-Vault-No-Request-Forwarding", + "X-Vault-Token", + "X-Vault-Wrap-Format", + "X-Vault-Wrap-TTL", + "X-Vault-Policy-Override", +} + +// CORSConfig stores the state of the CORS configuration. +type CORSConfig struct { + sync.RWMutex `json:"-"` + core *Core + Enabled uint32 `json:"enabled"` + AllowedOrigins []string `json:"allowed_origins,omitempty"` + AllowedHeaders []string `json:"allowed_headers,omitempty"` +} + +func (c *Core) saveCORSConfig(ctx context.Context) error { + view := c.systemBarrierView.SubView("config/") + + localConfig := &CORSConfig{ + Enabled: atomic.LoadUint32(&c.corsConfig.Enabled), + } + c.corsConfig.RLock() + localConfig.AllowedOrigins = c.corsConfig.AllowedOrigins + localConfig.AllowedHeaders = c.corsConfig.AllowedHeaders + c.corsConfig.RUnlock() + + entry, err := logical.StorageEntryJSON("cors", localConfig) + if err != nil { + return errwrap.Wrapf("failed to create CORS config entry: {{err}}", err) + } + + if err := view.Put(ctx, entry); err != nil { + return errwrap.Wrapf("failed to save CORS config: {{err}}", err) + } + + return nil +} + +// This should only be called with the core state lock held for writing +func (c *Core) loadCORSConfig(ctx context.Context) error { + view := c.systemBarrierView.SubView("config/") + + // Load the config in + out, err := view.Get(ctx, "cors") + if err != nil { + return errwrap.Wrapf("failed to read CORS config: {{err}}", err) + } + if out == nil { + return nil + } + + newConfig := new(CORSConfig) + err = out.DecodeJSON(newConfig) + if err != nil { + return err + } + newConfig.core = c + + c.corsConfig = newConfig + + return nil +} + +// Enable takes either a '*' or a comma-separated list of URLs that can make +// cross-origin requests to Vault. +func (c *CORSConfig) Enable(ctx context.Context, urls []string, headers []string) error { + if len(urls) == 0 { + return errors.New("at least one origin or the wildcard must be provided") + } + + if strutil.StrListContains(urls, "*") && len(urls) > 1 { + return errors.New("to allow all origins the '*' must be the only value for allowed_origins") + } + + c.Lock() + c.AllowedOrigins = urls + + // Start with the standard headers to Vault accepts. + c.AllowedHeaders = append(c.AllowedHeaders, StdAllowedHeaders...) + + // Allow the user to add additional headers to the list of + // headers allowed on cross-origin requests. + if len(headers) > 0 { + c.AllowedHeaders = append(c.AllowedHeaders, headers...) + } + c.Unlock() + + atomic.StoreUint32(&c.Enabled, CORSEnabled) + + return c.core.saveCORSConfig(ctx) +} + +// IsEnabled returns the value of CORSConfig.isEnabled +func (c *CORSConfig) IsEnabled() bool { + return atomic.LoadUint32(&c.Enabled) == CORSEnabled +} + +// Disable sets CORS to disabled and clears the allowed origins & headers. +func (c *CORSConfig) Disable(ctx context.Context) error { + atomic.StoreUint32(&c.Enabled, CORSDisabled) + c.Lock() + + c.AllowedOrigins = nil + c.AllowedHeaders = nil + + c.Unlock() + + return c.core.saveCORSConfig(ctx) +} + +// IsValidOrigin determines if the origin of the request is allowed to make +// cross-origin requests based on the CORSConfig. +func (c *CORSConfig) IsValidOrigin(origin string) bool { + // If we aren't enabling CORS then all origins are valid + if !c.IsEnabled() { + return true + } + + c.RLock() + defer c.RUnlock() + + if len(c.AllowedOrigins) == 0 { + return false + } + + if len(c.AllowedOrigins) == 1 && (c.AllowedOrigins)[0] == "*" { + return true + } + + return strutil.StrListContains(c.AllowedOrigins, origin) +} diff --git a/vendor/github.com/hashicorp/vault/vault/dynamic_system_view.go b/vendor/github.com/hashicorp/vault/vault/dynamic_system_view.go new file mode 100644 index 0000000..2b0aa78 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/dynamic_system_view.go @@ -0,0 +1,190 @@ +package vault + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" +) + +type dynamicSystemView struct { + core *Core + mountEntry *MountEntry +} + +func (d dynamicSystemView) DefaultLeaseTTL() time.Duration { + def, _ := d.fetchTTLs() + return def +} + +func (d dynamicSystemView) MaxLeaseTTL() time.Duration { + _, max := d.fetchTTLs() + return max +} + +func (d dynamicSystemView) SudoPrivilege(ctx context.Context, path string, token string) bool { + // Resolve the token policy + te, err := d.core.tokenStore.Lookup(ctx, token) + if err != nil { + d.core.logger.Error("failed to lookup token", "error", err) + return false + } + + // Ensure the token is valid + if te == nil { + d.core.logger.Error("entry not found for given token") + return false + } + + // Construct the corresponding ACL object + acl, err := d.core.policyStore.ACL(ctx, te.Policies...) + if err != nil { + d.core.logger.Error("failed to retrieve ACL for token's policies", "token_policies", te.Policies, "error", err) + return false + } + + // The operation type isn't important here as this is run from a path the + // user has already been given access to; we only care about whether they + // have sudo + req := new(logical.Request) + req.Operation = logical.ReadOperation + req.Path = path + authResults := acl.AllowOperation(req) + return authResults.RootPrivs +} + +// TTLsByPath returns the default and max TTLs corresponding to a particular +// mount point, or the system default +func (d dynamicSystemView) fetchTTLs() (def, max time.Duration) { + def = d.core.defaultLeaseTTL + max = d.core.maxLeaseTTL + + if d.mountEntry.Config.DefaultLeaseTTL != 0 { + def = d.mountEntry.Config.DefaultLeaseTTL + } + if d.mountEntry.Config.MaxLeaseTTL != 0 { + max = d.mountEntry.Config.MaxLeaseTTL + } + + return +} + +// Tainted indicates that the mount is in the process of being removed +func (d dynamicSystemView) Tainted() bool { + return d.mountEntry.Tainted +} + +// CachingDisabled indicates whether to use caching behavior +func (d dynamicSystemView) CachingDisabled() bool { + return d.core.cachingDisabled || (d.mountEntry != nil && d.mountEntry.Config.ForceNoCache) +} + +func (d dynamicSystemView) LocalMount() bool { + return d.mountEntry != nil && d.mountEntry.Local +} + +// Checks if this is a primary Vault instance. Caller should hold the stateLock +// in read mode. +func (d dynamicSystemView) ReplicationState() consts.ReplicationState { + return d.core.ReplicationState() +} + +// ResponseWrapData wraps the given data in a cubbyhole and returns the +// token used to unwrap. +func (d dynamicSystemView) ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "sys/wrapping/wrap", + } + + resp := &logical.Response{ + WrapInfo: &wrapping.ResponseWrapInfo{ + TTL: ttl, + }, + Data: data, + } + + if jwt { + resp.WrapInfo.Format = "jwt" + } + + _, err := d.core.wrapInCubbyhole(ctx, req, resp, nil) + if err != nil { + return nil, err + } + + return resp.WrapInfo, nil +} + +// LookupPlugin looks for a plugin with the given name in the plugin catalog. It +// returns a PluginRunner or an error if no plugin was found. +func (d dynamicSystemView) LookupPlugin(ctx context.Context, name string) (*pluginutil.PluginRunner, error) { + if d.core == nil { + return nil, fmt.Errorf("system view core is nil") + } + if d.core.pluginCatalog == nil { + return nil, fmt.Errorf("system view core plugin catalog is nil") + } + r, err := d.core.pluginCatalog.Get(ctx, name) + if err != nil { + return nil, err + } + if r == nil { + return nil, errwrap.Wrapf(fmt.Sprintf("{{err}}: %s", name), ErrPluginNotFound) + } + + return r, nil +} + +// MlockEnabled returns the configuration setting for enabling mlock on plugins. +func (d dynamicSystemView) MlockEnabled() bool { + return d.core.enableMlock +} + +func (d dynamicSystemView) EntityInfo(entityID string) (*logical.Entity, error) { + // Requests from token created from the token backend will not have entity information. + // Return missing entity instead of error when requesting from MemDB. + if entityID == "" { + return nil, nil + } + + if d.core == nil { + return nil, fmt.Errorf("system view core is nil") + } + if d.core.identityStore == nil { + return nil, fmt.Errorf("system view identity store is nil") + } + + // Retrieve the entity from MemDB + entity, err := d.core.identityStore.MemDBEntityByID(entityID, false) + if err != nil { + return nil, err + } + if entity == nil { + return nil, nil + } + + aliases := make([]*logical.Alias, len(entity.Aliases)) + for i, alias := range entity.Aliases { + aliases[i] = &logical.Alias{ + MountAccessor: alias.MountAccessor, + Name: alias.Name, + } + // MountType is not stored with the entity and must be looked up + if mount := d.core.router.validateMountByAccessor(alias.MountAccessor); mount != nil { + aliases[i].MountType = mount.MountType + } + } + + // Only returning a subset of the data + return &logical.Entity{ + ID: entity.ID, + Name: entity.Name, + Aliases: aliases, + }, nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/expiration.go b/vendor/github.com/hashicorp/vault/vault/expiration.go new file mode 100644 index 0000000..66b069d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/expiration.go @@ -0,0 +1,1372 @@ +package vault + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "path" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/armon/go-metrics" + log "github.com/hashicorp/go-hclog" + + "github.com/hashicorp/errwrap" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +const ( + // expirationSubPath is the sub-path used for the expiration manager + // view. This is nested under the system view. + expirationSubPath = "expire/" + + // leaseViewPrefix is the prefix used for the ID based lookup of leases. + leaseViewPrefix = "id/" + + // tokenViewPrefix is the prefix used for the token based lookup of leases. + tokenViewPrefix = "token/" + + // maxRevokeAttempts limits how many revoke attempts are made + maxRevokeAttempts = 6 + + // revokeRetryBase is a baseline retry time + revokeRetryBase = 10 * time.Second + + // maxLeaseDuration is the default maximum lease duration + maxLeaseTTL = 32 * 24 * time.Hour + + // defaultLeaseDuration is the default lease duration used when no lease is specified + defaultLeaseTTL = maxLeaseTTL + + //maxLeaseThreshold is the maximum lease count before generating log warning + maxLeaseThreshold = 256000 +) + +// ExpirationManager is used by the Core to manage leases. Secrets +// can provide a lease, meaning that they can be renewed or revoked. +// If a secret is not renewed in timely manner, it may be expired, and +// the ExpirationManager will handle doing automatic revocation. +type ExpirationManager struct { + router *Router + idView *BarrierView + tokenView *BarrierView + tokenStore *TokenStore + logger log.Logger + + pending map[string]*time.Timer + pendingLock sync.RWMutex + + tidyLock int32 + + restoreMode int32 + restoreModeLock sync.RWMutex + restoreRequestLock sync.RWMutex + restoreLocks []*locksutil.LockEntry + restoreLoaded sync.Map + quitCh chan struct{} + + coreStateLock *sync.RWMutex + quitContext context.Context + leaseCheckCounter uint32 + + logLeaseExpirations bool +} + +// NewExpirationManager creates a new ExpirationManager that is backed +// using a given view, and uses the provided router for revocation. +func NewExpirationManager(c *Core, view *BarrierView, logger log.Logger) *ExpirationManager { + exp := &ExpirationManager{ + router: c.router, + idView: view.SubView(leaseViewPrefix), + tokenView: view.SubView(tokenViewPrefix), + tokenStore: c.tokenStore, + logger: logger, + pending: make(map[string]*time.Timer), + + // new instances of the expiration manager will go immediately into + // restore mode + restoreMode: 1, + restoreLocks: locksutil.CreateLocks(), + quitCh: make(chan struct{}), + + coreStateLock: &c.stateLock, + quitContext: c.activeContext, + leaseCheckCounter: 0, + + logLeaseExpirations: os.Getenv("VAULT_SKIP_LOGGING_LEASE_EXPIRATIONS") == "", + } + + if exp.logger == nil { + opts := log.LoggerOptions{Name: "expiration_manager"} + exp.logger = log.New(&opts) + } + + return exp +} + +// setupExpiration is invoked after we've loaded the mount table to +// initialize the expiration manager +func (c *Core) setupExpiration() error { + c.metricsMutex.Lock() + defer c.metricsMutex.Unlock() + // Create a sub-view + view := c.systemBarrierView.SubView(expirationSubPath) + + // Create the manager + mgr := NewExpirationManager(c, view, c.logger.ResetNamed("expiration")) + c.expiration = mgr + + // Link the token store to this + c.tokenStore.SetExpirationManager(mgr) + + // Restore the existing state + c.logger.Info("restoring leases") + errorFunc := func() { + c.logger.Error("shutting down") + if err := c.Shutdown(); err != nil { + c.logger.Error("error shutting down core: %v", err) + } + } + go c.expiration.Restore(errorFunc) + + return nil +} + +// stopExpiration is used to stop the expiration manager before +// sealing the Vault. +func (c *Core) stopExpiration() error { + if c.expiration != nil { + if err := c.expiration.Stop(); err != nil { + return err + } + c.metricsMutex.Lock() + defer c.metricsMutex.Unlock() + c.expiration = nil + } + return nil +} + +// lockLease takes out a lock for a given lease ID +func (m *ExpirationManager) lockLease(leaseID string) { + locksutil.LockForKey(m.restoreLocks, leaseID).Lock() +} + +// unlockLease unlocks a given lease ID +func (m *ExpirationManager) unlockLease(leaseID string) { + locksutil.LockForKey(m.restoreLocks, leaseID).Unlock() +} + +// inRestoreMode returns if we are currently in restore mode +func (m *ExpirationManager) inRestoreMode() bool { + return atomic.LoadInt32(&m.restoreMode) == 1 +} + +// Tidy cleans up the dangling storage entries for leases. It scans the storage +// view to find all the available leases, checks if the token embedded in it is +// either empty or invalid and in both the cases, it revokes them. It also uses +// a token cache to avoid multiple lookups of the same token ID. It is normally +// not required to use the API that invokes this. This is only intended to +// clean up the corrupt storage due to bugs. +func (m *ExpirationManager) Tidy() error { + if m.inRestoreMode() { + return errors.New("cannot run tidy while restoring leases") + } + + var tidyErrors *multierror.Error + + if !atomic.CompareAndSwapInt32(&m.tidyLock, 0, 1) { + m.logger.Warn("tidy operation on leases is already in progress") + return fmt.Errorf("tidy operation on leases is already in progress") + } + + defer atomic.CompareAndSwapInt32(&m.tidyLock, 1, 0) + + m.logger.Info("beginning tidy operation on leases") + defer m.logger.Info("finished tidy operation on leases") + + // Create a cache to keep track of looked up tokens + tokenCache := make(map[string]bool) + var countLease, revokedCount, deletedCountInvalidToken, deletedCountEmptyToken int64 + + tidyFunc := func(leaseID string) { + countLease++ + if countLease%500 == 0 { + m.logger.Info("tidying leases", "progress", countLease) + } + + le, err := m.loadEntry(leaseID) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf(fmt.Sprintf("failed to load the lease ID %q: {{err}}", leaseID), err)) + return + } + + if le == nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf(fmt.Sprintf("nil entry for lease ID %q: {{err}}", leaseID), err)) + return + } + + var isValid, ok bool + revokeLease := false + if le.ClientToken == "" { + m.logger.Debug("revoking lease which has an empty token", "lease_id", leaseID) + revokeLease = true + deletedCountEmptyToken++ + goto REVOKE_CHECK + } + + isValid, ok = tokenCache[le.ClientToken] + if !ok { + saltedID, err := m.tokenStore.SaltID(m.quitContext, le.ClientToken) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to lookup salt id: {{err}}", err)) + return + } + lock := locksutil.LockForKey(m.tokenStore.tokenLocks, le.ClientToken) + lock.RLock() + te, err := m.tokenStore.lookupSalted(m.quitContext, saltedID, true) + lock.RUnlock() + + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to lookup token: {{err}}", err)) + return + } + + if te == nil { + m.logger.Debug("revoking lease which holds an invalid token", "lease_id", leaseID) + revokeLease = true + deletedCountInvalidToken++ + tokenCache[le.ClientToken] = false + } else { + tokenCache[le.ClientToken] = true + } + goto REVOKE_CHECK + } else { + if isValid { + return + } + + m.logger.Debug("revoking lease which contains an invalid token", "lease_id", leaseID) + revokeLease = true + deletedCountInvalidToken++ + goto REVOKE_CHECK + } + + REVOKE_CHECK: + if revokeLease { + // Force the revocation and skip going through the token store + // again + err = m.revokeCommon(leaseID, true, true) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf(fmt.Sprintf("failed to revoke an invalid lease with ID %q: {{err}}", leaseID), err)) + return + } + revokedCount++ + } + } + + if err := logical.ScanView(m.quitContext, m.idView, tidyFunc); err != nil { + return err + } + + m.logger.Info("number of leases scanned", "count", countLease) + m.logger.Info("number of leases which had empty tokens", "count", deletedCountEmptyToken) + m.logger.Info("number of leases which had invalid tokens", "count", deletedCountInvalidToken) + m.logger.Info("number of leases successfully revoked", "count", revokedCount) + + return tidyErrors.ErrorOrNil() +} + +// Restore is used to recover the lease states when starting. +// This is used after starting the vault. +func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) { + defer func() { + // Turn off restore mode. We can do this safely without the lock because + // if restore mode finished successfully, restore mode was already + // disabled with the lock. In an error state, this will allow the + // Stop() function to shut everything down. + atomic.StoreInt32(&m.restoreMode, 0) + + switch { + case retErr == nil: + case errwrap.Contains(retErr, ErrBarrierSealed.Error()): + // Don't run error func because we're likely already shutting down + m.logger.Warn("barrier sealed while restoring leases, stopping lease loading") + retErr = nil + default: + m.logger.Error("error restoring leases", "error", retErr) + if errorFunc != nil { + errorFunc() + } + } + }() + + // Accumulate existing leases + m.logger.Debug("collecting leases") + existing, err := logical.CollectKeys(m.quitContext, m.idView) + if err != nil { + return errwrap.Wrapf("failed to scan for leases: {{err}}", err) + } + m.logger.Debug("leases collected", "num_existing", len(existing)) + + // Make the channels used for the worker pool + broker := make(chan string) + quit := make(chan bool) + // Buffer these channels to prevent deadlocks + errs := make(chan error, len(existing)) + result := make(chan struct{}, len(existing)) + + // Use a wait group + wg := &sync.WaitGroup{} + + // Create 64 workers to distribute work to + for i := 0; i < consts.ExpirationRestoreWorkerCount; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + for { + select { + case leaseID, ok := <-broker: + // broker has been closed, we are done + if !ok { + return + } + + err := m.processRestore(leaseID) + if err != nil { + errs <- err + continue + } + + // Send message that lease is done + result <- struct{}{} + + // quit early + case <-quit: + return + + case <-m.quitCh: + return + } + } + }() + } + + // Distribute the collected keys to the workers in a go routine + wg.Add(1) + go func() { + defer wg.Done() + for i, leaseID := range existing { + if i > 0 && i%500 == 0 { + m.logger.Debug("leases loading", "progress", i) + } + + select { + case <-quit: + return + + case <-m.quitCh: + return + + default: + broker <- leaseID + } + } + + // Close the broker, causing worker routines to exit + close(broker) + }() + + // Ensure all keys on the chan are processed + for i := 0; i < len(existing); i++ { + select { + case err := <-errs: + // Close all go routines + close(quit) + return err + + case <-m.quitCh: + close(quit) + return nil + + case <-result: + } + } + + // Let all go routines finish + wg.Wait() + + m.restoreModeLock.Lock() + m.restoreLoaded = sync.Map{} + m.restoreLocks = nil + atomic.StoreInt32(&m.restoreMode, 0) + m.restoreModeLock.Unlock() + + m.logger.Info("lease restore complete") + return nil +} + +// processRestore takes a lease and restores it in the expiration manager if it has +// not already been seen +func (m *ExpirationManager) processRestore(leaseID string) error { + m.restoreRequestLock.RLock() + defer m.restoreRequestLock.RUnlock() + + // Check if the lease has been seen + if _, ok := m.restoreLoaded.Load(leaseID); ok { + return nil + } + + m.lockLease(leaseID) + defer m.unlockLease(leaseID) + + // Check again with the lease locked + if _, ok := m.restoreLoaded.Load(leaseID); ok { + return nil + } + + // Load lease and restore expiration timer + _, err := m.loadEntryInternal(leaseID, true, false) + if err != nil { + return err + } + return nil +} + +// Stop is used to prevent further automatic revocations. +// This must be called before sealing the view. +func (m *ExpirationManager) Stop() error { + // Stop all the pending expiration timers + m.logger.Debug("stop triggered") + defer m.logger.Debug("finished stopping") + + // Do this before stopping pending timers to avoid potential races with + // expiring timers + close(m.quitCh) + + m.pendingLock.Lock() + for _, timer := range m.pending { + timer.Stop() + } + m.pending = make(map[string]*time.Timer) + m.pendingLock.Unlock() + + if m.inRestoreMode() { + for { + if !m.inRestoreMode() { + break + } + time.Sleep(10 * time.Millisecond) + } + } + + return nil +} + +// Revoke is used to revoke a secret named by the given LeaseID +func (m *ExpirationManager) Revoke(leaseID string) error { + defer metrics.MeasureSince([]string{"expire", "revoke"}, time.Now()) + + return m.revokeCommon(leaseID, false, false) +} + +// revokeCommon does the heavy lifting. If force is true, we ignore a problem +// during revocation and still remove entries/index/lease timers +func (m *ExpirationManager) revokeCommon(leaseID string, force, skipToken bool) error { + defer metrics.MeasureSince([]string{"expire", "revoke-common"}, time.Now()) + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return err + } + + // If there is no entry, nothing to revoke + if le == nil { + return nil + } + + // Revoke the entry + if !skipToken || le.Auth == nil { + if err := m.revokeEntry(le); err != nil { + if !force { + return err + } + + if m.logger.IsWarn() { + m.logger.Warn("revocation from the backend failed, but in force mode so ignoring", "error", err) + } + } + } + + // Delete the entry + if err := m.deleteEntry(leaseID); err != nil { + return err + } + + // Delete the secondary index, but only if it's a leased secret (not auth) + if le.Secret != nil { + if err := m.removeIndexByToken(le.ClientToken, le.LeaseID); err != nil { + return err + } + } + + // Clear the expiration handler + m.pendingLock.Lock() + if timer, ok := m.pending[leaseID]; ok { + timer.Stop() + delete(m.pending, leaseID) + } + m.pendingLock.Unlock() + + if m.logger.IsInfo() && !skipToken && m.logLeaseExpirations { + m.logger.Info("revoked lease", "lease_id", leaseID) + } + + return nil +} + +// RevokeForce works similarly to RevokePrefix but continues in the case of a +// revocation error; this is mostly meant for recovery operations +func (m *ExpirationManager) RevokeForce(prefix string) error { + defer metrics.MeasureSince([]string{"expire", "revoke-force"}, time.Now()) + + return m.revokePrefixCommon(prefix, true) +} + +// RevokePrefix is used to revoke all secrets with a given prefix. +// The prefix maps to that of the mount table to make this simpler +// to reason about. +func (m *ExpirationManager) RevokePrefix(prefix string) error { + defer metrics.MeasureSince([]string{"expire", "revoke-prefix"}, time.Now()) + + return m.revokePrefixCommon(prefix, false) +} + +// RevokeByToken is used to revoke all the secrets issued with a given token. +// This is done by using the secondary index. It also removes the lease entry +// for the token itself. As a result it should *ONLY* ever be called from the +// token store's revokeSalted function. +func (m *ExpirationManager) RevokeByToken(te *TokenEntry) error { + defer metrics.MeasureSince([]string{"expire", "revoke-by-token"}, time.Now()) + + // Lookup the leases + existing, err := m.lookupLeasesByToken(te.ID) + if err != nil { + return errwrap.Wrapf("failed to scan for leases: {{err}}", err) + } + + // Revoke all the keys + for _, leaseID := range existing { + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return err + } + + // If there's a lease, set expiration to now, persist, and call + // updatePending to hand off revocation to the expiration manager's pending + // timer map + if le != nil { + le.ExpireTime = time.Now() + + if err := m.persistEntry(le); err != nil { + return err + } + + m.updatePending(le, 0) + } + } + + // te.Path should never be empty, but we check just in case + if te.Path != "" { + saltedID, err := m.tokenStore.SaltID(m.quitContext, te.ID) + if err != nil { + return err + } + tokenLeaseID := path.Join(te.Path, saltedID) + + // We want to skip the revokeEntry call as that will call back into + // revocation logic in the token store, which is what is running this + // function in the first place -- it'd be a deadlock loop. Since the only + // place that this function is called is revokeSalted in the token store, + // we're already revoking the token, so we just want to clean up the lease. + // This avoids spurious revocations later in the log when the timer runs + // out, and eases up resource usage. + return m.revokeCommon(tokenLeaseID, false, true) + } + + return nil +} + +func (m *ExpirationManager) revokePrefixCommon(prefix string, force bool) error { + if m.inRestoreMode() { + m.restoreRequestLock.Lock() + defer m.restoreRequestLock.Unlock() + } + + // Ensure there is a trailing slash; or, if there is no slash, see if there + // is a matching specific ID + if !strings.HasSuffix(prefix, "/") { + le, err := m.loadEntry(prefix) + if err == nil && le != nil { + if err := m.revokeCommon(prefix, force, false); err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to revoke %q: {{err}}", prefix), err) + } + return nil + } + prefix = prefix + "/" + } + + // Accumulate existing leases + sub := m.idView.SubView(prefix) + existing, err := logical.CollectKeys(m.quitContext, sub) + if err != nil { + return errwrap.Wrapf("failed to scan for leases: {{err}}", err) + } + + // Revoke all the keys + for idx, suffix := range existing { + leaseID := prefix + suffix + if err := m.revokeCommon(leaseID, force, false); err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to revoke %q (%d / %d): {{err}}", leaseID, idx+1, len(existing)), err) + } + } + return nil +} + +// Renew is used to renew a secret using the given leaseID +// and a renew interval. The increment may be ignored. +func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*logical.Response, error) { + defer metrics.MeasureSince([]string{"expire", "renew"}, time.Now()) + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return nil, err + } + + // Check if the lease is renewable + if _, err := le.renewable(); err != nil { + return nil, err + } + + if le.Secret == nil { + if le.Auth != nil { + return logical.ErrorResponse("tokens cannot be renewed through this endpoint"), logical.ErrPermissionDenied + } + return logical.ErrorResponse("lease does not correspond to a secret"), nil + } + + sysView := m.router.MatchingSystemView(le.Path) + if sysView == nil { + return nil, fmt.Errorf("unable to retrieve system view from router") + } + + // Attempt to renew the entry + resp, err := m.renewEntry(le, increment) + if err != nil { + return nil, err + } + if resp == nil { + return nil, nil + } + if resp.IsError() { + return &logical.Response{ + Data: resp.Data, + }, nil + } + if resp.Secret == nil { + return nil, nil + } + + ttl, warnings, err := framework.CalculateTTL(sysView, increment, resp.Secret.TTL, 0, resp.Secret.MaxTTL, 0, le.IssueTime) + if err != nil { + return nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) + } + resp.Secret.TTL = ttl + + // Attach the LeaseID + resp.Secret.LeaseID = leaseID + + // Update the lease entry + le.Data = resp.Data + le.Secret = resp.Secret + le.ExpireTime = resp.Secret.ExpirationTime() + le.LastRenewalTime = time.Now() + if err := m.persistEntry(le); err != nil { + return nil, err + } + + // Update the expiration time + m.updatePending(le, resp.Secret.LeaseTotal()) + + // Return the response + return resp, nil +} + +// RenewToken is used to renew a token which does not need to +// invoke a logical backend. +func (m *ExpirationManager) RenewToken(req *logical.Request, source string, token string, + increment time.Duration) (*logical.Response, error) { + defer metrics.MeasureSince([]string{"expire", "renew-token"}, time.Now()) + + // Compute the Lease ID + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return nil, err + } + leaseID := path.Join(source, saltedID) + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return nil, err + } + + // Check if the lease is renewable. Note that this also checks for a nil + // lease and errors in that case as well. + if _, err := le.renewable(); err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + + // Attempt to renew the auth entry + resp, err := m.renewAuthEntry(req, le, increment) + if err != nil { + return nil, err + } + if resp == nil { + return nil, nil + } + if resp.IsError() { + return &logical.Response{ + Data: resp.Data, + }, nil + } + if resp.Auth == nil { + return nil, nil + } + + sysView := m.router.MatchingSystemView(le.Path) + if sysView == nil { + return nil, fmt.Errorf("unable to retrieve system view from router") + } + + ttl, warnings, err := framework.CalculateTTL(sysView, increment, resp.Auth.TTL, resp.Auth.Period, resp.Auth.MaxTTL, resp.Auth.ExplicitMaxTTL, le.IssueTime) + if err != nil { + return nil, err + } + retResp := &logical.Response{} + for _, warning := range warnings { + retResp.AddWarning(warning) + } + resp.Auth.TTL = ttl + + // Attach the ClientToken + resp.Auth.ClientToken = token + + // Update the lease entry + le.Auth = resp.Auth + le.ExpireTime = resp.Auth.ExpirationTime() + le.LastRenewalTime = time.Now() + if err := m.persistEntry(le); err != nil { + return nil, err + } + + // Update the expiration time + m.updatePending(le, resp.Auth.LeaseTotal()) + + retResp.Auth = resp.Auth + return retResp, nil +} + +// Register is used to take a request and response with an associated +// lease. The secret gets assigned a LeaseID and the management of +// of lease is assumed by the expiration manager. +func (m *ExpirationManager) Register(req *logical.Request, resp *logical.Response) (id string, retErr error) { + defer metrics.MeasureSince([]string{"expire", "register"}, time.Now()) + + if req.ClientToken == "" { + return "", fmt.Errorf("cannot register a lease with an empty client token") + } + + // Ignore if there is no leased secret + if resp == nil || resp.Secret == nil { + return "", nil + } + + // Validate the secret + if err := resp.Secret.Validate(); err != nil { + return "", err + } + + // Create a lease entry + leaseUUID, err := uuid.GenerateUUID() + if err != nil { + return "", err + } + + leaseID := path.Join(req.Path, leaseUUID) + + defer func() { + // If there is an error we want to rollback as much as possible (note + // that errors here are ignored to do as much cleanup as we can). We + // want to revoke a generated secret (since an error means we may not + // be successfully tracking it), remove indexes, and delete the entry. + if retErr != nil { + revResp, err := m.router.Route(m.quitContext, logical.RevokeRequest(req.Path, resp.Secret, resp.Data)) + if err != nil { + retErr = multierror.Append(retErr, errwrap.Wrapf("an additional internal error was encountered revoking the newly-generated secret: {{err}}", err)) + } else if revResp != nil && revResp.IsError() { + retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered revoking the newly-generated secret: {{err}}", revResp.Error())) + } + + if err := m.deleteEntry(leaseID); err != nil { + retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered deleting any lease associated with the newly-generated secret: {{err}}", err)) + } + + if err := m.removeIndexByToken(req.ClientToken, leaseID); err != nil { + retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered removing lease indexes associated with the newly-generated secret: {{err}}", err)) + } + } + }() + + le := leaseEntry{ + LeaseID: leaseID, + ClientToken: req.ClientToken, + Path: req.Path, + Data: resp.Data, + Secret: resp.Secret, + IssueTime: time.Now(), + ExpireTime: resp.Secret.ExpirationTime(), + } + + // Encode the entry + if err := m.persistEntry(&le); err != nil { + return "", err + } + + // Maintain secondary index by token + if err := m.createIndexByToken(le.ClientToken, le.LeaseID); err != nil { + return "", err + } + + // Setup revocation timer if there is a lease + m.updatePending(&le, resp.Secret.LeaseTotal()) + + // Done + return le.LeaseID, nil +} + +// RegisterAuth is used to take an Auth response with an associated lease. +// The token does not get a LeaseID, but the lease management is handled by +// the expiration manager. +func (m *ExpirationManager) RegisterAuth(source string, auth *logical.Auth) error { + defer metrics.MeasureSince([]string{"expire", "register-auth"}, time.Now()) + + if auth.ClientToken == "" { + return fmt.Errorf("cannot register an auth lease with an empty token") + } + + if strings.Contains(source, "..") { + return consts.ErrPathContainsParentReferences + } + + saltedID, err := m.tokenStore.SaltID(m.quitContext, auth.ClientToken) + if err != nil { + return err + } + + // Create a lease entry + le := leaseEntry{ + LeaseID: path.Join(source, saltedID), + ClientToken: auth.ClientToken, + Auth: auth, + Path: source, + IssueTime: time.Now(), + ExpireTime: auth.ExpirationTime(), + } + + // Encode the entry + if err := m.persistEntry(&le); err != nil { + return err + } + + // Setup revocation timer + m.updatePending(&le, auth.LeaseTotal()) + + return nil +} + +// FetchLeaseTimesByToken is a helper function to use token values to compute +// the leaseID, rather than pushing that logic back into the token store. +func (m *ExpirationManager) FetchLeaseTimesByToken(source, token string) (*leaseEntry, error) { + defer metrics.MeasureSince([]string{"expire", "fetch-lease-times-by-token"}, time.Now()) + + // Compute the Lease ID + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return nil, err + } + leaseID := path.Join(source, saltedID) + return m.FetchLeaseTimes(leaseID) +} + +// FetchLeaseTimes is used to fetch the issue time, expiration time, and last +// renewed time of a lease entry. It returns a leaseEntry itself, but with only +// those values copied over. +func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error) { + defer metrics.MeasureSince([]string{"expire", "fetch-lease-times"}, time.Now()) + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return nil, err + } + if le == nil { + return nil, nil + } + + ret := &leaseEntry{ + IssueTime: le.IssueTime, + ExpireTime: le.ExpireTime, + LastRenewalTime: le.LastRenewalTime, + } + if le.Secret != nil { + ret.Secret = &logical.Secret{} + ret.Secret.Renewable = le.Secret.Renewable + ret.Secret.TTL = le.Secret.TTL + } + if le.Auth != nil { + ret.Auth = &logical.Auth{} + ret.Auth.Renewable = le.Auth.Renewable + ret.Auth.TTL = le.Auth.TTL + } + + return ret, nil +} + +// updatePending is used to update a pending invocation for a lease +func (m *ExpirationManager) updatePending(le *leaseEntry, leaseTotal time.Duration) { + m.pendingLock.Lock() + defer m.pendingLock.Unlock() + + // Check for an existing timer + timer, ok := m.pending[le.LeaseID] + + // If there is no expiry time, don't do anything + if le.ExpireTime.IsZero() { + // if the timer happened to exist, stop the time and delete it from the + // pending timers. + if ok { + timer.Stop() + delete(m.pending, le.LeaseID) + } + return + } + + // Create entry if it does not exist + if !ok { + timer := time.AfterFunc(leaseTotal, func() { + m.expireID(le.LeaseID) + }) + m.pending[le.LeaseID] = timer + return + } + + // Extend the timer by the lease total + timer.Reset(leaseTotal) +} + +// expireID is invoked when a given ID is expired +func (m *ExpirationManager) expireID(leaseID string) { + // Clear from the pending expiration + m.pendingLock.Lock() + delete(m.pending, leaseID) + m.pendingLock.Unlock() + + for attempt := uint(0); attempt < maxRevokeAttempts; attempt++ { + select { + case <-m.quitCh: + m.logger.Error("shutting down, not attempting further revocation of lease", "lease_id", leaseID) + return + default: + } + + m.coreStateLock.RLock() + if m.quitContext.Err() == context.Canceled { + m.logger.Error("core context canceled, not attempting further revocation of lease", "lease_id", leaseID) + m.coreStateLock.RUnlock() + return + } + + err := m.Revoke(leaseID) + if err == nil { + m.coreStateLock.RUnlock() + return + } + + m.coreStateLock.RUnlock() + m.logger.Error("failed to revoke lease", "lease_id", leaseID, "error", err) + time.Sleep((1 << attempt) * revokeRetryBase) + } + m.logger.Error("maximum revoke attempts reached", "lease_id", leaseID) +} + +// revokeEntry is used to attempt revocation of an internal entry +func (m *ExpirationManager) revokeEntry(le *leaseEntry) error { + // Revocation of login tokens is special since we can by-pass the + // backend and directly interact with the token store + if le.Auth != nil { + if err := m.tokenStore.revokeTree(m.quitContext, le.ClientToken); err != nil { + return errwrap.Wrapf("failed to revoke token: {{err}}", err) + } + + return nil + } + + // Handle standard revocation via backends + resp, err := m.router.Route(m.quitContext, logical.RevokeRequest(le.Path, le.Secret, le.Data)) + if err != nil || (resp != nil && resp.IsError()) { + return errwrap.Wrapf(fmt.Sprintf("failed to revoke entry: resp: %#v err: {{err}}", resp), err) + } + return nil +} + +// renewEntry is used to attempt renew of an internal entry +func (m *ExpirationManager) renewEntry(le *leaseEntry, increment time.Duration) (*logical.Response, error) { + secret := *le.Secret + secret.IssueTime = le.IssueTime + secret.Increment = increment + secret.LeaseID = "" + req := logical.RenewRequest(le.Path, &secret, le.Data) + resp, err := m.router.Route(m.quitContext, req) + if err != nil || (resp != nil && resp.IsError()) { + return nil, errwrap.Wrapf(fmt.Sprintf("failed to renew entry: resp: %#v err: {{err}}", resp), err) + } + return resp, nil +} + +// renewAuthEntry is used to attempt renew of an auth entry. Only the token +// store should get the actual token ID intact. +func (m *ExpirationManager) renewAuthEntry(req *logical.Request, le *leaseEntry, increment time.Duration) (*logical.Response, error) { + auth := *le.Auth + auth.IssueTime = le.IssueTime + auth.Increment = increment + if strings.HasPrefix(le.Path, "auth/token/") { + auth.ClientToken = le.ClientToken + } else { + auth.ClientToken = "" + } + + authReq := logical.RenewAuthRequest(le.Path, &auth, nil) + authReq.Connection = req.Connection + resp, err := m.router.Route(m.quitContext, authReq) + if err != nil { + return nil, errwrap.Wrapf("failed to renew entry: {{err}}", err) + } + return resp, nil +} + +// loadEntry is used to read a lease entry +func (m *ExpirationManager) loadEntry(leaseID string) (*leaseEntry, error) { + // Take out the lease locks after we ensure we are in restore mode + restoreMode := m.inRestoreMode() + if restoreMode { + m.restoreModeLock.RLock() + defer m.restoreModeLock.RUnlock() + + restoreMode = m.inRestoreMode() + if restoreMode { + m.lockLease(leaseID) + defer m.unlockLease(leaseID) + } + } + return m.loadEntryInternal(leaseID, restoreMode, true) +} + +// loadEntryInternal is used when you need to load an entry but also need to +// control the lifecycle of the restoreLock +func (m *ExpirationManager) loadEntryInternal(leaseID string, restoreMode bool, checkRestored bool) (*leaseEntry, error) { + out, err := m.idView.Get(m.quitContext, leaseID) + if err != nil { + return nil, errwrap.Wrapf("failed to read lease entry: {{err}}", err) + } + if out == nil { + return nil, nil + } + le, err := decodeLeaseEntry(out.Value) + if err != nil { + return nil, errwrap.Wrapf("failed to decode lease entry: {{err}}", err) + } + + if restoreMode { + if checkRestored { + // If we have already loaded this lease, we don't need to update on + // load. In the case of renewal and revocation, updatePending will be + // done after making the appropriate modifications to the lease. + if _, ok := m.restoreLoaded.Load(leaseID); ok { + return le, nil + } + } + + // Update the cache of restored leases, either synchronously or through + // the lazy loaded restore process + m.restoreLoaded.Store(le.LeaseID, struct{}{}) + + // Setup revocation timer + m.updatePending(le, le.ExpireTime.Sub(time.Now())) + } + return le, nil +} + +// persistEntry is used to persist a lease entry +func (m *ExpirationManager) persistEntry(le *leaseEntry) error { + // Encode the entry + buf, err := le.encode() + if err != nil { + return errwrap.Wrapf("failed to encode lease entry: {{err}}", err) + } + + // Write out to the view + ent := logical.StorageEntry{ + Key: le.LeaseID, + Value: buf, + } + if le.Auth != nil && len(le.Auth.Policies) == 1 && le.Auth.Policies[0] == "root" { + ent.SealWrap = true + } + if err := m.idView.Put(m.quitContext, &ent); err != nil { + return errwrap.Wrapf("failed to persist lease entry: {{err}}", err) + } + return nil +} + +// deleteEntry is used to delete a lease entry +func (m *ExpirationManager) deleteEntry(leaseID string) error { + if err := m.idView.Delete(m.quitContext, leaseID); err != nil { + return errwrap.Wrapf("failed to delete lease entry: {{err}}", err) + } + return nil +} + +// createIndexByToken creates a secondary index from the token to a lease entry +func (m *ExpirationManager) createIndexByToken(token, leaseID string) error { + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return err + } + + leaseSaltedID, err := m.tokenStore.SaltID(m.quitContext, leaseID) + if err != nil { + return err + } + + ent := logical.StorageEntry{ + Key: saltedID + "/" + leaseSaltedID, + Value: []byte(leaseID), + } + if err := m.tokenView.Put(m.quitContext, &ent); err != nil { + return errwrap.Wrapf("failed to persist lease index entry: {{err}}", err) + } + return nil +} + +// indexByToken looks up the secondary index from the token to a lease entry +func (m *ExpirationManager) indexByToken(token, leaseID string) (*logical.StorageEntry, error) { + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return nil, err + } + + leaseSaltedID, err := m.tokenStore.SaltID(m.quitContext, leaseID) + if err != nil { + return nil, err + } + + key := saltedID + "/" + leaseSaltedID + entry, err := m.tokenView.Get(m.quitContext, key) + if err != nil { + return nil, fmt.Errorf("failed to look up secondary index entry") + } + return entry, nil +} + +// removeIndexByToken removes the secondary index from the token to a lease entry +func (m *ExpirationManager) removeIndexByToken(token, leaseID string) error { + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return err + } + + leaseSaltedID, err := m.tokenStore.SaltID(m.quitContext, leaseID) + if err != nil { + return err + } + + key := saltedID + "/" + leaseSaltedID + if err := m.tokenView.Delete(m.quitContext, key); err != nil { + return errwrap.Wrapf("failed to delete lease index entry: {{err}}", err) + } + return nil +} + +// CreateOrFetchRevocationLeaseByToken is used to create or fetch the matching +// leaseID for a particular token. The lease is set to expire immediately after +// it's created. +func (m *ExpirationManager) CreateOrFetchRevocationLeaseByToken(te *TokenEntry) (string, error) { + // Fetch the saltedID of the token and construct the leaseID + saltedID, err := m.tokenStore.SaltID(m.quitContext, te.ID) + if err != nil { + return "", err + } + leaseID := path.Join(te.Path, saltedID) + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return "", err + } + + // If there's no associated leaseEntry for the token, we create one + if le == nil { + auth := &logical.Auth{ + ClientToken: te.ID, + LeaseOptions: logical.LeaseOptions{ + TTL: time.Nanosecond, + }, + } + + if strings.Contains(te.Path, "..") { + return "", consts.ErrPathContainsParentReferences + } + + // Create a lease entry + now := time.Now() + le = &leaseEntry{ + LeaseID: leaseID, + ClientToken: auth.ClientToken, + Auth: auth, + Path: te.Path, + IssueTime: now, + ExpireTime: now.Add(time.Nanosecond), + } + + // Encode the entry + if err := m.persistEntry(le); err != nil { + return "", err + } + } + + return le.LeaseID, nil +} + +// lookupLeasesByToken is used to lookup all the leaseID's via the tokenID +func (m *ExpirationManager) lookupLeasesByToken(token string) ([]string, error) { + saltedID, err := m.tokenStore.SaltID(m.quitContext, token) + if err != nil { + return nil, err + } + + // Scan via the index for sub-leases + prefix := saltedID + "/" + subKeys, err := m.tokenView.List(m.quitContext, prefix) + if err != nil { + return nil, errwrap.Wrapf("failed to list leases: {{err}}", err) + } + + // Read each index entry + leaseIDs := make([]string, 0, len(subKeys)) + for _, sub := range subKeys { + out, err := m.tokenView.Get(m.quitContext, prefix+sub) + if err != nil { + return nil, errwrap.Wrapf("failed to read lease index: {{err}}", err) + } + if out == nil { + continue + } + leaseIDs = append(leaseIDs, string(out.Value)) + } + return leaseIDs, nil +} + +// emitMetrics is invoked periodically to emit statistics +func (m *ExpirationManager) emitMetrics() { + m.pendingLock.RLock() + num := len(m.pending) + m.pendingLock.RUnlock() + metrics.SetGauge([]string{"expire", "num_leases"}, float32(num)) + // Check if lease count is greater than the threshold + if num > maxLeaseThreshold { + if atomic.LoadUint32(&m.leaseCheckCounter) > 59 { + m.logger.Warn("lease count exceeds warning lease threshold") + atomic.StoreUint32(&m.leaseCheckCounter, 0) + } else { + atomic.AddUint32(&m.leaseCheckCounter, 1) + } + } +} + +// leaseEntry is used to structure the values the expiration +// manager stores. This is used to handle renew and revocation. +type leaseEntry struct { + LeaseID string `json:"lease_id"` + ClientToken string `json:"client_token"` + Path string `json:"path"` + Data map[string]interface{} `json:"data"` + Secret *logical.Secret `json:"secret"` + Auth *logical.Auth `json:"auth"` + IssueTime time.Time `json:"issue_time"` + ExpireTime time.Time `json:"expire_time"` + LastRenewalTime time.Time `json:"last_renewal_time"` +} + +// encode is used to JSON encode the lease entry +func (le *leaseEntry) encode() ([]byte, error) { + return json.Marshal(le) +} + +func (le *leaseEntry) renewable() (bool, error) { + var err error + switch { + // If there is no entry, cannot review + case le == nil || le.ExpireTime.IsZero(): + err = fmt.Errorf("lease not found or lease is not renewable") + // Determine if the lease is expired + case le.ExpireTime.Before(time.Now()): + err = fmt.Errorf("lease expired") + // Determine if the lease is renewable + case le.Secret != nil && !le.Secret.Renewable: + err = fmt.Errorf("lease is not renewable") + case le.Auth != nil && !le.Auth.Renewable: + err = fmt.Errorf("lease is not renewable") + } + + if err != nil { + return false, err + } + return true, nil +} + +func (le *leaseEntry) ttl() int64 { + return int64(le.ExpireTime.Sub(time.Now().Round(time.Second)).Seconds()) +} + +// decodeLeaseEntry is used to reverse encode and return a new entry +func decodeLeaseEntry(buf []byte) (*leaseEntry, error) { + out := new(leaseEntry) + return out, jsonutil.DecodeJSON(buf, out) +} diff --git a/vendor/github.com/hashicorp/vault/vault/generate_root.go b/vendor/github.com/hashicorp/vault/vault/generate_root.go new file mode 100644 index 0000000..37f408e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/generate_root.go @@ -0,0 +1,366 @@ +package vault + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/pgpkeys" + "github.com/hashicorp/vault/helper/xor" + "github.com/hashicorp/vault/shamir" +) + +const coreDROperationTokenPath = "core/dr-operation-token" + +var ( + // GenerateStandardRootTokenStrategy is the strategy used to generate a + // typical root token + GenerateStandardRootTokenStrategy GenerateRootStrategy = generateStandardRootToken{} +) + +// GenerateRootStrategy allows us to swap out the strategy we want to use to +// create a token upon completion of the generate root process. +type GenerateRootStrategy interface { + generate(context.Context, *Core) (string, func(), error) +} + +// generateStandardRootToken implements the GenerateRootStrategy and is in +// charge of creating standard root tokens. +type generateStandardRootToken struct{} + +func (g generateStandardRootToken) generate(ctx context.Context, c *Core) (string, func(), error) { + te, err := c.tokenStore.rootToken(ctx) + if err != nil { + c.logger.Error("root token generation failed", "error", err) + return "", nil, err + } + if te == nil { + c.logger.Error("got nil token entry back from root generation") + return "", nil, fmt.Errorf("got nil token entry back from root generation") + } + + cleanupFunc := func() { + c.tokenStore.revokeOrphan(ctx, te.ID) + } + + return te.ID, cleanupFunc, nil +} + +// GenerateRootConfig holds the configuration for a root generation +// command. +type GenerateRootConfig struct { + Nonce string + PGPKey string + PGPFingerprint string + OTP string + Strategy GenerateRootStrategy +} + +// GenerateRootResult holds the result of a root generation update +// command +type GenerateRootResult struct { + Progress int + Required int + EncodedToken string + PGPFingerprint string +} + +// GenerateRootProgress is used to return the root generation progress (num shares) +func (c *Core) GenerateRootProgress() (int, error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return 0, consts.ErrSealed + } + if c.standby { + return 0, consts.ErrStandby + } + + c.generateRootLock.Lock() + defer c.generateRootLock.Unlock() + + return len(c.generateRootProgress), nil +} + +// GenerateRootConfiguration is used to read the root generation configuration +// It stubbornly refuses to return the OTP if one is there. +func (c *Core) GenerateRootConfiguration() (*GenerateRootConfig, error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, consts.ErrSealed + } + if c.standby { + return nil, consts.ErrStandby + } + + c.generateRootLock.Lock() + defer c.generateRootLock.Unlock() + + // Copy the config if any + var conf *GenerateRootConfig + if c.generateRootConfig != nil { + conf = new(GenerateRootConfig) + *conf = *c.generateRootConfig + conf.OTP = "" + conf.Strategy = nil + } + return conf, nil +} + +// GenerateRootInit is used to initialize the root generation settings +func (c *Core) GenerateRootInit(otp, pgpKey string, strategy GenerateRootStrategy) error { + var fingerprint string + switch { + case len(otp) > 0: + otpBytes, err := base64.StdEncoding.DecodeString(otp) + if err != nil { + return errwrap.Wrapf("error decoding base64 OTP value: {{err}}", err) + } + if otpBytes == nil || len(otpBytes) != 16 { + return fmt.Errorf("decoded OTP value is invalid or wrong length") + } + + case len(pgpKey) > 0: + fingerprints, err := pgpkeys.GetFingerprints([]string{pgpKey}, nil) + if err != nil { + return errwrap.Wrapf("error parsing PGP key: {{err}}", err) + } + if len(fingerprints) != 1 || fingerprints[0] == "" { + return fmt.Errorf("could not acquire PGP key entity") + } + fingerprint = fingerprints[0] + + default: + return fmt.Errorf("unreachable condition") + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return consts.ErrSealed + } + if c.standby { + return consts.ErrStandby + } + + c.generateRootLock.Lock() + defer c.generateRootLock.Unlock() + + // Prevent multiple concurrent root generations + if c.generateRootConfig != nil { + return fmt.Errorf("root generation already in progress") + } + + // Copy the configuration + generationNonce, err := uuid.GenerateUUID() + if err != nil { + return err + } + + c.generateRootConfig = &GenerateRootConfig{ + Nonce: generationNonce, + OTP: otp, + PGPKey: pgpKey, + PGPFingerprint: fingerprint, + Strategy: strategy, + } + + if c.logger.IsInfo() { + c.logger.Info("root generation initialized", "nonce", c.generateRootConfig.Nonce) + } + return nil +} + +// GenerateRootUpdate is used to provide a new key part +func (c *Core) GenerateRootUpdate(ctx context.Context, key []byte, nonce string, strategy GenerateRootStrategy) (*GenerateRootResult, error) { + // Verify the key length + min, max := c.barrier.KeyLength() + max += shamir.ShareOverhead + if len(key) < min { + return nil, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} + } + if len(key) > max { + return nil, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} + } + + // Get the seal configuration + var config *SealConfig + var err error + if c.seal.RecoveryKeySupported() { + config, err = c.seal.RecoveryConfig(ctx) + if err != nil { + return nil, err + } + } else { + config, err = c.seal.BarrierConfig(ctx) + if err != nil { + return nil, err + } + } + + // Ensure the barrier is initialized + if config == nil { + return nil, ErrNotInit + } + + // Ensure we are already unsealed + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, consts.ErrSealed + } + if c.standby { + return nil, consts.ErrStandby + } + + c.generateRootLock.Lock() + defer c.generateRootLock.Unlock() + + // Ensure a generateRoot is in progress + if c.generateRootConfig == nil { + return nil, fmt.Errorf("no root generation in progress") + } + + if nonce != c.generateRootConfig.Nonce { + return nil, fmt.Errorf("incorrect nonce supplied; nonce for this root generation operation is %q", c.generateRootConfig.Nonce) + } + + if strategy != c.generateRootConfig.Strategy { + return nil, fmt.Errorf("incorrect strategy supplied; a generate root operation of another type is already in progress") + } + + // Check if we already have this piece + for _, existing := range c.generateRootProgress { + if bytes.Equal(existing, key) { + return nil, fmt.Errorf("given key has already been provided during this generation operation") + } + } + + // Store this key + c.generateRootProgress = append(c.generateRootProgress, key) + progress := len(c.generateRootProgress) + + // Check if we don't have enough keys to unlock + if len(c.generateRootProgress) < config.SecretThreshold { + if c.logger.IsDebug() { + c.logger.Debug("cannot generate root, not enough keys", "keys", progress, "threshold", config.SecretThreshold) + } + return &GenerateRootResult{ + Progress: progress, + Required: config.SecretThreshold, + PGPFingerprint: c.generateRootConfig.PGPFingerprint, + }, nil + } + + // Recover the master key + var masterKey []byte + if config.SecretThreshold == 1 { + masterKey = c.generateRootProgress[0] + c.generateRootProgress = nil + } else { + masterKey, err = shamir.Combine(c.generateRootProgress) + c.generateRootProgress = nil + if err != nil { + return nil, errwrap.Wrapf("failed to compute master key: {{err}}", err) + } + } + + // Verify the master key + if c.seal.RecoveryKeySupported() { + if err := c.seal.VerifyRecoveryKey(ctx, masterKey); err != nil { + c.logger.Error("root generation aborted, recovery key verification failed", "error", err) + return nil, err + } + } else { + if err := c.barrier.VerifyMaster(masterKey); err != nil { + c.logger.Error("root generation aborted, master key verification failed", "error", err) + return nil, err + } + } + + // Run the generate strategy + tokenUUID, cleanupFunc, err := strategy.generate(ctx, c) + if err != nil { + return nil, err + } + + uuidBytes, err := uuid.ParseUUID(tokenUUID) + if err != nil { + cleanupFunc() + c.logger.Error("error getting generated token bytes", "error", err) + return nil, err + } + if uuidBytes == nil { + cleanupFunc() + c.logger.Error("got nil parsed UUID bytes") + return nil, fmt.Errorf("got nil parsed UUID bytes") + } + + var tokenBytes []byte + // Get the encoded value first so that if there is an error we don't create + // the root token. + switch { + case len(c.generateRootConfig.OTP) > 0: + // This function performs decoding checks so rather than decode the OTP, + // just encode the value we're passing in. + tokenBytes, err = xor.XORBase64(c.generateRootConfig.OTP, base64.StdEncoding.EncodeToString(uuidBytes)) + if err != nil { + cleanupFunc() + c.logger.Error("xor of root token failed", "error", err) + return nil, err + } + + case len(c.generateRootConfig.PGPKey) > 0: + _, tokenBytesArr, err := pgpkeys.EncryptShares([][]byte{[]byte(tokenUUID)}, []string{c.generateRootConfig.PGPKey}) + if err != nil { + cleanupFunc() + c.logger.Error("error encrypting new root token", "error", err) + return nil, err + } + tokenBytes = tokenBytesArr[0] + + default: + cleanupFunc() + return nil, fmt.Errorf("unreachable condition") + } + + results := &GenerateRootResult{ + Progress: progress, + Required: config.SecretThreshold, + EncodedToken: base64.StdEncoding.EncodeToString(tokenBytes), + PGPFingerprint: c.generateRootConfig.PGPFingerprint, + } + + if c.logger.IsInfo() { + c.logger.Info("root generation finished", "nonce", c.generateRootConfig.Nonce) + } + + c.generateRootProgress = nil + c.generateRootConfig = nil + return results, nil +} + +// GenerateRootCancel is used to cancel an in-progress root generation +func (c *Core) GenerateRootCancel() error { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return consts.ErrSealed + } + if c.standby { + return consts.ErrStandby + } + + c.generateRootLock.Lock() + defer c.generateRootLock.Unlock() + + // Clear any progress or config + c.generateRootConfig = nil + c.generateRootProgress = nil + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/ha.go b/vendor/github.com/hashicorp/vault/vault/ha.go new file mode 100644 index 0000000..8f08982 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/ha.go @@ -0,0 +1,718 @@ +package vault + +import ( + "context" + "crypto/ecdsa" + "crypto/x509" + "errors" + "fmt" + "sync/atomic" + "time" + + metrics "github.com/armon/go-metrics" + "github.com/hashicorp/errwrap" + multierror "github.com/hashicorp/go-multierror" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/physical" +) + +// Standby checks if the Vault is in standby mode +func (c *Core) Standby() (bool, error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + return c.standby, nil +} + +// Leader is used to get the current active leader +func (c *Core) Leader() (isLeader bool, leaderAddr, clusterAddr string, err error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + + // Check if sealed + if c.sealed { + return false, "", "", consts.ErrSealed + } + + // Check if HA enabled + if c.ha == nil { + return false, "", "", ErrHANotEnabled + } + + // Check if we are the leader + if !c.standby { + return true, c.redirectAddr, c.clusterAddr, nil + } + + // Initialize a lock + lock, err := c.ha.LockWith(coreLockPath, "read") + if err != nil { + return false, "", "", err + } + + // Read the value + held, leaderUUID, err := lock.Value() + if err != nil { + return false, "", "", err + } + if !held { + return false, "", "", nil + } + + c.clusterLeaderParamsLock.RLock() + localLeaderUUID := c.clusterLeaderUUID + localRedirAddr := c.clusterLeaderRedirectAddr + localClusterAddr := c.clusterLeaderClusterAddr + c.clusterLeaderParamsLock.RUnlock() + + // If the leader hasn't changed, return the cached value; nothing changes + // mid-leadership, and the barrier caches anyways + if leaderUUID == localLeaderUUID && localRedirAddr != "" { + return false, localRedirAddr, localClusterAddr, nil + } + + c.logger.Trace("found new active node information, refreshing") + + c.clusterLeaderParamsLock.Lock() + defer c.clusterLeaderParamsLock.Unlock() + + // Validate base conditions again + if leaderUUID == c.clusterLeaderUUID && c.clusterLeaderRedirectAddr != "" { + return false, localRedirAddr, localClusterAddr, nil + } + + key := coreLeaderPrefix + leaderUUID + // Use background because postUnseal isn't run on standby + entry, err := c.barrier.Get(context.Background(), key) + if err != nil { + return false, "", "", err + } + if entry == nil { + return false, "", "", nil + } + + var oldAdv bool + + var adv activeAdvertisement + err = jsonutil.DecodeJSON(entry.Value, &adv) + if err != nil { + // Fall back to pre-struct handling + adv.RedirectAddr = string(entry.Value) + c.logger.Debug("parsed redirect addr for new active node", "redirect_addr", adv.RedirectAddr) + oldAdv = true + } + + if !oldAdv { + c.logger.Debug("parsing information for new active node", "active_cluster_addr", adv.ClusterAddr, "active_redirect_addr", adv.RedirectAddr) + + // Ensure we are using current values + err = c.loadLocalClusterTLS(adv) + if err != nil { + return false, "", "", err + } + + // This will ensure that we both have a connection at the ready and that + // the address is the current known value + // Since this is standby, we don't use the active context. Later we may + // use a process-scoped context + err = c.refreshRequestForwardingConnection(context.Background(), adv.ClusterAddr) + if err != nil { + return false, "", "", err + } + } + + // Don't set these until everything has been parsed successfully or we'll + // never try again + c.clusterLeaderRedirectAddr = adv.RedirectAddr + c.clusterLeaderClusterAddr = adv.ClusterAddr + c.clusterLeaderUUID = leaderUUID + + return false, adv.RedirectAddr, adv.ClusterAddr, nil +} + +// StepDown is used to step down from leadership +func (c *Core) StepDown(req *logical.Request) (retErr error) { + defer metrics.MeasureSince([]string{"core", "step_down"}, time.Now()) + + if req == nil { + retErr = multierror.Append(retErr, errors.New("nil request to step-down")) + return retErr + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil + } + if c.ha == nil || c.standby { + return nil + } + + ctx := c.activeContext + + acl, te, entity, err := c.fetchACLTokenEntryAndEntity(req) + if err != nil { + retErr = multierror.Append(retErr, err) + return retErr + } + + // Audit-log the request before going any further + auth := &logical.Auth{ + ClientToken: req.ClientToken, + } + if te != nil { + auth.Policies = te.Policies + auth.Metadata = te.Meta + auth.DisplayName = te.DisplayName + auth.EntityID = te.EntityID + } + + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + } + if err := c.auditBroker.LogRequest(ctx, logInput, c.auditedHeaders); err != nil { + c.logger.Error("failed to audit request", "request_path", req.Path, "error", err) + retErr = multierror.Append(retErr, errors.New("failed to audit request, cannot continue")) + return retErr + } + + if entity != nil && entity.Disabled { + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + + // Attempt to use the token (decrement num_uses) + if te != nil { + te, err = c.tokenStore.UseToken(ctx, te) + if err != nil { + c.logger.Error("failed to use token", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return retErr + } + if te == nil { + // Token has been revoked + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + return retErr + } + } + + // Verify that this operation is allowed + authResults := c.performPolicyChecks(ctx, acl, te, req, entity, &PolicyCheckOpts{ + RootPrivsRequired: true, + }) + if authResults.Error.ErrorOrNil() != nil { + retErr = multierror.Append(retErr, authResults.Error) + return retErr + } + if !authResults.Allowed { + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + return retErr + } + + if te != nil && te.NumUses == tokenRevocationPending { + // Token needs to be revoked. We do this immediately here because + // we won't have a token store after sealing. + leaseID, err := c.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err == nil { + err = c.expiration.Revoke(leaseID) + } + if err != nil { + c.logger.Error("token needed revocation before step-down but failed to revoke", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + } + } + + select { + case c.manualStepDownCh <- struct{}{}: + default: + c.logger.Warn("manual step-down operation already queued") + } + + return retErr +} + +// runStandby is a long running routine that is used when an HA backend +// is enabled. It waits until we are leader and switches this Vault to +// active. +func (c *Core) runStandby(doneCh, manualStepDownCh, stopCh chan struct{}) { + defer close(doneCh) + defer close(manualStepDownCh) + c.logger.Info("entering standby mode") + + // Monitor for key rotation + keyRotateDone := make(chan struct{}) + keyRotateStop := make(chan struct{}) + go c.periodicCheckKeyUpgrade(context.Background(), keyRotateDone, keyRotateStop) + // Monitor for new leadership + checkLeaderDone := make(chan struct{}) + checkLeaderStop := make(chan struct{}) + go c.periodicLeaderRefresh(checkLeaderDone, checkLeaderStop) + defer func() { + c.logger.Debug("closed periodic key rotation checker stop channel") + close(keyRotateStop) + <-keyRotateDone + close(checkLeaderStop) + c.logger.Debug("closed periodic leader refresh stop channel") + <-checkLeaderDone + c.logger.Debug("periodic leader refresh returned") + }() + + var manualStepDown bool + for { + // Check for a shutdown + select { + case <-stopCh: + c.logger.Debug("stop channel triggered in runStandby") + return + default: + // If we've just down, we could instantly grab the lock again. Give + // the other nodes a chance. + if manualStepDown { + time.Sleep(manualStepDownSleepPeriod) + manualStepDown = false + } + } + + // Create a lock + uuid, err := uuid.GenerateUUID() + if err != nil { + c.logger.Error("failed to generate uuid", "error", err) + return + } + lock, err := c.ha.LockWith(coreLockPath, uuid) + if err != nil { + c.logger.Error("failed to create lock", "error", err) + return + } + + // Attempt the acquisition + leaderLostCh := c.acquireLock(lock, stopCh) + + // Bail if we are being shutdown + if leaderLostCh == nil { + return + } + c.logger.Info("acquired lock, enabling active operation") + + // This is used later to log a metrics event; this can be helpful to + // detect flapping + activeTime := time.Now() + + // Grab the lock as we need it for cluster setup, which needs to happen + // before advertising; + + lockGrabbedCh := make(chan struct{}) + go func() { + // Grab the lock + c.stateLock.Lock() + // If stopCh has been closed, which only happens while the + // stateLock is held, we have actually terminated, so we just + // instantly give up the lock, otherwise we notify that it's ready + // for consumption + select { + case <-stopCh: + c.stateLock.Unlock() + default: + close(lockGrabbedCh) + } + }() + + select { + case <-stopCh: + lock.Unlock() + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + return + case <-lockGrabbedCh: + // We now have the lock and can use it + } + + if c.sealed { + c.logger.Warn("grabbed HA lock but already sealed, exiting") + lock.Unlock() + c.stateLock.Unlock() + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + return + } + + // Store the lock so that we can manually clear it later if needed + c.heldHALock = lock + + // We haven't run postUnseal yet so we have nothing meaningful to use here + ctx := context.Background() + + // This block is used to wipe barrier/seal state and verify that + // everything is sane. If we have no sanity in the barrier, we actually + // seal, as there's little we can do. + { + c.seal.SetBarrierConfig(ctx, nil) + if c.seal.RecoveryKeySupported() { + c.seal.SetRecoveryConfig(ctx, nil) + } + + if err := c.performKeyUpgrades(ctx); err != nil { + // We call this in a goroutine so that we can give up the + // statelock and have this shut us down; sealInternal has a + // workflow where it watches for the stopCh to close so we want + // to return from here + c.logger.Error("error performing key upgrades", "error", err) + go c.Shutdown() + c.heldHALock = nil + lock.Unlock() + c.stateLock.Unlock() + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + return + } + } + + // Clear previous local cluster cert info so we generate new. Since the + // UUID will have changed, standbys will know to look for new info + c.localClusterParsedCert.Store((*x509.Certificate)(nil)) + c.localClusterCert.Store(([]byte)(nil)) + c.localClusterPrivateKey.Store((*ecdsa.PrivateKey)(nil)) + + if err := c.setupCluster(ctx); err != nil { + c.heldHALock = nil + lock.Unlock() + c.stateLock.Unlock() + c.logger.Error("cluster setup failed", "error", err) + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + continue + } + + // Advertise as leader + if err := c.advertiseLeader(ctx, uuid, leaderLostCh); err != nil { + c.heldHALock = nil + lock.Unlock() + c.stateLock.Unlock() + c.logger.Error("leader advertisement setup failed", "error", err) + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + continue + } + + // Attempt the post-unseal process + err = c.postUnseal() + if err == nil { + c.standby = false + } + + c.stateLock.Unlock() + + // Handle a failure to unseal + if err != nil { + c.logger.Error("post-unseal setup failed", "error", err) + lock.Unlock() + metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime) + continue + } + + // Monitor a loss of leadership + releaseHALock := true + grabStateLock := true + select { + case <-leaderLostCh: + c.logger.Warn("leadership lost, stopping active operation") + case <-stopCh: + // This case comes from sealInternal; we will already be having the + // state lock held so we do toggle grabStateLock to false + if atomic.LoadUint32(&c.keepHALockOnStepDown) == 1 { + releaseHALock = false + } + grabStateLock = false + case <-manualStepDownCh: + c.logger.Warn("stepping down from active operation to standby") + manualStepDown = true + } + + metrics.MeasureSince([]string{"core", "leadership_lost"}, activeTime) + + // Tell any requests that know about this to stop + if c.activeContextCancelFunc != nil { + c.activeContextCancelFunc() + } + + // Attempt the pre-seal process + if grabStateLock { + c.stateLock.Lock() + } + c.standby = true + preSealErr := c.preSeal() + if grabStateLock { + c.stateLock.Unlock() + } + + if releaseHALock { + if err := c.clearLeader(uuid); err != nil { + c.logger.Error("clearing leader advertisement failed", "error", err) + } + c.heldHALock.Unlock() + c.heldHALock = nil + } + + // Check for a failure to prepare to seal + if preSealErr != nil { + c.logger.Error("pre-seal teardown failed", "error", err) + } + } +} + +// This checks the leader periodically to ensure that we switch RPC to a new +// leader pretty quickly. There is logic in Leader() already to not make this +// onerous and avoid more traffic than needed, so we just call that and ignore +// the result. +func (c *Core) periodicLeaderRefresh(doneCh, stopCh chan struct{}) { + defer close(doneCh) + var opCount int32 + for { + select { + case <-time.After(leaderCheckInterval): + count := atomic.AddInt32(&opCount, 1) + if count > 1 { + atomic.AddInt32(&opCount, -1) + continue + } + // We do this in a goroutine because otherwise if this refresh is + // called while we're shutting down the call to Leader() can + // deadlock, which then means stopCh can never been seen and we can + // block shutdown + go func() { + defer atomic.AddInt32(&opCount, -1) + c.Leader() + }() + case <-stopCh: + return + } + } +} + +// periodicCheckKeyUpgrade is used to watch for key rotation events as a standby +func (c *Core) periodicCheckKeyUpgrade(ctx context.Context, doneCh, stopCh chan struct{}) { + defer close(doneCh) + var opCount int32 + for { + select { + case <-time.After(keyRotateCheckInterval): + count := atomic.AddInt32(&opCount, 1) + if count > 1 { + atomic.AddInt32(&opCount, -1) + continue + } + + go func() { + defer atomic.AddInt32(&opCount, -1) + // Only check if we are a standby + c.stateLock.RLock() + standby := c.standby + c.stateLock.RUnlock() + if !standby { + return + } + + // Check for a poison pill. If we can read it, it means we have stale + // keys (e.g. from replication being activated) and we need to seal to + // be unsealed again. + entry, _ := c.barrier.Get(ctx, poisonPillPath) + if entry != nil && len(entry.Value) > 0 { + c.logger.Warn("encryption keys have changed out from underneath us (possibly due to replication enabling), must be unsealed again") + go c.Shutdown() + return + } + + if err := c.checkKeyUpgrades(ctx); err != nil { + c.logger.Error("key rotation periodic upgrade check failed", "error", err) + } + }() + case <-stopCh: + return + } + } +} + +// checkKeyUpgrades is used to check if there have been any key rotations +// and if there is a chain of upgrades available +func (c *Core) checkKeyUpgrades(ctx context.Context) error { + for { + // Check for an upgrade + didUpgrade, newTerm, err := c.barrier.CheckUpgrade(ctx) + if err != nil { + return err + } + + // Nothing to do if no upgrade + if !didUpgrade { + break + } + if c.logger.IsInfo() { + c.logger.Info("upgraded to new key term", "term", newTerm) + } + } + return nil +} + +func (c *Core) performKeyUpgrades(ctx context.Context) error { + if err := c.checkKeyUpgrades(ctx); err != nil { + return errwrap.Wrapf("error checking for key upgrades: {{err}}", err) + } + + if err := c.barrier.ReloadMasterKey(ctx); err != nil { + return errwrap.Wrapf("error reloading master key: {{err}}", err) + } + + if err := c.barrier.ReloadKeyring(ctx); err != nil { + return errwrap.Wrapf("error reloading keyring: {{err}}", err) + } + + if err := c.scheduleUpgradeCleanup(ctx); err != nil { + return errwrap.Wrapf("error scheduling upgrade cleanup: {{err}}", err) + } + + return nil +} + +// scheduleUpgradeCleanup is used to ensure that all the upgrade paths +// are cleaned up in a timely manner if a leader failover takes place +func (c *Core) scheduleUpgradeCleanup(ctx context.Context) error { + // List the upgrades + upgrades, err := c.barrier.List(ctx, keyringUpgradePrefix) + if err != nil { + return errwrap.Wrapf("failed to list upgrades: {{err}}", err) + } + + // Nothing to do if no upgrades + if len(upgrades) == 0 { + return nil + } + + // Schedule cleanup for all of them + time.AfterFunc(keyRotateGracePeriod, func() { + sealed, err := c.barrier.Sealed() + if err != nil { + c.logger.Warn("failed to check barrier status at upgrade cleanup time") + return + } + if sealed { + c.logger.Warn("barrier sealed at upgrade cleanup time") + return + } + for _, upgrade := range upgrades { + path := fmt.Sprintf("%s%s", keyringUpgradePrefix, upgrade) + if err := c.barrier.Delete(ctx, path); err != nil { + c.logger.Error("failed to cleanup upgrade", "path", path, "error", err) + } + } + }) + return nil +} + +// acquireLock blocks until the lock is acquired, returning the leaderLostCh +func (c *Core) acquireLock(lock physical.Lock, stopCh <-chan struct{}) <-chan struct{} { + for { + // Attempt lock acquisition + leaderLostCh, err := lock.Lock(stopCh) + if err == nil { + return leaderLostCh + } + + // Retry the acquisition + c.logger.Error("failed to acquire lock", "error", err) + select { + case <-time.After(lockRetryInterval): + case <-stopCh: + return nil + } + } +} + +// advertiseLeader is used to advertise the current node as leader +func (c *Core) advertiseLeader(ctx context.Context, uuid string, leaderLostCh <-chan struct{}) error { + go c.cleanLeaderPrefix(ctx, uuid, leaderLostCh) + + var key *ecdsa.PrivateKey + switch c.localClusterPrivateKey.Load().(type) { + case *ecdsa.PrivateKey: + key = c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey) + default: + c.logger.Error("unknown cluster private key type", "key_type", fmt.Sprintf("%T", c.localClusterPrivateKey.Load())) + return fmt.Errorf("unknown cluster private key type %T", c.localClusterPrivateKey.Load()) + } + + keyParams := &clusterKeyParams{ + Type: corePrivateKeyTypeP521, + X: key.X, + Y: key.Y, + D: key.D, + } + + locCert := c.localClusterCert.Load().([]byte) + localCert := make([]byte, len(locCert)) + copy(localCert, locCert) + adv := &activeAdvertisement{ + RedirectAddr: c.redirectAddr, + ClusterAddr: c.clusterAddr, + ClusterCert: localCert, + ClusterKeyParams: keyParams, + } + val, err := jsonutil.EncodeJSON(adv) + if err != nil { + return err + } + ent := &Entry{ + Key: coreLeaderPrefix + uuid, + Value: val, + } + err = c.barrier.Put(ctx, ent) + if err != nil { + return err + } + + sd, ok := c.ha.(physical.ServiceDiscovery) + if ok { + if err := sd.NotifyActiveStateChange(); err != nil { + if c.logger.IsWarn() { + c.logger.Warn("failed to notify active status", "error", err) + } + } + } + return nil +} + +func (c *Core) cleanLeaderPrefix(ctx context.Context, uuid string, leaderLostCh <-chan struct{}) { + keys, err := c.barrier.List(ctx, coreLeaderPrefix) + if err != nil { + c.logger.Error("failed to list entries in core/leader", "error", err) + return + } + for len(keys) > 0 { + select { + case <-time.After(leaderPrefixCleanDelay): + if keys[0] != uuid { + c.barrier.Delete(ctx, coreLeaderPrefix+keys[0]) + } + keys = keys[1:] + case <-leaderLostCh: + return + } + } +} + +// clearLeader is used to clear our leadership entry +func (c *Core) clearLeader(uuid string) error { + key := coreLeaderPrefix + uuid + err := c.barrier.Delete(c.activeContext, key) + + // Advertise ourselves as a standby + sd, ok := c.ha.(physical.ServiceDiscovery) + if ok { + if err := sd.NotifyActiveStateChange(); err != nil { + if c.logger.IsWarn() { + c.logger.Warn("failed to notify standby status", "error", err) + } + } + } + + return err +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_lookup.go b/vendor/github.com/hashicorp/vault/vault/identity_lookup.go new file mode 100644 index 0000000..20d7ea0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_lookup.go @@ -0,0 +1,329 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func lookupPaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "lookup/entity$", + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeString, + Description: "Name of the entity.", + }, + "id": { + Type: framework.TypeString, + Description: "ID of the entity.", + }, + "alias_id": { + Type: framework.TypeString, + Description: "ID of the alias.", + }, + "alias_name": { + Type: framework.TypeString, + Description: "Name of the alias. This should be supplied in conjunction with 'alias_mount_accessor'.", + }, + "alias_mount_accessor": { + Type: framework.TypeString, + Description: "Accessor of the mount to which the alias belongs to. This should be supplied in conjunction with 'alias_name'.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathLookupEntityUpdate(), + }, + + HelpSynopsis: strings.TrimSpace(lookupHelp["lookup-entity"][0]), + HelpDescription: strings.TrimSpace(lookupHelp["lookup-entity"][1]), + }, + { + Pattern: "lookup/group$", + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeString, + Description: "Name of the group.", + }, + "id": { + Type: framework.TypeString, + Description: "ID of the group.", + }, + "alias_id": { + Type: framework.TypeString, + Description: "ID of the alias.", + }, + "alias_name": { + Type: framework.TypeString, + Description: "Name of the alias. This should be supplied in conjunction with 'alias_mount_accessor'.", + }, + "alias_mount_accessor": { + Type: framework.TypeString, + Description: "Accessor of the mount to which the alias belongs to. This should be supplied in conjunction with 'alias_name'.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathLookupGroupUpdate(), + }, + + HelpSynopsis: strings.TrimSpace(lookupHelp["lookup-group"][0]), + HelpDescription: strings.TrimSpace(lookupHelp["lookup-group"][1]), + }, + } +} + +func (i *IdentityStore) pathLookupEntityUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + var entity *identity.Entity + var err error + + inputCount := 0 + + id := "" + idRaw, ok := d.GetOk("id") + if ok { + inputCount++ + id = idRaw.(string) + } + + name := "" + nameRaw, ok := d.GetOk("name") + if ok { + inputCount++ + name = nameRaw.(string) + } + + aliasID := "" + aliasIDRaw, ok := d.GetOk("alias_id") + if ok { + inputCount++ + aliasID = aliasIDRaw.(string) + } + + aliasName := "" + aliasNameRaw, ok := d.GetOk("alias_name") + if ok { + inputCount++ + aliasName = aliasNameRaw.(string) + } + + aliasMountAccessor := "" + aliasMountAccessorRaw, ok := d.GetOk("alias_mount_accessor") + if ok { + inputCount++ + aliasMountAccessor = aliasMountAccessorRaw.(string) + } + + switch { + case inputCount == 0: + return logical.ErrorResponse(fmt.Sprintf("query parameter not supplied")), nil + + case inputCount != 1: + switch { + case inputCount == 2 && aliasName != "" && aliasMountAccessor != "": + default: + return logical.ErrorResponse(fmt.Sprintf("query parameter conflict; please supply distinct set of query parameters")), nil + } + + case inputCount == 1: + switch { + case aliasName != "" || aliasMountAccessor != "": + return logical.ErrorResponse(fmt.Sprintf("both 'alias_name' and 'alias_mount_accessor' needs to be set")), nil + } + } + + switch { + case id != "": + entity, err = i.MemDBEntityByID(id, false) + if err != nil { + return nil, err + } + + case name != "": + entity, err = i.MemDBEntityByName(name, false) + if err != nil { + return nil, err + } + + case aliasID != "": + alias, err := i.MemDBAliasByID(aliasID, false, false) + if err != nil { + return nil, err + } + + if alias == nil { + break + } + + entity, err = i.MemDBEntityByAliasID(alias.ID, false) + if err != nil { + return nil, err + } + + case aliasName != "" && aliasMountAccessor != "": + alias, err := i.MemDBAliasByFactors(aliasMountAccessor, aliasName, false, false) + if err != nil { + return nil, err + } + + if alias == nil { + break + } + + entity, err = i.MemDBEntityByAliasID(alias.ID, false) + if err != nil { + return nil, err + } + } + + if entity == nil { + return nil, nil + } + + return i.handleEntityReadCommon(entity) + } +} + +func (i *IdentityStore) pathLookupGroupUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + var group *identity.Group + var err error + + inputCount := 0 + + id := "" + idRaw, ok := d.GetOk("id") + if ok { + inputCount++ + id = idRaw.(string) + } + + name := "" + nameRaw, ok := d.GetOk("name") + if ok { + inputCount++ + name = nameRaw.(string) + } + + aliasID := "" + aliasIDRaw, ok := d.GetOk("alias_id") + if ok { + inputCount++ + aliasID = aliasIDRaw.(string) + } + + aliasName := "" + aliasNameRaw, ok := d.GetOk("alias_name") + if ok { + inputCount++ + aliasName = aliasNameRaw.(string) + } + + aliasMountAccessor := "" + aliasMountAccessorRaw, ok := d.GetOk("alias_mount_accessor") + if ok { + inputCount++ + aliasMountAccessor = aliasMountAccessorRaw.(string) + } + + switch { + case inputCount == 0: + return logical.ErrorResponse(fmt.Sprintf("query parameter not supplied")), nil + + case inputCount != 1: + switch { + case inputCount == 2 && aliasName != "" && aliasMountAccessor != "": + default: + return logical.ErrorResponse(fmt.Sprintf("query parameter conflict; please supply distinct set of query parameters")), nil + } + + case inputCount == 1: + switch { + case aliasName != "" || aliasMountAccessor != "": + return logical.ErrorResponse(fmt.Sprintf("both 'alias_name' and 'alias_mount_accessor' needs to be set")), nil + } + } + + switch { + case id != "": + group, err = i.MemDBGroupByID(id, false) + if err != nil { + return nil, err + } + case name != "": + group, err = i.MemDBGroupByName(name, false) + if err != nil { + return nil, err + } + case aliasID != "": + alias, err := i.MemDBAliasByID(aliasID, false, true) + if err != nil { + return nil, err + } + + if alias == nil { + break + } + + group, err = i.MemDBGroupByAliasID(alias.ID, false) + if err != nil { + return nil, err + } + + case aliasName != "" && aliasMountAccessor != "": + alias, err := i.MemDBAliasByFactors(aliasMountAccessor, aliasName, false, true) + if err != nil { + return nil, err + } + + if alias == nil { + break + } + + group, err = i.MemDBGroupByAliasID(alias.ID, false) + if err != nil { + return nil, err + } + } + + if group == nil { + return nil, nil + } + + return i.handleGroupReadCommon(group) + } +} + +var lookupHelp = map[string][2]string{ + "lookup-entity": { + "Query entities based on various properties.", + `Distinct query parameters to be set: + - 'id' + To query the entity by its ID. + - 'name' + To query the entity by its name. + - 'alias_id' + To query the entity by the ID of any of its aliases. + - 'alias_name' and 'alias_mount_accessor' + To query the entity by the unique factors that represent an alias; the name and the mount accessor. + `, + }, + "lookup-group": { + "Query groups based on various properties.", + `Distinct query parameters to be set: + - 'id' + To query the group by its ID. + - 'name' + To query the group by its name. + - 'alias_id' + To query the group by the ID of any of its aliases. + - 'alias_name' and 'alias_mount_accessor' + To query the group by the unique factors that represent an alias; the name and the mount accessor. + `, + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store.go b/vendor/github.com/hashicorp/vault/vault/identity_store.go new file mode 100644 index 0000000..6faddac --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store.go @@ -0,0 +1,399 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/storagepacker" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +const ( + groupBucketsPrefix = "packer/group/buckets/" +) + +func (c *Core) IdentityStore() *IdentityStore { + return c.identityStore +} + +// NewIdentityStore creates a new identity store +func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendConfig, logger log.Logger) (*IdentityStore, error) { + var err error + + // Create a new in-memory database for the identity store + db, err := memdb.NewMemDB(identityStoreSchema()) + if err != nil { + return nil, errwrap.Wrapf("failed to create memdb for identity store: {{err}}", err) + } + + iStore := &IdentityStore{ + view: config.StorageView, + db: db, + entityLocks: locksutil.CreateLocks(), + logger: logger, + core: core, + } + + iStore.entityPacker, err = storagepacker.NewStoragePacker(iStore.view, iStore.logger, "") + if err != nil { + return nil, errwrap.Wrapf("failed to create entity packer: {{err}}", err) + } + + iStore.groupPacker, err = storagepacker.NewStoragePacker(iStore.view, iStore.logger, groupBucketsPrefix) + if err != nil { + return nil, errwrap.Wrapf("failed to create group packer: {{err}}", err) + } + + iStore.Backend = &framework.Backend{ + BackendType: logical.TypeLogical, + Paths: framework.PathAppend( + entityPaths(iStore), + aliasPaths(iStore), + groupAliasPaths(iStore), + groupPaths(iStore), + lookupPaths(iStore), + upgradePaths(iStore), + ), + Invalidate: iStore.Invalidate, + } + + err = iStore.Setup(ctx, config) + if err != nil { + return nil, err + } + + return iStore, nil +} + +// Invalidate is a callback wherein the backend is informed that the value at +// the given key is updated. In identity store's case, it would be the entity +// storage entries that get updated. The value needs to be read and MemDB needs +// to be updated accordingly. +func (i *IdentityStore) Invalidate(ctx context.Context, key string) { + i.logger.Debug("invalidate notification received", "key", key) + + switch { + // Check if the key is a storage entry key for an entity bucket + case strings.HasPrefix(key, storagepacker.StoragePackerBucketsPrefix): + // Get the hash value of the storage bucket entry key + bucketKeyHash := i.entityPacker.BucketKeyHashByKey(key) + if len(bucketKeyHash) == 0 { + i.logger.Error("failed to get the bucket entry key hash") + return + } + + // Create a MemDB transaction + txn := i.db.Txn(true) + defer txn.Abort() + + // Each entity object in MemDB holds the MD5 hash of the storage + // entry key of the entity bucket. Fetch all the entities that + // belong to this bucket using the hash value. Remove these entities + // from MemDB along with all the aliases of each entity. + entitiesFetched, err := i.MemDBEntitiesByBucketEntryKeyHashInTxn(txn, string(bucketKeyHash)) + if err != nil { + i.logger.Error("failed to fetch entities using the bucket entry key hash", "bucket_entry_key_hash", bucketKeyHash) + return + } + + for _, entity := range entitiesFetched { + // Delete all the aliases in the entity. This function will also remove + // the corresponding alias indexes too. + err = i.deleteAliasesInEntityInTxn(txn, entity, entity.Aliases) + if err != nil { + i.logger.Error("failed to delete aliases in entity", "entity_id", entity.ID, "error", err) + return + } + + // Delete the entity using the same transaction + err = i.MemDBDeleteEntityByIDInTxn(txn, entity.ID) + if err != nil { + i.logger.Error("failed to delete entity from MemDB", "entity_id", entity.ID, "error", err) + return + } + } + + // Get the storage bucket entry + bucket, err := i.entityPacker.GetBucket(key) + if err != nil { + i.logger.Error("failed to refresh entities", "key", key, "error", err) + return + } + + // If the underlying entry is nil, it means that this invalidation + // notification is for the deletion of the underlying storage entry. At + // this point, since all the entities belonging to this bucket are + // already removed, there is nothing else to be done. But, if the + // storage entry is non-nil, its an indication of an update. In this + // case, entities in the updated bucket needs to be reinserted into + // MemDB. + if bucket != nil { + for _, item := range bucket.Items { + entity, err := i.parseEntityFromBucketItem(ctx, item) + if err != nil { + i.logger.Error("failed to parse entity from bucket entry item", "error", err) + return + } + + // Only update MemDB and don't touch the storage + err = i.upsertEntityInTxn(txn, entity, nil, false, false) + if err != nil { + i.logger.Error("failed to update entity in MemDB", "error", err) + return + } + } + } + + txn.Commit() + return + + // Check if the key is a storage entry key for an group bucket + case strings.HasPrefix(key, groupBucketsPrefix): + // Get the hash value of the storage bucket entry key + bucketKeyHash := i.groupPacker.BucketKeyHashByKey(key) + if len(bucketKeyHash) == 0 { + i.logger.Error("failed to get the bucket entry key hash") + return + } + + // Create a MemDB transaction + txn := i.db.Txn(true) + defer txn.Abort() + + groupsFetched, err := i.MemDBGroupsByBucketEntryKeyHashInTxn(txn, string(bucketKeyHash)) + if err != nil { + i.logger.Error("failed to fetch groups using the bucket entry key hash", "bucket_entry_key_hash", bucketKeyHash) + return + } + + for _, group := range groupsFetched { + // Delete the group using the same transaction + err = i.MemDBDeleteGroupByIDInTxn(txn, group.ID) + if err != nil { + i.logger.Error("failed to delete group from MemDB", "group_id", group.ID, "error", err) + return + } + } + + // Get the storage bucket entry + bucket, err := i.groupPacker.GetBucket(key) + if err != nil { + i.logger.Error("failed to refresh group", "key", key, "error", err) + return + } + + if bucket != nil { + for _, item := range bucket.Items { + group, err := i.parseGroupFromBucketItem(item) + if err != nil { + i.logger.Error("failed to parse group from bucket entry item", "error", err) + return + } + + // Before updating the group, check if the group exists. If it + // does, then delete the group alias from memdb, for the + // invalidation would have sent an update. + groupFetched, err := i.MemDBGroupByIDInTxn(txn, group.ID, true) + if err != nil { + i.logger.Error("failed to fetch group from MemDB", "error", err) + return + } + + // If the group has an alias remove it from memdb + if groupFetched != nil && groupFetched.Alias != nil { + err := i.MemDBDeleteAliasByIDInTxn(txn, groupFetched.Alias.ID, true) + if err != nil { + i.logger.Error("failed to delete old group alias from MemDB", "error", err) + return + } + } + + // Update MemDB with new group alias information + if group.Alias != nil { + err = i.MemDBUpsertAliasInTxn(txn, group.Alias, true) + if err != nil { + i.logger.Error("failed to update group alias in MemDB", "error", err) + return + } + } + + // Only update MemDB and don't touch the storage + err = i.upsertGroupInTxn(txn, group, false) + if err != nil { + i.logger.Error("failed to update group in MemDB", "error", err) + return + } + } + } + + txn.Commit() + return + } +} + +func (i *IdentityStore) parseEntityFromBucketItem(ctx context.Context, item *storagepacker.Item) (*identity.Entity, error) { + if item == nil { + return nil, fmt.Errorf("nil item") + } + + var entity identity.Entity + err := ptypes.UnmarshalAny(item.Message, &entity) + if err != nil { + return nil, errwrap.Wrapf("failed to decode entity from storage bucket item: {{err}}", err) + } + + return &entity, nil +} + +func (i *IdentityStore) parseGroupFromBucketItem(item *storagepacker.Item) (*identity.Group, error) { + if item == nil { + return nil, fmt.Errorf("nil item") + } + + var group identity.Group + err := ptypes.UnmarshalAny(item.Message, &group) + if err != nil { + return nil, errwrap.Wrapf("failed to decode group from storage bucket item: {{err}}", err) + } + + return &group, nil +} + +// entityByAliasFactors fetches the entity based on factors of alias, i.e mount +// accessor and the alias name. +func (i *IdentityStore) entityByAliasFactors(mountAccessor, aliasName string, clone bool) (*identity.Entity, error) { + if mountAccessor == "" { + return nil, fmt.Errorf("missing mount accessor") + } + + if aliasName == "" { + return nil, fmt.Errorf("missing alias name") + } + + txn := i.db.Txn(false) + + return i.entityByAliasFactorsInTxn(txn, mountAccessor, aliasName, clone) +} + +// entityByAlaisFactorsInTxn fetches the entity based on factors of alias, i.e +// mount accessor and the alias name. +func (i *IdentityStore) entityByAliasFactorsInTxn(txn *memdb.Txn, mountAccessor, aliasName string, clone bool) (*identity.Entity, error) { + if txn == nil { + return nil, fmt.Errorf("nil txn") + } + + if mountAccessor == "" { + return nil, fmt.Errorf("missing mount accessor") + } + + if aliasName == "" { + return nil, fmt.Errorf("missing alias name") + } + + alias, err := i.MemDBAliasByFactorsInTxn(txn, mountAccessor, aliasName, false, false) + if err != nil { + return nil, err + } + + if alias == nil { + return nil, nil + } + + return i.MemDBEntityByAliasIDInTxn(txn, alias.ID, clone) +} + +// CreateOrFetchEntity creates a new entity. This is used by core to +// associate each login attempt by an alias to a unified entity in Vault. +func (i *IdentityStore) CreateOrFetchEntity(alias *logical.Alias) (*identity.Entity, error) { + var entity *identity.Entity + var err error + + if alias == nil { + return nil, fmt.Errorf("alias is nil") + } + + if alias.Name == "" { + return nil, fmt.Errorf("empty alias name") + } + + mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor) + if mountValidationResp == nil { + return nil, fmt.Errorf("invalid mount accessor %q", alias.MountAccessor) + } + + if mountValidationResp.MountLocal { + return nil, fmt.Errorf("mount_accessor %q is of a local mount", alias.MountAccessor) + } + + if mountValidationResp.MountType != alias.MountType { + return nil, fmt.Errorf("mount accessor %q is not a mount of type %q", alias.MountAccessor, alias.MountType) + } + + // Check if an entity already exists for the given alais + entity, err = i.entityByAliasFactors(alias.MountAccessor, alias.Name, false) + if err != nil { + return nil, err + } + if entity != nil { + return entity, nil + } + + // Create a MemDB transaction to update both alias and entity + txn := i.db.Txn(true) + defer txn.Abort() + + // Check if an entity was created before acquiring the lock + entity, err = i.entityByAliasFactorsInTxn(txn, alias.MountAccessor, alias.Name, false) + if err != nil { + return nil, err + } + if entity != nil { + return entity, nil + } + + i.logger.Debug("creating a new entity", "alias", alias) + + entity = &identity.Entity{} + + err = i.sanitizeEntity(entity) + if err != nil { + return nil, err + } + + // Create a new alias + newAlias := &identity.Alias{ + CanonicalID: entity.ID, + Name: alias.Name, + MountAccessor: alias.MountAccessor, + MountPath: mountValidationResp.MountPath, + MountType: mountValidationResp.MountType, + } + + err = i.sanitizeAlias(newAlias) + if err != nil { + return nil, err + } + + // Append the new alias to the new entity + entity.Aliases = []*identity.Alias{ + newAlias, + } + + // Update MemDB and persist entity object + err = i.upsertEntityInTxn(txn, entity, nil, true, false) + if err != nil { + return nil, err + } + + txn.Commit() + + return entity, nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_aliases.go b/vendor/github.com/hashicorp/vault/vault/identity_store_aliases.go new file mode 100644 index 0000000..1f578df --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_aliases.go @@ -0,0 +1,480 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/errwrap" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// aliasPaths returns the API endpoints to operate on aliases. +// Following are the paths supported: +// entity-alias - To register/modify an alias +// entity-alias/id - To read, modify, delete and list aliases based on their ID +func aliasPaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "entity-alias$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the entity alias. If set, updates the corresponding entity alias.", + }, + // entity_id is deprecated in favor of canonical_id + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasRegister(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias"][1]), + }, + // BC path for identity/entity-alias + { + Pattern: "alias$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + // entity_id is deprecated + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasRegister(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias"][1]), + }, + { + Pattern: "entity-alias/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + // entity_id is deprecated + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias should be tied to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasIDUpdate(), + logical.ReadOperation: i.pathAliasIDRead(), + logical.DeleteOperation: i.pathAliasIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id"][1]), + }, + { + Pattern: "entity-alias/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathAliasIDList(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id-list"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id-list"][1]), + }, + } +} + +// pathAliasRegister is used to register new alias +func (i *IdentityStore) pathAliasRegister() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, ok := d.GetOk("id") + if ok { + return i.pathAliasIDUpdate()(ctx, req, d) + } + + return i.handleAliasUpdateCommon(req, d, nil) + } +} + +// pathAliasIDUpdate is used to update an alias based on the given +// alias ID +func (i *IdentityStore) pathAliasIDUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // Get alias id + aliasID := d.Get("id").(string) + + if aliasID == "" { + return logical.ErrorResponse("empty alias ID"), nil + } + + alias, err := i.MemDBAliasByID(aliasID, true, false) + if err != nil { + return nil, err + } + if alias == nil { + return logical.ErrorResponse("invalid alias id"), nil + } + + return i.handleAliasUpdateCommon(req, d, alias) + } +} + +// handleAliasUpdateCommon is used to update an alias +func (i *IdentityStore) handleAliasUpdateCommon(req *logical.Request, d *framework.FieldData, alias *identity.Alias) (*logical.Response, error) { + var err error + var newAlias bool + var entity *identity.Entity + var previousEntity *identity.Entity + + // Alias will be nil when a new alias is being registered; create a + // new struct in that case. + if alias == nil { + alias = &identity.Alias{} + newAlias = true + } + + // Get entity id + canonicalID := d.Get("entity_id").(string) + if canonicalID == "" { + canonicalID = d.Get("canonical_id").(string) + } + + if canonicalID != "" { + entity, err = i.MemDBEntityByID(canonicalID, true) + if err != nil { + return nil, err + } + if entity == nil { + return logical.ErrorResponse("invalid entity ID"), nil + } + } + + // Get alias name + aliasName := d.Get("name").(string) + if aliasName == "" { + return logical.ErrorResponse("missing alias name"), nil + } + + mountAccessor := d.Get("mount_accessor").(string) + if mountAccessor == "" { + return logical.ErrorResponse("missing mount_accessor"), nil + } + + mountValidationResp := i.core.router.validateMountByAccessor(mountAccessor) + if mountValidationResp == nil { + return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil + } + + if mountValidationResp.MountLocal { + return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", mountAccessor)), nil + } + + // Get alias metadata + metadata, ok, err := d.GetOkErr("metadata") + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("failed to parse metadata: %v", err)), nil + } + var aliasMetadata map[string]string + if ok { + aliasMetadata = metadata.(map[string]string) + } + + aliasByFactors, err := i.MemDBAliasByFactors(mountValidationResp.MountAccessor, aliasName, false, false) + if err != nil { + return nil, err + } + + resp := &logical.Response{} + + if newAlias { + if aliasByFactors != nil { + return logical.ErrorResponse("combination of mount and alias name is already in use"), nil + } + + // If this is an alias being tied to a non-existent entity, create + // a new entity for it. + if entity == nil { + entity = &identity.Entity{ + Aliases: []*identity.Alias{ + alias, + }, + } + } else { + entity.Aliases = append(entity.Aliases, alias) + } + } else { + // Verify that the combination of alias name and mount is not + // already tied to a different alias + if aliasByFactors != nil && aliasByFactors.ID != alias.ID { + return logical.ErrorResponse("combination of mount and alias name is already in use"), nil + } + + // Fetch the entity to which the alias is tied to + existingEntity, err := i.MemDBEntityByAliasID(alias.ID, true) + if err != nil { + return nil, err + } + + if existingEntity == nil { + return nil, fmt.Errorf("alias is not associated with an entity") + } + + if entity != nil && entity.ID != existingEntity.ID { + // Alias should be transferred from 'existingEntity' to 'entity' + err = i.deleteAliasFromEntity(existingEntity, alias) + if err != nil { + return nil, err + } + previousEntity = existingEntity + entity.Aliases = append(entity.Aliases, alias) + resp.AddWarning(fmt.Sprintf("alias is being transferred from entity %q to %q", existingEntity.ID, entity.ID)) + } else { + // Update entity with modified alias + err = i.updateAliasInEntity(existingEntity, alias) + if err != nil { + return nil, err + } + entity = existingEntity + } + } + + // ID creation and other validations; This is more useful for new entities + // and may not perform anything for the existing entities. Placing the + // check here to make the flow common for both new and existing entities. + err = i.sanitizeEntity(entity) + if err != nil { + return nil, err + } + + // Update the fields + alias.Name = aliasName + alias.Metadata = aliasMetadata + alias.MountAccessor = mountValidationResp.MountAccessor + + // Explicitly set to empty as in the past we incorrectly saved it + alias.MountPath = "" + alias.MountType = "" + + // Set the canonical ID in the alias index. This should be done after + // sanitizing entity. + alias.CanonicalID = entity.ID + + // ID creation and other validations + err = i.sanitizeAlias(alias) + if err != nil { + return nil, err + } + + // Index entity and its aliases in MemDB and persist entity along with + // aliases in storage. If the alias is being transferred over from + // one entity to another, previous entity needs to get refreshed in MemDB + // and persisted in storage as well. + err = i.upsertEntity(entity, previousEntity, true) + if err != nil { + return nil, err + } + + // Return ID of both alias and entity + resp.Data = map[string]interface{}{ + "id": alias.ID, + "canonical_id": entity.ID, + } + + return resp, nil +} + +// pathAliasIDRead returns the properties of an alias for a given +// alias ID +func (i *IdentityStore) pathAliasIDRead() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + aliasID := d.Get("id").(string) + if aliasID == "" { + return logical.ErrorResponse("missing alias id"), nil + } + + alias, err := i.MemDBAliasByID(aliasID, false, false) + if err != nil { + return nil, err + } + + return i.handleAliasReadCommon(alias) + } +} + +func (i *IdentityStore) handleAliasReadCommon(alias *identity.Alias) (*logical.Response, error) { + if alias == nil { + return nil, nil + } + + respData := map[string]interface{}{} + respData["id"] = alias.ID + respData["canonical_id"] = alias.CanonicalID + respData["mount_accessor"] = alias.MountAccessor + respData["metadata"] = alias.Metadata + respData["name"] = alias.Name + respData["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs + + if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil { + respData["mount_path"] = mountValidationResp.MountPath + respData["mount_type"] = mountValidationResp.MountType + } + + // Convert protobuf timestamp into RFC3339 format + respData["creation_time"] = ptypes.TimestampString(alias.CreationTime) + respData["last_update_time"] = ptypes.TimestampString(alias.LastUpdateTime) + + return &logical.Response{ + Data: respData, + }, nil +} + +// pathAliasIDDelete deletes the alias for a given alias ID +func (i *IdentityStore) pathAliasIDDelete() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + aliasID := d.Get("id").(string) + if aliasID == "" { + return logical.ErrorResponse("missing alias ID"), nil + } + + return nil, i.deleteAlias(aliasID) + } +} + +// pathAliasIDList lists the IDs of all the valid aliases in the identity +// store +func (i *IdentityStore) pathAliasIDList() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + ws := memdb.NewWatchSet() + iter, err := i.MemDBAliases(ws, false) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch iterator for aliases in memdb: {{err}}", err) + } + + var aliasIDs []string + aliasInfo := map[string]interface{}{} + + type mountInfo struct { + MountType string + MountPath string + } + mountAccessorMap := map[string]mountInfo{} + + for { + raw := iter.Next() + if raw == nil { + break + } + alias := raw.(*identity.Alias) + aliasIDs = append(aliasIDs, alias.ID) + aliasInfoEntry := map[string]interface{}{ + "name": alias.Name, + "canonical_id": alias.CanonicalID, + "mount_accessor": alias.MountAccessor, + } + + mi, ok := mountAccessorMap[alias.MountAccessor] + if ok { + aliasInfoEntry["mount_type"] = mi.MountType + aliasInfoEntry["mount_path"] = mi.MountPath + } else { + mi = mountInfo{} + if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil { + mi.MountType = mountValidationResp.MountType + mi.MountPath = mountValidationResp.MountPath + aliasInfoEntry["mount_type"] = mi.MountType + aliasInfoEntry["mount_path"] = mi.MountPath + } + mountAccessorMap[alias.MountAccessor] = mi + } + + aliasInfo[alias.ID] = aliasInfoEntry + } + + return logical.ListResponseWithInfo(aliasIDs, aliasInfo), nil + } +} + +var aliasHelp = map[string][2]string{ + "alias": { + "Create a new alias.", + "", + }, + "alias-id": { + "Update, read or delete an alias ID.", + "", + }, + "alias-id-list": { + "List all the alias IDs.", + "", + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_entities.go b/vendor/github.com/hashicorp/vault/vault/identity_store_entities.go new file mode 100644 index 0000000..5096ed0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_entities.go @@ -0,0 +1,599 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/errwrap" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/storagepacker" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// entityPaths returns the API endpoints supported to operate on entities. +// Following are the paths supported: +// entity - To register a new entity +// entity/id - To lookup, modify, delete and list entities based on ID +// entity/merge - To merge entities based on ID +func entityPaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "entity$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the entity. If set, updates the corresponding existing entity.", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the entity", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the entity. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + "policies": { + Type: framework.TypeCommaStringSlice, + Description: "Policies to be tied to the entity.", + }, + "disabled": { + Type: framework.TypeBool, + Description: "If set true, tokens tied to this identity will not be able to be used (but will not be revoked).", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathEntityRegister(), + }, + + HelpSynopsis: strings.TrimSpace(entityHelp["entity"][0]), + HelpDescription: strings.TrimSpace(entityHelp["entity"][1]), + }, + { + Pattern: "entity/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the entity.", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the entity.", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the entity. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + "policies": { + Type: framework.TypeCommaStringSlice, + Description: "Policies to be tied to the entity.", + }, + "disabled": { + Type: framework.TypeBool, + Description: "If set true, tokens tied to this identity will not be able to be used (but will not be revoked).", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathEntityIDUpdate(), + logical.ReadOperation: i.pathEntityIDRead(), + logical.DeleteOperation: i.pathEntityIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(entityHelp["entity-id"][0]), + HelpDescription: strings.TrimSpace(entityHelp["entity-id"][1]), + }, + { + Pattern: "entity/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathEntityIDList(), + }, + + HelpSynopsis: strings.TrimSpace(entityHelp["entity-id-list"][0]), + HelpDescription: strings.TrimSpace(entityHelp["entity-id-list"][1]), + }, + { + Pattern: "entity/merge/?$", + Fields: map[string]*framework.FieldSchema{ + "from_entity_ids": { + Type: framework.TypeCommaStringSlice, + Description: "Entity IDs which needs to get merged", + }, + "to_entity_id": { + Type: framework.TypeString, + Description: "Entity ID into which all the other entities need to get merged", + }, + "force": { + Type: framework.TypeBool, + Description: "Setting this will follow the 'mine' strategy for merging MFA secrets. If there are secrets of the same type both in entities that are merged from and in entity into which all others are getting merged, secrets in the destination will be unaltered. If not set, this API will throw an error containing all the conflicts.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathEntityMergeID(), + }, + + HelpSynopsis: strings.TrimSpace(entityHelp["entity-merge-id"][0]), + HelpDescription: strings.TrimSpace(entityHelp["entity-merge-id"][1]), + }, + } +} + +// pathEntityMergeID merges two or more entities into a single entity +func (i *IdentityStore) pathEntityMergeID() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + toEntityID := d.Get("to_entity_id").(string) + if toEntityID == "" { + return logical.ErrorResponse("missing entity id to merge to"), nil + } + + fromEntityIDs := d.Get("from_entity_ids").([]string) + if len(fromEntityIDs) == 0 { + return logical.ErrorResponse("missing entity ids to merge from"), nil + } + + force := d.Get("force").(bool) + + toEntityForLocking, err := i.MemDBEntityByID(toEntityID, false) + if err != nil { + return nil, err + } + + if toEntityForLocking == nil { + return logical.ErrorResponse("entity id to merge to is invalid"), nil + } + + // Acquire the lock to modify the entity storage entry to merge to + toEntityLock := locksutil.LockForKey(i.entityLocks, toEntityForLocking.ID) + toEntityLock.Lock() + defer toEntityLock.Unlock() + + // Create a MemDB transaction to merge entities + txn := i.db.Txn(true) + defer txn.Abort() + + // Re-read post lock acquisition + toEntity, err := i.MemDBEntityByID(toEntityID, true) + if err != nil { + return nil, err + } + + if toEntity == nil { + return logical.ErrorResponse("entity id to merge to is invalid"), nil + } + + if toEntity.ID != toEntityForLocking.ID { + return logical.ErrorResponse("acquired lock for an undesired entity"), nil + } + + var conflictErrors error + for _, fromEntityID := range fromEntityIDs { + if fromEntityID == toEntityID { + return logical.ErrorResponse("to_entity_id should not be present in from_entity_ids"), nil + } + + lockFromEntity, err := i.MemDBEntityByID(fromEntityID, false) + if err != nil { + return nil, err + } + + if lockFromEntity == nil { + return logical.ErrorResponse("entity id to merge from is invalid"), nil + } + + // Acquire the lock to modify the entity storage entry to merge from + fromEntityLock := locksutil.LockForKey(i.entityLocks, lockFromEntity.ID) + + fromLockHeld := false + + // There are only 256 lock buckets and the chances of entity ID collision + // is fairly high. When we are merging entities belonging to the same + // bucket, multiple attempts to acquire the same lock should be avoided. + if fromEntityLock != toEntityLock { + fromEntityLock.Lock() + fromLockHeld = true + } + + // Re-read the entities post lock acquisition + fromEntity, err := i.MemDBEntityByID(fromEntityID, false) + if err != nil { + if fromLockHeld { + fromEntityLock.Unlock() + } + return nil, err + } + + if fromEntity == nil { + if fromLockHeld { + fromEntityLock.Unlock() + } + return logical.ErrorResponse("entity id to merge from is invalid"), nil + } + + if fromEntity.ID != lockFromEntity.ID { + if fromLockHeld { + fromEntityLock.Unlock() + } + return logical.ErrorResponse("acquired lock for an undesired entity"), nil + } + + for _, alias := range fromEntity.Aliases { + // Set the desired canonical ID + alias.CanonicalID = toEntity.ID + + alias.MergedFromCanonicalIDs = append(alias.MergedFromCanonicalIDs, fromEntity.ID) + + err = i.MemDBUpsertAliasInTxn(txn, alias, false) + if err != nil { + if fromLockHeld { + fromEntityLock.Unlock() + } + return nil, errwrap.Wrapf("failed to update alias during merge: {{err}}", err) + } + + // Add the alias to the desired entity + toEntity.Aliases = append(toEntity.Aliases, alias) + } + + // If the entity from which we are merging from was already a merged + // entity, transfer over the Merged set to the entity we are + // merging into. + toEntity.MergedEntityIDs = append(toEntity.MergedEntityIDs, fromEntity.MergedEntityIDs...) + + // Add the entity from which we are merging from to the list of entities + // the entity we are merging into is composed of. + toEntity.MergedEntityIDs = append(toEntity.MergedEntityIDs, fromEntity.ID) + + // Delete the entity which we are merging from in MemDB using the same transaction + err = i.MemDBDeleteEntityByIDInTxn(txn, fromEntity.ID) + if err != nil { + if fromLockHeld { + fromEntityLock.Unlock() + } + return nil, err + } + + // Delete the entity which we are merging from in storage + err = i.entityPacker.DeleteItem(fromEntity.ID) + if err != nil { + if fromLockHeld { + fromEntityLock.Unlock() + } + return nil, err + } + + if fromLockHeld { + fromEntityLock.Unlock() + } + } + + if conflictErrors != nil && !force { + return logical.ErrorResponse(conflictErrors.Error()), nil + } + + // Update MemDB with changes to the entity we are merging to + err = i.MemDBUpsertEntityInTxn(txn, toEntity) + if err != nil { + return nil, err + } + + // Persist the entity which we are merging to + toEntityAsAny, err := ptypes.MarshalAny(toEntity) + if err != nil { + return nil, err + } + item := &storagepacker.Item{ + ID: toEntity.ID, + Message: toEntityAsAny, + } + + err = i.entityPacker.PutItem(item) + if err != nil { + return nil, err + } + + // Committing the transaction *after* successfully performing storage + // persistence + txn.Commit() + + return nil, nil + } +} + +// pathEntityRegister is used to register a new entity +func (i *IdentityStore) pathEntityRegister() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, ok := d.GetOk("id") + if ok { + return i.pathEntityIDUpdate()(ctx, req, d) + } + + return i.handleEntityUpdateCommon(req, d, nil) + } +} + +// pathEntityIDUpdate is used to update an entity based on the given entity ID +func (i *IdentityStore) pathEntityIDUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + // Get entity id + entityID := d.Get("id").(string) + + if entityID == "" { + return logical.ErrorResponse("missing entity id"), nil + } + + entity, err := i.MemDBEntityByID(entityID, true) + if err != nil { + return nil, err + } + if entity == nil { + return nil, fmt.Errorf("invalid entity id") + } + + return i.handleEntityUpdateCommon(req, d, entity) + } +} + +// handleEntityUpdateCommon is used to update an entity +func (i *IdentityStore) handleEntityUpdateCommon(req *logical.Request, d *framework.FieldData, entity *identity.Entity) (*logical.Response, error) { + var err error + var newEntity bool + + // Entity will be nil when a new entity is being registered; create a new + // struct in that case. + if entity == nil { + entity = &identity.Entity{} + newEntity = true + } + + // Update the policies if supplied + entityPoliciesRaw, ok := d.GetOk("policies") + if ok { + entity.Policies = entityPoliciesRaw.([]string) + } + + disabledRaw, ok := d.GetOk("disabled") + if ok { + entity.Disabled = disabledRaw.(bool) + } + + // Get the name + entityName := d.Get("name").(string) + if entityName != "" { + entityByName, err := i.MemDBEntityByName(entityName, false) + if err != nil { + return nil, err + } + switch { + case (newEntity && entityByName != nil), (entityByName != nil && entity.ID != "" && entityByName.ID != entity.ID): + return logical.ErrorResponse("entity name is already in use"), nil + } + entity.Name = entityName + } + + // Get entity metadata + metadata, ok, err := d.GetOkErr("metadata") + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("failed to parse metadata: %v", err)), nil + } + if ok { + entity.Metadata = metadata.(map[string]string) + } + // ID creation and some validations + err = i.sanitizeEntity(entity) + if err != nil { + return nil, err + } + + // Prepare the response + respData := map[string]interface{}{ + "id": entity.ID, + } + + var aliasIDs []string + for _, alias := range entity.Aliases { + aliasIDs = append(aliasIDs, alias.ID) + } + + respData["aliases"] = aliasIDs + + // Update MemDB and persist entity object + err = i.upsertEntity(entity, nil, true) + if err != nil { + return nil, err + } + + // Return ID of the entity that was either created or updated along with + // its aliases + return &logical.Response{ + Data: respData, + }, nil +} + +// pathEntityIDRead returns the properties of an entity for a given entity ID +func (i *IdentityStore) pathEntityIDRead() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entityID := d.Get("id").(string) + if entityID == "" { + return logical.ErrorResponse("missing entity id"), nil + } + + entity, err := i.MemDBEntityByID(entityID, false) + if err != nil { + return nil, err + } + if entity == nil { + return nil, nil + } + + return i.handleEntityReadCommon(entity) + } +} + +func (i *IdentityStore) handleEntityReadCommon(entity *identity.Entity) (*logical.Response, error) { + respData := map[string]interface{}{} + respData["id"] = entity.ID + respData["name"] = entity.Name + respData["metadata"] = entity.Metadata + respData["merged_entity_ids"] = entity.MergedEntityIDs + respData["policies"] = entity.Policies + respData["disabled"] = entity.Disabled + + // Convert protobuf timestamp into RFC3339 format + respData["creation_time"] = ptypes.TimestampString(entity.CreationTime) + respData["last_update_time"] = ptypes.TimestampString(entity.LastUpdateTime) + + // Convert each alias into a map and replace the time format in each + aliasesToReturn := make([]interface{}, len(entity.Aliases)) + for aliasIdx, alias := range entity.Aliases { + aliasMap := map[string]interface{}{} + aliasMap["id"] = alias.ID + aliasMap["canonical_id"] = alias.CanonicalID + aliasMap["mount_accessor"] = alias.MountAccessor + aliasMap["metadata"] = alias.Metadata + aliasMap["name"] = alias.Name + aliasMap["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs + aliasMap["creation_time"] = ptypes.TimestampString(alias.CreationTime) + aliasMap["last_update_time"] = ptypes.TimestampString(alias.LastUpdateTime) + + if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil { + aliasMap["mount_type"] = mountValidationResp.MountType + aliasMap["mount_path"] = mountValidationResp.MountPath + } + + aliasesToReturn[aliasIdx] = aliasMap + } + + // Add the aliases information to the response which has the correct time + // formats + respData["aliases"] = aliasesToReturn + + // Fetch the groups this entity belongs to and return their identifiers + groups, inheritedGroups, err := i.groupsByEntityID(entity.ID) + if err != nil { + return nil, err + } + + groupIDs := make([]string, len(groups)) + for i, group := range groups { + groupIDs[i] = group.ID + } + respData["direct_group_ids"] = groupIDs + + inheritedGroupIDs := make([]string, len(inheritedGroups)) + for i, group := range inheritedGroups { + inheritedGroupIDs[i] = group.ID + } + respData["inherited_group_ids"] = inheritedGroupIDs + + respData["group_ids"] = append(groupIDs, inheritedGroupIDs...) + + return &logical.Response{ + Data: respData, + }, nil +} + +// pathEntityIDDelete deletes the entity for a given entity ID +func (i *IdentityStore) pathEntityIDDelete() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entityID := d.Get("id").(string) + if entityID == "" { + return logical.ErrorResponse("missing entity id"), nil + } + + return nil, i.deleteEntity(entityID) + } +} + +// pathEntityIDList lists the IDs of all the valid entities in the identity +// store +func (i *IdentityStore) pathEntityIDList() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + ws := memdb.NewWatchSet() + iter, err := i.MemDBEntities(ws) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch iterator for entities in memdb: {{err}}", err) + } + + var entityIDs []string + entityInfo := map[string]interface{}{} + + type mountInfo struct { + MountType string + MountPath string + } + mountAccessorMap := map[string]mountInfo{} + + for { + raw := iter.Next() + if raw == nil { + break + } + entity := raw.(*identity.Entity) + entityIDs = append(entityIDs, entity.ID) + entityInfoEntry := map[string]interface{}{ + "name": entity.Name, + } + if len(entity.Aliases) > 0 { + aliasList := make([]interface{}, 0, len(entity.Aliases)) + for _, alias := range entity.Aliases { + entry := map[string]interface{}{ + "id": alias.ID, + "name": alias.Name, + "mount_accessor": alias.MountAccessor, + } + + mi, ok := mountAccessorMap[alias.MountAccessor] + if ok { + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } else { + mi = mountInfo{} + if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil { + mi.MountType = mountValidationResp.MountType + mi.MountPath = mountValidationResp.MountPath + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } + mountAccessorMap[alias.MountAccessor] = mi + } + + aliasList = append(aliasList, entry) + } + entityInfoEntry["aliases"] = aliasList + } + entityInfo[entity.ID] = entityInfoEntry + } + + return logical.ListResponseWithInfo(entityIDs, entityInfo), nil + } +} + +var entityHelp = map[string][2]string{ + "entity": { + "Create a new entity", + "", + }, + "entity-id": { + "Update, read or delete an entity using entity ID", + "", + }, + "entity-id-list": { + "List all the entity IDs", + "", + }, + "entity-merge-id": { + "Merge two or more entities together", + "", + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_group_aliases.go b/vendor/github.com/hashicorp/vault/vault/identity_store_group_aliases.go new file mode 100644 index 0000000..047fc47 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_group_aliases.go @@ -0,0 +1,327 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func groupAliasPaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "group-alias$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the group alias.", + }, + "name": { + Type: framework.TypeString, + Description: "Alias of the group.", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to.", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "ID of the group to which this is an alias.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathGroupAliasRegister(), + }, + + HelpSynopsis: strings.TrimSpace(groupAliasHelp["group-alias"][0]), + HelpDescription: strings.TrimSpace(groupAliasHelp["group-alias"][1]), + }, + { + Pattern: "group-alias/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the group alias.", + }, + "name": { + Type: framework.TypeString, + Description: "Alias of the group.", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to.", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "ID of the group to which this is an alias.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathGroupAliasIDUpdate(), + logical.ReadOperation: i.pathGroupAliasIDRead(), + logical.DeleteOperation: i.pathGroupAliasIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(groupAliasHelp["group-alias-by-id"][0]), + HelpDescription: strings.TrimSpace(groupAliasHelp["group-alias-by-id"][1]), + }, + { + Pattern: "group-alias/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathGroupAliasIDList(), + }, + + HelpSynopsis: strings.TrimSpace(groupAliasHelp["group-alias-id-list"][0]), + HelpDescription: strings.TrimSpace(groupAliasHelp["group-alias-id-list"][1]), + }, + } +} + +func (i *IdentityStore) pathGroupAliasRegister() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, ok := d.GetOk("id") + if ok { + return i.pathGroupAliasIDUpdate()(ctx, req, d) + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + return i.handleGroupAliasUpdateCommon(req, d, nil) + } +} + +func (i *IdentityStore) pathGroupAliasIDUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupAliasID := d.Get("id").(string) + if groupAliasID == "" { + return logical.ErrorResponse("empty group alias ID"), nil + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + groupAlias, err := i.MemDBAliasByID(groupAliasID, true, true) + if err != nil { + return nil, err + } + if groupAlias == nil { + return logical.ErrorResponse("invalid group alias ID"), nil + } + + return i.handleGroupAliasUpdateCommon(req, d, groupAlias) + } +} + +func (i *IdentityStore) handleGroupAliasUpdateCommon(req *logical.Request, d *framework.FieldData, groupAlias *identity.Alias) (*logical.Response, error) { + var err error + var newGroupAlias bool + var group *identity.Group + + if groupAlias == nil { + groupAlias = &identity.Alias{} + newGroupAlias = true + } + + groupID := d.Get("canonical_id").(string) + if groupID != "" { + group, err = i.MemDBGroupByID(groupID, true) + if err != nil { + return nil, err + } + if group == nil { + return logical.ErrorResponse("invalid group ID"), nil + } + if group.Type != groupTypeExternal { + return logical.ErrorResponse("alias can't be set on an internal group"), nil + } + } + + // Get group alias name + groupAliasName := d.Get("name").(string) + if groupAliasName == "" { + return logical.ErrorResponse("missing alias name"), nil + } + + mountAccessor := d.Get("mount_accessor").(string) + if mountAccessor == "" { + return logical.ErrorResponse("missing mount_accessor"), nil + } + + mountValidationResp := i.core.router.validateMountByAccessor(mountAccessor) + if mountValidationResp == nil { + return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil + } + + if mountValidationResp.MountLocal { + return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", mountAccessor)), nil + } + + groupAliasByFactors, err := i.MemDBAliasByFactors(mountValidationResp.MountAccessor, groupAliasName, false, true) + if err != nil { + return nil, err + } + + resp := &logical.Response{} + + if newGroupAlias { + if groupAliasByFactors != nil { + return logical.ErrorResponse("combination of mount and group alias name is already in use"), nil + } + + // If this is an alias being tied to a non-existent group, create + // a new group for it. + if group == nil { + group = &identity.Group{ + Type: groupTypeExternal, + Alias: groupAlias, + } + } else { + group.Alias = groupAlias + } + } else { + // Verify that the combination of group alias name and mount is not + // already tied to a different alias + if groupAliasByFactors != nil && groupAliasByFactors.ID != groupAlias.ID { + return logical.ErrorResponse("combination of mount and group alias name is already in use"), nil + } + + // Fetch the group to which the alias is tied to + existingGroup, err := i.MemDBGroupByAliasID(groupAlias.ID, true) + if err != nil { + return nil, err + } + + if existingGroup == nil { + return nil, fmt.Errorf("group alias is not associated with a group") + } + + if group != nil && group.ID != existingGroup.ID { + return logical.ErrorResponse("alias is already tied to a different group"), nil + } + + group = existingGroup + group.Alias = groupAlias + } + + group.Alias.Name = groupAliasName + group.Alias.MountAccessor = mountValidationResp.MountAccessor + // Explicitly correct for previous versions that persisted this + group.Alias.MountType = "" + + err = i.sanitizeAndUpsertGroup(group, nil) + if err != nil { + return nil, err + } + + resp.Data = map[string]interface{}{ + "id": groupAlias.ID, + "canonical_id": group.ID, + } + + return resp, nil +} + +// pathGroupAliasIDRead returns the properties of an alias for a given +// alias ID +func (i *IdentityStore) pathGroupAliasIDRead() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupAliasID := d.Get("id").(string) + if groupAliasID == "" { + return logical.ErrorResponse("empty group alias id"), nil + } + + groupAlias, err := i.MemDBAliasByID(groupAliasID, false, true) + if err != nil { + return nil, err + } + + return i.handleAliasReadCommon(groupAlias) + } +} + +// pathGroupAliasIDDelete deletes the group's alias for a given group alias ID +func (i *IdentityStore) pathGroupAliasIDDelete() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupAliasID := d.Get("id").(string) + if groupAliasID == "" { + return logical.ErrorResponse("missing group alias ID"), nil + } + + return nil, i.deleteGroupAlias(groupAliasID) + } +} + +// pathGroupAliasIDList lists the IDs of all the valid group aliases in the +// identity store +func (i *IdentityStore) pathGroupAliasIDList() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + ws := memdb.NewWatchSet() + iter, err := i.MemDBAliases(ws, true) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch iterator for group aliases in memdb: {{err}}", err) + } + + var groupAliasIDs []string + aliasInfo := map[string]interface{}{} + + type mountInfo struct { + MountType string + MountPath string + } + mountAccessorMap := map[string]mountInfo{} + + for { + raw := iter.Next() + if raw == nil { + break + } + alias := raw.(*identity.Alias) + groupAliasIDs = append(groupAliasIDs, alias.ID) + entry := map[string]interface{}{ + "name": alias.Name, + "canonical_id": alias.CanonicalID, + "mount_accessor": alias.MountAccessor, + } + + mi, ok := mountAccessorMap[alias.MountAccessor] + if ok { + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } else { + mi = mountInfo{} + if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil { + mi.MountType = mountValidationResp.MountType + mi.MountPath = mountValidationResp.MountPath + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } + mountAccessorMap[alias.MountAccessor] = mi + } + + aliasInfo[alias.ID] = entry + } + + return logical.ListResponseWithInfo(groupAliasIDs, aliasInfo), nil + } +} + +var groupAliasHelp = map[string][2]string{ + "group-alias": { + "Creates a new group alias, or updates an existing one.", + "", + }, + "group-alias-id": { + "Update, read or delete a group alias using ID.", + "", + }, + "group-alias-id-list": { + "List all the group alias IDs.", + "", + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_groups.go b/vendor/github.com/hashicorp/vault/vault/identity_store_groups.go new file mode 100644 index 0000000..3a56b46 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_groups.go @@ -0,0 +1,399 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/errwrap" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +const ( + groupTypeInternal = "internal" + groupTypeExternal = "external" +) + +func groupPaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "group$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the group. If set, updates the corresponding existing group.", + }, + "type": { + Type: framework.TypeString, + Description: "Type of the group, 'internal' or 'external'. Defaults to 'internal'", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the group.", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the group. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + "policies": { + Type: framework.TypeCommaStringSlice, + Description: "Policies to be tied to the group.", + }, + "member_group_ids": { + Type: framework.TypeCommaStringSlice, + Description: "Group IDs to be assigned as group members.", + }, + "member_entity_ids": { + Type: framework.TypeCommaStringSlice, + Description: "Entity IDs to be assigned as group members.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathGroupRegister(), + }, + + HelpSynopsis: strings.TrimSpace(groupHelp["register"][0]), + HelpDescription: strings.TrimSpace(groupHelp["register"][1]), + }, + { + Pattern: "group/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the group.", + }, + "type": { + Type: framework.TypeString, + Default: groupTypeInternal, + Description: "Type of the group, 'internal' or 'external'. Defaults to 'internal'", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the group.", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the group. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 + `, + }, + "policies": { + Type: framework.TypeCommaStringSlice, + Description: "Policies to be tied to the group.", + }, + "member_group_ids": { + Type: framework.TypeCommaStringSlice, + Description: "Group IDs to be assigned as group members.", + }, + "member_entity_ids": { + Type: framework.TypeCommaStringSlice, + Description: "Entity IDs to be assigned as group members.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathGroupIDUpdate(), + logical.ReadOperation: i.pathGroupIDRead(), + logical.DeleteOperation: i.pathGroupIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(groupHelp["group-by-id"][0]), + HelpDescription: strings.TrimSpace(groupHelp["group-by-id"][1]), + }, + { + Pattern: "group/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathGroupIDList(), + }, + + HelpSynopsis: strings.TrimSpace(groupHelp["group-id-list"][0]), + HelpDescription: strings.TrimSpace(groupHelp["group-id-list"][1]), + }, + } +} + +func (i *IdentityStore) pathGroupRegister() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, ok := d.GetOk("id") + if ok { + return i.pathGroupIDUpdate()(ctx, req, d) + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + return i.handleGroupUpdateCommon(req, d, nil) + } +} + +func (i *IdentityStore) pathGroupIDUpdate() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupID := d.Get("id").(string) + if groupID == "" { + return logical.ErrorResponse("empty group ID"), nil + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + group, err := i.MemDBGroupByID(groupID, true) + if err != nil { + return nil, err + } + if group == nil { + return logical.ErrorResponse("invalid group ID"), nil + } + + return i.handleGroupUpdateCommon(req, d, group) + } +} + +func (i *IdentityStore) handleGroupUpdateCommon(req *logical.Request, d *framework.FieldData, group *identity.Group) (*logical.Response, error) { + var err error + var newGroup bool + if group == nil { + group = &identity.Group{} + newGroup = true + } + + // Update the policies if supplied + policiesRaw, ok := d.GetOk("policies") + if ok { + group.Policies = policiesRaw.([]string) + } + + groupTypeRaw, ok := d.GetOk("type") + if ok { + groupType := groupTypeRaw.(string) + if group.Type != "" && groupType != group.Type { + return logical.ErrorResponse(fmt.Sprintf("group type cannot be changed")), nil + } + + group.Type = groupType + } + + // If group type is not set, default to internal type + if group.Type == "" { + group.Type = groupTypeInternal + } + + if group.Type != groupTypeInternal && group.Type != groupTypeExternal { + return logical.ErrorResponse(fmt.Sprintf("invalid group type %q", group.Type)), nil + } + + // Get the name + groupName := d.Get("name").(string) + if groupName != "" { + // Check if there is a group already existing for the given name + groupByName, err := i.MemDBGroupByName(groupName, false) + if err != nil { + return nil, err + } + + // If this is a new group and if there already exists a group by this + // name, error out. If the name of an existing group is about to be + // modified into something which is already tied to a different group, + // error out. + switch { + case (newGroup && groupByName != nil), (groupByName != nil && group.ID != "" && groupByName.ID != group.ID): + return logical.ErrorResponse("group name is already in use"), nil + } + group.Name = groupName + } + + metadata, ok, err := d.GetOkErr("metadata") + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("failed to parse metadata: %v", err)), nil + } + if ok { + group.Metadata = metadata.(map[string]string) + } + + memberEntityIDsRaw, ok := d.GetOk("member_entity_ids") + if ok { + if group.Type == groupTypeExternal { + return logical.ErrorResponse("member entities can't be set manually for external groups"), nil + } + group.MemberEntityIDs = memberEntityIDsRaw.([]string) + if len(group.MemberEntityIDs) > 512 { + return logical.ErrorResponse("member entity IDs exceeding the limit of 512"), nil + } + } + + memberGroupIDsRaw, ok := d.GetOk("member_group_ids") + var memberGroupIDs []string + if ok { + if group.Type == groupTypeExternal { + return logical.ErrorResponse("member groups can't be set for external groups"), nil + } + memberGroupIDs = memberGroupIDsRaw.([]string) + } + + err = i.sanitizeAndUpsertGroup(group, memberGroupIDs) + if err != nil { + return nil, err + } + + respData := map[string]interface{}{ + "id": group.ID, + "name": group.Name, + } + return &logical.Response{ + Data: respData, + }, nil +} + +func (i *IdentityStore) pathGroupIDRead() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupID := d.Get("id").(string) + if groupID == "" { + return logical.ErrorResponse("empty group id"), nil + } + + group, err := i.MemDBGroupByID(groupID, false) + if err != nil { + return nil, err + } + + return i.handleGroupReadCommon(group) + } +} + +func (i *IdentityStore) handleGroupReadCommon(group *identity.Group) (*logical.Response, error) { + if group == nil { + return nil, nil + } + + respData := map[string]interface{}{} + respData["id"] = group.ID + respData["name"] = group.Name + respData["policies"] = group.Policies + respData["member_entity_ids"] = group.MemberEntityIDs + respData["parent_group_ids"] = group.ParentGroupIDs + respData["metadata"] = group.Metadata + respData["creation_time"] = ptypes.TimestampString(group.CreationTime) + respData["last_update_time"] = ptypes.TimestampString(group.LastUpdateTime) + respData["modify_index"] = group.ModifyIndex + respData["type"] = group.Type + + aliasMap := map[string]interface{}{} + if group.Alias != nil { + aliasMap["id"] = group.Alias.ID + aliasMap["canonical_id"] = group.Alias.CanonicalID + aliasMap["mount_type"] = group.Alias.MountType + aliasMap["mount_accessor"] = group.Alias.MountAccessor + aliasMap["mount_path"] = group.Alias.MountPath + aliasMap["metadata"] = group.Alias.Metadata + aliasMap["name"] = group.Alias.Name + aliasMap["merged_from_canonical_ids"] = group.Alias.MergedFromCanonicalIDs + aliasMap["creation_time"] = ptypes.TimestampString(group.Alias.CreationTime) + aliasMap["last_update_time"] = ptypes.TimestampString(group.Alias.LastUpdateTime) + } + + respData["alias"] = aliasMap + + memberGroupIDs, err := i.memberGroupIDsByID(group.ID) + if err != nil { + return nil, err + } + respData["member_group_ids"] = memberGroupIDs + + return &logical.Response{ + Data: respData, + }, nil +} + +func (i *IdentityStore) pathGroupIDDelete() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + groupID := d.Get("id").(string) + if groupID == "" { + return logical.ErrorResponse("empty group ID"), nil + } + return nil, i.deleteGroupByID(groupID) + } +} + +// pathGroupIDList lists the IDs of all the groups in the identity store +func (i *IdentityStore) pathGroupIDList() framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + ws := memdb.NewWatchSet() + iter, err := i.MemDBGroupIterator(ws) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch iterator for group in memdb: {{err}}", err) + } + + var groupIDs []string + groupInfo := map[string]interface{}{} + + type mountInfo struct { + MountType string + MountPath string + } + mountAccessorMap := map[string]mountInfo{} + + for { + raw := iter.Next() + if raw == nil { + break + } + group := raw.(*identity.Group) + groupIDs = append(groupIDs, group.ID) + groupInfoEntry := map[string]interface{}{ + "name": group.Name, + "num_member_entities": len(group.MemberEntityIDs), + "num_parent_groups": len(group.ParentGroupIDs), + } + if group.Alias != nil { + entry := map[string]interface{}{ + "id": group.Alias.ID, + "name": group.Alias.Name, + "mount_accessor": group.Alias.MountAccessor, + } + + mi, ok := mountAccessorMap[group.Alias.MountAccessor] + if ok { + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } else { + mi = mountInfo{} + if mountValidationResp := i.core.router.validateMountByAccessor(group.Alias.MountAccessor); mountValidationResp != nil { + mi.MountType = mountValidationResp.MountType + mi.MountPath = mountValidationResp.MountPath + entry["mount_type"] = mi.MountType + entry["mount_path"] = mi.MountPath + } + mountAccessorMap[group.Alias.MountAccessor] = mi + } + + groupInfoEntry["alias"] = entry + } + groupInfo[group.ID] = groupInfoEntry + } + + return logical.ListResponseWithInfo(groupIDs, groupInfo), nil + } +} + +var groupHelp = map[string][2]string{ + "register": { + "Create a new group.", + "", + }, + "group-by-id": { + "Update or delete an existing group using its ID.", + "", + }, + "group-id-list": { + "List all the group IDs.", + "", + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_schema.go b/vendor/github.com/hashicorp/vault/vault/identity_store_schema.go new file mode 100644 index 0000000..3fce0bf --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_schema.go @@ -0,0 +1,217 @@ +package vault + +import ( + "fmt" + + memdb "github.com/hashicorp/go-memdb" +) + +const ( + entitiesTable = "entities" + entityAliasesTable = "entity_aliases" + groupsTable = "groups" + groupAliasesTable = "group_aliases" +) + +func identityStoreSchema() *memdb.DBSchema { + iStoreSchema := &memdb.DBSchema{ + Tables: make(map[string]*memdb.TableSchema), + } + + schemas := []func() *memdb.TableSchema{ + entitiesTableSchema, + aliasesTableSchema, + groupsTableSchema, + groupAliasesTableSchema, + } + + for _, schemaFunc := range schemas { + schema := schemaFunc() + if _, ok := iStoreSchema.Tables[schema.Name]; ok { + panic(fmt.Sprintf("duplicate table name: %s", schema.Name)) + } + iStoreSchema.Tables[schema.Name] = schema + } + + return iStoreSchema +} + +func aliasesTableSchema() *memdb.TableSchema { + return &memdb.TableSchema{ + Name: entityAliasesTable, + Indexes: map[string]*memdb.IndexSchema{ + "id": &memdb.IndexSchema{ + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "ID", + }, + }, + "canonical_id": &memdb.IndexSchema{ + Name: "canonical_id", + Unique: false, + Indexer: &memdb.StringFieldIndex{ + Field: "CanonicalID", + }, + }, + "factors": &memdb.IndexSchema{ + Name: "factors", + Unique: true, + Indexer: &memdb.CompoundIndex{ + Indexes: []memdb.Indexer{ + &memdb.StringFieldIndex{ + Field: "MountAccessor", + }, + &memdb.StringFieldIndex{ + Field: "Name", + }, + }, + }, + }, + "metadata": &memdb.IndexSchema{ + Name: "metadata", + Unique: false, + AllowMissing: true, + Indexer: &memdb.StringMapFieldIndex{ + Field: "Metadata", + }, + }, + }, + } +} + +func entitiesTableSchema() *memdb.TableSchema { + return &memdb.TableSchema{ + Name: entitiesTable, + Indexes: map[string]*memdb.IndexSchema{ + "id": &memdb.IndexSchema{ + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "ID", + }, + }, + "name": &memdb.IndexSchema{ + Name: "name", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "Name", + }, + }, + "metadata": &memdb.IndexSchema{ + Name: "metadata", + Unique: false, + AllowMissing: true, + Indexer: &memdb.StringMapFieldIndex{ + Field: "Metadata", + }, + }, + "merged_entity_ids": &memdb.IndexSchema{ + Name: "merged_entity_ids", + Unique: true, + AllowMissing: true, + Indexer: &memdb.StringSliceFieldIndex{ + Field: "MergedEntityIDs", + }, + }, + "bucket_key_hash": &memdb.IndexSchema{ + Name: "bucket_key_hash", + Unique: false, + AllowMissing: false, + Indexer: &memdb.StringFieldIndex{ + Field: "BucketKeyHash", + }, + }, + }, + } +} + +func groupsTableSchema() *memdb.TableSchema { + return &memdb.TableSchema{ + Name: groupsTable, + Indexes: map[string]*memdb.IndexSchema{ + "id": { + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "ID", + }, + }, + "name": { + Name: "name", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "Name", + }, + }, + "member_entity_ids": { + Name: "member_entity_ids", + Unique: false, + AllowMissing: true, + Indexer: &memdb.StringSliceFieldIndex{ + Field: "MemberEntityIDs", + }, + }, + "parent_group_ids": { + Name: "parent_group_ids", + Unique: false, + AllowMissing: true, + Indexer: &memdb.StringSliceFieldIndex{ + Field: "ParentGroupIDs", + }, + }, + "policies": { + Name: "policies", + Unique: false, + AllowMissing: true, + Indexer: &memdb.StringSliceFieldIndex{ + Field: "Policies", + }, + }, + "bucket_key_hash": &memdb.IndexSchema{ + Name: "bucket_key_hash", + Unique: false, + AllowMissing: false, + Indexer: &memdb.StringFieldIndex{ + Field: "BucketKeyHash", + }, + }, + }, + } +} + +func groupAliasesTableSchema() *memdb.TableSchema { + return &memdb.TableSchema{ + Name: groupAliasesTable, + Indexes: map[string]*memdb.IndexSchema{ + "id": &memdb.IndexSchema{ + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "ID", + }, + }, + "canonical_id": &memdb.IndexSchema{ + Name: "canonical_id", + Unique: false, + Indexer: &memdb.StringFieldIndex{ + Field: "CanonicalID", + }, + }, + "factors": &memdb.IndexSchema{ + Name: "factors", + Unique: true, + Indexer: &memdb.CompoundIndex{ + Indexes: []memdb.Indexer{ + &memdb.StringFieldIndex{ + Field: "MountAccessor", + }, + &memdb.StringFieldIndex{ + Field: "Name", + }, + }, + }, + }, + }, + } +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_structs.go b/vendor/github.com/hashicorp/vault/vault/identity_store_structs.go new file mode 100644 index 0000000..0f9435c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_structs.go @@ -0,0 +1,81 @@ +package vault + +import ( + "regexp" + "sync" + + log "github.com/hashicorp/go-hclog" + memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/storagepacker" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +const ( + // Storage prefixes + entityPrefix = "entity/" +) + +var ( + // metaKeyFormatRegEx checks if a metadata key string is valid + metaKeyFormatRegEx = regexp.MustCompile(`^[a-zA-Z0-9=/+_-]+$`).MatchString +) + +const ( + // The meta key prefix reserved for Vault's internal use + metaKeyReservedPrefix = "vault-" + + // The maximum number of metadata key pairs allowed to be registered + metaMaxKeyPairs = 64 + + // The maximum allowed length of a metadata key + metaKeyMaxLength = 128 + + // The maximum allowed length of a metadata value + metaValueMaxLength = 512 +) + +// IdentityStore is composed of its own storage view and a MemDB which +// maintains active in-memory replicas of the storage contents indexed by +// multiple fields. +type IdentityStore struct { + // IdentityStore is a secret backend in Vault + *framework.Backend + + // view is the storage sub-view where all the artifacts of identity store + // gets persisted + view logical.Storage + + // db is the in-memory database where the storage artifacts gets replicated + // to enable richer queries based on multiple indexes. + db *memdb.MemDB + + // entityLocks are a set of 256 locks to which all the entities will be + // categorized to while performing storage modifications. + entityLocks []*locksutil.LockEntry + + // groupLock is used to protect modifications to group entries + groupLock sync.RWMutex + + // logger is the server logger copied over from core + logger log.Logger + + // entityPacker is used to pack multiple entity storage entries into 256 + // buckets + entityPacker *storagepacker.StoragePacker + + // groupPacker is used to pack multiple group storage entries into 256 + // buckets + groupPacker *storagepacker.StoragePacker + + // core is the pointer to Vault's core + core *Core +} + +type groupDiff struct { + New []*identity.Group + Deleted []*identity.Group + Unmodified []*identity.Group +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_upgrade.go b/vendor/github.com/hashicorp/vault/vault/identity_store_upgrade.go new file mode 100644 index 0000000..9399e62 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_upgrade.go @@ -0,0 +1,184 @@ +package vault + +import ( + "strings" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func upgradePaths(i *IdentityStore) []*framework.Path { + return []*framework.Path{ + { + Pattern: "persona$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 +`, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasRegister(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias"][1]), + }, + { + Pattern: "persona/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias should be tied to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 +`, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasIDUpdate(), + logical.ReadOperation: i.pathAliasIDRead(), + logical.DeleteOperation: i.pathAliasIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id"][1]), + }, + { + Pattern: "persona/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathAliasIDList(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id-list"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id-list"][1]), + }, + { + Pattern: "alias$", + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to. This field is deprecated in favor of 'canonical_id'.", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias belongs to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 +`, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasRegister(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias"][1]), + }, + + { + Pattern: "alias/id/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeString, + Description: "ID of the alias", + }, + "entity_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias should be tied to. This field is deprecated in favor of 'canonical_id'.", + }, + "canonical_id": { + Type: framework.TypeString, + Description: "Entity ID to which this alias should be tied to", + }, + "mount_accessor": { + Type: framework.TypeString, + Description: "Mount accessor to which this alias belongs to", + }, + "name": { + Type: framework.TypeString, + Description: "Name of the alias", + }, + "metadata": { + Type: framework.TypeKVPairs, + Description: `Metadata to be associated with the alias. +In CLI, this parameter can be repeated multiple times, and it all gets merged together. +For example: +vault metadata=key1=value1 metadata=key2=value2 +`, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: i.pathAliasIDUpdate(), + logical.ReadOperation: i.pathAliasIDRead(), + logical.DeleteOperation: i.pathAliasIDDelete(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id"][1]), + }, + { + Pattern: "alias/id/?$", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: i.pathAliasIDList(), + }, + + HelpSynopsis: strings.TrimSpace(aliasHelp["alias-id-list"][0]), + HelpDescription: strings.TrimSpace(aliasHelp["alias-id-list"][1]), + }, + } +} diff --git a/vendor/github.com/hashicorp/vault/vault/identity_store_util.go b/vendor/github.com/hashicorp/vault/vault/identity_store_util.go new file mode 100644 index 0000000..e8b4cc1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/identity_store_util.go @@ -0,0 +1,2415 @@ +package vault + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/errwrap" + memdb "github.com/hashicorp/go-memdb" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/storagepacker" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" +) + +func (c *Core) loadIdentityStoreArtifacts(ctx context.Context) error { + var err error + if c.identityStore == nil { + c.logger.Warn("identity store is not setup, skipping loading") + return nil + } + + err = c.identityStore.loadEntities(ctx) + if err != nil { + return err + } + + err = c.identityStore.loadGroups(ctx) + if err != nil { + return err + } + + return nil +} + +func (i *IdentityStore) loadGroups(ctx context.Context) error { + i.logger.Debug("identity loading groups") + existing, err := i.groupPacker.View().List(ctx, groupBucketsPrefix) + if err != nil { + return errwrap.Wrapf("failed to scan for groups: {{err}}", err) + } + i.logger.Debug("groups collected", "num_existing", len(existing)) + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + for _, key := range existing { + bucket, err := i.groupPacker.GetBucket(i.groupPacker.BucketPath(key)) + if err != nil { + return err + } + + if bucket == nil { + continue + } + + for _, item := range bucket.Items { + group, err := i.parseGroupFromBucketItem(item) + if err != nil { + return err + } + if group == nil { + continue + } + + if i.logger.IsDebug() { + i.logger.Debug("loading group", "name", group.Name, "id", group.ID) + } + + txn := i.db.Txn(true) + + err = i.upsertGroupInTxn(txn, group, false) + if err != nil { + txn.Abort() + return errwrap.Wrapf("failed to update group in memdb: {{err}}", err) + } + + txn.Commit() + } + } + + if i.logger.IsInfo() { + i.logger.Info("groups restored") + } + + return nil +} + +func (i *IdentityStore) loadEntities(ctx context.Context) error { + // Accumulate existing entities + i.logger.Debug("loading entities") + existing, err := i.entityPacker.View().List(ctx, storagepacker.StoragePackerBucketsPrefix) + if err != nil { + return errwrap.Wrapf("failed to scan for entities: {{err}}", err) + } + i.logger.Debug("entities collected", "num_existing", len(existing)) + + // Make the channels used for the worker pool + broker := make(chan string) + quit := make(chan bool) + + // Buffer these channels to prevent deadlocks + errs := make(chan error, len(existing)) + result := make(chan *storagepacker.Bucket, len(existing)) + + // Use a wait group + wg := &sync.WaitGroup{} + + // Create 64 workers to distribute work to + for j := 0; j < consts.ExpirationRestoreWorkerCount; j++ { + wg.Add(1) + go func() { + defer wg.Done() + + for { + select { + case bucketKey, ok := <-broker: + // broker has been closed, we are done + if !ok { + return + } + + bucket, err := i.entityPacker.GetBucket(i.entityPacker.BucketPath(bucketKey)) + if err != nil { + errs <- err + continue + } + + // Write results out to the result channel + result <- bucket + + // quit early + case <-quit: + return + } + } + }() + } + + // Distribute the collected keys to the workers in a go routine + wg.Add(1) + go func() { + defer wg.Done() + for j, bucketKey := range existing { + if j%500 == 0 { + i.logger.Debug("entities loading", "progress", j) + } + + select { + case <-quit: + return + + default: + broker <- bucketKey + } + } + + // Close the broker, causing worker routines to exit + close(broker) + }() + + // Restore each key by pulling from the result chan + for j := 0; j < len(existing); j++ { + select { + case err := <-errs: + // Close all go routines + close(quit) + + return err + + case bucket := <-result: + // If there is no entry, nothing to restore + if bucket == nil { + continue + } + + for _, item := range bucket.Items { + entity, err := i.parseEntityFromBucketItem(ctx, item) + if err != nil { + return err + } + + if entity == nil { + continue + } + + // Only update MemDB and don't hit the storage again + err = i.upsertEntity(entity, nil, false) + if err != nil { + return errwrap.Wrapf("failed to update entity in MemDB: {{err}}", err) + } + } + } + } + + // Let all go routines finish + wg.Wait() + + if i.logger.IsInfo() { + i.logger.Info("entities restored") + } + + return nil +} + +// LockForEntityID returns the lock used to modify the entity. +func (i *IdentityStore) LockForEntityID(entityID string) *locksutil.LockEntry { + return locksutil.LockForKey(i.entityLocks, entityID) +} + +// upsertEntityInTxn either creates or updates an existing entity. The +// operations will be updated in both MemDB and storage. If 'persist' is set to +// false, then storage will not be updated. When an alias is transferred from +// one entity to another, both the source and destination entities should get +// updated, in which case, callers should send in both entity and +// previousEntity. +func (i *IdentityStore) upsertEntityInTxn(txn *memdb.Txn, entity *identity.Entity, previousEntity *identity.Entity, persist, lockHeld bool) error { + var err error + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + if entity == nil { + return fmt.Errorf("entity is nil") + } + + // Acquire the lock to modify the entity storage entry + if !lockHeld { + lock := locksutil.LockForKey(i.entityLocks, entity.ID) + lock.Lock() + defer lock.Unlock() + } + + for _, alias := range entity.Aliases { + // Verify that alias is not associated to a different one already + aliasByFactors, err := i.MemDBAliasByFactors(alias.MountAccessor, alias.Name, false, false) + if err != nil { + return err + } + + if aliasByFactors != nil && aliasByFactors.CanonicalID != entity.ID { + return fmt.Errorf("alias %q in already tied to a different entity %q", alias.ID, aliasByFactors.CanonicalID) + } + + // Insert or update alias in MemDB using the transaction created above + err = i.MemDBUpsertAliasInTxn(txn, alias, false) + if err != nil { + return err + } + } + + // If previous entity is set, update it in MemDB and persist it + if previousEntity != nil && persist { + err = i.MemDBUpsertEntityInTxn(txn, previousEntity) + if err != nil { + return err + } + + // Persist the previous entity object + marshaledPreviousEntity, err := ptypes.MarshalAny(previousEntity) + if err != nil { + return err + } + err = i.entityPacker.PutItem(&storagepacker.Item{ + ID: previousEntity.ID, + Message: marshaledPreviousEntity, + }) + if err != nil { + return err + } + } + + // Insert or update entity in MemDB using the transaction created above + err = i.MemDBUpsertEntityInTxn(txn, entity) + if err != nil { + return err + } + + if persist { + entityAsAny, err := ptypes.MarshalAny(entity) + if err != nil { + return err + } + item := &storagepacker.Item{ + ID: entity.ID, + Message: entityAsAny, + } + + // Persist the entity object + err = i.entityPacker.PutItem(item) + if err != nil { + return err + } + } + + return nil +} + +// upsertEntity either creates or updates an existing entity. The operations +// will be updated in both MemDB and storage. If 'persist' is set to false, +// then storage will not be updated. When an alias is transferred from one +// entity to another, both the source and destination entities should get +// updated, in which case, callers should send in both entity and +// previousEntity. +func (i *IdentityStore) upsertEntity(entity *identity.Entity, previousEntity *identity.Entity, persist bool) error { + + // Create a MemDB transaction to update both alias and entity + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.upsertEntityInTxn(txn, entity, previousEntity, persist, false) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +// upsertEntityNonLocked creates or updates an entity. The lock to modify the +// entity should be held before calling this function. +func (i *IdentityStore) upsertEntityNonLocked(entity *identity.Entity, previousEntity *identity.Entity, persist bool) error { + // Create a MemDB transaction to update both alias and entity + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.upsertEntityInTxn(txn, entity, previousEntity, persist, true) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) deleteEntity(entityID string) error { + var err error + var entity *identity.Entity + + if entityID == "" { + return fmt.Errorf("missing entity id") + } + + // Since an entity ID is required to acquire the lock to modify the + // storage, fetch the entity without acquiring the lock + + lockEntity, err := i.MemDBEntityByID(entityID, false) + if err != nil { + return err + } + + if lockEntity == nil { + return nil + } + + // Acquire the lock to modify the entity storage entry + lock := locksutil.LockForKey(i.entityLocks, lockEntity.ID) + lock.Lock() + defer lock.Unlock() + + // Create a MemDB transaction to delete entity + txn := i.db.Txn(true) + defer txn.Abort() + + // Fetch the entity using its ID + entity, err = i.MemDBEntityByIDInTxn(txn, entityID, true) + if err != nil { + return err + } + + // If there is no entity for the ID, do nothing + if entity == nil { + return nil + } + + // Delete all the aliases in the entity. This function will also remove + // the corresponding alias indexes too. + err = i.deleteAliasesInEntityInTxn(txn, entity, entity.Aliases) + if err != nil { + return err + } + + // Delete the entity using the same transaction + err = i.MemDBDeleteEntityByIDInTxn(txn, entity.ID) + if err != nil { + return err + } + + // Delete the entity from storage + err = i.entityPacker.DeleteItem(entity.ID) + if err != nil { + return err + } + + // Committing the transaction *after* successfully deleting entity + txn.Commit() + + return nil +} + +func (i *IdentityStore) deleteAlias(aliasID string) error { + var err error + var alias *identity.Alias + var entity *identity.Entity + + if aliasID == "" { + return fmt.Errorf("missing alias ID") + } + + // Since an entity ID is required to acquire the lock to modify the + // storage, fetch the entity without acquiring the lock + + // Fetch the alias using its ID + + alias, err = i.MemDBAliasByID(aliasID, false, false) + if err != nil { + return err + } + + // If there is no alias for the ID, do nothing + if alias == nil { + return nil + } + + // Find the entity to which the alias is tied to + lockEntity, err := i.MemDBEntityByAliasID(alias.ID, false) + if err != nil { + return err + } + + // If there is no entity tied to a valid alias, something is wrong + if lockEntity == nil { + return fmt.Errorf("alias not associated to an entity") + } + + // Acquire the lock to modify the entity storage entry + lock := locksutil.LockForKey(i.entityLocks, lockEntity.ID) + lock.Lock() + defer lock.Unlock() + + // Create a MemDB transaction to delete entity + txn := i.db.Txn(true) + defer txn.Abort() + + // Fetch the alias again after acquiring the lock using the transaction + // created above + alias, err = i.MemDBAliasByIDInTxn(txn, aliasID, false, false) + if err != nil { + return err + } + + // If there is no alias for the ID, do nothing + if alias == nil { + return nil + } + + // Fetch the entity again after acquiring the lock using the transaction + // created above + entity, err = i.MemDBEntityByAliasIDInTxn(txn, alias.ID, true) + if err != nil { + return err + } + + // If there is no entity tied to a valid alias, something is wrong + if entity == nil { + return fmt.Errorf("alias not associated to an entity") + } + + // Lock switching should not end up in this code pointing to different + // entities + if entity.ID != entity.ID { + return fmt.Errorf("operating on an entity to which the lock doesn't belong to") + } + + aliases := []*identity.Alias{ + alias, + } + + // Delete alias from the entity object + err = i.deleteAliasesInEntityInTxn(txn, entity, aliases) + if err != nil { + return err + } + + // Update the entity index in the entities table + err = i.MemDBUpsertEntityInTxn(txn, entity) + if err != nil { + return err + } + + // Persist the entity object + entityAsAny, err := ptypes.MarshalAny(entity) + if err != nil { + return err + } + item := &storagepacker.Item{ + ID: entity.ID, + Message: entityAsAny, + } + + err = i.entityPacker.PutItem(item) + if err != nil { + return err + } + + // Committing the transaction *after* successfully updating entity in + // storage + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBUpsertAliasInTxn(txn *memdb.Txn, alias *identity.Alias, groupAlias bool) error { + if txn == nil { + return fmt.Errorf("nil txn") + } + + if alias == nil { + return fmt.Errorf("alias is nil") + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + aliasRaw, err := txn.First(tableName, "id", alias.ID) + if err != nil { + return errwrap.Wrapf("failed to lookup alias from memdb using alias ID: {{err}}", err) + } + + if aliasRaw != nil { + err = txn.Delete(tableName, aliasRaw) + if err != nil { + return errwrap.Wrapf("failed to delete alias from memdb: {{err}}", err) + } + } + + if err := txn.Insert(tableName, alias); err != nil { + return errwrap.Wrapf("failed to update alias into memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) MemDBUpsertAlias(alias *identity.Alias, groupAlias bool) error { + if alias == nil { + return fmt.Errorf("alias is nil") + } + + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.MemDBUpsertAliasInTxn(txn, alias, groupAlias) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBAliasByCanonicalIDInTxn(txn *memdb.Txn, canonicalID string, clone bool, groupAlias bool) (*identity.Alias, error) { + if canonicalID == "" { + return nil, fmt.Errorf("missing canonical ID") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + aliasRaw, err := txn.First(tableName, "canonical_id", canonicalID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch alias from memdb using canonical ID: {{err}}", err) + } + + if aliasRaw == nil { + return nil, nil + } + + alias, ok := aliasRaw.(*identity.Alias) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched alias") + } + + if clone { + return alias.Clone() + } + + return alias, nil +} + +func (i *IdentityStore) MemDBAliasByCanonicalID(canonicalID string, clone bool, groupAlias bool) (*identity.Alias, error) { + if canonicalID == "" { + return nil, fmt.Errorf("missing canonical ID") + } + + txn := i.db.Txn(false) + + return i.MemDBAliasByCanonicalIDInTxn(txn, canonicalID, clone, groupAlias) +} + +func (i *IdentityStore) MemDBAliasByIDInTxn(txn *memdb.Txn, aliasID string, clone bool, groupAlias bool) (*identity.Alias, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + aliasRaw, err := txn.First(tableName, "id", aliasID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch alias from memdb using alias ID: {{err}}", err) + } + + if aliasRaw == nil { + return nil, nil + } + + alias, ok := aliasRaw.(*identity.Alias) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched alias") + } + + if clone { + return alias.Clone() + } + + return alias, nil +} + +func (i *IdentityStore) MemDBAliasByID(aliasID string, clone bool, groupAlias bool) (*identity.Alias, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + txn := i.db.Txn(false) + + return i.MemDBAliasByIDInTxn(txn, aliasID, clone, groupAlias) +} + +func (i *IdentityStore) MemDBAliasByFactors(mountAccessor, aliasName string, clone bool, groupAlias bool) (*identity.Alias, error) { + if aliasName == "" { + return nil, fmt.Errorf("missing alias name") + } + + if mountAccessor == "" { + return nil, fmt.Errorf("missing mount accessor") + } + + txn := i.db.Txn(false) + + return i.MemDBAliasByFactorsInTxn(txn, mountAccessor, aliasName, clone, groupAlias) +} + +func (i *IdentityStore) MemDBAliasByFactorsInTxn(txn *memdb.Txn, mountAccessor, aliasName string, clone bool, groupAlias bool) (*identity.Alias, error) { + if txn == nil { + return nil, fmt.Errorf("nil txn") + } + + if aliasName == "" { + return nil, fmt.Errorf("missing alias name") + } + + if mountAccessor == "" { + return nil, fmt.Errorf("missing mount accessor") + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + aliasRaw, err := txn.First(tableName, "factors", mountAccessor, aliasName) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch alias from memdb using factors: {{err}}", err) + } + + if aliasRaw == nil { + return nil, nil + } + + alias, ok := aliasRaw.(*identity.Alias) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched alias") + } + + if clone { + return alias.Clone() + } + + return alias, nil +} + +func (i *IdentityStore) MemDBAliasesByMetadata(filters map[string]string, clone bool, groupAlias bool) ([]*identity.Alias, error) { + if filters == nil { + return nil, fmt.Errorf("map filter is nil") + } + + txn := i.db.Txn(false) + defer txn.Abort() + + var args []interface{} + for key, value := range filters { + args = append(args, key, value) + break + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + aliasesIter, err := txn.Get(tableName, "metadata", args...) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup aliases using metadata: {{err}}", err) + } + + var aliases []*identity.Alias + for alias := aliasesIter.Next(); alias != nil; alias = aliasesIter.Next() { + entry := alias.(*identity.Alias) + if len(filters) <= 1 || satisfiesMetadataFilters(entry.Metadata, filters) { + if clone { + entry, err = entry.Clone() + if err != nil { + return nil, err + } + } + aliases = append(aliases, entry) + } + } + return aliases, nil +} + +func (i *IdentityStore) MemDBDeleteAliasByID(aliasID string, groupAlias bool) error { + if aliasID == "" { + return nil + } + + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.MemDBDeleteAliasByIDInTxn(txn, aliasID, groupAlias) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBDeleteAliasByIDInTxn(txn *memdb.Txn, aliasID string, groupAlias bool) error { + if aliasID == "" { + return nil + } + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + alias, err := i.MemDBAliasByIDInTxn(txn, aliasID, false, groupAlias) + if err != nil { + return err + } + + if alias == nil { + return nil + } + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + err = txn.Delete(tableName, alias) + if err != nil { + return errwrap.Wrapf("failed to delete alias from memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) MemDBAliases(ws memdb.WatchSet, groupAlias bool) (memdb.ResultIterator, error) { + txn := i.db.Txn(false) + + tableName := entityAliasesTable + if groupAlias { + tableName = groupAliasesTable + } + + iter, err := txn.Get(tableName, "id") + if err != nil { + return nil, err + } + + ws.Add(iter.WatchCh()) + + return iter, nil +} + +func (i *IdentityStore) MemDBUpsertEntityInTxn(txn *memdb.Txn, entity *identity.Entity) error { + if txn == nil { + return fmt.Errorf("nil txn") + } + + if entity == nil { + return fmt.Errorf("entity is nil") + } + + entityRaw, err := txn.First(entitiesTable, "id", entity.ID) + if err != nil { + return errwrap.Wrapf("failed to lookup entity from memdb using entity id: {{err}}", err) + } + + if entityRaw != nil { + err = txn.Delete(entitiesTable, entityRaw) + if err != nil { + return errwrap.Wrapf("failed to delete entity from memdb: {{err}}", err) + } + } + + if err := txn.Insert(entitiesTable, entity); err != nil { + return errwrap.Wrapf("failed to update entity into memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) MemDBUpsertEntity(entity *identity.Entity) error { + if entity == nil { + return fmt.Errorf("entity to upsert is nil") + } + + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.MemDBUpsertEntityInTxn(txn, entity) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBEntityByIDInTxn(txn *memdb.Txn, entityID string, clone bool) (*identity.Entity, error) { + if entityID == "" { + return nil, fmt.Errorf("missing entity id") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + entityRaw, err := txn.First(entitiesTable, "id", entityID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch entity from memdb using entity id: {{err}}", err) + } + + if entityRaw == nil { + return nil, nil + } + + entity, ok := entityRaw.(*identity.Entity) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched entity") + } + + if clone { + return entity.Clone() + } + + return entity, nil +} + +func (i *IdentityStore) MemDBEntityByID(entityID string, clone bool) (*identity.Entity, error) { + if entityID == "" { + return nil, fmt.Errorf("missing entity id") + } + + txn := i.db.Txn(false) + + return i.MemDBEntityByIDInTxn(txn, entityID, clone) +} + +func (i *IdentityStore) MemDBEntityByNameInTxn(txn *memdb.Txn, entityName string, clone bool) (*identity.Entity, error) { + if entityName == "" { + return nil, fmt.Errorf("missing entity name") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + entityRaw, err := txn.First(entitiesTable, "name", entityName) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch entity from memdb using entity name: {{err}}", err) + } + + if entityRaw == nil { + return nil, nil + } + + entity, ok := entityRaw.(*identity.Entity) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched entity") + } + + if clone { + return entity.Clone() + } + + return entity, nil +} + +func (i *IdentityStore) MemDBEntityByName(entityName string, clone bool) (*identity.Entity, error) { + if entityName == "" { + return nil, fmt.Errorf("missing entity name") + } + + txn := i.db.Txn(false) + + return i.MemDBEntityByNameInTxn(txn, entityName, clone) +} + +func (i *IdentityStore) MemDBEntitiesByMetadata(filters map[string]string, clone bool) ([]*identity.Entity, error) { + if filters == nil { + return nil, fmt.Errorf("map filter is nil") + } + + txn := i.db.Txn(false) + defer txn.Abort() + + var args []interface{} + for key, value := range filters { + args = append(args, key, value) + break + } + + entitiesIter, err := txn.Get(entitiesTable, "metadata", args...) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup entities using metadata: {{err}}", err) + } + + var entities []*identity.Entity + for entity := entitiesIter.Next(); entity != nil; entity = entitiesIter.Next() { + entry := entity.(*identity.Entity) + if clone { + entry, err = entry.Clone() + if err != nil { + return nil, err + } + } + if len(filters) <= 1 || satisfiesMetadataFilters(entry.Metadata, filters) { + entities = append(entities, entry) + } + } + return entities, nil +} + +func (i *IdentityStore) MemDBEntitiesByBucketEntryKeyHash(hashValue string) ([]*identity.Entity, error) { + if hashValue == "" { + return nil, fmt.Errorf("empty hash value") + } + + txn := i.db.Txn(false) + defer txn.Abort() + + return i.MemDBEntitiesByBucketEntryKeyHashInTxn(txn, hashValue) +} + +func (i *IdentityStore) MemDBEntitiesByBucketEntryKeyHashInTxn(txn *memdb.Txn, hashValue string) ([]*identity.Entity, error) { + if txn == nil { + return nil, fmt.Errorf("nil txn") + } + + if hashValue == "" { + return nil, fmt.Errorf("empty hash value") + } + + entitiesIter, err := txn.Get(entitiesTable, "bucket_key_hash", hashValue) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup entities using bucket entry key hash: {{err}}", err) + } + + var entities []*identity.Entity + for entity := entitiesIter.Next(); entity != nil; entity = entitiesIter.Next() { + entities = append(entities, entity.(*identity.Entity)) + } + + return entities, nil +} + +func (i *IdentityStore) MemDBEntityByMergedEntityIDInTxn(txn *memdb.Txn, mergedEntityID string, clone bool) (*identity.Entity, error) { + if mergedEntityID == "" { + return nil, fmt.Errorf("missing merged entity id") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + entityRaw, err := txn.First(entitiesTable, "merged_entity_ids", mergedEntityID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch entity from memdb using merged entity id: {{err}}", err) + } + + if entityRaw == nil { + return nil, nil + } + + entity, ok := entityRaw.(*identity.Entity) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched entity") + } + + if clone { + return entity.Clone() + } + + return entity, nil +} + +func (i *IdentityStore) MemDBEntityByMergedEntityID(mergedEntityID string, clone bool) (*identity.Entity, error) { + if mergedEntityID == "" { + return nil, fmt.Errorf("missing merged entity id") + } + + txn := i.db.Txn(false) + + return i.MemDBEntityByMergedEntityIDInTxn(txn, mergedEntityID, clone) +} + +func (i *IdentityStore) MemDBEntityByAliasIDInTxn(txn *memdb.Txn, aliasID string, clone bool) (*identity.Entity, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + alias, err := i.MemDBAliasByIDInTxn(txn, aliasID, false, false) + if err != nil { + return nil, err + } + + if alias == nil { + return nil, nil + } + + return i.MemDBEntityByIDInTxn(txn, alias.CanonicalID, clone) +} + +func (i *IdentityStore) MemDBEntityByAliasID(aliasID string, clone bool) (*identity.Entity, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + txn := i.db.Txn(false) + + return i.MemDBEntityByAliasIDInTxn(txn, aliasID, clone) +} + +func (i *IdentityStore) MemDBDeleteEntityByID(entityID string) error { + if entityID == "" { + return nil + } + + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.MemDBDeleteEntityByIDInTxn(txn, entityID) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBDeleteEntityByIDInTxn(txn *memdb.Txn, entityID string) error { + if entityID == "" { + return nil + } + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + entity, err := i.MemDBEntityByIDInTxn(txn, entityID, false) + if err != nil { + return err + } + + if entity == nil { + return nil + } + + err = txn.Delete(entitiesTable, entity) + if err != nil { + return errwrap.Wrapf("failed to delete entity from memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) MemDBEntities(ws memdb.WatchSet) (memdb.ResultIterator, error) { + txn := i.db.Txn(false) + + iter, err := txn.Get(entitiesTable, "id") + if err != nil { + return nil, err + } + + ws.Add(iter.WatchCh()) + + return iter, nil +} + +func (i *IdentityStore) sanitizeAlias(alias *identity.Alias) error { + var err error + + if alias == nil { + return fmt.Errorf("alias is nil") + } + + // Alias must always be tied to a canonical object + if alias.CanonicalID == "" { + return fmt.Errorf("missing canonical ID") + } + + // Alias must have a name + if alias.Name == "" { + return fmt.Errorf("missing alias name %q", alias.Name) + } + + // Alias metadata should always be map[string]string + err = validateMetadata(alias.Metadata) + if err != nil { + return errwrap.Wrapf("invalid alias metadata: {{err}}", err) + } + + // Create an ID if there isn't one already + if alias.ID == "" { + alias.ID, err = uuid.GenerateUUID() + if err != nil { + return fmt.Errorf("failed to generate alias ID") + } + } + + // Set the creation and last update times + if alias.CreationTime == nil { + alias.CreationTime = ptypes.TimestampNow() + alias.LastUpdateTime = alias.CreationTime + } else { + alias.LastUpdateTime = ptypes.TimestampNow() + } + + return nil +} + +func (i *IdentityStore) sanitizeEntity(entity *identity.Entity) error { + var err error + + if entity == nil { + return fmt.Errorf("entity is nil") + } + + // Create an ID if there isn't one already + if entity.ID == "" { + entity.ID, err = uuid.GenerateUUID() + if err != nil { + return fmt.Errorf("failed to generate entity id") + } + + // Set the hash value of the storage bucket key in entity + entity.BucketKeyHash = i.entityPacker.BucketKeyHashByItemID(entity.ID) + } + + // Create a name if there isn't one already + if entity.Name == "" { + entity.Name, err = i.generateName("entity") + if err != nil { + return fmt.Errorf("failed to generate entity name") + } + } + + // Entity metadata should always be map[string]string + err = validateMetadata(entity.Metadata) + if err != nil { + return errwrap.Wrapf("invalid entity metadata: {{err}}", err) + } + + // Set the creation and last update times + if entity.CreationTime == nil { + entity.CreationTime = ptypes.TimestampNow() + entity.LastUpdateTime = entity.CreationTime + } else { + entity.LastUpdateTime = ptypes.TimestampNow() + } + + return nil +} + +func (i *IdentityStore) sanitizeAndUpsertGroup(group *identity.Group, memberGroupIDs []string) error { + var err error + + if group == nil { + return fmt.Errorf("group is nil") + } + + // Create an ID if there isn't one already + if group.ID == "" { + group.ID, err = uuid.GenerateUUID() + if err != nil { + return fmt.Errorf("failed to generate group id") + } + + // Set the hash value of the storage bucket key in group + group.BucketKeyHash = i.groupPacker.BucketKeyHashByItemID(group.ID) + } + + // Create a name if there isn't one already + if group.Name == "" { + group.Name, err = i.generateName("group") + if err != nil { + return fmt.Errorf("failed to generate group name") + } + } + + // Entity metadata should always be map[string]string + err = validateMetadata(group.Metadata) + if err != nil { + return errwrap.Wrapf("invalid group metadata: {{err}}", err) + } + + // Set the creation and last update times + if group.CreationTime == nil { + group.CreationTime = ptypes.TimestampNow() + group.LastUpdateTime = group.CreationTime + } else { + group.LastUpdateTime = ptypes.TimestampNow() + } + + // Remove duplicate entity IDs and check if all IDs are valid + group.MemberEntityIDs = strutil.RemoveDuplicates(group.MemberEntityIDs, false) + for _, entityID := range group.MemberEntityIDs { + err = i.validateEntityID(entityID) + if err != nil { + return err + } + } + + txn := i.db.Txn(true) + defer txn.Abort() + + memberGroupIDs = strutil.RemoveDuplicates(memberGroupIDs, false) + // After the group lock is held, make membership updates to all the + // relevant groups + for _, memberGroupID := range memberGroupIDs { + memberGroup, err := i.MemDBGroupByID(memberGroupID, true) + if err != nil { + return err + } + if memberGroup == nil { + return fmt.Errorf("invalid member group ID %q", memberGroupID) + } + + // Skip if memberGroupID is already a member of group.ID + if strutil.StrListContains(memberGroup.ParentGroupIDs, group.ID) { + continue + } + + // Ensure that adding memberGroupID does not lead to cyclic + // relationships + err = i.validateMemberGroupID(group.ID, memberGroupID) + if err != nil { + return err + } + + memberGroup.ParentGroupIDs = append(memberGroup.ParentGroupIDs, group.ID) + + // This technically is not upsert. It is only update, only the method name is upsert here. + err = i.upsertGroupInTxn(txn, memberGroup, true) + if err != nil { + // Ideally we would want to revert the whole operation in case of + // errors while persisting in member groups. But there is no + // storage transaction support yet. When we do have it, this will need + // an update. + return err + } + } + + // Sanitize the group alias + if group.Alias != nil { + group.Alias.CanonicalID = group.ID + + err = i.sanitizeAlias(group.Alias) + if err != nil { + return err + } + + err = i.MemDBUpsertAliasInTxn(txn, group.Alias, true) + if err != nil { + return err + } + } + + err = i.upsertGroupInTxn(txn, group, true) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) validateMemberGroupID(groupID string, memberGroupID string) error { + // Detect self loop + if groupID == memberGroupID { + return fmt.Errorf("member group ID %q is same as the ID of the group", groupID) + } + + group, err := i.MemDBGroupByID(groupID, true) + if err != nil { + return err + } + + // If group is nil, that means that a group doesn't already exist and its + // okay to add any group as its member group. + if group == nil { + return nil + } + + // If adding the memberGroupID to groupID creates a cycle, then groupID must + // be a hop in that loop. Start a DFS traversal from memberGroupID and see if + // it reaches back to groupID. If it does, then it's a loop. + + // Created a visited set + visited := make(map[string]bool) + cycleDetected, err := i.detectCycleDFS(visited, groupID, memberGroupID) + if err != nil { + return fmt.Errorf("failed to perform cyclic relationship detection for member group ID %q", memberGroupID) + } + if cycleDetected { + return fmt.Errorf("cyclic relationship detected for member group ID %q", memberGroupID) + } + + return nil +} + +func (i *IdentityStore) validateEntityID(entityID string) error { + entity, err := i.MemDBEntityByID(entityID, false) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to validate entity ID %q: {{err}}", entityID), err) + } + if entity == nil { + return fmt.Errorf("invalid entity ID %q", entityID) + } + return nil +} + +func (i *IdentityStore) validateGroupID(groupID string) error { + group, err := i.MemDBGroupByID(groupID, false) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to validate group ID %q: {{err}}", groupID), err) + } + if group == nil { + return fmt.Errorf("invalid group ID %q", groupID) + } + return nil +} + +func (i *IdentityStore) deleteAliasesInEntityInTxn(txn *memdb.Txn, entity *identity.Entity, aliases []*identity.Alias) error { + if entity == nil { + return fmt.Errorf("entity is nil") + } + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + var remainList []*identity.Alias + var removeList []*identity.Alias + + for _, item := range aliases { + for _, alias := range entity.Aliases { + if alias.ID == item.ID { + removeList = append(removeList, alias) + } else { + remainList = append(remainList, alias) + } + } + } + + // Remove identity indices from aliases table for those that needs to + // be removed + for _, alias := range removeList { + aliasToBeRemoved, err := i.MemDBAliasByIDInTxn(txn, alias.ID, false, false) + if err != nil { + return err + } + if aliasToBeRemoved == nil { + return fmt.Errorf("alias was not indexed") + } + err = i.MemDBDeleteAliasByIDInTxn(txn, aliasToBeRemoved.ID, false) + if err != nil { + return err + } + } + + // Update the entity with remaining items + entity.Aliases = remainList + + return nil +} + +func (i *IdentityStore) deleteAliasFromEntity(entity *identity.Entity, alias *identity.Alias) error { + if entity == nil { + return fmt.Errorf("entity is nil") + } + + if alias == nil { + return fmt.Errorf("alias is nil") + } + + for aliasIndex, item := range entity.Aliases { + if item.ID == alias.ID { + entity.Aliases = append(entity.Aliases[:aliasIndex], entity.Aliases[aliasIndex+1:]...) + break + } + } + + return nil +} + +func (i *IdentityStore) updateAliasInEntity(entity *identity.Entity, alias *identity.Alias) error { + if entity == nil { + return fmt.Errorf("entity is nil") + } + + if alias == nil { + return fmt.Errorf("alias is nil") + } + + aliasFound := false + for aliasIndex, item := range entity.Aliases { + if item.ID == alias.ID { + aliasFound = true + entity.Aliases[aliasIndex] = alias + } + } + + if !aliasFound { + return fmt.Errorf("alias does not exist in entity") + } + + return nil +} + +// validateMeta validates a set of key/value pairs from the agent config +func validateMetadata(meta map[string]string) error { + if len(meta) > metaMaxKeyPairs { + return fmt.Errorf("metadata cannot contain more than %d key/value pairs", metaMaxKeyPairs) + } + + for key, value := range meta { + if err := validateMetaPair(key, value); err != nil { + return errwrap.Wrapf(fmt.Sprintf("failed to load metadata pair (%q, %q): {{err}}", key, value), err) + } + } + + return nil +} + +// validateMetaPair checks that the given key/value pair is in a valid format +func validateMetaPair(key, value string) error { + if key == "" { + return fmt.Errorf("key cannot be blank") + } + if !metaKeyFormatRegEx(key) { + return fmt.Errorf("key contains invalid characters") + } + if len(key) > metaKeyMaxLength { + return fmt.Errorf("key is too long (limit: %d characters)", metaKeyMaxLength) + } + if strings.HasPrefix(key, metaKeyReservedPrefix) { + return fmt.Errorf("key prefix %q is reserved for internal use", metaKeyReservedPrefix) + } + if len(value) > metaValueMaxLength { + return fmt.Errorf("value is too long (limit: %d characters)", metaValueMaxLength) + } + return nil +} + +// satisfiesMetadataFilters returns true if the metadata map contains the given filters +func satisfiesMetadataFilters(meta map[string]string, filters map[string]string) bool { + for key, value := range filters { + if v, ok := meta[key]; !ok || v != value { + return false + } + } + return true +} + +func (i *IdentityStore) MemDBGroupByNameInTxn(txn *memdb.Txn, groupName string, clone bool) (*identity.Group, error) { + if groupName == "" { + return nil, fmt.Errorf("missing group name") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + groupRaw, err := txn.First(groupsTable, "name", groupName) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch group from memdb using group name: {{err}}", err) + } + + if groupRaw == nil { + return nil, nil + } + + group, ok := groupRaw.(*identity.Group) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched group") + } + + if clone { + return group.Clone() + } + + return group, nil +} + +func (i *IdentityStore) MemDBGroupByName(groupName string, clone bool) (*identity.Group, error) { + if groupName == "" { + return nil, fmt.Errorf("missing group name") + } + + txn := i.db.Txn(false) + + return i.MemDBGroupByNameInTxn(txn, groupName, clone) +} + +func (i *IdentityStore) UpsertGroup(group *identity.Group, persist bool) error { + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.upsertGroupInTxn(txn, group, persist) + if err != nil { + return err + } + + txn.Commit() + return nil +} + +func (i *IdentityStore) upsertGroupInTxn(txn *memdb.Txn, group *identity.Group, persist bool) error { + var err error + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + if group == nil { + return fmt.Errorf("group is nil") + } + + // Increment the modify index of the group + group.ModifyIndex++ + + // Insert or update group in MemDB using the transaction created above + err = i.MemDBUpsertGroupInTxn(txn, group) + if err != nil { + return err + } + + if persist { + groupAsAny, err := ptypes.MarshalAny(group) + if err != nil { + return err + } + + item := &storagepacker.Item{ + ID: group.ID, + Message: groupAsAny, + } + + err = i.groupPacker.PutItem(item) + if err != nil { + return err + } + } + + return nil +} + +func (i *IdentityStore) MemDBUpsertGroup(group *identity.Group) error { + txn := i.db.Txn(true) + defer txn.Abort() + + err := i.MemDBUpsertGroupInTxn(txn, group) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBUpsertGroupInTxn(txn *memdb.Txn, group *identity.Group) error { + if txn == nil { + return fmt.Errorf("nil txn") + } + + if group == nil { + return fmt.Errorf("group is nil") + } + + groupRaw, err := txn.First(groupsTable, "id", group.ID) + if err != nil { + return errwrap.Wrapf("failed to lookup group from memdb using group id: {{err}}", err) + } + + if groupRaw != nil { + err = txn.Delete(groupsTable, groupRaw) + if err != nil { + return errwrap.Wrapf("failed to delete group from memdb: {{err}}", err) + } + } + + if err := txn.Insert(groupsTable, group); err != nil { + return errwrap.Wrapf("failed to update group into memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) deleteGroupByID(groupID string) error { + var err error + var group *identity.Group + + if groupID == "" { + return fmt.Errorf("missing group ID") + } + + // Acquire the lock to modify the group storage entry + i.groupLock.Lock() + defer i.groupLock.Unlock() + + // Create a MemDB transaction to delete group + txn := i.db.Txn(true) + defer txn.Abort() + + group, err = i.MemDBGroupByIDInTxn(txn, groupID, false) + if err != nil { + return err + } + + // If there is no group for the ID, do nothing + if group == nil { + return nil + } + + // Delete group alias from memdb + if group.Type == groupTypeExternal && group.Alias != nil { + err = i.MemDBDeleteAliasByIDInTxn(txn, group.Alias.ID, true) + if err != nil { + return err + } + } + + // Delete the group using the same transaction + err = i.MemDBDeleteGroupByIDInTxn(txn, group.ID) + if err != nil { + return err + } + + // Delete the group from storage + err = i.groupPacker.DeleteItem(group.ID) + if err != nil { + return err + } + + // Committing the transaction *after* successfully deleting group + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBDeleteGroupByIDInTxn(txn *memdb.Txn, groupID string) error { + if groupID == "" { + return nil + } + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + group, err := i.MemDBGroupByIDInTxn(txn, groupID, false) + if err != nil { + return err + } + + if group == nil { + return nil + } + + err = txn.Delete("groups", group) + if err != nil { + return errwrap.Wrapf("failed to delete group from memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) deleteGroupByName(groupName string) error { + var err error + var group *identity.Group + + if groupName == "" { + return fmt.Errorf("missing group name") + } + + // Acquire the lock to modify the group storage entry + i.groupLock.Lock() + defer i.groupLock.Unlock() + + // Create a MemDB transaction to delete group + txn := i.db.Txn(true) + defer txn.Abort() + + // Fetch the group using its ID + group, err = i.MemDBGroupByNameInTxn(txn, groupName, false) + if err != nil { + return err + } + + // If there is no entity for the ID, do nothing + if group == nil { + return nil + } + + // Delete the group using the same transaction + err = i.MemDBDeleteGroupByNameInTxn(txn, group.Name) + if err != nil { + return err + } + + // Delete the entity from storage + err = i.groupPacker.DeleteItem(group.ID) + if err != nil { + return err + } + + // Committing the transaction *after* successfully deleting group + txn.Commit() + + return nil +} + +func (i *IdentityStore) MemDBDeleteGroupByNameInTxn(txn *memdb.Txn, groupName string) error { + if groupName == "" { + return nil + } + + if txn == nil { + return fmt.Errorf("txn is nil") + } + + group, err := i.MemDBGroupByNameInTxn(txn, groupName, false) + if err != nil { + return err + } + + if group == nil { + return nil + } + + err = txn.Delete(groupsTable, group) + if err != nil { + return errwrap.Wrapf("failed to delete group from memdb: {{err}}", err) + } + + return nil +} + +func (i *IdentityStore) MemDBGroupByIDInTxn(txn *memdb.Txn, groupID string, clone bool) (*identity.Group, error) { + if groupID == "" { + return nil, fmt.Errorf("missing group ID") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + groupRaw, err := txn.First(groupsTable, "id", groupID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch group from memdb using group ID: {{err}}", err) + } + + if groupRaw == nil { + return nil, nil + } + + group, ok := groupRaw.(*identity.Group) + if !ok { + return nil, fmt.Errorf("failed to declare the type of fetched group") + } + + if clone { + return group.Clone() + } + + return group, nil +} + +func (i *IdentityStore) MemDBGroupByID(groupID string, clone bool) (*identity.Group, error) { + if groupID == "" { + return nil, fmt.Errorf("missing group ID") + } + + txn := i.db.Txn(false) + + return i.MemDBGroupByIDInTxn(txn, groupID, clone) +} + +func (i *IdentityStore) MemDBGroupsByPolicyInTxn(txn *memdb.Txn, policyName string, clone bool) ([]*identity.Group, error) { + if policyName == "" { + return nil, fmt.Errorf("missing policy name") + } + + groupsIter, err := txn.Get(groupsTable, "policies", policyName) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup groups using policy name: {{err}}", err) + } + + var groups []*identity.Group + for group := groupsIter.Next(); group != nil; group = groupsIter.Next() { + entry := group.(*identity.Group) + if clone { + entry, err = entry.Clone() + if err != nil { + return nil, err + } + } + groups = append(groups, entry) + } + + return groups, nil +} + +func (i *IdentityStore) MemDBGroupsByPolicy(policyName string, clone bool) ([]*identity.Group, error) { + if policyName == "" { + return nil, fmt.Errorf("missing policy name") + } + + txn := i.db.Txn(false) + + return i.MemDBGroupsByPolicyInTxn(txn, policyName, clone) +} + +func (i *IdentityStore) MemDBGroupsByParentGroupIDInTxn(txn *memdb.Txn, memberGroupID string, clone bool) ([]*identity.Group, error) { + if memberGroupID == "" { + return nil, fmt.Errorf("missing member group ID") + } + + groupsIter, err := txn.Get(groupsTable, "parent_group_ids", memberGroupID) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup groups using member group ID: {{err}}", err) + } + + var groups []*identity.Group + for group := groupsIter.Next(); group != nil; group = groupsIter.Next() { + entry := group.(*identity.Group) + if clone { + entry, err = entry.Clone() + if err != nil { + return nil, err + } + } + groups = append(groups, entry) + } + + return groups, nil +} + +func (i *IdentityStore) MemDBGroupsByParentGroupID(memberGroupID string, clone bool) ([]*identity.Group, error) { + if memberGroupID == "" { + return nil, fmt.Errorf("missing member group ID") + } + + txn := i.db.Txn(false) + + return i.MemDBGroupsByParentGroupIDInTxn(txn, memberGroupID, clone) +} + +func (i *IdentityStore) MemDBGroupsByMemberEntityID(entityID string, clone bool, externalOnly bool) ([]*identity.Group, error) { + txn := i.db.Txn(false) + defer txn.Abort() + + return i.MemDBGroupsByMemberEntityIDInTxn(txn, entityID, clone, externalOnly) +} + +func (i *IdentityStore) MemDBGroupsByMemberEntityIDInTxn(txn *memdb.Txn, entityID string, clone bool, externalOnly bool) ([]*identity.Group, error) { + if entityID == "" { + return nil, fmt.Errorf("missing entity ID") + } + + groupsIter, err := txn.Get(groupsTable, "member_entity_ids", entityID) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup groups using entity ID: {{err}}", err) + } + + var groups []*identity.Group + for group := groupsIter.Next(); group != nil; group = groupsIter.Next() { + entry := group.(*identity.Group) + if externalOnly && entry.Type == groupTypeInternal { + continue + } + if clone { + entry, err = entry.Clone() + if err != nil { + return nil, err + } + } + groups = append(groups, entry) + } + + return groups, nil +} + +func (i *IdentityStore) groupPoliciesByEntityID(entityID string) ([]string, error) { + if entityID == "" { + return nil, fmt.Errorf("empty entity ID") + } + + groups, err := i.MemDBGroupsByMemberEntityID(entityID, false, false) + if err != nil { + return nil, err + } + + visited := make(map[string]bool) + var policies []string + for _, group := range groups { + groupPolicies, err := i.collectPoliciesReverseDFS(group, visited, nil) + if err != nil { + return nil, err + } + policies = append(policies, groupPolicies...) + } + + return strutil.RemoveDuplicates(policies, false), nil +} + +func (i *IdentityStore) groupsByEntityID(entityID string) ([]*identity.Group, []*identity.Group, error) { + if entityID == "" { + return nil, nil, fmt.Errorf("empty entity ID") + } + + groups, err := i.MemDBGroupsByMemberEntityID(entityID, true, false) + if err != nil { + return nil, nil, err + } + + visited := make(map[string]bool) + var tGroups []*identity.Group + for _, group := range groups { + gGroups, err := i.collectGroupsReverseDFS(group, visited, nil) + if err != nil { + return nil, nil, err + } + tGroups = append(tGroups, gGroups...) + } + + // Remove duplicates + groupMap := make(map[string]*identity.Group) + for _, group := range tGroups { + groupMap[group.ID] = group + } + + tGroups = make([]*identity.Group, 0, len(groupMap)) + for _, group := range groupMap { + tGroups = append(tGroups, group) + } + + diff := diffGroups(groups, tGroups) + + // For sanity + // There should not be any group that gets deleted + if len(diff.Deleted) != 0 { + return nil, nil, fmt.Errorf("failed to diff group memberships") + } + + return diff.Unmodified, diff.New, nil +} + +func (i *IdentityStore) collectGroupsReverseDFS(group *identity.Group, visited map[string]bool, groups []*identity.Group) ([]*identity.Group, error) { + if group == nil { + return nil, fmt.Errorf("nil group") + } + + // If traversal for a groupID is performed before, skip it + if visited[group.ID] { + return groups, nil + } + visited[group.ID] = true + + groups = append(groups, group) + + // Traverse all the parent groups + for _, parentGroupID := range group.ParentGroupIDs { + parentGroup, err := i.MemDBGroupByID(parentGroupID, false) + if err != nil { + return nil, err + } + pGroups, err := i.collectGroupsReverseDFS(parentGroup, visited, groups) + if err != nil { + return nil, fmt.Errorf("failed to collect group at parent group ID %q", parentGroup.ID) + } + groups = append(groups, pGroups...) + } + + return groups, nil +} + +func (i *IdentityStore) collectPoliciesReverseDFS(group *identity.Group, visited map[string]bool, policies []string) ([]string, error) { + if group == nil { + return nil, fmt.Errorf("nil group") + } + + // If traversal for a groupID is performed before, skip it + if visited[group.ID] { + return policies, nil + } + visited[group.ID] = true + + policies = append(policies, group.Policies...) + + // Traverse all the parent groups + for _, parentGroupID := range group.ParentGroupIDs { + parentGroup, err := i.MemDBGroupByID(parentGroupID, false) + if err != nil { + return nil, err + } + parentPolicies, err := i.collectPoliciesReverseDFS(parentGroup, visited, policies) + if err != nil { + return nil, fmt.Errorf("failed to collect policies at parent group ID %q", parentGroup.ID) + } + policies = append(policies, parentPolicies...) + } + + return strutil.RemoveDuplicates(policies, false), nil +} + +func (i *IdentityStore) detectCycleDFS(visited map[string]bool, startingGroupID, groupID string) (bool, error) { + // If the traversal reaches the startingGroupID, a loop is detected + if startingGroupID == groupID { + return true, nil + } + + // If traversal for a groupID is performed before, skip it + if visited[groupID] { + return false, nil + } + visited[groupID] = true + + group, err := i.MemDBGroupByID(groupID, true) + if err != nil { + return false, err + } + if group == nil { + return false, nil + } + + // Fetch all groups in which groupID is present as a ParentGroupID. In + // other words, find all the subgroups of groupID. + memberGroups, err := i.MemDBGroupsByParentGroupID(groupID, false) + if err != nil { + return false, err + } + + // DFS traverse the member groups + for _, memberGroup := range memberGroups { + cycleDetected, err := i.detectCycleDFS(visited, startingGroupID, memberGroup.ID) + if err != nil { + return false, fmt.Errorf("failed to perform cycle detection at member group ID %q", memberGroup.ID) + } + if cycleDetected { + return true, fmt.Errorf("cycle detected at member group ID %q", memberGroup.ID) + } + } + + return false, nil +} + +func (i *IdentityStore) memberGroupIDsByID(groupID string) ([]string, error) { + var memberGroupIDs []string + memberGroups, err := i.MemDBGroupsByParentGroupID(groupID, false) + if err != nil { + return nil, err + } + for _, memberGroup := range memberGroups { + memberGroupIDs = append(memberGroupIDs, memberGroup.ID) + } + return memberGroupIDs, nil +} + +func (i *IdentityStore) MemDBGroupIterator(ws memdb.WatchSet) (memdb.ResultIterator, error) { + txn := i.db.Txn(false) + + iter, err := txn.Get(groupsTable, "id") + if err != nil { + return nil, err + } + + ws.Add(iter.WatchCh()) + + return iter, nil +} + +func (i *IdentityStore) generateName(entryType string) (string, error) { + var name string +OUTER: + for { + randBytes, err := uuid.GenerateRandomBytes(4) + if err != nil { + return "", err + } + name = fmt.Sprintf("%s_%s", entryType, fmt.Sprintf("%08x", randBytes[0:4])) + + switch entryType { + case "entity": + entity, err := i.MemDBEntityByName(name, false) + if err != nil { + return "", err + } + if entity == nil { + break OUTER + } + case "group": + group, err := i.MemDBGroupByName(name, false) + if err != nil { + return "", err + } + if group == nil { + break OUTER + } + default: + return "", fmt.Errorf("unrecognized type %q", entryType) + } + } + + return name, nil +} + +func (i *IdentityStore) MemDBGroupsByBucketEntryKeyHash(hashValue string) ([]*identity.Group, error) { + if hashValue == "" { + return nil, fmt.Errorf("empty hash value") + } + + txn := i.db.Txn(false) + defer txn.Abort() + + return i.MemDBGroupsByBucketEntryKeyHashInTxn(txn, hashValue) +} + +func (i *IdentityStore) MemDBGroupsByBucketEntryKeyHashInTxn(txn *memdb.Txn, hashValue string) ([]*identity.Group, error) { + if txn == nil { + return nil, fmt.Errorf("nil txn") + } + + if hashValue == "" { + return nil, fmt.Errorf("empty hash value") + } + + groupsIter, err := txn.Get(groupsTable, "bucket_key_hash", hashValue) + if err != nil { + return nil, errwrap.Wrapf("failed to lookup groups using bucket entry key hash: {{err}}", err) + } + + var groups []*identity.Group + for group := groupsIter.Next(); group != nil; group = groupsIter.Next() { + groups = append(groups, group.(*identity.Group)) + } + + return groups, nil +} + +func (i *IdentityStore) MemDBGroupByAliasIDInTxn(txn *memdb.Txn, aliasID string, clone bool) (*identity.Group, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + if txn == nil { + return nil, fmt.Errorf("txn is nil") + } + + alias, err := i.MemDBAliasByIDInTxn(txn, aliasID, false, true) + if err != nil { + return nil, err + } + + if alias == nil { + return nil, nil + } + + return i.MemDBGroupByIDInTxn(txn, alias.CanonicalID, clone) +} + +func (i *IdentityStore) MemDBGroupByAliasID(aliasID string, clone bool) (*identity.Group, error) { + if aliasID == "" { + return nil, fmt.Errorf("missing alias ID") + } + + txn := i.db.Txn(false) + + return i.MemDBGroupByAliasIDInTxn(txn, aliasID, clone) +} + +func (i *IdentityStore) deleteGroupAlias(aliasID string) error { + if aliasID == "" { + return fmt.Errorf("missing alias ID") + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + txn := i.db.Txn(true) + defer txn.Abort() + + alias, err := i.MemDBAliasByIDInTxn(txn, aliasID, false, true) + if err != nil { + return err + } + + if alias == nil { + return nil + } + + group, err := i.MemDBGroupByAliasIDInTxn(txn, alias.ID, true) + if err != nil { + return err + } + + // If there is no group tied to a valid alias, something is wrong + if group == nil { + return fmt.Errorf("alias not associated to a group") + } + + // Delete group alias in memdb + err = i.MemDBDeleteAliasByIDInTxn(txn, group.Alias.ID, true) + if err != nil { + return err + } + + // Delete the alias + group.Alias = nil + + err = i.upsertGroupInTxn(txn, group, true) + if err != nil { + return err + } + + txn.Commit() + + return nil +} + +func (i *IdentityStore) refreshExternalGroupMembershipsByEntityID(entityID string, groupAliases []*logical.Alias) error { + if entityID == "" { + return fmt.Errorf("empty entity ID") + } + + i.groupLock.Lock() + defer i.groupLock.Unlock() + + txn := i.db.Txn(true) + defer txn.Abort() + + oldGroups, err := i.MemDBGroupsByMemberEntityIDInTxn(txn, entityID, true, true) + if err != nil { + return err + } + + mountAccessor := "" + if len(groupAliases) != 0 { + mountAccessor = groupAliases[0].MountAccessor + } + + var newGroups []*identity.Group + for _, alias := range groupAliases { + aliasByFactors, err := i.MemDBAliasByFactors(alias.MountAccessor, alias.Name, true, true) + if err != nil { + return err + } + if aliasByFactors == nil { + continue + } + mappingGroup, err := i.MemDBGroupByAliasID(aliasByFactors.ID, true) + if err != nil { + return err + } + if mappingGroup == nil { + return fmt.Errorf("group unavailable for a valid alias ID %q", aliasByFactors.ID) + } + newGroups = append(newGroups, mappingGroup) + } + + diff := diffGroups(oldGroups, newGroups) + + // Add the entity ID to all the new groups + for _, group := range diff.New { + if group.Type != groupTypeExternal { + continue + } + + i.logger.Debug("adding member entity ID to external group", "member_entity_id", entityID, "group_id", group.ID) + + group.MemberEntityIDs = append(group.MemberEntityIDs, entityID) + + err = i.upsertGroupInTxn(txn, group, true) + if err != nil { + return err + } + } + + // Remove the entity ID from all the deleted groups + for _, group := range diff.Deleted { + if group.Type != groupTypeExternal { + continue + } + + // If the external group is from a different mount, don't remove the + // entity ID from it. + if mountAccessor != "" && group.Alias.MountAccessor != mountAccessor { + continue + } + + i.logger.Debug("removing member entity ID from external group", "member_entity_id", entityID, "group_id", group.ID) + + group.MemberEntityIDs = strutil.StrListDelete(group.MemberEntityIDs, entityID) + + err = i.upsertGroupInTxn(txn, group, true) + if err != nil { + return err + } + } + + txn.Commit() + + return nil +} + +// diffGroups is used to diff two sets of groups +func diffGroups(old, new []*identity.Group) *groupDiff { + diff := &groupDiff{} + + existing := make(map[string]*identity.Group) + for _, group := range old { + existing[group.ID] = group + } + + for _, group := range new { + // Check if the entry in new is present in the old + _, ok := existing[group.ID] + + // If its not present, then its a new entry + if !ok { + diff.New = append(diff.New, group) + continue + } + + // If its present, it means that its unmodified + diff.Unmodified = append(diff.Unmodified, group) + + // By deleting the unmodified from the old set, we could determine the + // ones that are stale by looking at the remaining ones. + delete(existing, group.ID) + } + + // Any remaining entries must have been deleted + for _, me := range existing { + diff.Deleted = append(diff.Deleted, me) + } + + return diff +} diff --git a/vendor/github.com/hashicorp/vault/vault/init.go b/vendor/github.com/hashicorp/vault/vault/init.go new file mode 100644 index 0000000..659858e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/init.go @@ -0,0 +1,305 @@ +package vault + +import ( + "context" + "encoding/base64" + "encoding/hex" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/pgpkeys" + "github.com/hashicorp/vault/shamir" +) + +// InitParams keeps the init function from being littered with too many +// params, that's it! +type InitParams struct { + BarrierConfig *SealConfig + RecoveryConfig *SealConfig + RootTokenPGPKey string +} + +// InitResult is used to provide the key parts back after +// they are generated as part of the initialization. +type InitResult struct { + SecretShares [][]byte + RecoveryShares [][]byte + RootToken string +} + +// Initialized checks if the Vault is already initialized +func (c *Core) Initialized(ctx context.Context) (bool, error) { + // Check the barrier first + init, err := c.barrier.Initialized(ctx) + if err != nil { + c.logger.Error("barrier init check failed", "error", err) + return false, err + } + if !init { + c.logger.Info("security barrier not initialized") + return false, nil + } + + // Verify the seal configuration + sealConf, err := c.seal.BarrierConfig(ctx) + if err != nil { + return false, err + } + if sealConf == nil { + return false, fmt.Errorf("core: barrier reports initialized but no seal configuration found") + } + + return true, nil +} + +func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) { + // Generate a master key + masterKey, err := c.barrier.GenerateKey() + if err != nil { + return nil, nil, errwrap.Wrapf("key generation failed: {{err}}", err) + } + + // Return the master key if only a single key part is used + var unsealKeys [][]byte + if sc.SecretShares == 1 { + unsealKeys = append(unsealKeys, masterKey) + } else { + // Split the master key using the Shamir algorithm + shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold) + if err != nil { + return nil, nil, errwrap.Wrapf("failed to generate barrier shares: {{err}}", err) + } + unsealKeys = shares + } + + // If we have PGP keys, perform the encryption + if len(sc.PGPKeys) > 0 { + hexEncodedShares := make([][]byte, len(unsealKeys)) + for i, _ := range unsealKeys { + hexEncodedShares[i] = []byte(hex.EncodeToString(unsealKeys[i])) + } + _, encryptedShares, err := pgpkeys.EncryptShares(hexEncodedShares, sc.PGPKeys) + if err != nil { + return nil, nil, err + } + unsealKeys = encryptedShares + } + + return masterKey, unsealKeys, nil +} + +// Initialize is used to initialize the Vault with the given +// configurations. +func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitResult, error) { + barrierConfig := initParams.BarrierConfig + recoveryConfig := initParams.RecoveryConfig + + if c.seal.RecoveryKeySupported() { + if recoveryConfig == nil { + return nil, fmt.Errorf("recovery configuration must be supplied") + } + + if recoveryConfig.SecretShares < 1 { + return nil, fmt.Errorf("recovery configuration must specify a positive number of shares") + } + + // Check if the seal configuration is valid + if err := recoveryConfig.Validate(); err != nil { + c.logger.Error("invalid recovery configuration", "error", err) + return nil, errwrap.Wrapf("invalid recovery configuration: {{err}}", err) + } + } + + // Check if the seal configuration is valid + if err := barrierConfig.Validate(); err != nil { + c.logger.Error("invalid seal configuration", "error", err) + return nil, errwrap.Wrapf("invalid seal configuration: {{err}}", err) + } + + // Avoid an initialization race + c.stateLock.Lock() + defer c.stateLock.Unlock() + + // Check if we are initialized + init, err := c.Initialized(ctx) + if err != nil { + return nil, err + } + if init { + return nil, ErrAlreadyInit + } + + err = c.seal.Init(ctx) + if err != nil { + c.logger.Error("failed to initialize seal", "error", err) + return nil, errwrap.Wrapf("error initializing seal: {{err}}", err) + } + + barrierKey, barrierUnsealKeys, err := c.generateShares(barrierConfig) + if err != nil { + c.logger.Error("error generating shares", "error", err) + return nil, err + } + + // Initialize the barrier + if err := c.barrier.Initialize(ctx, barrierKey); err != nil { + c.logger.Error("failed to initialize barrier", "error", err) + return nil, errwrap.Wrapf("failed to initialize barrier: {{err}}", err) + } + if c.logger.IsInfo() { + c.logger.Info("security barrier initialized", "shares", barrierConfig.SecretShares, "threshold", barrierConfig.SecretThreshold) + } + + // Unseal the barrier + if err := c.barrier.Unseal(ctx, barrierKey); err != nil { + c.logger.Error("failed to unseal barrier", "error", err) + return nil, errwrap.Wrapf("failed to unseal barrier: {{err}}", err) + } + + // Ensure the barrier is re-sealed + defer func() { + // Defers are LIFO so we need to run this here too to ensure the stop + // happens before sealing. preSeal also stops, so we just make the + // stopping safe against multiple calls. + if err := c.barrier.Seal(); err != nil { + c.logger.Error("failed to seal barrier", "error", err) + } + }() + + err = c.seal.SetBarrierConfig(ctx, barrierConfig) + if err != nil { + c.logger.Error("failed to save barrier configuration", "error", err) + return nil, errwrap.Wrapf("barrier configuration saving failed: {{err}}", err) + } + + // If we are storing shares, pop them out of the returned results and push + // them through the seal + if barrierConfig.StoredShares > 0 { + var keysToStore [][]byte + for i := 0; i < barrierConfig.StoredShares; i++ { + keysToStore = append(keysToStore, barrierUnsealKeys[0]) + barrierUnsealKeys = barrierUnsealKeys[1:] + } + if err := c.seal.SetStoredKeys(ctx, keysToStore); err != nil { + c.logger.Error("failed to store keys", "error", err) + return nil, errwrap.Wrapf("failed to store keys: {{err}}", err) + } + } + + results := &InitResult{ + SecretShares: barrierUnsealKeys, + } + + // Perform initial setup + if err := c.setupCluster(ctx); err != nil { + c.logger.Error("cluster setup failed during init", "error", err) + return nil, err + } + if err := c.postUnseal(); err != nil { + c.logger.Error("post-unseal setup failed during init", "error", err) + return nil, err + } + + // Save the configuration regardless, but only generate a key if it's not + // disabled. When using recovery keys they are stored in the barrier, so + // this must happen post-unseal. + if c.seal.RecoveryKeySupported() { + err = c.seal.SetRecoveryConfig(ctx, recoveryConfig) + if err != nil { + c.logger.Error("failed to save recovery configuration", "error", err) + return nil, errwrap.Wrapf("recovery configuration saving failed: {{err}}", err) + } + + if recoveryConfig.SecretShares > 0 { + recoveryKey, recoveryUnsealKeys, err := c.generateShares(recoveryConfig) + if err != nil { + c.logger.Error("failed to generate recovery shares", "error", err) + return nil, err + } + + err = c.seal.SetRecoveryKey(ctx, recoveryKey) + if err != nil { + return nil, err + } + + results.RecoveryShares = recoveryUnsealKeys + } + } + + // Generate a new root token + rootToken, err := c.tokenStore.rootToken(ctx) + if err != nil { + c.logger.Error("root token generation failed", "error", err) + return nil, err + } + results.RootToken = rootToken.ID + c.logger.Info("root token generated") + + if initParams.RootTokenPGPKey != "" { + _, encryptedVals, err := pgpkeys.EncryptShares([][]byte{[]byte(results.RootToken)}, []string{initParams.RootTokenPGPKey}) + if err != nil { + c.logger.Error("root token encryption failed", "error", err) + return nil, err + } + results.RootToken = base64.StdEncoding.EncodeToString(encryptedVals[0]) + } + + // Prepare to re-seal + if err := c.preSeal(); err != nil { + c.logger.Error("pre-seal teardown failed", "error", err) + return nil, err + } + + return results, nil +} + +// UnsealWithStoredKeys performs auto-unseal using stored keys. +func (c *Core) UnsealWithStoredKeys(ctx context.Context) error { + if !c.seal.StoredKeysSupported() { + return nil + } + + sealed, err := c.Sealed() + if err != nil { + c.logger.Error("error checking sealed status in auto-unseal", "error", err) + return errwrap.Wrapf("error checking sealed status in auto-unseal: {{err}}", err) + } + if !sealed { + return nil + } + + c.logger.Info("stored unseal keys supported, attempting fetch") + keys, err := c.seal.GetStoredKeys(ctx) + if err != nil { + c.logger.Error("fetching stored unseal keys failed", "error", err) + return &NonFatalError{Err: errwrap.Wrapf("fetching stored unseal keys failed: {{err}}", err)} + } + if len(keys) == 0 { + c.logger.Warn("stored unseal key(s) supported but none found") + } else { + unsealed := false + keysUsed := 0 + for _, key := range keys { + unsealed, err = c.Unseal(key) + if err != nil { + c.logger.Error("unseal with stored unseal key failed", "error", err) + return &NonFatalError{Err: errwrap.Wrapf("unseal with stored key failed: {{err}}", err)} + } + keysUsed += 1 + if unsealed { + break + } + } + if !unsealed { + if c.logger.IsWarn() { + c.logger.Warn("stored unseal key(s) used but Vault not unsealed yet", "stored_keys_used", keysUsed) + } + } else { + if c.logger.IsInfo() { + c.logger.Info("successfully unsealed with stored key(s)", "stored_keys_used", keysUsed) + } + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/keyring.go b/vendor/github.com/hashicorp/vault/vault/keyring.go new file mode 100644 index 0000000..fd65647 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/keyring.go @@ -0,0 +1,203 @@ +package vault + +import ( + "bytes" + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" +) + +// Keyring is used to manage multiple encryption keys used by +// the barrier. New keys can be installed and each has a sequential term. +// The term used to encrypt a key is prefixed to the key written out. +// All data is encrypted with the latest key, but storing the old keys +// allows for decryption of keys written previously. Along with the encryption +// keys, the keyring also tracks the master key. This is necessary so that +// when a new key is added to the keyring, we can encrypt with the master key +// and write out the new keyring. +type Keyring struct { + masterKey []byte + keys map[uint32]*Key + activeTerm uint32 +} + +// EncodedKeyring is used for serialization of the keyring +type EncodedKeyring struct { + MasterKey []byte + Keys []*Key +} + +// Key represents a single term, along with the key used. +type Key struct { + Term uint32 + Version int + Value []byte + InstallTime time.Time +} + +// Serialize is used to create a byte encoded key +func (k *Key) Serialize() ([]byte, error) { + return json.Marshal(k) +} + +// DeserializeKey is used to deserialize and return a new key +func DeserializeKey(buf []byte) (*Key, error) { + k := new(Key) + if err := jsonutil.DecodeJSON(buf, k); err != nil { + return nil, errwrap.Wrapf("deserialization failed: {{err}}", err) + } + return k, nil +} + +// NewKeyring creates a new keyring +func NewKeyring() *Keyring { + k := &Keyring{ + keys: make(map[uint32]*Key), + activeTerm: 0, + } + return k +} + +// Clone returns a new copy of the keyring +func (k *Keyring) Clone() *Keyring { + clone := &Keyring{ + masterKey: k.masterKey, + keys: make(map[uint32]*Key, len(k.keys)), + activeTerm: k.activeTerm, + } + for idx, key := range k.keys { + clone.keys[idx] = key + } + return clone +} + +// AddKey adds a new key to the keyring +func (k *Keyring) AddKey(key *Key) (*Keyring, error) { + // Ensure there is no conflict + if exist, ok := k.keys[key.Term]; ok { + if !bytes.Equal(key.Value, exist.Value) { + return nil, fmt.Errorf("conflicting key for term %d already installed", key.Term) + } + return k, nil + } + + // Add a time if none + if key.InstallTime.IsZero() { + key.InstallTime = time.Now() + } + + // Make a new keyring + clone := k.Clone() + + // Install the new key + clone.keys[key.Term] = key + + // Update the active term if newer + if key.Term > clone.activeTerm { + clone.activeTerm = key.Term + } + return clone, nil +} + +// RemoveKey removes a key from the keyring +func (k *Keyring) RemoveKey(term uint32) (*Keyring, error) { + // Ensure this is not the active key + if term == k.activeTerm { + return nil, fmt.Errorf("cannot remove active key") + } + + // Check if this term does not exist + if _, ok := k.keys[term]; !ok { + return k, nil + } + + // Delete the key + clone := k.Clone() + delete(clone.keys, term) + return clone, nil +} + +// ActiveTerm returns the currently active term +func (k *Keyring) ActiveTerm() uint32 { + return k.activeTerm +} + +// ActiveKey returns the active encryption key, or nil +func (k *Keyring) ActiveKey() *Key { + return k.keys[k.activeTerm] +} + +// TermKey returns the key for the given term, or nil +func (k *Keyring) TermKey(term uint32) *Key { + return k.keys[term] +} + +// SetMasterKey is used to update the master key +func (k *Keyring) SetMasterKey(val []byte) *Keyring { + valCopy := make([]byte, len(val)) + copy(valCopy, val) + clone := k.Clone() + clone.masterKey = valCopy + return clone +} + +// MasterKey returns the master key +func (k *Keyring) MasterKey() []byte { + return k.masterKey +} + +// Serialize is used to create a byte encoded keyring +func (k *Keyring) Serialize() ([]byte, error) { + // Create the encoded entry + enc := EncodedKeyring{ + MasterKey: k.masterKey, + } + for _, key := range k.keys { + enc.Keys = append(enc.Keys, key) + } + + // JSON encode the keyring + buf, err := json.Marshal(enc) + return buf, err +} + +// DeserializeKeyring is used to deserialize and return a new keyring +func DeserializeKeyring(buf []byte) (*Keyring, error) { + // Deserialize the keyring + var enc EncodedKeyring + if err := jsonutil.DecodeJSON(buf, &enc); err != nil { + return nil, errwrap.Wrapf("deserialization failed: {{err}}", err) + } + + // Create a new keyring + k := NewKeyring() + k.masterKey = enc.MasterKey + for _, key := range enc.Keys { + k.keys[key.Term] = key + if key.Term > k.activeTerm { + k.activeTerm = key.Term + } + } + return k, nil +} + +// N.B.: +// Since Go 1.5 these are not reliable; see the documentation around the memzero +// function. These are best-effort. +func (k *Keyring) Zeroize(keysToo bool) { + if k == nil { + return + } + if k.masterKey != nil { + memzero(k.masterKey) + } + if !keysToo || k.keys == nil { + return + } + for _, key := range k.keys { + memzero(key.Value) + } +} diff --git a/vendor/github.com/hashicorp/vault/vault/logical_cubbyhole.go b/vendor/github.com/hashicorp/vault/vault/logical_cubbyhole.go new file mode 100644 index 0000000..08055dd --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/logical_cubbyhole.go @@ -0,0 +1,207 @@ +package vault + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// CubbyholeBackendFactory constructs a new cubbyhole backend +func CubbyholeBackendFactory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + var b CubbyholeBackend + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(cubbyholeHelp), + + Paths: []*framework.Path{ + &framework.Path{ + Pattern: ".*", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleRead, + logical.CreateOperation: b.handleWrite, + logical.UpdateOperation: b.handleWrite, + logical.DeleteOperation: b.handleDelete, + logical.ListOperation: b.handleList, + }, + + ExistenceCheck: b.handleExistenceCheck, + + HelpSynopsis: strings.TrimSpace(cubbyholeHelpSynopsis), + HelpDescription: strings.TrimSpace(cubbyholeHelpDescription), + }, + }, + } + + if conf == nil { + return nil, fmt.Errorf("configuration passed into backend is nil") + } + b.Backend.Setup(ctx, conf) + + return &b, nil +} + +// CubbyholeBackend is used for storing secrets directly into the physical +// backend. The secrets are encrypted in the durable storage. +// This differs from kv in that every token has its own private +// storage view. The view is removed when the token expires. +type CubbyholeBackend struct { + *framework.Backend + + saltUUID string + storageView logical.Storage +} + +func (b *CubbyholeBackend) revoke(ctx context.Context, saltedToken string) error { + if saltedToken == "" { + return fmt.Errorf("client token empty during revocation") + } + + if err := logical.ClearView(ctx, b.storageView.(*BarrierView).SubView(saltedToken+"/")); err != nil { + return err + } + + return nil +} + +func (b *CubbyholeBackend) handleExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.ClientToken+"/"+req.Path) + if err != nil { + return false, errwrap.Wrapf("existence check failed: {{err}}", err) + } + + return out != nil, nil +} + +func (b *CubbyholeBackend) handleRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + if req.ClientToken == "" { + return nil, fmt.Errorf("client token empty") + } + + // Read the path + out, err := req.Storage.Get(ctx, req.ClientToken+"/"+req.Path) + if err != nil { + return nil, errwrap.Wrapf("read failed: {{err}}", err) + } + + // Fast-path the no data case + if out == nil { + return nil, nil + } + + // Decode the data + var rawData map[string]interface{} + if err := jsonutil.DecodeJSON(out.Value, &rawData); err != nil { + return nil, errwrap.Wrapf("json decoding failed: {{err}}", err) + } + + // Generate the response + resp := &logical.Response{ + Data: rawData, + } + + return resp, nil +} + +func (b *CubbyholeBackend) handleWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + if req.ClientToken == "" { + return nil, fmt.Errorf("client token empty") + } + // Check that some fields are given + if len(req.Data) == 0 { + return nil, fmt.Errorf("missing data fields") + } + + // JSON encode the data + buf, err := json.Marshal(req.Data) + if err != nil { + return nil, errwrap.Wrapf("json encoding failed: {{err}}", err) + } + + // Write out a new key + entry := &logical.StorageEntry{ + Key: req.ClientToken + "/" + req.Path, + Value: buf, + } + if req.WrapInfo != nil && req.WrapInfo.SealWrap { + entry.SealWrap = true + } + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, errwrap.Wrapf("failed to write: {{err}}", err) + } + + return nil, nil +} + +func (b *CubbyholeBackend) handleDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + if req.ClientToken == "" { + return nil, fmt.Errorf("client token empty") + } + // Delete the key at the request path + if err := req.Storage.Delete(ctx, req.ClientToken+"/"+req.Path); err != nil { + return nil, err + } + + return nil, nil +} + +func (b *CubbyholeBackend) handleList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + if req.ClientToken == "" { + return nil, fmt.Errorf("client token empty") + } + + // Right now we only handle directories, so ensure it ends with / We also + // check if it's empty so we don't end up doing a listing on '//' + path := req.Path + if path != "" && !strings.HasSuffix(path, "/") { + path = path + "/" + } + + // List the keys at the prefix given by the request + keys, err := req.Storage.List(ctx, req.ClientToken+"/"+path) + if err != nil { + return nil, err + } + + // Strip the token + strippedKeys := make([]string, len(keys)) + for i, key := range keys { + strippedKeys[i] = strings.TrimPrefix(key, req.ClientToken+"/") + } + + // Generate the response + return logical.ListResponse(strippedKeys), nil +} + +const cubbyholeHelp = ` +The cubbyhole backend reads and writes arbitrary secrets to the backend. +The secrets are encrypted/decrypted by Vault: they are never stored +unencrypted in the backend and the backend never has an opportunity to +see the unencrypted value. + +This backend differs from the 'kv' backend in that it is namespaced +per-token. Tokens can only read and write their own values, with no +sharing possible (per-token cubbyholes). This can be useful for implementing +certain authentication workflows, as well as "scratch" areas for individual +clients. When the token is revoked, the entire set of stored values for that +token is also removed. +` + +const cubbyholeHelpSynopsis = ` +Pass-through secret storage to a token-specific cubbyhole in the storage +backend, allowing you to read/write arbitrary data into secret storage. +` + +const cubbyholeHelpDescription = ` +The cubbyhole backend reads and writes arbitrary data into secret storage, +encrypting it along the way. + +The view into the cubbyhole storage space is different for each token; it is +a per-token cubbyhole. When the token is revoked all values are removed. +` diff --git a/vendor/github.com/hashicorp/vault/vault/logical_passthrough.go b/vendor/github.com/hashicorp/vault/vault/logical_passthrough.go new file mode 100644 index 0000000..3a40da2 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/logical_passthrough.go @@ -0,0 +1,247 @@ +package vault + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// PassthroughBackendFactory returns a PassthroughBackend +// with leases switched off +func PassthroughBackendFactory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + return LeaseSwitchedPassthroughBackend(ctx, conf, false) +} + +// LeasedPassthroughBackendFactory returns a PassthroughBackend +// with leases switched on +func LeasedPassthroughBackendFactory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + return LeaseSwitchedPassthroughBackend(ctx, conf, true) +} + +// LeaseSwitchedPassthroughBackend returns a PassthroughBackend +// with leases switched on or off +func LeaseSwitchedPassthroughBackend(ctx context.Context, conf *logical.BackendConfig, leases bool) (logical.Backend, error) { + var b PassthroughBackend + b.generateLeases = leases + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(passthroughHelp), + + PathsSpecial: &logical.Paths{ + SealWrapStorage: []string{ + "*", + }, + }, + + Paths: []*framework.Path{ + &framework.Path{ + Pattern: ".*", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleRead, + logical.CreateOperation: b.handleWrite, + logical.UpdateOperation: b.handleWrite, + logical.DeleteOperation: b.handleDelete, + logical.ListOperation: b.handleList, + }, + + ExistenceCheck: b.handleExistenceCheck, + + HelpSynopsis: strings.TrimSpace(passthroughHelpSynopsis), + HelpDescription: strings.TrimSpace(passthroughHelpDescription), + }, + }, + } + + b.Backend.Secrets = []*framework.Secret{ + &framework.Secret{ + Type: "kv", + + Renew: b.handleRead, + Revoke: b.handleRevoke, + }, + } + + if conf == nil { + return nil, fmt.Errorf("configuration passed into backend is nil") + } + b.Backend.Setup(ctx, conf) + + return &b, nil +} + +// PassthroughBackend is used storing secrets directly into the physical +// backend. The secrets are encrypted in the durable storage and custom TTL +// information can be specified, but otherwise this backend doesn't do anything +// fancy. +type PassthroughBackend struct { + *framework.Backend + generateLeases bool +} + +func (b *PassthroughBackend) handleRevoke(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // This is a no-op + return nil, nil +} + +func (b *PassthroughBackend) handleExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, errwrap.Wrapf("existence check failed: {{err}}", err) + } + + return out != nil, nil +} + +func (b *PassthroughBackend) handleRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Read the path + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return nil, errwrap.Wrapf("read failed: {{err}}", err) + } + + // Fast-path the no data case + if out == nil { + return nil, nil + } + + // Decode the data + var rawData map[string]interface{} + + if err := jsonutil.DecodeJSON(out.Value, &rawData); err != nil { + return nil, errwrap.Wrapf("json decoding failed: {{err}}", err) + } + + var resp *logical.Response + if b.generateLeases { + // Generate the response + resp = b.Secret("kv").Response(rawData, nil) + resp.Secret.Renewable = false + } else { + resp = &logical.Response{ + Secret: &logical.Secret{}, + Data: rawData, + } + } + + // Ensure seal wrapping is carried through if the response is + // response-wrapped + if out.SealWrap { + if resp.WrapInfo == nil { + resp.WrapInfo = &wrapping.ResponseWrapInfo{} + } + resp.WrapInfo.SealWrap = out.SealWrap + } + + // Check if there is a ttl key + ttlDuration := b.System().DefaultLeaseTTL() + ttlRaw, ok := rawData["ttl"] + if !ok { + ttlRaw, ok = rawData["lease"] + } + if ok { + dur, err := parseutil.ParseDurationSecond(ttlRaw) + if err == nil { + ttlDuration = dur + } + + if b.generateLeases { + resp.Secret.Renewable = true + } + } + + resp.Secret.TTL = ttlDuration + + return resp, nil +} + +func (b *PassthroughBackend) GeneratesLeases() bool { + return b.generateLeases +} + +func (b *PassthroughBackend) handleWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Check that some fields are given + if len(req.Data) == 0 { + return logical.ErrorResponse("missing data fields"), nil + } + + // JSON encode the data + buf, err := json.Marshal(req.Data) + if err != nil { + return nil, errwrap.Wrapf("json encoding failed: {{err}}", err) + } + + // Write out a new key + entry := &logical.StorageEntry{ + Key: req.Path, + Value: buf, + } + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, errwrap.Wrapf("failed to write: {{err}}", err) + } + + return nil, nil +} + +func (b *PassthroughBackend) handleDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Delete the key at the request path + if err := req.Storage.Delete(ctx, req.Path); err != nil { + return nil, err + } + + return nil, nil +} + +func (b *PassthroughBackend) handleList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Right now we only handle directories, so ensure it ends with /; however, + // some physical backends may not handle the "/" case properly, so only add + // it if we're not listing the root + path := req.Path + if path != "" && !strings.HasSuffix(path, "/") { + path = path + "/" + } + + // List the keys at the prefix given by the request + keys, err := req.Storage.List(ctx, path) + if err != nil { + return nil, err + } + + // Generate the response + return logical.ListResponse(keys), nil +} + +const passthroughHelp = ` +The kv backend reads and writes arbitrary secrets to the backend. +The secrets are encrypted/decrypted by Vault: they are never stored +unencrypted in the backend and the backend never has an opportunity to +see the unencrypted value. + +TTLs can be set on a per-secret basis. These TTLs will be sent down +when that secret is read, and it is assumed that some outside process will +revoke and/or replace the secret at that path. +` + +const passthroughHelpSynopsis = ` +Pass-through secret storage to the storage backend, allowing you to +read/write arbitrary data into secret storage. +` + +const passthroughHelpDescription = ` +The pass-through backend reads and writes arbitrary data into secret storage, +encrypting it along the way. + +A TTL can be specified when writing with the "ttl" field. If given, the +duration of leases returned by this backend will be set to this value. This +can be used as a hint from the writer of a secret to the consumer of a secret +that the consumer should re-read the value before the TTL has expired. +However, any revocation must be handled by the user of this backend; the lease +duration does not affect the provided data in any way. +` diff --git a/vendor/github.com/hashicorp/vault/vault/logical_system.go b/vendor/github.com/hashicorp/vault/vault/logical_system.go new file mode 100644 index 0000000..7a119dc --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/logical_system.go @@ -0,0 +1,4303 @@ +package vault + +import ( + "context" + "crypto/sha256" + "crypto/sha512" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "hash" + "net/http" + "path/filepath" + "strconv" + "strings" + "sync" + "time" + + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/compressutil" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "github.com/mitchellh/mapstructure" +) + +var ( + // protectedPaths cannot be accessed via the raw APIs. + // This is both for security and to prevent disrupting Vault. + protectedPaths = []string{ + keyringPath, + coreLocalClusterInfoPath, + } + + replicationPaths = func(b *SystemBackend) []*framework.Path { + return []*framework.Path{ + &framework.Path{ + Pattern: "replication/status", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + resp := &logical.Response{ + Data: map[string]interface{}{ + "mode": "disabled", + }, + } + return resp, nil + }, + }, + }, + } + } +) + +func NewSystemBackend(core *Core, logger log.Logger) *SystemBackend { + b := &SystemBackend{ + Core: core, + logger: logger, + } + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(sysHelpRoot), + + PathsSpecial: &logical.Paths{ + Root: []string{ + "auth/*", + "remount", + "audit", + "audit/*", + "raw", + "raw/*", + "replication/primary/secondary-token", + "replication/reindex", + "rotate", + "config/cors", + "config/auditing/*", + "config/ui/headers/*", + "plugins/catalog/*", + "revoke-prefix/*", + "revoke-force/*", + "leases/revoke-prefix/*", + "leases/revoke-force/*", + "leases/lookup/*", + }, + + Unauthenticated: []string{ + "wrapping/lookup", + "wrapping/pubkey", + "replication/status", + "internal/ui/mounts", + "internal/ui/mounts/*", + }, + }, + + Paths: []*framework.Path{ + &framework.Path{ + Pattern: "capabilities-accessor$", + + Fields: map[string]*framework.FieldSchema{ + "accessor": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Accessor of the token for which capabilities are being queried.", + }, + "path": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "(DEPRECATED) Path on which capabilities are being queried. Use 'paths' instead.", + }, + "paths": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "Paths on which capabilities are being queried.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleCapabilitiesAccessor, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["capabilities_accessor"][0]), + HelpDescription: strings.TrimSpace(sysHelp["capabilities_accessor"][1]), + }, + + &framework.Path{ + Pattern: "config/cors$", + + Fields: map[string]*framework.FieldSchema{ + "enable": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: "Enables or disables CORS headers on requests.", + }, + "allowed_origins": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "A comma-separated string or array of strings indicating origins that may make cross-origin requests.", + }, + "allowed_headers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "A comma-separated string or array of strings indicating headers that are allowed on cross-origin requests.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleCORSRead, + logical.UpdateOperation: b.handleCORSUpdate, + logical.DeleteOperation: b.handleCORSDelete, + }, + + HelpDescription: strings.TrimSpace(sysHelp["config/cors"][0]), + HelpSynopsis: strings.TrimSpace(sysHelp["config/cors"][1]), + }, + + &framework.Path{ + Pattern: "config/ui/headers/" + framework.GenericNameRegex("header"), + + Fields: map[string]*framework.FieldSchema{ + "header": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The name of the header.", + }, + "values": &framework.FieldSchema{ + Type: framework.TypeStringSlice, + Description: "The values to set the header.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleConfigUIHeadersRead, + logical.UpdateOperation: b.handleConfigUIHeadersUpdate, + logical.DeleteOperation: b.handleConfigUIHeadersDelete, + }, + + HelpDescription: strings.TrimSpace(sysHelp["config/ui/headers"][0]), + HelpSynopsis: strings.TrimSpace(sysHelp["config/ui/headers"][1]), + }, + + &framework.Path{ + Pattern: "config/ui/headers/$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.handleConfigUIHeadersList, + }, + + HelpDescription: strings.TrimSpace(sysHelp["config/ui/headers"][0]), + HelpSynopsis: strings.TrimSpace(sysHelp["config/ui/headers"][1]), + }, + + &framework.Path{ + Pattern: "capabilities$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token for which capabilities are being queried.", + }, + "path": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "(DEPRECATED) Path on which capabilities are being queried. Use 'paths' instead.", + }, + "paths": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "Paths on which capabilities are being queried.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleCapabilities, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["capabilities"][0]), + HelpDescription: strings.TrimSpace(sysHelp["capabilities"][1]), + }, + + &framework.Path{ + Pattern: "capabilities-self$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token for which capabilities are being queried.", + }, + "path": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "(DEPRECATED) Path on which capabilities are being queried. Use 'paths' instead.", + }, + "paths": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: "Paths on which capabilities are being queried.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleCapabilities, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["capabilities_self"][0]), + HelpDescription: strings.TrimSpace(sysHelp["capabilities_self"][1]), + }, + + &framework.Path{ + Pattern: "generate-root(/attempt)?$", + HelpSynopsis: strings.TrimSpace(sysHelp["generate-root"][0]), + HelpDescription: strings.TrimSpace(sysHelp["generate-root"][1]), + }, + + &framework.Path{ + Pattern: "init$", + HelpSynopsis: strings.TrimSpace(sysHelp["init"][0]), + HelpDescription: strings.TrimSpace(sysHelp["init"][1]), + }, + + &framework.Path{ + Pattern: "rekey/backup$", + + Fields: map[string]*framework.FieldSchema{}, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleRekeyRetrieveBarrier, + logical.DeleteOperation: b.handleRekeyDeleteBarrier, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["rekey_backup"][0]), + HelpDescription: strings.TrimSpace(sysHelp["rekey_backup"][0]), + }, + + &framework.Path{ + Pattern: "rekey/recovery-key-backup$", + + Fields: map[string]*framework.FieldSchema{}, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleRekeyRetrieveRecovery, + logical.DeleteOperation: b.handleRekeyDeleteRecovery, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["rekey_backup"][0]), + HelpDescription: strings.TrimSpace(sysHelp["rekey_backup"][0]), + }, + + &framework.Path{ + Pattern: "auth/(?P.+?)/tune$", + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_tune"][0]), + }, + "default_lease_ttl": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["tune_default_lease_ttl"][0]), + }, + "max_lease_ttl": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["tune_max_lease_ttl"][0]), + }, + "description": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_desc"][0]), + }, + "audit_non_hmac_request_keys": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["tune_audit_non_hmac_request_keys"][0]), + }, + "audit_non_hmac_response_keys": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["tune_audit_non_hmac_response_keys"][0]), + }, + "options": &framework.FieldSchema{ + Type: framework.TypeKVPairs, + Description: strings.TrimSpace(sysHelp["tune_mount_options"][0]), + }, + "listing_visibility": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["listing_visibility"][0]), + }, + "passthrough_request_headers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["passthrough_request_headers"][0]), + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleAuthTuneRead, + logical.UpdateOperation: b.handleAuthTuneWrite, + }, + HelpSynopsis: strings.TrimSpace(sysHelp["auth_tune"][0]), + HelpDescription: strings.TrimSpace(sysHelp["auth_tune"][1]), + }, + + &framework.Path{ + Pattern: "mounts/(?P.+?)/tune$", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["mount_path"][0]), + }, + "default_lease_ttl": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["tune_default_lease_ttl"][0]), + }, + "max_lease_ttl": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["tune_max_lease_ttl"][0]), + }, + "description": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_desc"][0]), + }, + "audit_non_hmac_request_keys": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["tune_audit_non_hmac_request_keys"][0]), + }, + "audit_non_hmac_response_keys": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["tune_audit_non_hmac_response_keys"][0]), + }, + "options": &framework.FieldSchema{ + Type: framework.TypeKVPairs, + Description: strings.TrimSpace(sysHelp["tune_mount_options"][0]), + }, + "listing_visibility": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["listing_visibility"][0]), + }, + "passthrough_request_headers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["passthrough_request_headers"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleMountTuneRead, + logical.UpdateOperation: b.handleMountTuneWrite, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["mount_tune"][0]), + HelpDescription: strings.TrimSpace(sysHelp["mount_tune"][1]), + }, + + &framework.Path{ + Pattern: "mounts/(?P.+?)", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["mount_path"][0]), + }, + "type": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["mount_type"][0]), + }, + "description": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["mount_desc"][0]), + }, + "config": &framework.FieldSchema{ + Type: framework.TypeMap, + Description: strings.TrimSpace(sysHelp["mount_config"][0]), + }, + "local": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: strings.TrimSpace(sysHelp["mount_local"][0]), + }, + "seal_wrap": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: strings.TrimSpace(sysHelp["seal_wrap"][0]), + }, + "plugin_name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["mount_plugin_name"][0]), + }, + "options": &framework.FieldSchema{ + Type: framework.TypeKVPairs, + Description: strings.TrimSpace(sysHelp["mount_options"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleMount, + logical.DeleteOperation: b.handleUnmount, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["mount"][0]), + HelpDescription: strings.TrimSpace(sysHelp["mount"][1]), + }, + + &framework.Path{ + Pattern: "mounts$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleMountTable, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["mounts"][0]), + HelpDescription: strings.TrimSpace(sysHelp["mounts"][1]), + }, + + &framework.Path{ + Pattern: "remount", + + Fields: map[string]*framework.FieldSchema{ + "from": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The previous mount point.", + }, + "to": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The new mount point.", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRemount, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["remount"][0]), + HelpDescription: strings.TrimSpace(sysHelp["remount"][1]), + }, + + &framework.Path{ + Pattern: "leases/lookup/(?P.+?)?", + + Fields: map[string]*framework.FieldSchema{ + "prefix": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["leases-list-prefix"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.handleLeaseLookupList, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["leases"][0]), + HelpDescription: strings.TrimSpace(sysHelp["leases"][1]), + }, + + &framework.Path{ + Pattern: "leases/lookup", + + Fields: map[string]*framework.FieldSchema{ + "lease_id": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["lease_id"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleLeaseLookup, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["leases"][0]), + HelpDescription: strings.TrimSpace(sysHelp["leases"][1]), + }, + + &framework.Path{ + Pattern: "(leases/)?renew" + framework.OptionalParamRegex("url_lease_id"), + + Fields: map[string]*framework.FieldSchema{ + "url_lease_id": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["lease_id"][0]), + }, + "lease_id": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["lease_id"][0]), + }, + "increment": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: strings.TrimSpace(sysHelp["increment"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRenew, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["renew"][0]), + HelpDescription: strings.TrimSpace(sysHelp["renew"][1]), + }, + + &framework.Path{ + Pattern: "(leases/)?revoke" + framework.OptionalParamRegex("url_lease_id"), + + Fields: map[string]*framework.FieldSchema{ + "url_lease_id": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["lease_id"][0]), + }, + "lease_id": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["lease_id"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRevoke, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["revoke"][0]), + HelpDescription: strings.TrimSpace(sysHelp["revoke"][1]), + }, + + &framework.Path{ + Pattern: "(leases/)?revoke-force/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "prefix": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["revoke-force-path"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRevokeForce, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["revoke-force"][0]), + HelpDescription: strings.TrimSpace(sysHelp["revoke-force"][1]), + }, + + &framework.Path{ + Pattern: "(leases/)?revoke-prefix/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "prefix": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["revoke-prefix-path"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRevokePrefix, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["revoke-prefix"][0]), + HelpDescription: strings.TrimSpace(sysHelp["revoke-prefix"][1]), + }, + + &framework.Path{ + Pattern: "leases/tidy$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleTidyLeases, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["tidy_leases"][0]), + HelpDescription: strings.TrimSpace(sysHelp["tidy_leases"][1]), + }, + + &framework.Path{ + Pattern: "auth$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleAuthTable, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["auth-table"][0]), + HelpDescription: strings.TrimSpace(sysHelp["auth-table"][1]), + }, + + &framework.Path{ + Pattern: "auth/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_path"][0]), + }, + "type": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_type"][0]), + }, + "description": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_desc"][0]), + }, + "config": &framework.FieldSchema{ + Type: framework.TypeMap, + Description: strings.TrimSpace(sysHelp["auth_config"][0]), + }, + "local": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: strings.TrimSpace(sysHelp["mount_local"][0]), + }, + "seal_wrap": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: strings.TrimSpace(sysHelp["seal_wrap"][0]), + }, + "plugin_name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["auth_plugin"][0]), + }, + "options": &framework.FieldSchema{ + Type: framework.TypeKVPairs, + Description: strings.TrimSpace(sysHelp["auth_options"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleEnableAuth, + logical.DeleteOperation: b.handleDisableAuth, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["auth"][0]), + HelpDescription: strings.TrimSpace(sysHelp["auth"][1]), + }, + + &framework.Path{ + Pattern: "policy/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handlePoliciesList(PolicyTypeACL), + logical.ListOperation: b.handlePoliciesList(PolicyTypeACL), + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]), + HelpDescription: strings.TrimSpace(sysHelp["policy-list"][1]), + }, + + &framework.Path{ + Pattern: "policy/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["policy-name"][0]), + }, + "rules": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["policy-rules"][0]), + }, + "policy": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["policy-rules"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handlePoliciesRead(PolicyTypeACL), + logical.UpdateOperation: b.handlePoliciesSet(PolicyTypeACL), + logical.DeleteOperation: b.handlePoliciesDelete(PolicyTypeACL), + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["policy"][0]), + HelpDescription: strings.TrimSpace(sysHelp["policy"][1]), + }, + + &framework.Path{ + Pattern: "policies/acl/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.handlePoliciesList(PolicyTypeACL), + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]), + HelpDescription: strings.TrimSpace(sysHelp["policy-list"][1]), + }, + + &framework.Path{ + Pattern: "policies/acl/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["policy-name"][0]), + }, + "policy": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["policy-rules"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handlePoliciesRead(PolicyTypeACL), + logical.UpdateOperation: b.handlePoliciesSet(PolicyTypeACL), + logical.DeleteOperation: b.handlePoliciesDelete(PolicyTypeACL), + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["policy"][0]), + HelpDescription: strings.TrimSpace(sysHelp["policy"][1]), + }, + + &framework.Path{ + Pattern: "seal-status$", + HelpSynopsis: strings.TrimSpace(sysHelp["seal-status"][0]), + HelpDescription: strings.TrimSpace(sysHelp["seal-status"][1]), + }, + + &framework.Path{ + Pattern: "seal$", + HelpSynopsis: strings.TrimSpace(sysHelp["seal"][0]), + HelpDescription: strings.TrimSpace(sysHelp["seal"][1]), + }, + + &framework.Path{ + Pattern: "unseal$", + HelpSynopsis: strings.TrimSpace(sysHelp["unseal"][0]), + HelpDescription: strings.TrimSpace(sysHelp["unseal"][1]), + }, + + &framework.Path{ + Pattern: "audit-hash/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["audit_path"][0]), + }, + + "input": &framework.FieldSchema{ + Type: framework.TypeString, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleAuditHash, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["audit-hash"][0]), + HelpDescription: strings.TrimSpace(sysHelp["audit-hash"][1]), + }, + + &framework.Path{ + Pattern: "audit$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleAuditTable, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["audit-table"][0]), + HelpDescription: strings.TrimSpace(sysHelp["audit-table"][1]), + }, + + &framework.Path{ + Pattern: "audit/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["audit_path"][0]), + }, + "type": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["audit_type"][0]), + }, + "description": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["audit_desc"][0]), + }, + "options": &framework.FieldSchema{ + Type: framework.TypeKVPairs, + Description: strings.TrimSpace(sysHelp["audit_opts"][0]), + }, + "local": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: strings.TrimSpace(sysHelp["mount_local"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleEnableAudit, + logical.DeleteOperation: b.handleDisableAudit, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["audit"][0]), + HelpDescription: strings.TrimSpace(sysHelp["audit"][1]), + }, + + &framework.Path{ + Pattern: "key-status$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleKeyStatus, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["key-status"][0]), + HelpDescription: strings.TrimSpace(sysHelp["key-status"][1]), + }, + + &framework.Path{ + Pattern: "rotate$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleRotate, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["rotate"][0]), + HelpDescription: strings.TrimSpace(sysHelp["rotate"][1]), + }, + + &framework.Path{ + Pattern: "wrapping/wrap$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleWrappingWrap, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["wrap"][0]), + HelpDescription: strings.TrimSpace(sysHelp["wrap"][1]), + }, + + &framework.Path{ + Pattern: "wrapping/unwrap$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleWrappingUnwrap, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["unwrap"][0]), + HelpDescription: strings.TrimSpace(sysHelp["unwrap"][1]), + }, + + &framework.Path{ + Pattern: "wrapping/lookup$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleWrappingLookup, + logical.ReadOperation: b.handleWrappingLookup, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["wraplookup"][0]), + HelpDescription: strings.TrimSpace(sysHelp["wraplookup"][1]), + }, + + &framework.Path{ + Pattern: "wrapping/rewrap$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleWrappingRewrap, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["rewrap"][0]), + HelpDescription: strings.TrimSpace(sysHelp["rewrap"][1]), + }, + + &framework.Path{ + Pattern: "config/auditing/request-headers/(?P
.+)", + + Fields: map[string]*framework.FieldSchema{ + "header": &framework.FieldSchema{ + Type: framework.TypeString, + }, + "hmac": &framework.FieldSchema{ + Type: framework.TypeBool, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handleAuditedHeaderUpdate, + logical.DeleteOperation: b.handleAuditedHeaderDelete, + logical.ReadOperation: b.handleAuditedHeaderRead, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["audited-headers-name"][0]), + HelpDescription: strings.TrimSpace(sysHelp["audited-headers-name"][1]), + }, + + &framework.Path{ + Pattern: "config/auditing/request-headers$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleAuditedHeadersRead, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["audited-headers"][0]), + HelpDescription: strings.TrimSpace(sysHelp["audited-headers"][1]), + }, + + &framework.Path{ + Pattern: "plugins/catalog/?$", + + Fields: map[string]*framework.FieldSchema{}, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.handlePluginCatalogList, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["plugin-catalog"][0]), + HelpDescription: strings.TrimSpace(sysHelp["plugin-catalog"][1]), + }, + + &framework.Path{ + Pattern: "plugins/catalog/(?P.+)", + + Fields: map[string]*framework.FieldSchema{ + "name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-catalog_name"][0]), + }, + "sha256": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-catalog_sha-256"][0]), + }, + "sha_256": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-catalog_sha-256"][0]), + }, + "command": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-catalog_command"][0]), + }, + "args": &framework.FieldSchema{ + Type: framework.TypeStringSlice, + Description: strings.TrimSpace(sysHelp["plugin-catalog_args"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handlePluginCatalogUpdate, + logical.DeleteOperation: b.handlePluginCatalogDelete, + logical.ReadOperation: b.handlePluginCatalogRead, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["plugin-catalog"][0]), + HelpDescription: strings.TrimSpace(sysHelp["plugin-catalog"][1]), + }, + &framework.Path{ + Pattern: "plugins/reload/backend$", + + Fields: map[string]*framework.FieldSchema{ + "plugin": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-backend-reload-plugin"][0]), + }, + "mounts": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: strings.TrimSpace(sysHelp["plugin-backend-reload-mounts"][0]), + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.handlePluginReloadUpdate, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["plugin-reload"][0]), + HelpDescription: strings.TrimSpace(sysHelp["plugin-reload"][1]), + }, + &framework.Path{ + Pattern: "tools/hash" + framework.OptionalParamRegex("urlalgorithm"), + Fields: map[string]*framework.FieldSchema{ + "input": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The base64-encoded input data", + }, + + "algorithm": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "sha2-256", + Description: `Algorithm to use (POST body parameter). Valid values are: + + * sha2-224 + * sha2-256 + * sha2-384 + * sha2-512 + + Defaults to "sha2-256".`, + }, + + "urlalgorithm": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `Algorithm to use (POST URL parameter)`, + }, + + "format": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "hex", + Description: `Encoding format to use. Can be "hex" or "base64". Defaults to "hex".`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathHashWrite, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["hash"][0]), + HelpDescription: strings.TrimSpace(sysHelp["hash"][1]), + }, + + &framework.Path{ + Pattern: "tools/random" + framework.OptionalParamRegex("urlbytes"), + Fields: map[string]*framework.FieldSchema{ + "urlbytes": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The number of bytes to generate (POST URL parameter)", + }, + + "bytes": &framework.FieldSchema{ + Type: framework.TypeInt, + Default: 32, + Description: "The number of bytes to generate (POST body parameter). Defaults to 32 (256 bits).", + }, + + "format": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "base64", + Description: `Encoding format to use. Can be "hex" or "base64". Defaults to "base64".`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathRandomWrite, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["random"][0]), + HelpDescription: strings.TrimSpace(sysHelp["random"][1]), + }, + &framework.Path{ + Pattern: "internal/ui/mounts", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathInternalUIMountsRead, + }, + HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]), + HelpDescription: strings.TrimSpace(sysHelp["internal-ui-mounts"][1]), + }, + &framework.Path{ + Pattern: "internal/ui/mounts/(?P.+)", + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The path of the mount.", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathInternalUIMountRead, + }, + HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]), + HelpDescription: strings.TrimSpace(sysHelp["internal-ui-mounts"][1]), + }, + &framework.Path{ + Pattern: "internal/ui/resultant-acl", + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathInternalUIResultantACL, + }, + HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][0]), + HelpDescription: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][1]), + }, + }, + } + + b.Backend.Paths = append(b.Backend.Paths, replicationPaths(b)...) + + if core.rawEnabled { + b.Backend.Paths = append(b.Backend.Paths, &framework.Path{ + Pattern: "(raw/?$|raw/(?P.+))", + + Fields: map[string]*framework.FieldSchema{ + "path": &framework.FieldSchema{ + Type: framework.TypeString, + }, + "value": &framework.FieldSchema{ + Type: framework.TypeString, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.handleRawRead, + logical.UpdateOperation: b.handleRawWrite, + logical.DeleteOperation: b.handleRawDelete, + logical.ListOperation: b.handleRawList, + }, + HelpSynopsis: strings.TrimSpace(sysHelp["raw"][0]), + HelpDescription: strings.TrimSpace(sysHelp["raw"][1]), + }) + } + + b.Backend.Invalidate = b.invalidate + + return b +} + +// SystemBackend implements logical.Backend and is used to interact with +// the core of the system. This backend is hardcoded to exist at the "sys" +// prefix. Conceptually it is similar to procfs on Linux. +type SystemBackend struct { + *framework.Backend + Core *Core + logger log.Logger +} + +// handleCORSRead returns the current CORS configuration +func (b *SystemBackend) handleCORSRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + corsConf := b.Core.corsConfig + + enabled := corsConf.IsEnabled() + + resp := &logical.Response{ + Data: map[string]interface{}{ + "enabled": enabled, + }, + } + + if enabled { + corsConf.RLock() + resp.Data["allowed_origins"] = corsConf.AllowedOrigins + resp.Data["allowed_headers"] = corsConf.AllowedHeaders + corsConf.RUnlock() + } + + return resp, nil +} + +// handleCORSUpdate sets the list of origins that are allowed to make +// cross-origin requests and sets the CORS enabled flag to true +func (b *SystemBackend) handleCORSUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + origins := d.Get("allowed_origins").([]string) + headers := d.Get("allowed_headers").([]string) + + return nil, b.Core.corsConfig.Enable(ctx, origins, headers) +} + +// handleCORSDelete sets the CORS enabled flag to false and clears the list of +// allowed origins & headers. +func (b *SystemBackend) handleCORSDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + return nil, b.Core.corsConfig.Disable(ctx) +} + +func (b *SystemBackend) handleTidyLeases(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + err := b.Core.expiration.Tidy() + if err != nil { + b.Backend.Logger().Error("failed to tidy leases", "error", err) + return handleErrorNoReadOnlyForward(err) + } + return nil, err +} + +func (b *SystemBackend) invalidate(ctx context.Context, key string) { + /* + if b.Core.logger.IsTrace() { + b.Core.logger.Trace("invalidating key", "key", key) + } + */ + switch { + case strings.HasPrefix(key, policyACLSubPath): + b.Core.stateLock.RLock() + defer b.Core.stateLock.RUnlock() + if b.Core.policyStore != nil { + b.Core.policyStore.invalidate(ctx, strings.TrimPrefix(key, policyACLSubPath), PolicyTypeACL) + } + case strings.HasPrefix(key, tokenSubPath): + b.Core.stateLock.RLock() + defer b.Core.stateLock.RUnlock() + if b.Core.tokenStore != nil { + b.Core.tokenStore.Invalidate(ctx, key) + } + } +} + +func (b *SystemBackend) handlePluginCatalogList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + plugins, err := b.Core.pluginCatalog.List(ctx) + if err != nil { + return nil, err + } + + return logical.ListResponse(plugins), nil +} + +func (b *SystemBackend) handlePluginCatalogUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + pluginName := d.Get("name").(string) + if pluginName == "" { + return logical.ErrorResponse("missing plugin name"), nil + } + + sha256 := d.Get("sha256").(string) + if sha256 == "" { + sha256 = d.Get("sha_256").(string) + if sha256 == "" { + return logical.ErrorResponse("missing SHA-256 value"), nil + } + } + + command := d.Get("command").(string) + if command == "" { + return logical.ErrorResponse("missing command value"), nil + } + + // For backwards compatibility, also accept args as part of command. Don't + // accepts args in both command and args. + args := d.Get("args").([]string) + parts := strings.Split(command, " ") + if len(parts) <= 0 { + return logical.ErrorResponse("missing command value"), nil + } else if len(parts) > 1 && len(args) > 0 { + return logical.ErrorResponse("must not specify args in command and args field"), nil + } else if len(parts) > 1 { + args = parts[1:] + } + + sha256Bytes, err := hex.DecodeString(sha256) + if err != nil { + return logical.ErrorResponse("Could not decode SHA-256 value from Hex"), err + } + + err = b.Core.pluginCatalog.Set(ctx, pluginName, parts[0], args, sha256Bytes) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (b *SystemBackend) handlePluginCatalogRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + pluginName := d.Get("name").(string) + if pluginName == "" { + return logical.ErrorResponse("missing plugin name"), nil + } + plugin, err := b.Core.pluginCatalog.Get(ctx, pluginName) + if err != nil { + return nil, err + } + if plugin == nil { + return nil, nil + } + + command := "" + if !plugin.Builtin { + command, err = filepath.Rel(b.Core.pluginCatalog.directory, plugin.Command) + if err != nil { + return nil, err + } + } + + data := map[string]interface{}{ + "name": plugin.Name, + "args": plugin.Args, + "command": command, + "sha256": hex.EncodeToString(plugin.Sha256), + "builtin": plugin.Builtin, + } + + return &logical.Response{ + Data: data, + }, nil +} + +func (b *SystemBackend) handlePluginCatalogDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + pluginName := d.Get("name").(string) + if pluginName == "" { + return logical.ErrorResponse("missing plugin name"), nil + } + err := b.Core.pluginCatalog.Delete(ctx, pluginName) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (b *SystemBackend) handlePluginReloadUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + pluginName := d.Get("plugin").(string) + pluginMounts := d.Get("mounts").([]string) + + if pluginName != "" && len(pluginMounts) > 0 { + return logical.ErrorResponse("plugin and mounts cannot be set at the same time"), nil + } + if pluginName == "" && len(pluginMounts) == 0 { + return logical.ErrorResponse("plugin or mounts must be provided"), nil + } + + if pluginName != "" { + err := b.Core.reloadMatchingPlugin(ctx, pluginName) + if err != nil { + return nil, err + } + } else if len(pluginMounts) > 0 { + err := b.Core.reloadMatchingPluginMounts(ctx, pluginMounts) + if err != nil { + return nil, err + } + } + + return nil, nil +} + +// handleAuditedHeaderUpdate creates or overwrites a header entry +func (b *SystemBackend) handleAuditedHeaderUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + header := d.Get("header").(string) + hmac := d.Get("hmac").(bool) + if header == "" { + return logical.ErrorResponse("missing header name"), nil + } + + headerConfig := b.Core.AuditedHeadersConfig() + err := headerConfig.add(ctx, header, hmac) + if err != nil { + return nil, err + } + + return nil, nil +} + +// handleAuditedHeaderDelete deletes the header with the given name +func (b *SystemBackend) handleAuditedHeaderDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + header := d.Get("header").(string) + if header == "" { + return logical.ErrorResponse("missing header name"), nil + } + + headerConfig := b.Core.AuditedHeadersConfig() + err := headerConfig.remove(ctx, header) + if err != nil { + return nil, err + } + + return nil, nil +} + +// handleAuditedHeaderRead returns the header configuration for the given header name +func (b *SystemBackend) handleAuditedHeaderRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + header := d.Get("header").(string) + if header == "" { + return logical.ErrorResponse("missing header name"), nil + } + + headerConfig := b.Core.AuditedHeadersConfig() + settings, ok := headerConfig.Headers[strings.ToLower(header)] + if !ok { + return logical.ErrorResponse("Could not find header in config"), nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + header: settings, + }, + }, nil +} + +// handleAuditedHeadersRead returns the whole audited headers config +func (b *SystemBackend) handleAuditedHeadersRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + headerConfig := b.Core.AuditedHeadersConfig() + + return &logical.Response{ + Data: map[string]interface{}{ + "headers": headerConfig.Headers, + }, + }, nil +} + +// handleCapabilitiesAccessor returns the ACL capabilities of the +// token associated with the given accessor for a given path. +func (b *SystemBackend) handleCapabilitiesAccessor(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + accessor := d.Get("accessor").(string) + if accessor == "" { + return logical.ErrorResponse("missing accessor"), nil + } + + aEntry, err := b.Core.tokenStore.lookupByAccessor(ctx, accessor, false) + if err != nil { + return nil, err + } + + d.Raw["token"] = aEntry.TokenID + return b.handleCapabilities(ctx, req, d) +} + +// handleCapabilities returns the ACL capabilities of the token for a given path +func (b *SystemBackend) handleCapabilities(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + var token string + if strings.HasSuffix(req.Path, "capabilities-self") { + token = req.ClientToken + } else { + tokenRaw, ok := d.Raw["token"] + if ok { + token, _ = tokenRaw.(string) + } + } + if token == "" { + return nil, fmt.Errorf("no token found") + } + + ret := &logical.Response{ + Data: map[string]interface{}{}, + } + + paths := d.Get("paths").([]string) + if len(paths) == 0 { + // Read from the deprecated field + paths = d.Get("path").([]string) + } + + if len(paths) == 0 { + return logical.ErrorResponse("paths must be supplied"), nil + } + + for _, path := range paths { + pathCap, err := b.Core.Capabilities(ctx, token, path) + if err != nil { + return nil, err + } + ret.Data[path] = pathCap + } + + // This is only here for backwards compatibility + if len(paths) == 1 { + ret.Data["capabilities"] = ret.Data[paths[0]] + } + + return ret, nil +} + +// handleRekeyRetrieve returns backed-up, PGP-encrypted unseal keys from a +// rekey operation +func (b *SystemBackend) handleRekeyRetrieve( + ctx context.Context, + req *logical.Request, + data *framework.FieldData, + recovery bool) (*logical.Response, error) { + backup, err := b.Core.RekeyRetrieveBackup(ctx, recovery) + if err != nil { + return nil, errwrap.Wrapf("unable to look up backed-up keys: {{err}}", err) + } + if backup == nil { + return logical.ErrorResponse("no backed-up keys found"), nil + } + + keysB64 := map[string][]string{} + for k, v := range backup.Keys { + for _, j := range v { + currB64Keys := keysB64[k] + if currB64Keys == nil { + currB64Keys = []string{} + } + key, err := hex.DecodeString(j) + if err != nil { + return nil, errwrap.Wrapf("error decoding hex-encoded backup key: {{err}}", err) + } + currB64Keys = append(currB64Keys, base64.StdEncoding.EncodeToString(key)) + keysB64[k] = currB64Keys + } + } + + // Format the status + resp := &logical.Response{ + Data: map[string]interface{}{ + "nonce": backup.Nonce, + "keys": backup.Keys, + "keys_base64": keysB64, + }, + } + + return resp, nil +} + +func (b *SystemBackend) handleRekeyRetrieveBarrier(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRekeyRetrieve(ctx, req, data, false) +} + +func (b *SystemBackend) handleRekeyRetrieveRecovery(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRekeyRetrieve(ctx, req, data, true) +} + +// handleRekeyDelete deletes backed-up, PGP-encrypted unseal keys from a rekey +// operation +func (b *SystemBackend) handleRekeyDelete( + ctx context.Context, + req *logical.Request, + data *framework.FieldData, + recovery bool) (*logical.Response, error) { + err := b.Core.RekeyDeleteBackup(ctx, recovery) + if err != nil { + return nil, errwrap.Wrapf("error during deletion of backed-up keys: {{err}}", err) + } + + return nil, nil +} + +func (b *SystemBackend) handleRekeyDeleteBarrier(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRekeyDelete(ctx, req, data, false) +} + +func (b *SystemBackend) handleRekeyDeleteRecovery(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRekeyDelete(ctx, req, data, true) +} + +func mountInfo(entry *MountEntry) map[string]interface{} { + info := map[string]interface{}{ + "type": entry.Type, + "description": entry.Description, + "accessor": entry.Accessor, + "local": entry.Local, + "seal_wrap": entry.SealWrap, + "options": entry.Options, + } + entryConfig := map[string]interface{}{ + "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), + "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), + "force_no_cache": entry.Config.ForceNoCache, + "plugin_name": entry.Config.PluginName, + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + entryConfig["audit_non_hmac_request_keys"] = rawVal.([]string) + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + entryConfig["audit_non_hmac_response_keys"] = rawVal.([]string) + } + // Even though empty value is valid for ListingVisibility, we can ignore + // this case during mount since there's nothing to unset/hide. + if len(entry.Config.ListingVisibility) > 0 { + entryConfig["listing_visibility"] = entry.Config.ListingVisibility + } + if rawVal, ok := entry.synthesizedConfigCache.Load("passthrough_request_headers"); ok { + entryConfig["passthrough_request_headers"] = rawVal.([]string) + } + + info["config"] = entryConfig + + return info +} + +// handleMountTable handles the "mounts" endpoint to provide the mount table +func (b *SystemBackend) handleMountTable(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + b.Core.mountsLock.RLock() + defer b.Core.mountsLock.RUnlock() + + resp := &logical.Response{ + Data: make(map[string]interface{}), + } + + for _, entry := range b.Core.mounts.Entries { + // Populate mount info + info := mountInfo(entry) + resp.Data[entry.Path] = info + } + + return resp, nil +} + +// handleMount is used to mount a new path +func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + + local := data.Get("local").(bool) + if !local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot add a non-local mount to a replication secondary"), nil + } + + // Get all the options + path := data.Get("path").(string) + path = sanitizeMountPath(path) + + logicalType := data.Get("type").(string) + description := data.Get("description").(string) + pluginName := data.Get("plugin_name").(string) + sealWrap := data.Get("seal_wrap").(bool) + options := data.Get("options").(map[string]string) + + var config MountConfig + var apiConfig APIMountConfig + + configMap := data.Get("config").(map[string]interface{}) + if configMap != nil && len(configMap) != 0 { + err := mapstructure.Decode(configMap, &apiConfig) + if err != nil { + return logical.ErrorResponse( + "unable to convert given mount config information"), + logical.ErrInvalidRequest + } + } + + switch apiConfig.DefaultLeaseTTL { + case "": + case "system": + default: + tmpDef, err := parseutil.ParseDurationSecond(apiConfig.DefaultLeaseTTL) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf( + "unable to parse default TTL of %s: %s", apiConfig.DefaultLeaseTTL, err)), + logical.ErrInvalidRequest + } + config.DefaultLeaseTTL = tmpDef + } + + switch apiConfig.MaxLeaseTTL { + case "": + case "system": + default: + tmpMax, err := parseutil.ParseDurationSecond(apiConfig.MaxLeaseTTL) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf( + "unable to parse max TTL of %s: %s", apiConfig.MaxLeaseTTL, err)), + logical.ErrInvalidRequest + } + config.MaxLeaseTTL = tmpMax + } + + if config.MaxLeaseTTL != 0 && config.DefaultLeaseTTL > config.MaxLeaseTTL { + return logical.ErrorResponse( + "given default lease TTL greater than given max lease TTL"), + logical.ErrInvalidRequest + } + + if config.DefaultLeaseTTL > b.Core.maxLeaseTTL && config.MaxLeaseTTL == 0 { + return logical.ErrorResponse(fmt.Sprintf( + "given default lease TTL greater than system max lease TTL of %d", int(b.Core.maxLeaseTTL.Seconds()))), + logical.ErrInvalidRequest + } + + switch logicalType { + case "": + return logical.ErrorResponse( + "backend type must be specified as a string"), + logical.ErrInvalidRequest + + case "plugin": + // Only set plugin-name if mount is of type plugin, with apiConfig.PluginName + // option taking precedence. + switch { + case apiConfig.PluginName != "": + config.PluginName = apiConfig.PluginName + case pluginName != "": + config.PluginName = pluginName + default: + return logical.ErrorResponse( + "plugin_name must be provided for plugin backend"), + logical.ErrInvalidRequest + } + } + + switch logicalType { + case "kv": + case "kv-v1": + // Alias KV v1 + logicalType = "kv" + if options == nil { + options = map[string]string{} + } + options["version"] = "1" + + case "kv-v2": + // Alias KV v2 + logicalType = "kv" + if options == nil { + options = map[string]string{} + } + options["version"] = "2" + + default: + if options != nil && options["version"] != "" { + return logical.ErrorResponse(fmt.Sprintf( + "secrets engine %q does not allow setting a version", logicalType)), + logical.ErrInvalidRequest + } + } + + // Copy over the force no cache if set + if apiConfig.ForceNoCache { + config.ForceNoCache = true + } + + if err := checkListingVisibility(apiConfig.ListingVisibility); err != nil { + return logical.ErrorResponse(fmt.Sprintf("invalid listing_visibility %s", apiConfig.ListingVisibility)), nil + } + config.ListingVisibility = apiConfig.ListingVisibility + + if len(apiConfig.AuditNonHMACRequestKeys) > 0 { + config.AuditNonHMACRequestKeys = apiConfig.AuditNonHMACRequestKeys + } + if len(apiConfig.AuditNonHMACResponseKeys) > 0 { + config.AuditNonHMACResponseKeys = apiConfig.AuditNonHMACResponseKeys + } + if len(apiConfig.PassthroughRequestHeaders) > 0 { + config.PassthroughRequestHeaders = apiConfig.PassthroughRequestHeaders + } + + // Create the mount entry + me := &MountEntry{ + Table: mountTableType, + Path: path, + Type: logicalType, + Description: description, + Config: config, + Local: local, + SealWrap: sealWrap, + Options: options, + } + + // Attempt mount + if err := b.Core.mount(ctx, me); err != nil { + b.Backend.Logger().Error("mount failed", "path", me.Path, "error", err) + return handleError(err) + } + + return nil, nil +} + +// used to intercept an HTTPCodedError so it goes back to callee +func handleError( + err error) (*logical.Response, error) { + if strings.Contains(err.Error(), logical.ErrReadOnly.Error()) { + return logical.ErrorResponse(err.Error()), err + } + switch err.(type) { + case logical.HTTPCodedError: + return logical.ErrorResponse(err.Error()), err + default: + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } +} + +// Performs a similar function to handleError, but upon seeing a ReadOnlyError +// will actually strip it out to prevent forwarding +func handleErrorNoReadOnlyForward( + err error) (*logical.Response, error) { + if strings.Contains(err.Error(), logical.ErrReadOnly.Error()) { + return nil, fmt.Errorf("operation could not be completed as storage is read-only") + } + switch err.(type) { + case logical.HTTPCodedError: + return logical.ErrorResponse(err.Error()), err + default: + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } +} + +// handleUnmount is used to unmount a path +func (b *SystemBackend) handleUnmount(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + path = sanitizeMountPath(path) + + repState := b.Core.ReplicationState() + entry := b.Core.router.MatchingMountEntry(path) + if entry != nil && !entry.Local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot unmount a non-local mount on a replication secondary"), nil + } + + // We return success when the mount does not exists to not expose if the + // mount existed or not + match := b.Core.router.MatchingMount(path) + if match == "" || path != match { + return nil, nil + } + + // Attempt unmount + if err := b.Core.unmount(ctx, path); err != nil { + b.Backend.Logger().Error("unmount failed", "path", path, "error", err) + return handleError(err) + } + + return nil, nil +} + +// handleRemount is used to remount a path +func (b *SystemBackend) handleRemount(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + + // Get the paths + fromPath := data.Get("from").(string) + toPath := data.Get("to").(string) + if fromPath == "" || toPath == "" { + return logical.ErrorResponse( + "both 'from' and 'to' path must be specified as a string"), + logical.ErrInvalidRequest + } + + fromPath = sanitizeMountPath(fromPath) + toPath = sanitizeMountPath(toPath) + + entry := b.Core.router.MatchingMountEntry(fromPath) + if entry != nil && !entry.Local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot remount a non-local mount on a replication secondary"), nil + } + + // Attempt remount + if err := b.Core.remount(ctx, fromPath, toPath); err != nil { + b.Backend.Logger().Error("remount failed", "from_path", fromPath, "to_path", toPath, "error", err) + return handleError(err) + } + + return nil, nil +} + +// handleAuthTuneRead is used to get config settings on a auth path +func (b *SystemBackend) handleAuthTuneRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + if path == "" { + return logical.ErrorResponse( + "path must be specified as a string"), + logical.ErrInvalidRequest + } + return b.handleTuneReadCommon("auth/" + path) +} + +// handleMountTuneRead is used to get config settings on a backend +func (b *SystemBackend) handleMountTuneRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + if path == "" { + return logical.ErrorResponse( + "path must be specified as a string"), + logical.ErrInvalidRequest + } + + // This call will read both logical backend's configuration as well as auth methods'. + // Retaining this behavior for backward compatibility. If this behavior is not desired, + // an error can be returned if path has a prefix of "auth/". + return b.handleTuneReadCommon(path) +} + +// handleTuneReadCommon returns the config settings of a path +func (b *SystemBackend) handleTuneReadCommon(path string) (*logical.Response, error) { + path = sanitizeMountPath(path) + + sysView := b.Core.router.MatchingSystemView(path) + if sysView == nil { + b.Backend.Logger().Error("cannot fetch sysview", "path", path) + return handleError(fmt.Errorf("sys: cannot fetch sysview for path %q", path)) + } + + mountEntry := b.Core.router.MatchingMountEntry(path) + if mountEntry == nil { + b.Backend.Logger().Error("cannot fetch mount entry", "path", path) + return handleError(fmt.Errorf("sys: cannot fetch mount entry for path %q", path)) + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "default_lease_ttl": int(sysView.DefaultLeaseTTL().Seconds()), + "max_lease_ttl": int(sysView.MaxLeaseTTL().Seconds()), + "force_no_cache": mountEntry.Config.ForceNoCache, + }, + } + + if rawVal, ok := mountEntry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + resp.Data["audit_non_hmac_request_keys"] = rawVal.([]string) + } + + if rawVal, ok := mountEntry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + resp.Data["audit_non_hmac_response_keys"] = rawVal.([]string) + } + + if len(mountEntry.Config.ListingVisibility) > 0 { + resp.Data["listing_visibility"] = mountEntry.Config.ListingVisibility + } + + if rawVal, ok := mountEntry.synthesizedConfigCache.Load("passthrough_request_headers"); ok { + resp.Data["passthrough_request_headers"] = rawVal.([]string) + } + + if len(mountEntry.Options) > 0 { + resp.Data["options"] = mountEntry.Options + } + + return resp, nil +} + +// handleAuthTuneWrite is used to set config settings on an auth path +func (b *SystemBackend) handleAuthTuneWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + if path == "" { + return logical.ErrorResponse("path must be specified as a string"), + logical.ErrInvalidRequest + } + return b.handleTuneWriteCommon(ctx, "auth/"+path, data) +} + +// handleMountTuneWrite is used to set config settings on a backend +func (b *SystemBackend) handleMountTuneWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + if path == "" { + return logical.ErrorResponse("path must be specified as a string"), + logical.ErrInvalidRequest + } + // This call will write both logical backend's configuration as well as auth methods'. + // Retaining this behavior for backward compatibility. If this behavior is not desired, + // an error can be returned if path has a prefix of "auth/". + return b.handleTuneWriteCommon(ctx, path, data) +} + +// handleTuneWriteCommon is used to set config settings on a path +func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + + path = sanitizeMountPath(path) + + // Prevent protected paths from being changed + for _, p := range untunableMounts { + if strings.HasPrefix(path, p) { + b.Backend.Logger().Error("cannot tune this mount", "path", path) + return handleError(fmt.Errorf("cannot tune %q", path)) + } + } + + mountEntry := b.Core.router.MatchingMountEntry(path) + if mountEntry == nil { + b.Backend.Logger().Error("tune failed: no mount entry found", "path", path) + return handleError(fmt.Errorf("tune of path %q failed: no mount entry found", path)) + } + if mountEntry != nil && !mountEntry.Local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot tune a non-local mount on a replication secondary"), nil + } + + var lock *sync.RWMutex + switch { + case strings.HasPrefix(path, credentialRoutePrefix): + lock = &b.Core.authLock + default: + lock = &b.Core.mountsLock + } + + lock.Lock() + defer lock.Unlock() + + // Check again after grabbing the lock + mountEntry = b.Core.router.MatchingMountEntry(path) + if mountEntry == nil { + b.Backend.Logger().Error("tune failed: no mount entry found", "path", path) + return handleError(fmt.Errorf("tune of path %q failed: no mount entry found", path)) + } + if mountEntry != nil && !mountEntry.Local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot tune a non-local mount on a replication secondary"), nil + } + + // Timing configuration parameters + { + var newDefault, newMax time.Duration + defTTL := data.Get("default_lease_ttl").(string) + switch defTTL { + case "": + newDefault = mountEntry.Config.DefaultLeaseTTL + case "system": + newDefault = time.Duration(0) + default: + tmpDef, err := parseutil.ParseDurationSecond(defTTL) + if err != nil { + return handleError(err) + } + newDefault = tmpDef + } + + maxTTL := data.Get("max_lease_ttl").(string) + switch maxTTL { + case "": + newMax = mountEntry.Config.MaxLeaseTTL + case "system": + newMax = time.Duration(0) + default: + tmpMax, err := parseutil.ParseDurationSecond(maxTTL) + if err != nil { + return handleError(err) + } + newMax = tmpMax + } + + if newDefault != mountEntry.Config.DefaultLeaseTTL || + newMax != mountEntry.Config.MaxLeaseTTL { + + if err := b.tuneMountTTLs(ctx, path, mountEntry, newDefault, newMax); err != nil { + b.Backend.Logger().Error("tuning failed", "path", path, "error", err) + return handleError(err) + } + } + } + + description := data.Get("description").(string) + if description != "" { + oldDesc := mountEntry.Description + mountEntry.Description = description + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Description = oldDesc + return handleError(err) + } + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of description successful", "path", path) + } + } + + if rawVal, ok := data.GetOk("audit_non_hmac_request_keys"); ok { + auditNonHMACRequestKeys := rawVal.([]string) + + oldVal := mountEntry.Config.AuditNonHMACRequestKeys + mountEntry.Config.AuditNonHMACRequestKeys = auditNonHMACRequestKeys + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Config.AuditNonHMACRequestKeys = oldVal + return handleError(err) + } + + mountEntry.SyncCache() + + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of audit_non_hmac_request_keys successful", "path", path) + } + } + + if rawVal, ok := data.GetOk("audit_non_hmac_response_keys"); ok { + auditNonHMACResponseKeys := rawVal.([]string) + + oldVal := mountEntry.Config.AuditNonHMACResponseKeys + mountEntry.Config.AuditNonHMACResponseKeys = auditNonHMACResponseKeys + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Config.AuditNonHMACResponseKeys = oldVal + return handleError(err) + } + + mountEntry.SyncCache() + + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of audit_non_hmac_response_keys successful", "path", path) + } + } + + if rawVal, ok := data.GetOk("listing_visibility"); ok { + lvString := rawVal.(string) + listingVisibility := ListingVisibilityType(lvString) + + if err := checkListingVisibility(listingVisibility); err != nil { + return logical.ErrorResponse(fmt.Sprintf("invalid listing_visibility %s", listingVisibility)), nil + } + + oldVal := mountEntry.Config.ListingVisibility + mountEntry.Config.ListingVisibility = listingVisibility + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Config.ListingVisibility = oldVal + return handleError(err) + } + + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of listing_visibility successful", "path", path) + } + } + + if rawVal, ok := data.GetOk("passthrough_request_headers"); ok { + headers := rawVal.([]string) + + oldVal := mountEntry.Config.PassthroughRequestHeaders + mountEntry.Config.PassthroughRequestHeaders = headers + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Config.PassthroughRequestHeaders = oldVal + return handleError(err) + } + + mountEntry.SyncCache() + + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of passthrough_request_headers successful", "path", path) + } + } + + var err error + var resp *logical.Response + var options map[string]string + if optionsRaw, ok := data.GetOk("options"); ok { + options = optionsRaw.(map[string]string) + } + if len(options) > 0 { + b.Core.logger.Info("mount tuning of options", "path", path, "options", options) + + var changed bool + var numBuiltIn int + if v, ok := options["version"]; ok { + changed = true + numBuiltIn++ + // Special case to make sure we can not disable versioning once it's + // enabeled. If the vkv backend suports downgrading this can be removed. + meVersion, err := parseutil.ParseInt(mountEntry.Options["version"]) + if err != nil { + return nil, errwrap.Wrapf("unable to parse mount entry: {{err}}", err) + } + optVersion, err := parseutil.ParseInt(v) + if err != nil { + return handleError(errwrap.Wrapf("unable to parse options: {{err}}", err)) + } + if meVersion > optVersion { + return logical.ErrorResponse(fmt.Sprintf("cannot downgrade mount from version %d", meVersion)), logical.ErrInvalidRequest + } + if meVersion < optVersion { + resp = &logical.Response{} + resp.AddWarning(fmt.Sprintf("Upgrading mount from version %d to version %d. This mount will be unavailable for a brief period and will resume service shortly.", meVersion, optVersion)) + } + } + if options != nil { + // For anything we don't recognize and provide special handling, + // always write + if len(options) > numBuiltIn { + changed = true + } + } + + if changed { + oldVal := mountEntry.Options + mountEntry.Options = options + // Update the mount table + switch { + case strings.HasPrefix(path, "auth/"): + err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local) + } + if err != nil { + mountEntry.Options = oldVal + return handleError(err) + } + + // Reload the backend to kick off the upgrade process. + b.Core.reloadBackendCommon(ctx, mountEntry, strings.HasPrefix(path, credentialRoutePrefix)) + } + } + + return resp, nil +} + +// handleLease is use to view the metadata for a given LeaseID +func (b *SystemBackend) handleLeaseLookup(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + leaseID := data.Get("lease_id").(string) + if leaseID == "" { + return logical.ErrorResponse("lease_id must be specified"), + logical.ErrInvalidRequest + } + + leaseTimes, err := b.Core.expiration.FetchLeaseTimes(leaseID) + if err != nil { + b.Backend.Logger().Error("error retrieving lease", "lease_id", leaseID, "error", err) + return handleError(err) + } + if leaseTimes == nil { + return logical.ErrorResponse("invalid lease"), logical.ErrInvalidRequest + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "id": leaseID, + "issue_time": leaseTimes.IssueTime, + "expire_time": nil, + "last_renewal": nil, + "ttl": int64(0), + }, + } + renewable, _ := leaseTimes.renewable() + resp.Data["renewable"] = renewable + + if !leaseTimes.LastRenewalTime.IsZero() { + resp.Data["last_renewal"] = leaseTimes.LastRenewalTime + } + if !leaseTimes.ExpireTime.IsZero() { + resp.Data["expire_time"] = leaseTimes.ExpireTime + resp.Data["ttl"] = leaseTimes.ttl() + } + return resp, nil +} + +func (b *SystemBackend) handleLeaseLookupList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + prefix := data.Get("prefix").(string) + if prefix != "" && !strings.HasSuffix(prefix, "/") { + prefix = prefix + "/" + } + + keys, err := b.Core.expiration.idView.List(ctx, prefix) + if err != nil { + b.Backend.Logger().Error("error listing leases", "prefix", prefix, "error", err) + return handleErrorNoReadOnlyForward(err) + } + return logical.ListResponse(keys), nil +} + +// handleRenew is used to renew a lease with a given LeaseID +func (b *SystemBackend) handleRenew(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Get all the options + leaseID := data.Get("lease_id").(string) + if leaseID == "" { + leaseID = data.Get("url_lease_id").(string) + } + if leaseID == "" { + return logical.ErrorResponse("lease_id must be specified"), + logical.ErrInvalidRequest + } + incrementRaw := data.Get("increment").(int) + + // Convert the increment + increment := time.Duration(incrementRaw) * time.Second + + // Invoke the expiration manager directly + resp, err := b.Core.expiration.Renew(leaseID, increment) + if err != nil { + b.Backend.Logger().Error("lease renewal failed", "lease_id", leaseID, "error", err) + return handleErrorNoReadOnlyForward(err) + } + return resp, err +} + +// handleRevoke is used to revoke a given LeaseID +func (b *SystemBackend) handleRevoke(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Get all the options + leaseID := data.Get("lease_id").(string) + if leaseID == "" { + leaseID = data.Get("url_lease_id").(string) + } + if leaseID == "" { + return logical.ErrorResponse("lease_id must be specified"), + logical.ErrInvalidRequest + } + + // Invoke the expiration manager directly + if err := b.Core.expiration.Revoke(leaseID); err != nil { + b.Backend.Logger().Error("lease revocation failed", "lease_id", leaseID, "error", err) + return handleErrorNoReadOnlyForward(err) + } + return nil, nil +} + +// handleRevokePrefix is used to revoke a prefix with many LeaseIDs +func (b *SystemBackend) handleRevokePrefix(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRevokePrefixCommon(req, data, false) +} + +// handleRevokeForce is used to revoke a prefix with many LeaseIDs, ignoring errors +func (b *SystemBackend) handleRevokeForce(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.handleRevokePrefixCommon(req, data, true) +} + +// handleRevokePrefixCommon is used to revoke a prefix with many LeaseIDs +func (b *SystemBackend) handleRevokePrefixCommon( + req *logical.Request, data *framework.FieldData, force bool) (*logical.Response, error) { + // Get all the options + prefix := data.Get("prefix").(string) + + // Invoke the expiration manager directly + var err error + if force { + err = b.Core.expiration.RevokeForce(prefix) + } else { + err = b.Core.expiration.RevokePrefix(prefix) + } + if err != nil { + b.Backend.Logger().Error("revoke prefix failed", "prefix", prefix, "error", err) + return handleErrorNoReadOnlyForward(err) + } + return nil, nil +} + +// handleAuthTable handles the "auth" endpoint to provide the auth table +func (b *SystemBackend) handleAuthTable(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + b.Core.authLock.RLock() + defer b.Core.authLock.RUnlock() + + resp := &logical.Response{ + Data: make(map[string]interface{}), + } + for _, entry := range b.Core.auth.Entries { + info := map[string]interface{}{ + "type": entry.Type, + "description": entry.Description, + "accessor": entry.Accessor, + "local": entry.Local, + "seal_wrap": entry.SealWrap, + "options": entry.Options, + } + entryConfig := map[string]interface{}{ + "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), + "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), + "plugin_name": entry.Config.PluginName, + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + entryConfig["audit_non_hmac_request_keys"] = rawVal.([]string) + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + entryConfig["audit_non_hmac_response_keys"] = rawVal.([]string) + } + // Even though empty value is valid for ListingVisibility, we can ignore + // this case during mount since there's nothing to unset/hide. + if len(entry.Config.ListingVisibility) > 0 { + entryConfig["listing_visibility"] = entry.Config.ListingVisibility + } + if rawVal, ok := entry.synthesizedConfigCache.Load("passthrough_request_headers"); ok { + entryConfig["passthrough_request_headers"] = rawVal.([]string) + } + + info["config"] = entryConfig + resp.Data[entry.Path] = info + } + return resp, nil +} + +// handleEnableAuth is used to enable a new credential backend +func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + local := data.Get("local").(bool) + if !local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot add a non-local mount to a replication secondary"), nil + } + + // Get all the options + path := data.Get("path").(string) + path = sanitizeMountPath(path) + logicalType := data.Get("type").(string) + description := data.Get("description").(string) + pluginName := data.Get("plugin_name").(string) + sealWrap := data.Get("seal_wrap").(bool) + options := data.Get("options").(map[string]string) + + var config MountConfig + var apiConfig APIMountConfig + + configMap := data.Get("config").(map[string]interface{}) + if configMap != nil && len(configMap) != 0 { + err := mapstructure.Decode(configMap, &apiConfig) + if err != nil { + return logical.ErrorResponse( + "unable to convert given auth config information"), + logical.ErrInvalidRequest + } + } + + switch apiConfig.DefaultLeaseTTL { + case "": + case "system": + default: + tmpDef, err := parseutil.ParseDurationSecond(apiConfig.DefaultLeaseTTL) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf( + "unable to parse default TTL of %s: %s", apiConfig.DefaultLeaseTTL, err)), + logical.ErrInvalidRequest + } + config.DefaultLeaseTTL = tmpDef + } + + switch apiConfig.MaxLeaseTTL { + case "": + case "system": + default: + tmpMax, err := parseutil.ParseDurationSecond(apiConfig.MaxLeaseTTL) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf( + "unable to parse max TTL of %s: %s", apiConfig.MaxLeaseTTL, err)), + logical.ErrInvalidRequest + } + config.MaxLeaseTTL = tmpMax + } + + if config.MaxLeaseTTL != 0 && config.DefaultLeaseTTL > config.MaxLeaseTTL { + return logical.ErrorResponse( + "given default lease TTL greater than given max lease TTL"), + logical.ErrInvalidRequest + } + + if config.DefaultLeaseTTL > b.Core.maxLeaseTTL && config.MaxLeaseTTL == 0 { + return logical.ErrorResponse(fmt.Sprintf( + "given default lease TTL greater than system max lease TTL of %d", int(b.Core.maxLeaseTTL.Seconds()))), + logical.ErrInvalidRequest + } + + switch logicalType { + case "": + return logical.ErrorResponse( + "backend type must be specified as a string"), + logical.ErrInvalidRequest + + case "plugin": + // Only set plugin name if mount is of type plugin, with apiConfig.PluginName + // option taking precedence. + switch { + case apiConfig.PluginName != "": + config.PluginName = apiConfig.PluginName + case pluginName != "": + config.PluginName = pluginName + default: + return logical.ErrorResponse( + "plugin_name must be provided for plugin backend"), + logical.ErrInvalidRequest + } + } + + if options != nil && options["version"] != "" { + return logical.ErrorResponse(fmt.Sprintf( + "auth method %q does not allow setting a version", logicalType)), + logical.ErrInvalidRequest + } + + if err := checkListingVisibility(apiConfig.ListingVisibility); err != nil { + return logical.ErrorResponse(fmt.Sprintf("invalid listing_visibility %s", apiConfig.ListingVisibility)), nil + } + config.ListingVisibility = apiConfig.ListingVisibility + + if len(apiConfig.AuditNonHMACRequestKeys) > 0 { + config.AuditNonHMACRequestKeys = apiConfig.AuditNonHMACRequestKeys + } + if len(apiConfig.AuditNonHMACResponseKeys) > 0 { + config.AuditNonHMACResponseKeys = apiConfig.AuditNonHMACResponseKeys + } + if len(apiConfig.PassthroughRequestHeaders) > 0 { + config.PassthroughRequestHeaders = apiConfig.PassthroughRequestHeaders + } + + // Create the mount entry + me := &MountEntry{ + Table: credentialTableType, + Path: path, + Type: logicalType, + Description: description, + Config: config, + Local: local, + SealWrap: sealWrap, + Options: options, + } + + // Attempt enabling + if err := b.Core.enableCredential(ctx, me); err != nil { + b.Backend.Logger().Error("enable auth mount failed", "path", me.Path, "error", err) + return handleError(err) + } + return nil, nil +} + +// handleDisableAuth is used to disable a credential backend +func (b *SystemBackend) handleDisableAuth(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + path = sanitizeMountPath(path) + + fullPath := credentialRoutePrefix + path + + repState := b.Core.ReplicationState() + entry := b.Core.router.MatchingMountEntry(fullPath) + if entry != nil && !entry.Local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot unmount a non-local mount on a replication secondary"), nil + } + + // We return success when the mount does not exists to not expose if the + // mount existed or not + match := b.Core.router.MatchingMount(fullPath) + if match == "" || fullPath != match { + return nil, nil + } + + // Attempt disable + if err := b.Core.disableCredential(ctx, path); err != nil { + b.Backend.Logger().Error("disable auth mount failed", "path", path, "error", err) + return handleError(err) + } + return nil, nil +} + +// handlePoliciesList handles /sys/policy/ and /sys/policies/ endpoints to provide the enabled policies +func (b *SystemBackend) handlePoliciesList(policyType PolicyType) framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + policies, err := b.Core.policyStore.ListPolicies(ctx, policyType) + if err != nil { + return nil, err + } + + switch policyType { + case PolicyTypeACL: + // Add the special "root" policy if not egp + policies = append(policies, "root") + resp := logical.ListResponse(policies) + + // If the request is from sys/policy/ we handle backwards compatibility + if strings.HasPrefix(req.Path, "policy") { + resp.Data["policies"] = resp.Data["keys"] + } + + return resp, nil + } + + return logical.ErrorResponse("unknown policy type"), nil + } +} + +// handlePoliciesRead handles the "/sys/policy/" and "/sys/policies//" endpoints to read a policy +func (b *SystemBackend) handlePoliciesRead(policyType PolicyType) framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + name := data.Get("name").(string) + + policy, err := b.Core.policyStore.GetPolicy(ctx, name, policyType) + if err != nil { + return handleError(err) + } + + if policy == nil { + return nil, nil + } + + // If the request is from sys/policy/ we handle backwards compatibility + var respDataPolicyName string + if policyType == PolicyTypeACL && strings.HasPrefix(req.Path, "policy") { + respDataPolicyName = "rules" + } else { + respDataPolicyName = "policy" + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "name": policy.Name, + respDataPolicyName: policy.Raw, + }, + } + + return resp, nil + } +} + +// handlePoliciesSet handles the "/sys/policy/" and "/sys/policies//" endpoints to set a policy +func (b *SystemBackend) handlePoliciesSet(policyType PolicyType) framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var resp *logical.Response + + policy := &Policy{ + Name: strings.ToLower(data.Get("name").(string)), + Type: policyType, + } + if policy.Name == "" { + return logical.ErrorResponse("policy name must be provided in the URL"), nil + } + + policy.Raw = data.Get("policy").(string) + if policy.Raw == "" && policyType == PolicyTypeACL && strings.HasPrefix(req.Path, "policy") { + policy.Raw = data.Get("rules").(string) + if resp == nil { + resp = &logical.Response{} + } + resp.AddWarning("'rules' is deprecated, please use 'policy' instead") + } + if policy.Raw == "" { + return logical.ErrorResponse("'policy' parameter not supplied or empty"), nil + } + + if polBytes, err := base64.StdEncoding.DecodeString(policy.Raw); err == nil { + policy.Raw = string(polBytes) + } + + switch policyType { + case PolicyTypeACL: + p, err := ParseACLPolicy(policy.Raw) + if err != nil { + return handleError(err) + } + policy.Paths = p.Paths + + default: + return logical.ErrorResponse("unknown policy type"), nil + } + + // Update the policy + if err := b.Core.policyStore.SetPolicy(ctx, policy); err != nil { + return handleError(err) + } + return resp, nil + } +} + +func (b *SystemBackend) handlePoliciesDelete(policyType PolicyType) framework.OperationFunc { + return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + name := data.Get("name").(string) + + if err := b.Core.policyStore.DeletePolicy(ctx, name, policyType); err != nil { + return handleError(err) + } + return nil, nil + } +} + +// handleAuditTable handles the "audit" endpoint to provide the audit table +func (b *SystemBackend) handleAuditTable(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + b.Core.auditLock.RLock() + defer b.Core.auditLock.RUnlock() + + resp := &logical.Response{ + Data: make(map[string]interface{}), + } + for _, entry := range b.Core.audit.Entries { + info := map[string]interface{}{ + "path": entry.Path, + "type": entry.Type, + "description": entry.Description, + "options": entry.Options, + "local": entry.Local, + } + resp.Data[entry.Path] = info + } + return resp, nil +} + +// handleAuditHash is used to fetch the hash of the given input data with the +// specified audit backend's salt +func (b *SystemBackend) handleAuditHash(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + input := data.Get("input").(string) + if input == "" { + return logical.ErrorResponse("the \"input\" parameter is empty"), nil + } + + path = sanitizeMountPath(path) + + hash, err := b.Core.auditBroker.GetHash(ctx, path, input) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "hash": hash, + }, + }, nil +} + +// handleEnableAudit is used to enable a new audit backend +func (b *SystemBackend) handleEnableAudit(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + + local := data.Get("local").(bool) + if !local && repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot add a non-local mount to a replication secondary"), nil + } + + // Get all the options + path := data.Get("path").(string) + backendType := data.Get("type").(string) + description := data.Get("description").(string) + options := data.Get("options").(map[string]string) + + // Create the mount entry + me := &MountEntry{ + Table: auditTableType, + Path: path, + Type: backendType, + Description: description, + Options: options, + Local: local, + } + + // Attempt enabling + if err := b.Core.enableAudit(ctx, me); err != nil { + b.Backend.Logger().Error("enable audit mount failed", "path", me.Path, "error", err) + return handleError(err) + } + return nil, nil +} + +// handleDisableAudit is used to disable an audit backend +func (b *SystemBackend) handleDisableAudit(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + + // Attempt disable + if existed, err := b.Core.disableAudit(ctx, path); existed && err != nil { + b.Backend.Logger().Error("disable audit mount failed", "path", path, "error", err) + return handleError(err) + } + return nil, nil +} + +func (b *SystemBackend) handleConfigUIHeadersRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + header := data.Get("header").(string) + + value, err := b.Core.uiConfig.GetHeader(ctx, header) + if err != nil { + return nil, err + } + if value == "" { + return nil, nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "value": value, + }, + }, nil +} + +func (b *SystemBackend) handleConfigUIHeadersList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + headers, err := b.Core.uiConfig.HeaderKeys(ctx) + if err != nil { + return nil, err + } + if len(headers) == 0 { + return nil, nil + } + + return logical.ListResponse(headers), nil +} + +func (b *SystemBackend) handleConfigUIHeadersUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + header := data.Get("header").(string) + values := data.Get("values").([]string) + if header == "" || len(values) == 0 { + return logical.ErrorResponse("header and values must be specified"), logical.ErrInvalidRequest + } + + lowerHeader := strings.ToLower(header) + if strings.HasPrefix(lowerHeader, "x-vault-") { + return logical.ErrorResponse("X-Vault headers cannot be set"), logical.ErrInvalidRequest + } + + // Translate the list of values to the valid header string + value := http.Header{} + for _, v := range values { + value.Add(header, v) + } + err := b.Core.uiConfig.SetHeader(ctx, header, value.Get(header)) + if err != nil { + return nil, err + } + + // Warn when overriding the CSP + resp := &logical.Response{} + if lowerHeader == "content-security-policy" { + resp.AddWarning("overriding default Content-Security-Policy which is secure by default, proceed with caution") + } + + return resp, nil +} + +func (b *SystemBackend) handleConfigUIHeadersDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + header := data.Get("header").(string) + err := b.Core.uiConfig.DeleteHeader(ctx, header) + if err != nil { + return nil, err + } + return nil, nil +} + +// handleRawRead is used to read directly from the barrier +func (b *SystemBackend) handleRawRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + + // Prevent access of protected paths + for _, p := range protectedPaths { + if strings.HasPrefix(path, p) { + err := fmt.Sprintf("cannot read '%s'", path) + return logical.ErrorResponse(err), logical.ErrInvalidRequest + } + } + + entry, err := b.Core.barrier.Get(ctx, path) + if err != nil { + return handleErrorNoReadOnlyForward(err) + } + if entry == nil { + return nil, nil + } + + // Run this through the decompression helper to see if it's been compressed. + // If the input contained the compression canary, `outputBytes` will hold + // the decompressed data. If the input was not compressed, then `outputBytes` + // will be nil. + outputBytes, _, err := compressutil.Decompress(entry.Value) + if err != nil { + return handleErrorNoReadOnlyForward(err) + } + + // `outputBytes` is nil if the input is uncompressed. In that case set it to the original input. + if outputBytes == nil { + outputBytes = entry.Value + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "value": string(outputBytes), + }, + } + return resp, nil +} + +// handleRawWrite is used to write directly to the barrier +func (b *SystemBackend) handleRawWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + + // Prevent access of protected paths + for _, p := range protectedPaths { + if strings.HasPrefix(path, p) { + err := fmt.Sprintf("cannot write '%s'", path) + return logical.ErrorResponse(err), logical.ErrInvalidRequest + } + } + + value := data.Get("value").(string) + entry := &Entry{ + Key: path, + Value: []byte(value), + } + if err := b.Core.barrier.Put(ctx, entry); err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + return nil, nil +} + +// handleRawDelete is used to delete directly from the barrier +func (b *SystemBackend) handleRawDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + + // Prevent access of protected paths + for _, p := range protectedPaths { + if strings.HasPrefix(path, p) { + err := fmt.Sprintf("cannot delete '%s'", path) + return logical.ErrorResponse(err), logical.ErrInvalidRequest + } + } + + if err := b.Core.barrier.Delete(ctx, path); err != nil { + return handleErrorNoReadOnlyForward(err) + } + return nil, nil +} + +// handleRawList is used to list directly from the barrier +func (b *SystemBackend) handleRawList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + path := data.Get("path").(string) + if path != "" && !strings.HasSuffix(path, "/") { + path = path + "/" + } + + // Prevent access of protected paths + for _, p := range protectedPaths { + if strings.HasPrefix(path, p) { + err := fmt.Sprintf("cannot list '%s'", path) + return logical.ErrorResponse(err), logical.ErrInvalidRequest + } + } + + keys, err := b.Core.barrier.List(ctx, path) + if err != nil { + return handleErrorNoReadOnlyForward(err) + } + return logical.ListResponse(keys), nil +} + +// handleKeyStatus returns status information about the backend key +func (b *SystemBackend) handleKeyStatus(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // Get the key info + info, err := b.Core.barrier.ActiveKeyInfo() + if err != nil { + return nil, err + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "term": info.Term, + "install_time": info.InstallTime.Format(time.RFC3339Nano), + }, + } + return resp, nil +} + +// handleRotate is used to trigger a key rotation +func (b *SystemBackend) handleRotate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + repState := b.Core.ReplicationState() + if repState.HasState(consts.ReplicationPerformanceSecondary) { + return logical.ErrorResponse("cannot rotate on a replication secondary"), nil + } + + // Rotate to the new term + newTerm, err := b.Core.barrier.Rotate(ctx) + if err != nil { + b.Backend.Logger().Error("failed to create new encryption key", "error", err) + return handleError(err) + } + b.Backend.Logger().Info("installed new encryption key") + + // In HA mode, we need to an upgrade path for the standby instances + if b.Core.ha != nil { + // Create the upgrade path to the new term + if err := b.Core.barrier.CreateUpgrade(ctx, newTerm); err != nil { + b.Backend.Logger().Error("failed to create new upgrade", "term", newTerm, "error", err) + } + + // Schedule the destroy of the upgrade path + time.AfterFunc(keyRotateGracePeriod, func() { + if err := b.Core.barrier.DestroyUpgrade(ctx, newTerm); err != nil { + b.Backend.Logger().Error("failed to destroy upgrade", "term", newTerm, "error", err) + } + }) + } + + // Write to the canary path, which will force a synchronous truing during + // replication + if err := b.Core.barrier.Put(ctx, &Entry{ + Key: coreKeyringCanaryPath, + Value: []byte(fmt.Sprintf("new-rotation-term-%d", newTerm)), + }); err != nil { + b.Core.logger.Error("error saving keyring canary", "error", err) + return nil, errwrap.Wrapf("failed to save keyring canary: {{err}}", err) + } + + return nil, nil +} + +func (b *SystemBackend) handleWrappingPubkey(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + x, _ := b.Core.wrappingJWTKey.X.MarshalText() + y, _ := b.Core.wrappingJWTKey.Y.MarshalText() + return &logical.Response{ + Data: map[string]interface{}{ + "jwt_x": string(x), + "jwt_y": string(y), + "jwt_curve": corePrivateKeyTypeP521, + }, + }, nil +} + +func (b *SystemBackend) handleWrappingWrap(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + if req.WrapInfo == nil || req.WrapInfo.TTL == 0 { + return logical.ErrorResponse("endpoint requires response wrapping to be used"), logical.ErrInvalidRequest + } + + // N.B.: Do *NOT* allow JWT wrapping tokens to be created through this + // endpoint. JWTs are signed so if we don't allow users to create wrapping + // tokens using them we can ensure that an operator can't spoof a legit JWT + // wrapped token, which makes certain init/rekey/generate-root cases have + // better properties. + req.WrapInfo.Format = "uuid" + + return &logical.Response{ + Data: data.Raw, + }, nil +} + +func (b *SystemBackend) handleWrappingUnwrap(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // If a third party is unwrapping (rather than the calling token being the + // wrapping token) we detect this so that we can revoke the original + // wrapping token after reading it + var thirdParty bool + + token := data.Get("token").(string) + if token != "" { + thirdParty = true + } else { + token = req.ClientToken + } + + // Get the policies so we can determine if this is a normal response + // wrapping request or a control group token. + // + // We use lookupTainted here because the token might have already been used + // by handleRequest(), this happens when it's a normal response wrapping + // request and the token was provided "first party". We want to inspect the + // token policies but will not use this token entry for anything else. + te, err := b.Core.tokenStore.lookupTainted(ctx, token) + if err != nil { + return nil, err + } + if te == nil { + return nil, errors.New("could not find token") + } + if len(te.Policies) != 1 { + return nil, errors.New("token is not a valid unwrap token") + } + + var response string + switch te.Policies[0] { + case responseWrappingPolicyName: + response, err = b.responseWrappingUnwrap(ctx, token, thirdParty) + } + if err != nil { + var respErr *logical.Response + if len(response) > 0 { + respErr = logical.ErrorResponse(response) + } + + return respErr, err + } + + resp := &logical.Response{ + Data: map[string]interface{}{}, + } + + // Most of the time we want to just send over the marshalled HTTP bytes. + // However there is a sad separate case: if the original response was using + // bare values we need to use those or else what comes back is garbled. + httpResp := &logical.HTTPResponse{} + err = jsonutil.DecodeJSON([]byte(response), httpResp) + if err != nil { + return nil, errwrap.Wrapf("error decoding wrapped response: {{err}}", err) + } + if httpResp.Data != nil && + (httpResp.Data[logical.HTTPStatusCode] != nil || + httpResp.Data[logical.HTTPRawBody] != nil || + httpResp.Data[logical.HTTPContentType] != nil) { + if httpResp.Data[logical.HTTPStatusCode] != nil { + resp.Data[logical.HTTPStatusCode] = httpResp.Data[logical.HTTPStatusCode] + } + if httpResp.Data[logical.HTTPContentType] != nil { + resp.Data[logical.HTTPContentType] = httpResp.Data[logical.HTTPContentType] + } + + rawBody := httpResp.Data[logical.HTTPRawBody] + if rawBody != nil { + // Decode here so that we can audit properly + switch rawBody.(type) { + case string: + // Best effort decoding; if this works, the original value was + // probably a []byte instead of a string, but was marshaled + // when the value was saved, so this restores it as it was + decBytes, err := base64.StdEncoding.DecodeString(rawBody.(string)) + if err == nil { + // We end up with []byte, will not be HMAC'd + resp.Data[logical.HTTPRawBody] = decBytes + } else { + // We end up with string, will be HMAC'd + resp.Data[logical.HTTPRawBody] = rawBody + } + default: + b.Core.Logger().Error("unexpected type of raw body when decoding wrapped token", "type", fmt.Sprintf("%T", rawBody)) + } + + resp.Data[logical.HTTPRawBodyAlreadyJSONDecoded] = true + } + + return resp, nil + } + + if len(response) == 0 { + resp.Data[logical.HTTPStatusCode] = 204 + } else { + resp.Data[logical.HTTPStatusCode] = 200 + resp.Data[logical.HTTPRawBody] = []byte(response) + resp.Data[logical.HTTPContentType] = "application/json" + } + + return resp, nil +} + +// responseWrappingUnwrap will read the stored response in the cubbyhole and +// return the raw HTTP response. +func (b *SystemBackend) responseWrappingUnwrap(ctx context.Context, token string, thirdParty bool) (string, error) { + if thirdParty { + // Use the token to decrement the use count to avoid a second operation on the token. + _, err := b.Core.tokenStore.UseTokenByID(ctx, token) + if err != nil { + return "", errwrap.Wrapf("error decrementing wrapping token's use-count: {{err}}", err) + } + + defer b.Core.tokenStore.revokeOrphan(ctx, token) + } + + cubbyReq := &logical.Request{ + Operation: logical.ReadOperation, + Path: "cubbyhole/response", + ClientToken: token, + } + cubbyResp, err := b.Core.router.Route(ctx, cubbyReq) + if err != nil { + return "", errwrap.Wrapf("error looking up wrapping information: {{err}}", err) + } + if cubbyResp == nil { + return "no information found; wrapping token may be from a previous Vault version", ErrInternalError + } + if cubbyResp != nil && cubbyResp.IsError() { + return cubbyResp.Error().Error(), nil + } + if cubbyResp.Data == nil { + return "wrapping information was nil; wrapping token may be from a previous Vault version", ErrInternalError + } + + responseRaw := cubbyResp.Data["response"] + if responseRaw == nil { + return "", fmt.Errorf("no response found inside the cubbyhole") + } + response, ok := responseRaw.(string) + if !ok { + return "", fmt.Errorf("could not decode response inside the cubbyhole") + } + + return response, nil +} + +func (b *SystemBackend) handleWrappingLookup(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // This ordering of lookups has been validated already in the wrapping + // validation func, we're just doing this for a safety check + token := data.Get("token").(string) + if token == "" { + token = req.ClientToken + if token == "" { + return logical.ErrorResponse("missing \"token\" value in input"), logical.ErrInvalidRequest + } + } + + cubbyReq := &logical.Request{ + Operation: logical.ReadOperation, + Path: "cubbyhole/wrapinfo", + ClientToken: token, + } + cubbyResp, err := b.Core.router.Route(ctx, cubbyReq) + if err != nil { + return nil, errwrap.Wrapf("error looking up wrapping information: {{err}}", err) + } + if cubbyResp == nil { + return logical.ErrorResponse("no information found; wrapping token may be from a previous Vault version"), nil + } + if cubbyResp != nil && cubbyResp.IsError() { + return cubbyResp, nil + } + if cubbyResp.Data == nil { + return logical.ErrorResponse("wrapping information was nil; wrapping token may be from a previous Vault version"), nil + } + + creationTTLRaw := cubbyResp.Data["creation_ttl"] + creationTime := cubbyResp.Data["creation_time"] + creationPath := cubbyResp.Data["creation_path"] + + resp := &logical.Response{ + Data: map[string]interface{}{}, + } + if creationTTLRaw != nil { + creationTTL, err := creationTTLRaw.(json.Number).Int64() + if err != nil { + return nil, errwrap.Wrapf("error reading creation_ttl value from wrapping information: {{err}}", err) + } + resp.Data["creation_ttl"] = time.Duration(creationTTL).Seconds() + } + if creationTime != nil { + // This was JSON marshaled so it's already a string in RFC3339 format + resp.Data["creation_time"] = cubbyResp.Data["creation_time"] + } + if creationPath != nil { + resp.Data["creation_path"] = cubbyResp.Data["creation_path"] + } + + return resp, nil +} + +func (b *SystemBackend) handleWrappingRewrap(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + // If a third party is rewrapping (rather than the calling token being the + // wrapping token) we detect this so that we can revoke the original + // wrapping token after reading it. Right now wrapped tokens can't unwrap + // themselves, but in case we change it, this will be ready to do the right + // thing. + var thirdParty bool + + token := data.Get("token").(string) + if token != "" { + thirdParty = true + } else { + token = req.ClientToken + } + + if thirdParty { + // Use the token to decrement the use count to avoid a second operation on the token. + _, err := b.Core.tokenStore.UseTokenByID(ctx, token) + if err != nil { + return nil, errwrap.Wrapf("error decrementing wrapping token's use-count: {{err}}", err) + } + defer b.Core.tokenStore.revokeOrphan(ctx, token) + } + + // Fetch the original TTL + cubbyReq := &logical.Request{ + Operation: logical.ReadOperation, + Path: "cubbyhole/wrapinfo", + ClientToken: token, + } + cubbyResp, err := b.Core.router.Route(ctx, cubbyReq) + if err != nil { + return nil, errwrap.Wrapf("error looking up wrapping information: {{err}}", err) + } + if cubbyResp == nil { + return logical.ErrorResponse("no information found; wrapping token may be from a previous Vault version"), nil + } + if cubbyResp != nil && cubbyResp.IsError() { + return cubbyResp, nil + } + if cubbyResp.Data == nil { + return logical.ErrorResponse("wrapping information was nil; wrapping token may be from a previous Vault version"), nil + } + + // Set the creation TTL on the request + creationTTLRaw := cubbyResp.Data["creation_ttl"] + if creationTTLRaw == nil { + return nil, fmt.Errorf("creation_ttl value in wrapping information was nil") + } + creationTTL, err := cubbyResp.Data["creation_ttl"].(json.Number).Int64() + if err != nil { + return nil, errwrap.Wrapf("error reading creation_ttl value from wrapping information: {{err}}", err) + } + + // Get creation_path to return as the response later + creationPathRaw := cubbyResp.Data["creation_path"] + if creationPathRaw == nil { + return nil, fmt.Errorf("creation_path value in wrapping information was nil") + } + creationPath := creationPathRaw.(string) + + // Fetch the original response and return it as the data for the new response + cubbyReq = &logical.Request{ + Operation: logical.ReadOperation, + Path: "cubbyhole/response", + ClientToken: token, + } + cubbyResp, err = b.Core.router.Route(ctx, cubbyReq) + if err != nil { + return nil, errwrap.Wrapf("error looking up response: {{err}}", err) + } + if cubbyResp == nil { + return logical.ErrorResponse("no information found; wrapping token may be from a previous Vault version"), nil + } + if cubbyResp != nil && cubbyResp.IsError() { + return cubbyResp, nil + } + if cubbyResp.Data == nil { + return logical.ErrorResponse("wrapping information was nil; wrapping token may be from a previous Vault version"), nil + } + + response := cubbyResp.Data["response"] + if response == nil { + return nil, fmt.Errorf("no response found inside the cubbyhole") + } + + // Return response in "response"; wrapping code will detect the rewrap and + // slot in instead of nesting + return &logical.Response{ + Data: map[string]interface{}{ + "response": response, + }, + WrapInfo: &wrapping.ResponseWrapInfo{ + TTL: time.Duration(creationTTL), + CreationPath: creationPath, + }, + }, nil +} + +func (b *SystemBackend) pathHashWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + inputB64 := d.Get("input").(string) + format := d.Get("format").(string) + algorithm := d.Get("urlalgorithm").(string) + if algorithm == "" { + algorithm = d.Get("algorithm").(string) + } + + input, err := base64.StdEncoding.DecodeString(inputB64) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("unable to decode input as base64: %s", err)), logical.ErrInvalidRequest + } + + switch format { + case "hex": + case "base64": + default: + return logical.ErrorResponse(fmt.Sprintf("unsupported encoding format %s; must be \"hex\" or \"base64\"", format)), nil + } + + var hf hash.Hash + switch algorithm { + case "sha2-224": + hf = sha256.New224() + case "sha2-256": + hf = sha256.New() + case "sha2-384": + hf = sha512.New384() + case "sha2-512": + hf = sha512.New() + default: + return logical.ErrorResponse(fmt.Sprintf("unsupported algorithm %s", algorithm)), nil + } + hf.Write(input) + retBytes := hf.Sum(nil) + + var retStr string + switch format { + case "hex": + retStr = hex.EncodeToString(retBytes) + case "base64": + retStr = base64.StdEncoding.EncodeToString(retBytes) + } + + // Generate the response + resp := &logical.Response{ + Data: map[string]interface{}{ + "sum": retStr, + }, + } + return resp, nil +} + +func (b *SystemBackend) pathRandomWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + bytes := 0 + var err error + strBytes := d.Get("urlbytes").(string) + if strBytes != "" { + bytes, err = strconv.Atoi(strBytes) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("error parsing url-set byte count: %s", err)), nil + } + } else { + bytes = d.Get("bytes").(int) + } + format := d.Get("format").(string) + + if bytes < 1 { + return logical.ErrorResponse(`"bytes" cannot be less than 1`), nil + } + + switch format { + case "hex": + case "base64": + default: + return logical.ErrorResponse(fmt.Sprintf("unsupported encoding format %s; must be \"hex\" or \"base64\"", format)), nil + } + + randBytes, err := uuid.GenerateRandomBytes(bytes) + if err != nil { + return nil, err + } + + var retStr string + switch format { + case "hex": + retStr = hex.EncodeToString(randBytes) + case "base64": + retStr = base64.StdEncoding.EncodeToString(randBytes) + } + + // Generate the response + resp := &logical.Response{ + Data: map[string]interface{}{ + "random_bytes": retStr, + }, + } + return resp, nil +} + +func hasMountAccess(acl *ACL, path string) bool { + // If an ealier policy is giving us access to the mount path then we can do + // a fast return. + capabilities := acl.Capabilities(path) + if !strutil.StrListContains(capabilities, DenyCapability) { + return true + } + + var aclCapabilitiesGiven bool + walkFn := func(s string, v interface{}) bool { + if v == nil { + return false + } + + perms := v.(*ACLPermissions) + + switch { + case perms.CapabilitiesBitmap&DenyCapabilityInt > 0: + return false + + case perms.CapabilitiesBitmap&CreateCapabilityInt > 0, + perms.CapabilitiesBitmap&DeleteCapabilityInt > 0, + perms.CapabilitiesBitmap&ListCapabilityInt > 0, + perms.CapabilitiesBitmap&ReadCapabilityInt > 0, + perms.CapabilitiesBitmap&SudoCapabilityInt > 0, + perms.CapabilitiesBitmap&UpdateCapabilityInt > 0: + + aclCapabilitiesGiven = true + return true + } + + return false + } + + acl.exactRules.WalkPrefix(path, walkFn) + if !aclCapabilitiesGiven { + acl.globRules.WalkPrefix(path, walkFn) + } + + return aclCapabilitiesGiven +} + +func (b *SystemBackend) pathInternalUIMountsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + resp := &logical.Response{ + Data: make(map[string]interface{}), + } + + secretMounts := make(map[string]interface{}) + authMounts := make(map[string]interface{}) + resp.Data["secret"] = secretMounts + resp.Data["auth"] = authMounts + + var acl *ACL + var isAuthed bool + var err error + if req.ClientToken != "" { + isAuthed = true + + var entity *identity.Entity + // Load the ACL policies so we can walk the prefix for this mount + acl, _, entity, err = b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + if entity != nil && entity.Disabled { + return nil, logical.ErrPermissionDenied + } + + } + + hasAccess := func(me *MountEntry) bool { + if me.Config.ListingVisibility == ListingVisibilityUnauth { + return true + } + + if isAuthed { + return hasMountAccess(acl, me.Path) + } + + return false + } + + b.Core.mountsLock.RLock() + for _, entry := range b.Core.mounts.Entries { + if hasAccess(entry) { + if isAuthed { + // If this is an authed request return all the mount info + secretMounts[entry.Path] = mountInfo(entry) + } else { + secretMounts[entry.Path] = map[string]interface{}{ + "type": entry.Type, + "description": entry.Description, + "options": entry.Options, + } + } + } + } + b.Core.mountsLock.RUnlock() + + b.Core.authLock.RLock() + for _, entry := range b.Core.auth.Entries { + if hasAccess(entry) { + if isAuthed { + // If this is an authed request return all the mount info + authMounts[entry.Path] = mountInfo(entry) + } else { + authMounts[entry.Path] = map[string]interface{}{ + "type": entry.Type, + "description": entry.Description, + "options": entry.Options, + } + } + } + } + b.Core.authLock.RUnlock() + + return resp, nil +} + +func (b *SystemBackend) pathInternalUIMountRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + path := d.Get("path").(string) + if path == "" { + return logical.ErrorResponse("path not set"), logical.ErrInvalidRequest + } + path = sanitizeMountPath(path) + + errResp := logical.ErrorResponse(fmt.Sprintf("Preflight capability check returned 403, please ensure client's policies grant access to path \"%s\"", path)) + + me := b.Core.router.MatchingMountEntry(path) + if me == nil { + // Return a permission denied error here so this path cannot be used to + // brute force a list of mounts. + return errResp, logical.ErrPermissionDenied + } + + resp := &logical.Response{ + Data: mountInfo(me), + } + resp.Data["path"] = me.Path + + // Load the ACL policies so we can walk the prefix for this mount + acl, _, entity, err := b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + if entity != nil && entity.Disabled { + return errResp, logical.ErrPermissionDenied + } + + if !hasMountAccess(acl, me.Path) { + return errResp, logical.ErrPermissionDenied + } + + return resp, nil +} + +func (b *SystemBackend) pathInternalUIResultantACL(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + if req.ClientToken == "" { + // 204 -- no ACL + return nil, nil + } + + acl, _, entity, err := b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + + if entity != nil && entity.Disabled { + return logical.ErrorResponse(logical.ErrPermissionDenied.Error()), nil + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "root": false, + }, + } + + if acl.root { + resp.Data["root"] = true + return resp, nil + } + + exact := map[string]interface{}{} + glob := map[string]interface{}{} + + walkFn := func(pt map[string]interface{}, s string, v interface{}) { + if v == nil { + return + } + + perms := v.(*ACLPermissions) + capabilities := []string{} + + if perms.CapabilitiesBitmap&CreateCapabilityInt > 0 { + capabilities = append(capabilities, CreateCapability) + } + if perms.CapabilitiesBitmap&DeleteCapabilityInt > 0 { + capabilities = append(capabilities, DeleteCapability) + } + if perms.CapabilitiesBitmap&ListCapabilityInt > 0 { + capabilities = append(capabilities, ListCapability) + } + if perms.CapabilitiesBitmap&ReadCapabilityInt > 0 { + capabilities = append(capabilities, ReadCapability) + } + if perms.CapabilitiesBitmap&SudoCapabilityInt > 0 { + capabilities = append(capabilities, SudoCapability) + } + if perms.CapabilitiesBitmap&UpdateCapabilityInt > 0 { + capabilities = append(capabilities, UpdateCapability) + } + + // If "deny" is explicitly set or if the path has no capabilities at all, + // set the path capabilities to "deny" + if perms.CapabilitiesBitmap&DenyCapabilityInt > 0 || len(capabilities) == 0 { + capabilities = []string{DenyCapability} + } + + res := map[string]interface{}{} + if len(capabilities) > 0 { + res["capabilities"] = capabilities + } + if perms.MinWrappingTTL != 0 { + res["min_wrapping_ttl"] = int64(perms.MinWrappingTTL.Seconds()) + } + if perms.MaxWrappingTTL != 0 { + res["max_wrapping_ttl"] = int64(perms.MaxWrappingTTL.Seconds()) + } + if len(perms.AllowedParameters) > 0 { + res["allowed_parameters"] = perms.AllowedParameters + } + if len(perms.DeniedParameters) > 0 { + res["denied_parameters"] = perms.DeniedParameters + } + if len(perms.RequiredParameters) > 0 { + res["required_parameters"] = perms.RequiredParameters + } + + pt[s] = res + } + + exactWalkFn := func(s string, v interface{}) bool { + walkFn(exact, s, v) + return false + } + + globWalkFn := func(s string, v interface{}) bool { + walkFn(glob, s, v) + return false + } + + acl.exactRules.Walk(exactWalkFn) + acl.globRules.Walk(globWalkFn) + + resp.Data["exact_paths"] = exact + resp.Data["glob_paths"] = glob + + return resp, nil +} + +func sanitizeMountPath(path string) string { + if !strings.HasSuffix(path, "/") { + path += "/" + } + + if strings.HasPrefix(path, "/") { + path = path[1:] + } + + return path +} + +func checkListingVisibility(visibility ListingVisibilityType) error { + switch visibility { + case ListingVisibilityHidden: + case ListingVisibilityUnauth: + default: + return fmt.Errorf("invalid listing visilibity type") + } + + return nil +} + +const sysHelpRoot = ` +The system backend is built-in to Vault and cannot be remounted or +unmounted. It contains the paths that are used to configure Vault itself +as well as perform core operations. +` + +// sysHelp is all the help text for the sys backend. +var sysHelp = map[string][2]string{ + "config/cors": { + "Configures or returns the current configuration of CORS settings.", + ` +This path responds to the following HTTP methods. + + GET / + Returns the configuration of the CORS setting. + + POST / + Sets the comma-separated list of origins that can make cross-origin requests. + + DELETE / + Clears the CORS configuration and disables acceptance of CORS requests. + `, + }, + "config/ui/headers": { + "Configures response headers that should be returned from the UI.", + ` +This path responds to the following HTTP methods. + GET /
+ Returns the header value. + POST /
+ Sets the header value for the UI. + DELETE /
+ Clears the header value for UI. + + LIST / + List the headers configured for the UI. + `, + }, + "init": { + "Initializes or returns the initialization status of the Vault.", + ` +This path responds to the following HTTP methods. + + GET / + Returns the initialization status of the Vault. + + POST / + Initializes a new vault. + `, + }, + "generate-root": { + "Reads, generates, or deletes a root token regeneration process.", + ` +This path responds to multiple HTTP methods which change the behavior. Those +HTTP methods are listed below. + + GET /attempt + Reads the configuration and progress of the current root generation + attempt. + + POST /attempt + Initializes a new root generation attempt. Only a single root generation + attempt can take place at a time. One (and only one) of otp or pgp_key + are required. + + DELETE /attempt + Cancels any in-progress root generation attempt. This clears any + progress made. This must be called to change the OTP or PGP key being + used. + `, + }, + "seal-status": { + "Returns the seal status of the Vault.", + ` +This path responds to the following HTTP methods. + + GET / + Returns the seal status of the Vault. This is an unauthenticated + endpoint. + `, + }, + "seal": { + "Seals the Vault.", + ` +This path responds to the following HTTP methods. + + PUT / + Seals the Vault. + `, + }, + "unseal": { + "Unseals the Vault.", + ` +This path responds to the following HTTP methods. + + PUT / + Unseals the Vault. + `, + }, + "mounts": { + "List the currently mounted backends.", + ` +This path responds to the following HTTP methods. + + GET / + Lists all the mounted secret backends. + + GET / + Get information about the mount at the specified path. + + POST / + Mount a new secret backend to the mount point in the URL. + + POST //tune + Tune configuration parameters for the given mount point. + + DELETE / + Unmount the specified mount point. + `, + }, + + "mount": { + `Mount a new backend at a new path.`, + ` +Mount a backend at a new path. A backend can be mounted multiple times at +multiple paths in order to configure multiple separately configured backends. +Example: you might have an AWS backend for the east coast, and one for the +west coast. + `, + }, + + "mount_path": { + `The path to mount to. Example: "aws/east"`, + "", + }, + + "mount_type": { + `The type of the backend. Example: "passthrough"`, + "", + }, + + "mount_desc": { + `User-friendly description for this mount.`, + "", + }, + + "mount_config": { + `Configuration for this mount, such as default_lease_ttl +and max_lease_ttl.`, + }, + + "mount_local": { + `Mark the mount as a local mount, which is not replicated +and is unaffected by replication.`, + }, + + "mount_plugin_name": { + `Name of the plugin to mount based from the name registered +in the plugin catalog.`, + }, + + "mount_options": { + `The options to pass into the backend. Should be a json object with string keys and values.`, + }, + + "seal_wrap": { + `Whether to turn on seal wrapping for the mount.`, + }, + + "tune_default_lease_ttl": { + `The default lease TTL for this mount.`, + }, + + "tune_max_lease_ttl": { + `The max lease TTL for this mount.`, + }, + + "tune_audit_non_hmac_request_keys": { + `The list of keys in the request data object that will not be HMAC'ed by audit devices.`, + }, + + "tune_audit_non_hmac_response_keys": { + `The list of keys in the response data object that will not be HMAC'ed by audit devices.`, + }, + + "tune_mount_options": { + `The options to pass into the backend. Should be a json object with string keys and values.`, + }, + + "remount": { + "Move the mount point of an already-mounted backend.", + ` +This path responds to the following HTTP methods. + + POST /sys/remount + Changes the mount point of an already-mounted backend. + `, + }, + + "auth_tune": { + "Tune the configuration parameters for an auth path.", + `Read and write the 'default-lease-ttl' and 'max-lease-ttl' values of +the auth path.`, + }, + + "mount_tune": { + "Tune backend configuration parameters for this mount.", + `Read and write the 'default-lease-ttl' and 'max-lease-ttl' values of +the mount.`, + }, + + "renew": { + "Renew a lease on a secret", + ` +When a secret is read, it may optionally include a lease interval +and a boolean indicating if renew is possible. For secrets that support +lease renewal, this endpoint is used to extend the validity of the +lease and to prevent an automatic revocation. + `, + }, + + "lease_id": { + "The lease identifier to renew. This is included with a lease.", + "", + }, + + "increment": { + "The desired increment in seconds to the lease", + "", + }, + + "revoke": { + "Revoke a leased secret immediately", + ` +When a secret is generated with a lease, it is automatically revoked +at the end of the lease period if not renewed. However, in some cases +you may want to force an immediate revocation. This endpoint can be +used to revoke the secret with the given Lease ID. + `, + }, + + "revoke-prefix": { + "Revoke all secrets generated in a given prefix", + ` +Revokes all the secrets generated under a given mount prefix. As +an example, "prod/aws/" might be the AWS logical backend, and due to +a change in the "ops" policy, we may want to invalidate all the secrets +generated. We can do a revoke prefix at "prod/aws/ops" to revoke all +the ops secrets. This does a prefix match on the Lease IDs and revokes +all matching leases. + `, + }, + + "revoke-prefix-path": { + `The path to revoke keys under. Example: "prod/aws/ops"`, + "", + }, + + "revoke-force": { + "Revoke all secrets generated in a given prefix, ignoring errors.", + ` +See the path help for 'revoke-prefix'; this behaves the same, except that it +ignores errors encountered during revocation. This can be used in certain +recovery situations; for instance, when you want to unmount a backend, but it +is impossible to fix revocation errors and these errors prevent the unmount +from proceeding. This is a DANGEROUS operation as it removes Vault's oversight +of external secrets. Access to this prefix should be tightly controlled. + `, + }, + + "revoke-force-path": { + `The path to revoke keys under. Example: "prod/aws/ops"`, + "", + }, + + "auth-table": { + "List the currently enabled credential backends.", + ` +This path responds to the following HTTP methods. + + GET / + List the currently enabled credential backends: the name, the type of + the backend, and a user friendly description of the purpose for the + credential backend. + + POST / + Enable a new auth method. + + DELETE / + Disable the auth method at the given mount point. + `, + }, + + "auth": { + `Enable a new credential backend with a name.`, + ` +Enable a credential mechanism at a new path. A backend can be mounted multiple times at +multiple paths in order to configure multiple separately configured backends. +Example: you might have an OAuth backend for GitHub, and one for Google Apps. + `, + }, + + "auth_path": { + `The path to mount to. Cannot be delimited. Example: "user"`, + "", + }, + + "auth_type": { + `The type of the backend. Example: "userpass"`, + "", + }, + + "auth_desc": { + `User-friendly description for this credential backend.`, + "", + }, + + "auth_config": { + `Configuration for this mount, such as plugin_name.`, + }, + + "auth_plugin": { + `Name of the auth plugin to use based from the name in the plugin catalog.`, + "", + }, + + "auth_options": { + `The options to pass into the backend. Should be a json object with string keys and values.`, + }, + + "policy-list": { + `List the configured access control policies.`, + ` +This path responds to the following HTTP methods. + + GET / + List the names of the configured access control policies. + + GET / + Retrieve the rules for the named policy. + + PUT / + Add or update a policy. + + DELETE / + Delete the policy with the given name. + `, + }, + + "policy": { + `Read, Modify, or Delete an access control policy.`, + ` +Read the rules of an existing policy, create or update the rules of a policy, +or delete a policy. + `, + }, + + "policy-name": { + `The name of the policy. Example: "ops"`, + "", + }, + + "policy-rules": { + `The rules of the policy. Either given in HCL or JSON format.`, + "", + }, + + "audit-hash": { + "The hash of the given string via the given audit backend", + "", + }, + + "audit-table": { + "List the currently enabled audit backends.", + ` +This path responds to the following HTTP methods. + + GET / + List the currently enabled audit backends. + + PUT / + Enable an audit backend at the given path. + + DELETE / + Disable the given audit backend. + `, + }, + + "audit_path": { + `The name of the backend. Cannot be delimited. Example: "mysql"`, + "", + }, + + "audit_type": { + `The type of the backend. Example: "mysql"`, + "", + }, + + "audit_desc": { + `User-friendly description for this audit backend.`, + "", + }, + + "audit_opts": { + `Configuration options for the audit backend.`, + "", + }, + + "audit": { + `Enable or disable audit backends.`, + ` +Enable a new audit backend or disable an existing backend. + `, + }, + + "key-status": { + "Provides information about the backend encryption key.", + ` + Provides the current backend encryption key term and installation time. + `, + }, + + "rotate": { + "Rotates the backend encryption key used to persist data.", + ` + Rotate generates a new encryption key which is used to encrypt all + data going to the storage backend. The old encryption keys are kept so + that data encrypted using those keys can still be decrypted. + `, + }, + + "rekey_backup": { + "Allows fetching or deleting the backup of the rotated unseal keys.", + "", + }, + + "capabilities": { + "Fetches the capabilities of the given token on the given path.", + `Returns the capabilities of the given token on the path. + The path will be searched for a path match in all the policies associated with the token.`, + }, + + "capabilities_self": { + "Fetches the capabilities of the given token on the given path.", + `Returns the capabilities of the client token on the path. + The path will be searched for a path match in all the policies associated with the client token.`, + }, + + "capabilities_accessor": { + "Fetches the capabilities of the token associated with the given token, on the given path.", + `When there is no access to the token, token accessor can be used to fetch the token's capabilities + on a given path.`, + }, + + "tidy_leases": { + `This endpoint performs cleanup tasks that can be run if certain error +conditions have occurred.`, + `This endpoint performs cleanup tasks that can be run to clean up the +lease entries after certain error conditions. Usually running this is not +necessary, and is only required if upgrade notes or support personnel suggest +it.`, + }, + + "wrap": { + "Response-wraps an arbitrary JSON object.", + `Round trips the given input data into a response-wrapped token.`, + }, + + "wrappubkey": { + "Returns pubkeys used in some wrapping formats.", + "Returns pubkeys used in some wrapping formats.", + }, + + "unwrap": { + "Unwraps a response-wrapped token.", + `Unwraps a response-wrapped token. Unlike simply reading from cubbyhole/response, + this provides additional validation on the token, and rather than a JSON-escaped + string, the returned response is the exact same as the contained wrapped response.`, + }, + + "wraplookup": { + "Looks up the properties of a response-wrapped token.", + `Returns the creation TTL and creation time of a response-wrapped token.`, + }, + + "rewrap": { + "Rotates a response-wrapped token.", + `Rotates a response-wrapped token; the output is a new token with the same + response wrapped inside and the same creation TTL. The original token is revoked.`, + }, + "audited-headers-name": { + "Configures the headers sent to the audit logs.", + ` +This path responds to the following HTTP methods. + + GET / + Returns the setting for the header with the given name. + + POST / + Enable auditing of the given header. + + DELETE / + Disable auditing of the given header. + `, + }, + "audited-headers": { + "Lists the headers configured to be audited.", + `Returns a list of headers that have been configured to be audited.`, + }, + "plugin-catalog": { + "Configures the plugins known to vault", + ` +This path responds to the following HTTP methods. + LIST / + Returns a list of names of configured plugins. + + GET / + Retrieve the metadata for the named plugin. + + PUT / + Add or update plugin. + + DELETE / + Delete the plugin with the given name. + `, + }, + "plugin-catalog_name": { + "The name of the plugin", + "", + }, + "plugin-catalog_sha-256": { + `The SHA256 sum of the executable used in the +command field. This should be HEX encoded.`, + "", + }, + "plugin-catalog_command": { + `The command used to start the plugin. The +executable defined in this command must exist in vault's +plugin directory.`, + "", + }, + "plugin-catalog_args": { + `The args passed to plugin command.`, + "", + }, + "leases": { + `View or list lease metadata.`, + ` +This path responds to the following HTTP methods. + + PUT / + Retrieve the metadata for the provided lease id. + + LIST / + Lists the leases for the named prefix. + `, + }, + + "leases-list-prefix": { + `The path to list leases under. Example: "aws/creds/deploy"`, + "", + }, + "plugin-reload": { + "Reload mounts that use a particular backend plugin.", + `Reload mounts that use a particular backend plugin. Either the plugin name + or the desired plugin backend mounts must be provided, but not both. In the + case that the plugin name is provided, all mounted paths that use that plugin + backend will be reloaded.`, + }, + "plugin-backend-reload-plugin": { + `The name of the plugin to reload, as registered in the plugin catalog.`, + "", + }, + "plugin-backend-reload-mounts": { + `The mount paths of the plugin backends to reload.`, + "", + }, + "hash": { + "Generate a hash sum for input data", + "Generates a hash sum of the given algorithm against the given input data.", + }, + "random": { + "Generate random bytes", + "This function can be used to generate high-entropy random bytes.", + }, + "listing_visibility": { + "Determines the visibility of the mount in the UI-specific listing endpoint. Accepted value are 'unauth' and ''.", + "", + }, + "passthrough_request_headers": { + "A list of headers to whitelist and pass from the request to the backend.", + "", + }, + "raw": { + "Write, Read, and Delete data directly in the Storage backend.", + "", + }, + "internal-ui-mounts": { + "Information about mounts returned according to their tuned visibility. Internal API; its location, inputs, and outputs may change.", + "", + }, + "internal-ui-resultant-acl": { + "Information about a token's resultant ACL. Internal API; its location, inputs, and outputs may change.", + "", + }, +} diff --git a/vendor/github.com/hashicorp/vault/vault/logical_system_helpers.go b/vendor/github.com/hashicorp/vault/vault/logical_system_helpers.go new file mode 100644 index 0000000..d9fdb04 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/logical_system_helpers.go @@ -0,0 +1,54 @@ +package vault + +import ( + "context" + "fmt" + "strings" + "time" +) + +// tuneMount is used to set config on a mount point +func (b *SystemBackend) tuneMountTTLs(ctx context.Context, path string, me *MountEntry, newDefault, newMax time.Duration) error { + zero := time.Duration(0) + + switch { + case newDefault == zero && newMax == zero: + // No checks needed + + case newDefault == zero && newMax != zero: + // No default/max conflict, no checks needed + + case newDefault != zero && newMax == zero: + // No default/max conflict, no checks needed + + case newDefault != zero && newMax != zero: + if newMax < newDefault { + return fmt.Errorf("backend max lease TTL of %d would be less than backend default lease TTL of %d", int(newMax.Seconds()), int(newDefault.Seconds())) + } + } + + origMax := me.Config.MaxLeaseTTL + origDefault := me.Config.DefaultLeaseTTL + + me.Config.MaxLeaseTTL = newMax + me.Config.DefaultLeaseTTL = newDefault + + // Update the mount table + var err error + switch { + case strings.HasPrefix(path, credentialRoutePrefix): + err = b.Core.persistAuth(ctx, b.Core.auth, &me.Local) + default: + err = b.Core.persistMounts(ctx, b.Core.mounts, &me.Local) + } + if err != nil { + me.Config.MaxLeaseTTL = origMax + me.Config.DefaultLeaseTTL = origDefault + return fmt.Errorf("failed to update mount table, rolling back TTL changes") + } + if b.Core.logger.IsInfo() { + b.Core.logger.Info("mount tuning of leases successful", "path", path) + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/mount.go b/vendor/github.com/hashicorp/vault/vault/mount.go new file mode 100644 index 0000000..7a2c70b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/mount.go @@ -0,0 +1,1111 @@ +package vault + +import ( + "context" + "errors" + "fmt" + "os" + "sort" + "strings" + "sync" + "time" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" + "github.com/mitchellh/copystructure" +) + +const ( + // coreMountConfigPath is used to store the mount configuration. + // Mounts are protected within the Vault itself, which means they + // can only be viewed or modified after an unseal. + coreMountConfigPath = "core/mounts" + + // coreLocalMountConfigPath is used to store mount configuration for local + // (non-replicated) mounts + coreLocalMountConfigPath = "core/local-mounts" + + // backendBarrierPrefix is the prefix to the UUID used in the + // barrier view for the backends. + backendBarrierPrefix = "logical/" + + // systemBarrierPrefix is the prefix used for the + // system logical backend. + systemBarrierPrefix = "sys/" + + // mountTableType is the value we expect to find for the mount table and + // corresponding entries + mountTableType = "mounts" +) + +// ListingVisibilityType represents the types for listing visibility +type ListingVisibilityType string + +const ( + // ListingVisibilityHidden is the hidden type for listing visibility + ListingVisibilityHidden ListingVisibilityType = "" + // ListingVisibilityUnauth is the unauth type for listing visibility + ListingVisibilityUnauth ListingVisibilityType = "unauth" +) + +var ( + // loadMountsFailed if loadMounts encounters an error + errLoadMountsFailed = errors.New("failed to setup mount table") + + // protectedMounts cannot be remounted + protectedMounts = []string{ + "audit/", + "auth/", + "sys/", + "cubbyhole/", + "identity/", + } + + untunableMounts = []string{ + "cubbyhole/", + "sys/", + "audit/", + "identity/", + } + + // singletonMounts can only exist in one location and are + // loaded by default. These are types, not paths. + singletonMounts = []string{ + "cubbyhole", + "system", + "token", + "identity", + } + + // mountAliases maps old backend names to new backend names, allowing us + // to move/rename backends but maintain backwards compatibility + mountAliases = map[string]string{"generic": "kv"} +) + +func collectBackendLocalPaths(backend logical.Backend, viewPath string) []string { + if backend == nil || backend.SpecialPaths() == nil || len(backend.SpecialPaths().LocalStorage) == 0 { + return nil + } + + var paths []string + for _, path := range backend.SpecialPaths().LocalStorage { + paths = append(paths, viewPath+path) + } + + return paths +} + +func (c *Core) generateMountAccessor(entryType string) (string, error) { + var accessor string + for { + randBytes, err := uuid.GenerateRandomBytes(4) + if err != nil { + return "", err + } + accessor = fmt.Sprintf("%s_%s", entryType, fmt.Sprintf("%08x", randBytes[0:4])) + if entry := c.router.MatchingMountByAccessor(accessor); entry == nil { + break + } + } + + return accessor, nil +} + +// MountTable is used to represent the internal mount table +type MountTable struct { + Type string `json:"type"` + Entries []*MountEntry `json:"entries"` +} + +// shallowClone returns a copy of the mount table that +// keeps the MountEntry locations, so as not to invalidate +// other locations holding pointers. Care needs to be taken +// if modifying entries rather than modifying the table itself +func (t *MountTable) shallowClone() *MountTable { + mt := &MountTable{ + Type: t.Type, + Entries: make([]*MountEntry, len(t.Entries)), + } + for i, e := range t.Entries { + mt.Entries[i] = e + } + return mt +} + +// setTaint is used to set the taint on given entry +func (t *MountTable) setTaint(path string, value bool) *MountEntry { + n := len(t.Entries) + for i := 0; i < n; i++ { + if t.Entries[i].Path == path { + t.Entries[i].Tainted = value + return t.Entries[i] + } + } + return nil +} + +// remove is used to remove a given path entry; returns the entry that was +// removed +func (t *MountTable) remove(path string) *MountEntry { + n := len(t.Entries) + for i := 0; i < n; i++ { + if entry := t.Entries[i]; entry.Path == path { + t.Entries[i], t.Entries[n-1] = t.Entries[n-1], nil + t.Entries = t.Entries[:n-1] + return entry + } + } + return nil +} + +// sortEntriesByPath sorts the entries in the table by path and returns the +// table; this is useful for tests +func (t *MountTable) sortEntriesByPath() *MountTable { + sort.Slice(t.Entries, func(i, j int) bool { + return t.Entries[i].Path < t.Entries[j].Path + }) + return t +} + +// MountEntry is used to represent a mount table entry +type MountEntry struct { + Table string `json:"table"` // The table it belongs to + Path string `json:"path"` // Mount Path + Type string `json:"type"` // Logical backend Type + Description string `json:"description"` // User-provided description + UUID string `json:"uuid"` // Barrier view UUID + BackendAwareUUID string `json:"backend_aware_uuid"` // UUID that can be used by the backend as a helper when a consistent value is needed outside of storage. + Accessor string `json:"accessor"` // Unique but more human-friendly ID. Does not change, not used for any sensitive things (like as a salt, which the UUID sometimes is). + Config MountConfig `json:"config"` // Configuration related to this mount (but not backend-derived) + Options map[string]string `json:"options"` // Backend options + Local bool `json:"local"` // Local mounts are not replicated or affected by replication + SealWrap bool `json:"seal_wrap"` // Whether to wrap CSPs + Tainted bool `json:"tainted,omitempty"` // Set as a Write-Ahead flag for unmount/remount + + // synthesizedConfigCache is used to cache configuration values. These + // particular values are cached since we want to get them at a point-in-time + // without separately managing their locks individually. See SyncCache() for + // the specific values that are being cached. + synthesizedConfigCache sync.Map +} + +// MountConfig is used to hold settable options +type MountConfig struct { + DefaultLeaseTTL time.Duration `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` // Override for global default + MaxLeaseTTL time.Duration `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` // Override for global default + ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"` // Override for global default + PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility ListingVisibilityType `json:"listing_visibility,omitempty" structs:"listing_visibility" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" structs:"passthrough_request_headers" mapstructure:"passthrough_request_headers"` +} + +// APIMountConfig is an embedded struct of api.MountConfigInput +type APIMountConfig struct { + DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` + ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"` + PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"` + ListingVisibility ListingVisibilityType `json:"listing_visibility,omitempty" structs:"listing_visibility" mapstructure:"listing_visibility"` + PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" structs:"passthrough_request_headers" mapstructure:"passthrough_request_headers"` +} + +// Clone returns a deep copy of the mount entry +func (e *MountEntry) Clone() (*MountEntry, error) { + cp, err := copystructure.Copy(e) + if err != nil { + return nil, err + } + return cp.(*MountEntry), nil +} + +// SyncCache syncs tunable configuration values to the cache. In the case of +// cached values, they should be retrieved via synthesizedConfigCache.Load() +// instead of accessing them directly through MountConfig. +func (e *MountEntry) SyncCache() { + if len(e.Config.AuditNonHMACRequestKeys) == 0 { + e.synthesizedConfigCache.Delete("audit_non_hmac_request_keys") + } else { + e.synthesizedConfigCache.Store("audit_non_hmac_request_keys", e.Config.AuditNonHMACRequestKeys) + } + + if len(e.Config.AuditNonHMACResponseKeys) == 0 { + e.synthesizedConfigCache.Delete("audit_non_hmac_response_keys") + } else { + e.synthesizedConfigCache.Store("audit_non_hmac_response_keys", e.Config.AuditNonHMACResponseKeys) + } + + if len(e.Config.PassthroughRequestHeaders) == 0 { + e.synthesizedConfigCache.Delete("passthrough_request_headers") + } else { + e.synthesizedConfigCache.Store("passthrough_request_headers", e.Config.PassthroughRequestHeaders) + } +} + +// Mount is used to mount a new backend to the mount table. +func (c *Core) mount(ctx context.Context, entry *MountEntry) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(entry.Path, "/") { + entry.Path += "/" + } + + // Prevent protected paths from being mounted + for _, p := range protectedMounts { + if strings.HasPrefix(entry.Path, p) { + return logical.CodedError(403, fmt.Sprintf("cannot mount '%s'", entry.Path)) + } + } + + // Do not allow more than one instance of a singleton mount + for _, p := range singletonMounts { + if entry.Type == p { + return logical.CodedError(403, fmt.Sprintf("Cannot mount more than one instance of '%s'", entry.Type)) + } + } + return c.mountInternal(ctx, entry) +} + +func (c *Core) mountInternal(ctx context.Context, entry *MountEntry) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + // Verify there are no conflicting mounts + if match := c.router.MountConflict(entry.Path); match != "" { + return logical.CodedError(409, fmt.Sprintf("existing mount at %s", match)) + } + + // Generate a new UUID and view + if entry.UUID == "" { + entryUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.UUID = entryUUID + } + if entry.BackendAwareUUID == "" { + bUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.BackendAwareUUID = bUUID + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor(entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + } + // Sync values to the cache + entry.SyncCache() + + viewPath := backendBarrierPrefix + entry.UUID + "/" + view := NewBarrierView(c.barrier, viewPath) + + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + // We defer this because we're already up and running so we don't need to + // time it for after postUnseal + defer view.setReadOnlyErr(nil) + + var backend logical.Backend + var err error + sysView := c.mountEntrySysView(entry) + + // Consider having plugin name under entry.Options + backend, err = c.newLogicalBackend(ctx, entry, sysView, view) + if err != nil { + return err + } + if backend == nil { + return fmt.Errorf("nil backend of type %q returned from creation function", entry.Type) + } + + // Check for the correct backend type + backendType := backend.Type() + if entry.Type == "plugin" && backendType != logical.TypeLogical { + return fmt.Errorf("cannot mount %q of type %q as a logical backend", entry.Config.PluginName, backendType) + } + + c.setCoreBackend(entry, backend, view) + + newTable := c.mounts.shallowClone() + newTable.Entries = append(newTable.Entries, entry) + if err := c.persistMounts(ctx, newTable, &entry.Local); err != nil { + c.logger.Error("failed to update mount table", "error", err) + return logical.CodedError(500, "failed to update mount table") + } + c.mounts = newTable + + if err := c.router.Mount(backend, entry.Path, entry, view); err != nil { + return err + } + + if c.logger.IsInfo() { + c.logger.Info("successful mount", "path", entry.Path, "type", entry.Type) + } + return nil +} + +// Unmount is used to unmount a path. The boolean indicates whether the mount +// was found. +func (c *Core) unmount(ctx context.Context, path string) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(path, "/") { + path += "/" + } + + // Prevent protected paths from being unmounted + for _, p := range protectedMounts { + if strings.HasPrefix(path, p) { + return fmt.Errorf("cannot unmount %q", path) + } + } + return c.unmountInternal(ctx, path) +} + +func (c *Core) unmountInternal(ctx context.Context, path string) error { + // Verify exact match of the route + match := c.router.MatchingMount(path) + if match == "" || path != match { + return fmt.Errorf("no matching mount") + } + + // Get the view for this backend + view := c.router.MatchingStorageByAPIPath(path) + + // Get the backend/mount entry for this path, used to remove ignored + // replication prefixes + backend := c.router.MatchingBackend(path) + entry := c.router.MatchingMountEntry(path) + + // Mark the entry as tainted + if err := c.taintMountEntry(ctx, path); err != nil { + c.logger.Error("failed to taint mount entry for path being unmounted", "error", err, "path", path) + return err + } + + // Taint the router path to prevent routing. Note that in-flight requests + // are uncertain, right now. + if err := c.router.Taint(path); err != nil { + return err + } + + if backend != nil { + // Invoke the rollback manager a final time + if err := c.rollback.Rollback(path); err != nil { + return err + } + + // Revoke all the dynamic keys + if err := c.expiration.RevokePrefix(path); err != nil { + return err + } + + // Call cleanup function if it exists + backend.Cleanup(ctx) + } + + // Unmount the backend entirely + if err := c.router.Unmount(ctx, path); err != nil { + return err + } + + switch { + case entry.Local, !c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary): + // Have writable storage, remove the whole thing + if err := logical.ClearView(ctx, view); err != nil { + c.logger.Error("failed to clear view for path being unmounted", "error", err, "path", path) + return err + } + } + + // Remove the mount table entry + if err := c.removeMountEntry(ctx, path); err != nil { + c.logger.Error("failed to remove mount entry for path being unmounted", "error", err, "path", path) + return err + } + + if c.logger.IsInfo() { + c.logger.Info("successfully unmounted", "path", path) + } + return nil +} + +// removeMountEntry is used to remove an entry from the mount table +func (c *Core) removeMountEntry(ctx context.Context, path string) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + // Remove the entry from the mount table + newTable := c.mounts.shallowClone() + entry := newTable.remove(path) + if entry == nil { + c.logger.Error("nil entry found removing entry in mounts table", "path", path) + return logical.CodedError(500, "failed to remove entry in mounts table") + } + + // When unmounting all entries the JSON code will load back up from storage + // as a nil slice, which kills tests...just set it nil explicitly + if len(newTable.Entries) == 0 { + newTable.Entries = nil + } + + // Update the mount table + if err := c.persistMounts(ctx, newTable, &entry.Local); err != nil { + c.logger.Error("failed to remove entry from mounts table", "error", err) + return logical.CodedError(500, "failed to remove entry from mounts table") + } + + c.mounts = newTable + return nil +} + +// taintMountEntry is used to mark an entry in the mount table as tainted +func (c *Core) taintMountEntry(ctx context.Context, path string) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + // As modifying the taint of an entry affects shallow clones, + // we simply use the original + entry := c.mounts.setTaint(path, true) + if entry == nil { + c.logger.Error("nil entry found tainting entry in mounts table", "path", path) + return logical.CodedError(500, "failed to taint entry in mounts table") + } + + // Update the mount table + if err := c.persistMounts(ctx, c.mounts, &entry.Local); err != nil { + c.logger.Error("failed to taint entry in mounts table", "error", err) + return logical.CodedError(500, "failed to taint entry in mounts table") + } + + return nil +} + +// remountForce takes a copy of the mount entry for the path and fully unmounts +// and remounts the backend to pick up any changes, such as filtered paths +func (c *Core) remountForce(ctx context.Context, path string) error { + me := c.router.MatchingMountEntry(path) + if me == nil { + return fmt.Errorf("cannot find mount for path %q", path) + } + + me, err := me.Clone() + if err != nil { + return err + } + + if err := c.unmount(ctx, path); err != nil { + return err + } + return c.mount(ctx, me) +} + +// Remount is used to remount a path at a new mount point. +func (c *Core) remount(ctx context.Context, src, dst string) error { + // Ensure we end the path in a slash + if !strings.HasSuffix(src, "/") { + src += "/" + } + if !strings.HasSuffix(dst, "/") { + dst += "/" + } + + // Prevent protected paths from being remounted + for _, p := range protectedMounts { + if strings.HasPrefix(src, p) { + return fmt.Errorf("cannot remount %q", src) + } + } + + // Verify exact match of the route + match := c.router.MatchingMount(src) + if match == "" || src != match { + return fmt.Errorf("no matching mount at %q", src) + } + + if match := c.router.MatchingMount(dst); match != "" { + return fmt.Errorf("existing mount at %q", match) + } + + // Mark the entry as tainted + if err := c.taintMountEntry(ctx, src); err != nil { + return err + } + + // Taint the router path to prevent routing + if err := c.router.Taint(src); err != nil { + return err + } + + // Invoke the rollback manager a final time + if err := c.rollback.Rollback(src); err != nil { + return err + } + + // Revoke all the dynamic keys + if err := c.expiration.RevokePrefix(src); err != nil { + return err + } + + c.mountsLock.Lock() + var entry *MountEntry + for _, entry = range c.mounts.Entries { + if entry.Path == src { + entry.Path = dst + entry.Tainted = false + break + } + } + + if entry == nil { + c.mountsLock.Unlock() + c.logger.Error("failed to find entry in mounts table") + return logical.CodedError(500, "failed to find entry in mounts table") + } + + // Update the mount table + if err := c.persistMounts(ctx, c.mounts, &entry.Local); err != nil { + entry.Path = src + entry.Tainted = true + c.mountsLock.Unlock() + c.logger.Error("failed to update mounts table", "error", err) + return logical.CodedError(500, "failed to update mounts table") + } + c.mountsLock.Unlock() + + // Remount the backend + if err := c.router.Remount(src, dst); err != nil { + return err + } + + // Un-taint the path + if err := c.router.Untaint(dst); err != nil { + return err + } + + if c.logger.IsInfo() { + c.logger.Info("successful remount", "old_path", src, "new_path", dst) + } + return nil +} + +// loadMounts is invoked as part of postUnseal to load the mount table +func (c *Core) loadMounts(ctx context.Context) error { + mountTable := &MountTable{} + localMountTable := &MountTable{} + // Load the existing mount table + raw, err := c.barrier.Get(ctx, coreMountConfigPath) + if err != nil { + c.logger.Error("failed to read mount table", "error", err) + return errLoadMountsFailed + } + rawLocal, err := c.barrier.Get(ctx, coreLocalMountConfigPath) + if err != nil { + c.logger.Error("failed to read local mount table", "error", err) + return errLoadMountsFailed + } + + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + if raw != nil { + // Check if the persisted value has canary in the beginning. If + // yes, decompress the table and then JSON decode it. If not, + // simply JSON decode it. + if err := jsonutil.DecodeJSON(raw.Value, mountTable); err != nil { + c.logger.Error("failed to decompress and/or decode the mount table", "error", err) + return err + } + c.mounts = mountTable + } + + var needPersist bool + if c.mounts == nil { + c.logger.Info("no mounts; adding default mount table") + c.mounts = c.defaultMountTable() + needPersist = true + } + + if rawLocal != nil { + if err := jsonutil.DecodeJSON(rawLocal.Value, localMountTable); err != nil { + c.logger.Error("failed to decompress and/or decode the local mount table", "error", err) + return err + } + if localMountTable != nil && len(localMountTable.Entries) > 0 { + c.mounts.Entries = append(c.mounts.Entries, localMountTable.Entries...) + } + } + + // Note that this is only designed to work with singletons, as it checks by + // type only. + + // Upgrade to typed mount table + if c.mounts.Type == "" { + c.mounts.Type = mountTableType + needPersist = true + } + + for _, requiredMount := range c.requiredMountTable().Entries { + foundRequired := false + for _, coreMount := range c.mounts.Entries { + if coreMount.Type == requiredMount.Type { + foundRequired = true + break + } + } + + // In a replication scenario we will let sync invalidation take + // care of creating a new required mount that doesn't exist yet. + // This should only happen in the upgrade case where a new one is + // introduced on the primary; otherwise initial bootstrapping will + // ensure this comes over. If we upgrade first, we simply don't + // create the mount, so we won't conflict when we sync. If this is + // local (e.g. cubbyhole) we do still add it. + if !foundRequired && (!c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) || requiredMount.Local) { + c.mounts.Entries = append(c.mounts.Entries, requiredMount) + needPersist = true + } + } + + // Upgrade to table-scoped entries + for _, entry := range c.mounts.Entries { + if entry.Type == "cubbyhole" && !entry.Local { + entry.Local = true + needPersist = true + } + if entry.Table == "" { + entry.Table = c.mounts.Type + needPersist = true + } + if entry.Accessor == "" { + accessor, err := c.generateMountAccessor(entry.Type) + if err != nil { + return err + } + entry.Accessor = accessor + needPersist = true + } + if entry.BackendAwareUUID == "" { + bUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.BackendAwareUUID = bUUID + needPersist = true + } + + // Sync values to the cache + entry.SyncCache() + } + + // Done if we have restored the mount table and we don't need + // to persist + if !needPersist { + return nil + } + + if err := c.persistMounts(ctx, c.mounts, nil); err != nil { + c.logger.Error("failed to persist mount table", "error", err) + return errLoadMountsFailed + } + return nil +} + +// persistMounts is used to persist the mount table after modification +func (c *Core) persistMounts(ctx context.Context, table *MountTable, local *bool) error { + if table.Type != mountTableType { + c.logger.Error("given table to persist has wrong type", "actual_type", table.Type, "expected_type", mountTableType) + return fmt.Errorf("invalid table type given, not persisting") + } + + for _, entry := range table.Entries { + if entry.Table != table.Type { + c.logger.Error("given entry to persist in mount table has wrong table value", "path", entry.Path, "entry_table_type", entry.Table, "actual_type", table.Type) + return fmt.Errorf("invalid mount entry found, not persisting") + } + } + + nonLocalMounts := &MountTable{ + Type: mountTableType, + } + + localMounts := &MountTable{ + Type: mountTableType, + } + + for _, entry := range table.Entries { + if entry.Local { + localMounts.Entries = append(localMounts.Entries, entry) + } else { + nonLocalMounts.Entries = append(nonLocalMounts.Entries, entry) + } + } + + writeTable := func(mt *MountTable, path string) error { + // Encode the mount table into JSON and compress it (lzw). + compressedBytes, err := jsonutil.EncodeJSONAndCompress(mt, nil) + if err != nil { + c.logger.Error("failed to encode or compress mount table", "error", err) + return err + } + + // Create an entry + entry := &Entry{ + Key: path, + Value: compressedBytes, + } + + // Write to the physical backend + if err := c.barrier.Put(ctx, entry); err != nil { + c.logger.Error("failed to persist mount table", "error", err) + return err + } + + return nil + } + + var err error + switch { + case local == nil: + // Write non-local mounts + err := writeTable(nonLocalMounts, coreMountConfigPath) + if err != nil { + return err + } + + // Write local mounts + err = writeTable(localMounts, coreLocalMountConfigPath) + if err != nil { + return err + } + case *local: + // Write local mounts + err = writeTable(localMounts, coreLocalMountConfigPath) + default: + // Write non-local mounts + err = writeTable(nonLocalMounts, coreMountConfigPath) + } + + return err +} + +// setupMounts is invoked after we've loaded the mount table to +// initialize the logical backends and setup the router +func (c *Core) setupMounts(ctx context.Context) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + var backendType logical.BackendType + + for _, entry := range c.mounts.Entries { + + // Initialize the backend, special casing for system + barrierPath := backendBarrierPrefix + entry.UUID + "/" + if entry.Type == "system" { + barrierPath = systemBarrierPrefix + } + + // Create a barrier view using the UUID + view := NewBarrierView(c.barrier, barrierPath) + + // Mark the view as read-only until the mounting is complete and + // ensure that it is reset after. This ensures that there will be no + // writes during the construction of the backend. + view.setReadOnlyErr(logical.ErrSetupReadOnly) + if strutil.StrListContains(singletonMounts, entry.Type) { + defer view.setReadOnlyErr(nil) + } else { + c.postUnsealFuncs = append(c.postUnsealFuncs, func() { + view.setReadOnlyErr(nil) + }) + } + + var backend logical.Backend + var err error + sysView := c.mountEntrySysView(entry) + + // Create the new backend + backend, err = c.newLogicalBackend(ctx, entry, sysView, view) + if err != nil { + c.logger.Error("failed to create mount entry", "path", entry.Path, "error", err) + if entry.Type == "plugin" { + // If we encounter an error instantiating the backend due to an error, + // skip backend initialization but register the entry to the mount table + // to preserve storage and path. + c.logger.Warn("skipping plugin-based mount entry", "path", entry.Path) + goto ROUTER_MOUNT + } + return errLoadMountsFailed + } + if backend == nil { + return fmt.Errorf("created mount entry of type %q is nil", entry.Type) + } + + // Check for the correct backend type + backendType = backend.Type() + if entry.Type == "plugin" && backendType != logical.TypeLogical { + return fmt.Errorf("cannot mount %q of type %q as a logical backend", entry.Config.PluginName, backendType) + } + + c.setCoreBackend(entry, backend, view) + + ROUTER_MOUNT: + // Mount the backend + err = c.router.Mount(backend, entry.Path, entry, view) + if err != nil { + c.logger.Error("failed to mount entry", "path", entry.Path, "error", err) + return errLoadMountsFailed + } + + if c.logger.IsInfo() { + c.logger.Info("successfully mounted backend", "type", entry.Type, "path", entry.Path) + } + + // Ensure the path is tainted if set in the mount table + if entry.Tainted { + c.router.Taint(entry.Path) + } + } + return nil +} + +// unloadMounts is used before we seal the vault to reset the mounts to +// their unloaded state, calling Cleanup if defined. This is reversed by load and setup mounts. +func (c *Core) unloadMounts(ctx context.Context) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + if c.mounts != nil { + mountTable := c.mounts.shallowClone() + for _, e := range mountTable.Entries { + backend := c.router.MatchingBackend(e.Path) + if backend != nil { + backend.Cleanup(ctx) + } + } + } + + c.mounts = nil + c.router = NewRouter() + c.systemBarrierView = nil + return nil +} + +// newLogicalBackend is used to create and configure a new logical backend by name +func (c *Core) newLogicalBackend(ctx context.Context, entry *MountEntry, sysView logical.SystemView, view logical.Storage) (logical.Backend, error) { + t := entry.Type + if alias, ok := mountAliases[t]; ok { + t = alias + } + f, ok := c.logicalBackends[t] + if !ok { + return nil, fmt.Errorf("unknown backend type: %q", t) + } + + // Set up conf to pass in plugin_name + conf := make(map[string]string, len(entry.Options)+1) + for k, v := range entry.Options { + conf[k] = v + } + if entry.Config.PluginName != "" { + conf["plugin_name"] = entry.Config.PluginName + } + + config := &logical.BackendConfig{ + StorageView: view, + Logger: c.logger.ResetNamed(fmt.Sprintf("secrets.%s.%s", t, entry.Accessor)), + Config: conf, + System: sysView, + BackendUUID: entry.BackendAwareUUID, + } + + b, err := f(ctx, config) + if err != nil { + return nil, err + } + if b == nil { + return nil, fmt.Errorf("nil backend of type %q returned from factory", t) + } + return b, nil +} + +// mountEntrySysView creates a logical.SystemView from global and +// mount-specific entries; because this should be called when setting +// up a mountEntry, it doesn't check to ensure that me is not nil +func (c *Core) mountEntrySysView(entry *MountEntry) logical.SystemView { + return dynamicSystemView{ + core: c, + mountEntry: entry, + } +} + +// defaultMountTable creates a default mount table +func (c *Core) defaultMountTable() *MountTable { + table := &MountTable{ + Type: mountTableType, + } + mountUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create default secret mount UUID: %v", err)) + } + mountAccessor, err := c.generateMountAccessor("kv") + if err != nil { + panic(fmt.Sprintf("could not generate default secret mount accessor: %v", err)) + } + bUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create default secret mount backend UUID: %v", err)) + } + + kvMount := &MountEntry{ + Table: mountTableType, + Path: "secret/", + Type: "kv", + Description: "key/value secret storage", + UUID: mountUUID, + Accessor: mountAccessor, + BackendAwareUUID: bUUID, + Options: map[string]string{ + "version": "1", + }, + } + if os.Getenv("VAULT_INTERACTIVE_DEMO_SERVER") != "" { + kvMount.Options["version"] = "2" + } + table.Entries = append(table.Entries, kvMount) + table.Entries = append(table.Entries, c.requiredMountTable().Entries...) + return table +} + +// requiredMountTable() creates a mount table with entries required +// to be available +func (c *Core) requiredMountTable() *MountTable { + table := &MountTable{ + Type: mountTableType, + } + cubbyholeUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create cubbyhole UUID: %v", err)) + } + cubbyholeAccessor, err := c.generateMountAccessor("cubbyhole") + if err != nil { + panic(fmt.Sprintf("could not generate cubbyhole accessor: %v", err)) + } + cubbyholeBackendUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create cubbyhole backend UUID: %v", err)) + } + cubbyholeMount := &MountEntry{ + Table: mountTableType, + Path: "cubbyhole/", + Type: "cubbyhole", + Description: "per-token private secret storage", + UUID: cubbyholeUUID, + Accessor: cubbyholeAccessor, + Local: true, + BackendAwareUUID: cubbyholeBackendUUID, + } + + sysUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create sys UUID: %v", err)) + } + sysAccessor, err := c.generateMountAccessor("system") + if err != nil { + panic(fmt.Sprintf("could not generate sys accessor: %v", err)) + } + sysBackendUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create sys backend UUID: %v", err)) + } + sysMount := &MountEntry{ + Table: mountTableType, + Path: "sys/", + Type: "system", + Description: "system endpoints used for control, policy and debugging", + UUID: sysUUID, + Accessor: sysAccessor, + BackendAwareUUID: sysBackendUUID, + } + + identityUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create identity mount entry UUID: %v", err)) + } + identityAccessor, err := c.generateMountAccessor("identity") + if err != nil { + panic(fmt.Sprintf("could not generate identity accessor: %v", err)) + } + identityBackendUUID, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Sprintf("could not create identity backend UUID: %v", err)) + } + identityMount := &MountEntry{ + Table: mountTableType, + Path: "identity/", + Type: "identity", + Description: "identity store", + UUID: identityUUID, + Accessor: identityAccessor, + BackendAwareUUID: identityBackendUUID, + } + + table.Entries = append(table.Entries, cubbyholeMount) + table.Entries = append(table.Entries, sysMount) + table.Entries = append(table.Entries, identityMount) + + return table +} + +// This function returns tables that are singletons. The main usage of this is +// for replication, so we can send over mount info (especially, UUIDs of +// mounts, which are used for salts) for mounts that may not be able to be +// handled normally. After saving these values on the secondary, we let normal +// sync invalidation do its thing. Because of its use for replication, we +// exclude local mounts. +func (c *Core) singletonMountTables() (mounts, auth *MountTable) { + mounts = &MountTable{} + auth = &MountTable{} + + c.mountsLock.RLock() + for _, entry := range c.mounts.Entries { + if strutil.StrListContains(singletonMounts, entry.Type) && !entry.Local { + mounts.Entries = append(mounts.Entries, entry) + } + } + c.mountsLock.RUnlock() + + c.authLock.RLock() + for _, entry := range c.auth.Entries { + if strutil.StrListContains(singletonMounts, entry.Type) && !entry.Local { + auth.Entries = append(auth.Entries, entry) + } + } + c.authLock.RUnlock() + + return +} + +func (c *Core) setCoreBackend(entry *MountEntry, backend logical.Backend, view *BarrierView) { + switch entry.Type { + case "system": + c.systemBackend = backend.(*SystemBackend) + c.systemBarrierView = view + case "cubbyhole": + ch := backend.(*CubbyholeBackend) + ch.saltUUID = entry.UUID + ch.storageView = view + case "identity": + c.identityStore = backend.(*IdentityStore) + } +} diff --git a/vendor/github.com/hashicorp/vault/vault/plugin_catalog.go b/vendor/github.com/hashicorp/vault/vault/plugin_catalog.go new file mode 100644 index 0000000..633b7c3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/plugin_catalog.go @@ -0,0 +1,189 @@ +package vault + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "path/filepath" + "sort" + "strings" + "sync" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/builtinplugins" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/pluginutil" + "github.com/hashicorp/vault/logical" +) + +var ( + pluginCatalogPath = "core/plugin-catalog/" + ErrDirectoryNotConfigured = errors.New("could not set plugin, plugin directory is not configured") + ErrPluginNotFound = errors.New("plugin not found in the catalog") +) + +// PluginCatalog keeps a record of plugins known to vault. External plugins need +// to be registered to the catalog before they can be used in backends. Builtin +// plugins are automatically detected and included in the catalog. +type PluginCatalog struct { + catalogView *BarrierView + directory string + + lock sync.RWMutex +} + +func (c *Core) setupPluginCatalog() error { + c.pluginCatalog = &PluginCatalog{ + catalogView: NewBarrierView(c.barrier, pluginCatalogPath), + directory: c.pluginDirectory, + } + + if c.logger.IsInfo() { + c.logger.Info("successfully setup plugin catalog", "plugin-directory", c.pluginDirectory) + } + + return nil +} + +// Get retrieves a plugin with the specified name from the catalog. It first +// looks for external plugins with this name and then looks for builtin plugins. +// It returns a PluginRunner or an error if no plugin was found. +func (c *PluginCatalog) Get(ctx context.Context, name string) (*pluginutil.PluginRunner, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + // If the directory isn't set only look for builtin plugins. + if c.directory != "" { + // Look for external plugins in the barrier + out, err := c.catalogView.Get(ctx, name) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("failed to retrieve plugin %q: {{err}}", name), err) + } + if out != nil { + entry := new(pluginutil.PluginRunner) + if err := jsonutil.DecodeJSON(out.Value, entry); err != nil { + return nil, errwrap.Wrapf("failed to decode plugin entry: {{err}}", err) + } + + // prepend the plugin directory to the command + entry.Command = filepath.Join(c.directory, entry.Command) + + return entry, nil + } + } + // Look for builtin plugins + if factory, ok := builtinplugins.Get(name); ok { + return &pluginutil.PluginRunner{ + Name: name, + Builtin: true, + BuiltinFactory: factory, + }, nil + } + + return nil, nil +} + +// Set registers a new external plugin with the catalog, or updates an existing +// external plugin. It takes the name, command and SHA256 of the plugin. +func (c *PluginCatalog) Set(ctx context.Context, name, command string, args []string, sha256 []byte) error { + if c.directory == "" { + return ErrDirectoryNotConfigured + } + + switch { + case strings.Contains(name, ".."): + fallthrough + case strings.Contains(command, ".."): + return consts.ErrPathContainsParentReferences + } + + c.lock.Lock() + defer c.lock.Unlock() + + // Best effort check to make sure the command isn't breaking out of the + // configured plugin directory. + commandFull := filepath.Join(c.directory, command) + sym, err := filepath.EvalSymlinks(commandFull) + if err != nil { + return errwrap.Wrapf("error while validating the command path: {{err}}", err) + } + symAbs, err := filepath.Abs(filepath.Dir(sym)) + if err != nil { + return errwrap.Wrapf("error while validating the command path: {{err}}", err) + } + + if symAbs != c.directory { + return errors.New("can not execute files outside of configured plugin directory") + } + + entry := &pluginutil.PluginRunner{ + Name: name, + Command: command, + Args: args, + Sha256: sha256, + Builtin: false, + } + + buf, err := json.Marshal(entry) + if err != nil { + return errwrap.Wrapf("failed to encode plugin entry: {{err}}", err) + } + + logicalEntry := logical.StorageEntry{ + Key: name, + Value: buf, + } + if err := c.catalogView.Put(ctx, &logicalEntry); err != nil { + return errwrap.Wrapf("failed to persist plugin entry: {{err}}", err) + } + return nil +} + +// Delete is used to remove an external plugin from the catalog. Builtin plugins +// can not be deleted. +func (c *PluginCatalog) Delete(ctx context.Context, name string) error { + c.lock.Lock() + defer c.lock.Unlock() + + return c.catalogView.Delete(ctx, name) +} + +// List returns a list of all the known plugin names. If an external and builtin +// plugin share the same name, only one instance of the name will be returned. +func (c *PluginCatalog) List(ctx context.Context) ([]string, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + // Collect keys for external plugins in the barrier. + keys, err := logical.CollectKeys(ctx, c.catalogView) + if err != nil { + return nil, err + } + + // Get the keys for builtin plugins + builtinKeys := builtinplugins.Keys() + + // Use a map to unique the two lists + mapKeys := make(map[string]bool) + + for _, plugin := range keys { + mapKeys[plugin] = true + } + + for _, plugin := range builtinKeys { + mapKeys[plugin] = true + } + + retList := make([]string, len(mapKeys)) + i := 0 + for k := range mapKeys { + retList[i] = k + i++ + } + // sort for consistent ordering of builtin plugins + sort.Strings(retList) + + return retList, nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/plugin_reload.go b/vendor/github.com/hashicorp/vault/vault/plugin_reload.go new file mode 100644 index 0000000..e130df8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/plugin_reload.go @@ -0,0 +1,143 @@ +package vault + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" +) + +// reloadPluginMounts reloads provided mounts, regardless of +// plugin name, as long as the backend type is plugin. +func (c *Core) reloadMatchingPluginMounts(ctx context.Context, mounts []string) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + var errors error + for _, mount := range mounts { + entry := c.router.MatchingMountEntry(mount) + if entry == nil { + errors = multierror.Append(errors, fmt.Errorf("cannot fetch mount entry on %q", mount)) + continue + } + + var isAuth bool + fullPath := c.router.MatchingMount(mount) + if strings.HasPrefix(fullPath, credentialRoutePrefix) { + isAuth = true + } + + if entry.Type == "plugin" { + err := c.reloadBackendCommon(ctx, entry, isAuth) + if err != nil { + errors = multierror.Append(errors, errwrap.Wrapf(fmt.Sprintf("cannot reload plugin on %q: {{err}}", mount), err)) + continue + } + c.logger.Info("successfully reloaded plugin", "plugin", entry.Config.PluginName, "path", entry.Path) + } + } + return errors +} + +// reloadPlugin reloads all mounted backends that are of +// plugin pluginName (name of the plugin as registered in +// the plugin catalog). +func (c *Core) reloadMatchingPlugin(ctx context.Context, pluginName string) error { + c.mountsLock.Lock() + defer c.mountsLock.Unlock() + + // Filter mount entries that only matches the plugin name + for _, entry := range c.mounts.Entries { + if entry.Config.PluginName == pluginName && entry.Type == "plugin" { + err := c.reloadBackendCommon(ctx, entry, false) + if err != nil { + return err + } + c.logger.Info("successfully reloaded plugin", "plugin", pluginName, "path", entry.Path) + } + } + + // Filter auth mount entries that ony matches the plugin name + for _, entry := range c.auth.Entries { + if entry.Config.PluginName == pluginName && entry.Type == "plugin" { + err := c.reloadBackendCommon(ctx, entry, true) + if err != nil { + return err + } + c.logger.Info("successfully reloaded plugin", "plugin", pluginName, "path", entry.Path) + } + } + + return nil +} + +// reloadBackendCommon is a generic method to reload a backend provided a +// MountEntry. +func (c *Core) reloadBackendCommon(ctx context.Context, entry *MountEntry, isAuth bool) error { + // We don't want to reload the singleton mounts. They often have specific + // inmemory elements and we don't want to touch them here. + if strutil.StrListContains(singletonMounts, entry.Type) { + c.logger.Debug("Skipping reload of singleton mount", "type", entry.Type) + return nil + } + + path := entry.Path + + if isAuth { + path = credentialRoutePrefix + path + } + + // Fast-path out if the backend doesn't exist + raw, ok := c.router.root.Get(path) + if !ok { + return nil + } + + re := raw.(*routeEntry) + + // Grab the lock, this allows requests to drain before we cleanup the + // client. + re.l.Lock() + defer re.l.Unlock() + + // Only call Cleanup if backend is initialized + if re.backend != nil { + // Call backend's Cleanup routine + re.backend.Cleanup(ctx) + } + + view := re.storageView + + sysView := c.mountEntrySysView(entry) + + var backend logical.Backend + var err error + if !isAuth { + // Dispense a new backend + backend, err = c.newLogicalBackend(ctx, entry, sysView, view) + } else { + backend, err = c.newCredentialBackend(ctx, entry, sysView, view) + } + if err != nil { + return err + } + if backend == nil { + return fmt.Errorf("nil backend of type %q returned from creation function", entry.Type) + } + + // Set the backend back + re.backend = backend + + // Set paths as well + paths := backend.SpecialPaths() + if paths != nil { + re.rootPaths.Store(pathsToRadix(paths.Root)) + re.loginPaths.Store(pathsToRadix(paths.Unauthenticated)) + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/policy.go b/vendor/github.com/hashicorp/vault/vault/policy.go new file mode 100644 index 0000000..d92a404 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/policy.go @@ -0,0 +1,334 @@ +package vault + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/mitchellh/copystructure" +) + +const ( + DenyCapability = "deny" + CreateCapability = "create" + ReadCapability = "read" + UpdateCapability = "update" + DeleteCapability = "delete" + ListCapability = "list" + SudoCapability = "sudo" + RootCapability = "root" + + // Backwards compatibility + OldDenyPathPolicy = "deny" + OldReadPathPolicy = "read" + OldWritePathPolicy = "write" + OldSudoPathPolicy = "sudo" +) + +const ( + DenyCapabilityInt uint32 = 1 << iota + CreateCapabilityInt + ReadCapabilityInt + UpdateCapabilityInt + DeleteCapabilityInt + ListCapabilityInt + SudoCapabilityInt +) + +type PolicyType uint32 + +const ( + PolicyTypeACL PolicyType = iota + PolicyTypeRGP + PolicyTypeEGP + + // Triggers a lookup in the map to figure out if ACL or RGP + PolicyTypeToken +) + +func (p PolicyType) String() string { + switch p { + case PolicyTypeACL: + return "acl" + case PolicyTypeRGP: + return "rgp" + case PolicyTypeEGP: + return "egp" + } + + return "" +} + +var ( + cap2Int = map[string]uint32{ + DenyCapability: DenyCapabilityInt, + CreateCapability: CreateCapabilityInt, + ReadCapability: ReadCapabilityInt, + UpdateCapability: UpdateCapabilityInt, + DeleteCapability: DeleteCapabilityInt, + ListCapability: ListCapabilityInt, + SudoCapability: SudoCapabilityInt, + } +) + +// Policy is used to represent the policy specified by +// an ACL configuration. +type Policy struct { + Name string `hcl:"name"` + Paths []*PathRules `hcl:"-"` + Raw string + Type PolicyType +} + +// PathRules represents a policy for a path in the namespace. +type PathRules struct { + Prefix string + Policy string + Permissions *ACLPermissions + Glob bool + Capabilities []string + + // These keys are used at the top level to make the HCL nicer; we store in + // the ACLPermissions object though + MinWrappingTTLHCL interface{} `hcl:"min_wrapping_ttl"` + MaxWrappingTTLHCL interface{} `hcl:"max_wrapping_ttl"` + AllowedParametersHCL map[string][]interface{} `hcl:"allowed_parameters"` + DeniedParametersHCL map[string][]interface{} `hcl:"denied_parameters"` + RequiredParametersHCL []string `hcl:"required_parameters"` +} + +type ACLPermissions struct { + CapabilitiesBitmap uint32 + MinWrappingTTL time.Duration + MaxWrappingTTL time.Duration + AllowedParameters map[string][]interface{} + DeniedParameters map[string][]interface{} + RequiredParameters []string +} + +func (p *ACLPermissions) Clone() (*ACLPermissions, error) { + ret := &ACLPermissions{ + CapabilitiesBitmap: p.CapabilitiesBitmap, + MinWrappingTTL: p.MinWrappingTTL, + MaxWrappingTTL: p.MaxWrappingTTL, + RequiredParameters: p.RequiredParameters[:], + } + + switch { + case p.AllowedParameters == nil: + case len(p.AllowedParameters) == 0: + ret.AllowedParameters = make(map[string][]interface{}) + default: + clonedAllowed, err := copystructure.Copy(p.AllowedParameters) + if err != nil { + return nil, err + } + ret.AllowedParameters = clonedAllowed.(map[string][]interface{}) + } + + switch { + case p.DeniedParameters == nil: + case len(p.DeniedParameters) == 0: + ret.DeniedParameters = make(map[string][]interface{}) + default: + clonedDenied, err := copystructure.Copy(p.DeniedParameters) + if err != nil { + return nil, err + } + ret.DeniedParameters = clonedDenied.(map[string][]interface{}) + } + + return ret, nil +} + +// Parse is used to parse the specified ACL rules into an +// intermediary set of policies, before being compiled into +// the ACL +func ParseACLPolicy(rules string) (*Policy, error) { + // Parse the rules + root, err := hcl.Parse(rules) + if err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + + // Top-level item should be the object list + list, ok := root.Node.(*ast.ObjectList) + if !ok { + return nil, fmt.Errorf("failed to parse policy: does not contain a root object") + } + + // Check for invalid top-level keys + valid := []string{ + "name", + "path", + } + if err := checkHCLKeys(list, valid); err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + + // Create the initial policy and store the raw text of the rules + var p Policy + p.Raw = rules + p.Type = PolicyTypeACL + if err := hcl.DecodeObject(&p, list); err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + + if o := list.Filter("path"); len(o.Items) > 0 { + if err := parsePaths(&p, o); err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + } + + return &p, nil +} + +func parsePaths(result *Policy, list *ast.ObjectList) error { + paths := make([]*PathRules, 0, len(list.Items)) + for _, item := range list.Items { + key := "path" + if len(item.Keys) > 0 { + key = item.Keys[0].Token.Value().(string) + } + valid := []string{ + "policy", + "capabilities", + "allowed_parameters", + "denied_parameters", + "required_parameters", + "min_wrapping_ttl", + "max_wrapping_ttl", + } + if err := checkHCLKeys(item.Val, valid); err != nil { + return multierror.Prefix(err, fmt.Sprintf("path %q:", key)) + } + + var pc PathRules + + // allocate memory so that DecodeObject can initialize the ACLPermissions struct + pc.Permissions = new(ACLPermissions) + + pc.Prefix = key + if err := hcl.DecodeObject(&pc, item.Val); err != nil { + return multierror.Prefix(err, fmt.Sprintf("path %q:", key)) + } + + // Strip a leading '/' as paths in Vault start after the / in the API path + if len(pc.Prefix) > 0 && pc.Prefix[0] == '/' { + pc.Prefix = pc.Prefix[1:] + } + + // Strip the glob character if found + if strings.HasSuffix(pc.Prefix, "*") { + pc.Prefix = strings.TrimSuffix(pc.Prefix, "*") + pc.Glob = true + } + + // Map old-style policies into capabilities + if len(pc.Policy) > 0 { + switch pc.Policy { + case OldDenyPathPolicy: + pc.Capabilities = []string{DenyCapability} + case OldReadPathPolicy: + pc.Capabilities = append(pc.Capabilities, []string{ReadCapability, ListCapability}...) + case OldWritePathPolicy: + pc.Capabilities = append(pc.Capabilities, []string{CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability}...) + case OldSudoPathPolicy: + pc.Capabilities = append(pc.Capabilities, []string{CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability, SudoCapability}...) + default: + return fmt.Errorf("path %q: invalid policy %q", key, pc.Policy) + } + } + + // Initialize the map + pc.Permissions.CapabilitiesBitmap = 0 + for _, cap := range pc.Capabilities { + switch cap { + // If it's deny, don't include any other capability + case DenyCapability: + pc.Capabilities = []string{DenyCapability} + pc.Permissions.CapabilitiesBitmap = DenyCapabilityInt + goto PathFinished + case CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability, SudoCapability: + pc.Permissions.CapabilitiesBitmap |= cap2Int[cap] + default: + return fmt.Errorf("path %q: invalid capability %q", key, cap) + } + } + + if pc.AllowedParametersHCL != nil { + pc.Permissions.AllowedParameters = make(map[string][]interface{}, len(pc.AllowedParametersHCL)) + for key, val := range pc.AllowedParametersHCL { + pc.Permissions.AllowedParameters[strings.ToLower(key)] = val + } + } + if pc.DeniedParametersHCL != nil { + pc.Permissions.DeniedParameters = make(map[string][]interface{}, len(pc.DeniedParametersHCL)) + + for key, val := range pc.DeniedParametersHCL { + pc.Permissions.DeniedParameters[strings.ToLower(key)] = val + } + } + if pc.MinWrappingTTLHCL != nil { + dur, err := parseutil.ParseDurationSecond(pc.MinWrappingTTLHCL) + if err != nil { + return errwrap.Wrapf("error parsing min_wrapping_ttl: {{err}}", err) + } + pc.Permissions.MinWrappingTTL = dur + } + if pc.MaxWrappingTTLHCL != nil { + dur, err := parseutil.ParseDurationSecond(pc.MaxWrappingTTLHCL) + if err != nil { + return errwrap.Wrapf("error parsing max_wrapping_ttl: {{err}}", err) + } + pc.Permissions.MaxWrappingTTL = dur + } + if pc.Permissions.MinWrappingTTL != 0 && + pc.Permissions.MaxWrappingTTL != 0 && + pc.Permissions.MaxWrappingTTL < pc.Permissions.MinWrappingTTL { + return errors.New("max_wrapping_ttl cannot be less than min_wrapping_ttl") + } + if len(pc.RequiredParametersHCL) > 0 { + pc.Permissions.RequiredParameters = pc.RequiredParametersHCL[:] + } + + PathFinished: + paths = append(paths, &pc) + } + + result.Paths = paths + return nil +} + +func checkHCLKeys(node ast.Node, valid []string) error { + var list *ast.ObjectList + switch n := node.(type) { + case *ast.ObjectList: + list = n + case *ast.ObjectType: + list = n.List + default: + return fmt.Errorf("cannot check HCL keys of type %T", n) + } + + validMap := make(map[string]struct{}, len(valid)) + for _, v := range valid { + validMap[v] = struct{}{} + } + + var result error + for _, item := range list.Items { + key := item.Keys[0].Token.Value().(string) + if _, ok := validMap[key]; !ok { + result = multierror.Append(result, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line)) + } + } + + return result +} diff --git a/vendor/github.com/hashicorp/vault/vault/policy_store.go b/vendor/github.com/hashicorp/vault/vault/policy_store.go new file mode 100644 index 0000000..bb2bd5d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/policy_store.go @@ -0,0 +1,519 @@ +package vault + +import ( + "context" + "fmt" + "strings" + "sync" + "time" + + "github.com/armon/go-metrics" + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/golang-lru" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" +) + +const ( + // policySubPath is the sub-path used for the policy store + // view. This is nested under the system view. + policyACLSubPath = "policy/" + + // policyCacheSize is the number of policies that are kept cached + policyCacheSize = 1024 + + // defaultPolicyName is the name of the default policy + defaultPolicyName = "default" + + // responseWrappingPolicyName is the name of the fixed policy + responseWrappingPolicyName = "response-wrapping" + + // controlGroupPolicyName is the name of the fixed policy for control group + // tokens + controlGroupPolicyName = "control-group" + + // responseWrappingPolicy is the policy that ensures cubbyhole response + // wrapping can always succeed. + responseWrappingPolicy = ` +path "cubbyhole/response" { + capabilities = ["create", "read"] +} + +path "sys/wrapping/unwrap" { + capabilities = ["update"] +} +` + + // defaultPolicy is the "default" policy + defaultPolicy = ` +# Allow tokens to look up their own properties +path "auth/token/lookup-self" { + capabilities = ["read"] +} + +# Allow tokens to renew themselves +path "auth/token/renew-self" { + capabilities = ["update"] +} + +# Allow tokens to revoke themselves +path "auth/token/revoke-self" { + capabilities = ["update"] +} + +# Allow a token to look up its own capabilities on a path +path "sys/capabilities-self" { + capabilities = ["update"] +} + +# Allow a token to look up its resultant ACL from all policies. This is useful +# for UIs. It is an internal path because the format may change at any time +# based on how the internal ACL features and capabilities change. +path "sys/internal/ui/resultant-acl" { + capabilities = ["read"] +} + +# Allow a token to renew a lease via lease_id in the request body; old path for +# old clients, new path for newer +path "sys/renew" { + capabilities = ["update"] +} +path "sys/leases/renew" { + capabilities = ["update"] +} + +# Allow looking up lease properties. This requires knowing the lease ID ahead +# of time and does not divulge any sensitive information. +path "sys/leases/lookup" { + capabilities = ["update"] +} + +# Allow a token to manage its own cubbyhole +path "cubbyhole/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} + +# Allow a token to wrap arbitrary values in a response-wrapping token +path "sys/wrapping/wrap" { + capabilities = ["update"] +} + +# Allow a token to look up the creation time and TTL of a given +# response-wrapping token +path "sys/wrapping/lookup" { + capabilities = ["update"] +} + +# Allow a token to unwrap a response-wrapping token. This is a convenience to +# avoid client token swapping since this is also part of the response wrapping +# policy. +path "sys/wrapping/unwrap" { + capabilities = ["update"] +} + +# Allow general purpose tools +path "sys/tools/hash" { + capabilities = ["update"] +} +path "sys/tools/hash/*" { + capabilities = ["update"] +} +path "sys/tools/random" { + capabilities = ["update"] +} +path "sys/tools/random/*" { + capabilities = ["update"] +} +` +) + +var ( + immutablePolicies = []string{ + "root", + responseWrappingPolicyName, + controlGroupPolicyName, + } + nonAssignablePolicies = []string{ + responseWrappingPolicyName, + controlGroupPolicyName, + } +) + +// PolicyStore is used to provide durable storage of policy, and to +// manage ACLs associated with them. +type PolicyStore struct { + core *Core + aclView *BarrierView + tokenPoliciesLRU *lru.TwoQueueCache + // This is used to ensure that writes to the store (acl/rgp) or to the egp + // path tree don't happen concurrently. We are okay reading stale data so + // long as there aren't concurrent writes. + modifyLock *sync.RWMutex + // Stores whether a token policy is ACL or RGP + policyTypeMap sync.Map + // logger is the server logger copied over from core + logger log.Logger +} + +// PolicyEntry is used to store a policy by name +type PolicyEntry struct { + Version int + Raw string + Type PolicyType +} + +// NewPolicyStore creates a new PolicyStore that is backed +// using a given view. It used used to durable store and manage named policy. +func NewPolicyStore(ctx context.Context, core *Core, baseView *BarrierView, system logical.SystemView, logger log.Logger) *PolicyStore { + ps := &PolicyStore{ + aclView: baseView.SubView(policyACLSubPath), + modifyLock: new(sync.RWMutex), + logger: logger, + core: core, + } + if !system.CachingDisabled() { + cache, _ := lru.New2Q(policyCacheSize) + ps.tokenPoliciesLRU = cache + } + + keys, err := logical.CollectKeys(ctx, ps.aclView) + if err != nil { + ps.logger.Error("error collecting acl policy keys", "error", err) + return nil + } + for _, key := range keys { + ps.policyTypeMap.Store(ps.sanitizeName(key), PolicyTypeACL) + } + // Special-case root; doesn't exist on disk but does need to be found + ps.policyTypeMap.Store("root", PolicyTypeACL) + return ps +} + +// setupPolicyStore is used to initialize the policy store +// when the vault is being unsealed. +func (c *Core) setupPolicyStore(ctx context.Context) error { + // Create the policy store + sysView := &dynamicSystemView{core: c} + c.policyStore = NewPolicyStore(ctx, c, c.systemBarrierView, sysView, c.logger.ResetNamed("policy")) + + if c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) { + // Policies will sync from the primary + return nil + } + + // Ensure that the default policy exists, and if not, create it + if err := c.policyStore.loadACLPolicy(ctx, defaultPolicyName, defaultPolicy); err != nil { + return err + } + // Ensure that the response wrapping policy exists + if err := c.policyStore.loadACLPolicy(ctx, responseWrappingPolicyName, responseWrappingPolicy); err != nil { + return err + } + + return nil +} + +// teardownPolicyStore is used to reverse setupPolicyStore +// when the vault is being sealed. +func (c *Core) teardownPolicyStore() error { + c.policyStore = nil + return nil +} + +func (ps *PolicyStore) invalidate(ctx context.Context, name string, policyType PolicyType) { + // This may come with a prefixed "/" due to joining the file path + saneName := strings.TrimPrefix(name, "/") + + // We don't lock before removing from the LRU here because the worst that + // can happen is we load again if something since added it + switch policyType { + case PolicyTypeACL: + if ps.tokenPoliciesLRU != nil { + ps.tokenPoliciesLRU.Remove(saneName) + } + + default: + // Can't do anything + return + } + + // Force a reload + _, err := ps.GetPolicy(ctx, name, policyType) + if err != nil { + ps.logger.Error("error fetching policy after invalidation", "name", saneName) + } +} + +// SetPolicy is used to create or update the given policy +func (ps *PolicyStore) SetPolicy(ctx context.Context, p *Policy) error { + defer metrics.MeasureSince([]string{"policy", "set_policy"}, time.Now()) + if p == nil { + return fmt.Errorf("nil policy passed in for storage") + } + if p.Name == "" { + return fmt.Errorf("policy name missing") + } + // Policies are normalized to lower-case + p.Name = ps.sanitizeName(p.Name) + if strutil.StrListContains(immutablePolicies, p.Name) { + return fmt.Errorf("cannot update %q policy", p.Name) + } + + return ps.setPolicyInternal(ctx, p) +} + +func (ps *PolicyStore) setPolicyInternal(ctx context.Context, p *Policy) error { + ps.modifyLock.Lock() + defer ps.modifyLock.Unlock() + // Create the entry + entry, err := logical.StorageEntryJSON(p.Name, &PolicyEntry{ + Version: 2, + Raw: p.Raw, + Type: p.Type, + }) + if err != nil { + return errwrap.Wrapf("failed to create entry: {{err}}", err) + } + switch p.Type { + case PolicyTypeACL: + if err := ps.aclView.Put(ctx, entry); err != nil { + return errwrap.Wrapf("failed to persist policy: {{err}}", err) + } + ps.policyTypeMap.Store(p.Name, PolicyTypeACL) + + if ps.tokenPoliciesLRU != nil { + // Update the LRU cache + ps.tokenPoliciesLRU.Add(p.Name, p) + } + + default: + return fmt.Errorf("unknown policy type, cannot set") + } + + return nil +} + +// GetPolicy is used to fetch the named policy +func (ps *PolicyStore) GetPolicy(ctx context.Context, name string, policyType PolicyType) (*Policy, error) { + defer metrics.MeasureSince([]string{"policy", "get_policy"}, time.Now()) + + // Policies are normalized to lower-case + name = ps.sanitizeName(name) + + var cache *lru.TwoQueueCache + var view *BarrierView + switch policyType { + case PolicyTypeACL: + cache = ps.tokenPoliciesLRU + view = ps.aclView + case PolicyTypeToken: + cache = ps.tokenPoliciesLRU + val, ok := ps.policyTypeMap.Load(name) + if !ok { + // Doesn't exist + return nil, nil + } + policyType = val.(PolicyType) + switch policyType { + case PolicyTypeACL: + view = ps.aclView + default: + return nil, fmt.Errorf("invalid type of policy in type map: %q", policyType) + } + } + + if cache != nil { + // Check for cached policy + if raw, ok := cache.Get(name); ok { + return raw.(*Policy), nil + } + } + + // Special case the root policy + if policyType == PolicyTypeACL && name == "root" { + p := &Policy{Name: "root"} + if cache != nil { + cache.Add(p.Name, p) + } + return p, nil + } + + ps.modifyLock.Lock() + defer ps.modifyLock.Unlock() + + // See if anything has added it since we got the lock + if cache != nil { + if raw, ok := cache.Get(name); ok { + return raw.(*Policy), nil + } + } + + out, err := view.Get(ctx, name) + if err != nil { + return nil, errwrap.Wrapf("failed to read policy: {{err}}", err) + } + + if out == nil { + return nil, nil + } + + policyEntry := new(PolicyEntry) + policy := new(Policy) + err = out.DecodeJSON(policyEntry) + if err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + + // Set these up here so that they're available for loading into + // Sentinel + policy.Name = name + policy.Raw = policyEntry.Raw + policy.Type = policyEntry.Type + switch policyEntry.Type { + case PolicyTypeACL: + // Parse normally + p, err := ParseACLPolicy(policyEntry.Raw) + if err != nil { + return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) + } + policy.Paths = p.Paths + // Reset this in case they set the name in the policy itself + policy.Name = name + + ps.policyTypeMap.Store(name, PolicyTypeACL) + + default: + return nil, fmt.Errorf("unknown policy type %q", policyEntry.Type.String()) + } + + if cache != nil { + // Update the LRU cache + cache.Add(name, policy) + } + + return policy, nil +} + +// ListPolicies is used to list the available policies +func (ps *PolicyStore) ListPolicies(ctx context.Context, policyType PolicyType) ([]string, error) { + defer metrics.MeasureSince([]string{"policy", "list_policies"}, time.Now()) + // Scan the view, since the policy names are the same as the + // key names. + var keys []string + var err error + switch policyType { + case PolicyTypeACL: + keys, err = logical.CollectKeys(ctx, ps.aclView) + default: + return nil, fmt.Errorf("unknown policy type %q", policyType) + } + + // We only have non-assignable ACL policies at the moment + for _, nonAssignable := range nonAssignablePolicies { + deleteIndex := -1 + //Find indices of non-assignable policies in keys + for index, key := range keys { + if key == nonAssignable { + // Delete collection outside the loop + deleteIndex = index + break + } + } + // Remove non-assignable policies when found + if deleteIndex != -1 { + keys = append(keys[:deleteIndex], keys[deleteIndex+1:]...) + } + } + + return keys, err +} + +// DeletePolicy is used to delete the named policy +func (ps *PolicyStore) DeletePolicy(ctx context.Context, name string, policyType PolicyType) error { + defer metrics.MeasureSince([]string{"policy", "delete_policy"}, time.Now()) + + ps.modifyLock.Lock() + defer ps.modifyLock.Unlock() + + // Policies are normalized to lower-case + name = ps.sanitizeName(name) + + switch policyType { + case PolicyTypeACL: + if strutil.StrListContains(immutablePolicies, name) { + return fmt.Errorf("cannot delete %q policy", name) + } + if name == "default" { + return fmt.Errorf("cannot delete default policy") + } + + err := ps.aclView.Delete(ctx, name) + if err != nil { + return errwrap.Wrapf("failed to delete policy: {{err}}", err) + } + + if ps.tokenPoliciesLRU != nil { + // Clear the cache + ps.tokenPoliciesLRU.Remove(name) + } + + ps.policyTypeMap.Delete(name) + + } + return nil +} + +// ACL is used to return an ACL which is built using the +// named policies. +func (ps *PolicyStore) ACL(ctx context.Context, names ...string) (*ACL, error) { + // Fetch the policies + var policies []*Policy + for _, name := range names { + p, err := ps.GetPolicy(ctx, name, PolicyTypeToken) + if err != nil { + return nil, errwrap.Wrapf("failed to get policy: {{err}}", err) + } + policies = append(policies, p) + } + + // Construct the ACL + acl, err := NewACL(policies) + if err != nil { + return nil, errwrap.Wrapf("failed to construct ACL: {{err}}", err) + } + return acl, nil +} + +func (ps *PolicyStore) loadACLPolicy(ctx context.Context, policyName, policyText string) error { + // Check if the policy already exists + policy, err := ps.GetPolicy(ctx, policyName, PolicyTypeACL) + + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error fetching %s policy from store: {{err}}", policyName), err) + } + + if policy != nil { + if !strutil.StrListContains(immutablePolicies, policyName) || policyText == policy.Raw { + return nil + } + } + + policy, err = ParseACLPolicy(policyText) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error parsing %s policy: {{err}}", policyName), err) + } + + if policy == nil { + return fmt.Errorf("parsing %q policy resulted in nil policy", policyName) + } + + policy.Name = policyName + policy.Type = PolicyTypeACL + return ps.setPolicyInternal(ctx, policy) +} + +func (ps *PolicyStore) sanitizeName(name string) string { + return strings.ToLower(strings.TrimSpace(name)) +} diff --git a/vendor/github.com/hashicorp/vault/vault/rekey.go b/vendor/github.com/hashicorp/vault/vault/rekey.go new file mode 100644 index 0000000..a55f184 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/rekey.go @@ -0,0 +1,968 @@ +package vault + +import ( + "bytes" + "context" + "crypto/subtle" + "encoding/hex" + "encoding/json" + "fmt" + "net/http" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/pgpkeys" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/physical" + "github.com/hashicorp/vault/shamir" +) + +const ( + // coreUnsealKeysBackupPath is the path used to backup encrypted unseal + // keys if specified during a rekey operation. This is outside of the + // barrier. + coreBarrierUnsealKeysBackupPath = "core/unseal-keys-backup" + + // coreRecoveryUnsealKeysBackupPath is the path used to backup encrypted + // recovery keys if specified during a rekey operation. This is outside of + // the barrier. + coreRecoveryUnsealKeysBackupPath = "core/recovery-keys-backup" +) + +// RekeyResult is used to provide the key parts back after +// they are generated as part of the rekey. +type RekeyResult struct { + SecretShares [][]byte + PGPFingerprints []string + Backup bool + RecoveryKey bool + VerificationRequired bool + VerificationNonce string +} + +type RekeyVerifyResult struct { + Complete bool + Nonce string +} + +// RekeyBackup stores the backup copy of PGP-encrypted keys +type RekeyBackup struct { + Nonce string + Keys map[string][]string +} + +// RekeyThreshold returns the secret threshold for the current seal +// config. This threshold can either be the barrier key threshold or +// the recovery key threshold, depending on whether rekey is being +// performed on the recovery key, or whether the seal supports +// recovery keys. +func (c *Core) RekeyThreshold(ctx context.Context, recovery bool) (int, logical.HTTPCodedError) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return 0, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return 0, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.RLock() + defer c.rekeyLock.RUnlock() + + var config *SealConfig + var err error + // If we are rekeying the recovery key, or if the seal supports + // recovery keys and we are rekeying the barrier key, we use the + // recovery config as the threshold instead. + if recovery || c.seal.RecoveryKeySupported() { + config, err = c.seal.RecoveryConfig(ctx) + } else { + config, err = c.seal.BarrierConfig(ctx) + } + if err != nil { + return 0, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("unable to look up config: {{err}}", err).Error()) + } + if config == nil { + return 0, logical.CodedError(http.StatusBadRequest, ErrNotInit.Error()) + } + + return config.SecretThreshold, nil +} + +// RekeyProgress is used to return the rekey progress (num shares). +func (c *Core) RekeyProgress(recovery, verification bool) (bool, int, logical.HTTPCodedError) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return false, 0, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return false, 0, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.RLock() + defer c.rekeyLock.RUnlock() + + var conf *SealConfig + if recovery { + conf = c.recoveryRekeyConfig + } else { + conf = c.barrierRekeyConfig + } + + if conf == nil { + return false, 0, logical.CodedError(http.StatusBadRequest, "rekey operation not in progress") + } + + if verification { + return len(conf.VerificationKey) > 0, len(conf.VerificationProgress), nil + } + return true, len(conf.RekeyProgress), nil +} + +// RekeyConfig is used to read the rekey configuration +func (c *Core) RekeyConfig(recovery bool) (*SealConfig, logical.HTTPCodedError) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return nil, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Copy the seal config if any + var conf *SealConfig + if recovery { + if c.recoveryRekeyConfig != nil { + conf = c.recoveryRekeyConfig.Clone() + } + } else { + if c.barrierRekeyConfig != nil { + conf = c.barrierRekeyConfig.Clone() + } + } + + return conf, nil +} + +// RekeyInit will either initialize the rekey of barrier or recovery key. +// recovery determines whether this is a rekey on the barrier or recovery key. +func (c *Core) RekeyInit(config *SealConfig, recovery bool) logical.HTTPCodedError { + if config.SecretThreshold > config.SecretShares { + return logical.CodedError(http.StatusBadRequest, "provided threshold greater than the total shares") + } + + if recovery { + return c.RecoveryRekeyInit(config) + } + return c.BarrierRekeyInit(config) +} + +// BarrierRekeyInit is used to initialize the rekey settings for the barrier key +func (c *Core) BarrierRekeyInit(config *SealConfig) logical.HTTPCodedError { + if c.seal.StoredKeysSupported() { + c.logger.Warn("stored keys supported, forcing rekey shares/threshold to 1") + config.SecretShares = 1 + config.SecretThreshold = 1 + config.StoredShares = 1 + } + + if config.StoredShares > 0 { + if !c.seal.StoredKeysSupported() { + return logical.CodedError(http.StatusBadRequest, "storing keys not supported by barrier seal") + } + if len(config.PGPKeys) > 0 { + return logical.CodedError(http.StatusBadRequest, "PGP key encryption not supported when using stored keys") + } + if config.Backup { + return logical.CodedError(http.StatusBadRequest, "key backup not supported when using stored keys") + } + + if c.seal.RecoveryKeySupported() { + if config.VerificationRequired { + return logical.CodedError(http.StatusBadRequest, "requiring verification not supported when rekeying the barrier key with recovery keys") + } + c.logger.Debug("using recovery seal configuration to rekey barrier key") + } + } + + // Check if the seal configuration is valid + if err := config.Validate(); err != nil { + c.logger.Error("invalid rekey seal configuration", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("invalid rekey seal configuration: {{err}}", err).Error()) + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Prevent multiple concurrent re-keys + if c.barrierRekeyConfig != nil { + return logical.CodedError(http.StatusBadRequest, "rekey already in progress") + } + + // Copy the configuration + c.barrierRekeyConfig = config.Clone() + + // Initialize the nonce + nonce, err := uuid.GenerateUUID() + if err != nil { + c.barrierRekeyConfig = nil + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error generating nonce for procedure: {{err}}", err).Error()) + } + c.barrierRekeyConfig.Nonce = nonce + + if c.logger.IsInfo() { + c.logger.Info("rekey initialized", "nonce", c.barrierRekeyConfig.Nonce, "shares", c.barrierRekeyConfig.SecretShares, "threshold", c.barrierRekeyConfig.SecretThreshold, "validation_required", c.barrierRekeyConfig.VerificationRequired) + } + return nil +} + +// RecoveryRekeyInit is used to initialize the rekey settings for the recovery key +func (c *Core) RecoveryRekeyInit(config *SealConfig) logical.HTTPCodedError { + if config.StoredShares > 0 { + return logical.CodedError(http.StatusBadRequest, "stored shares not supported by recovery key") + } + + // Check if the seal configuration is valid + if err := config.Validate(); err != nil { + c.logger.Error("invalid recovery configuration", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("invalid recovery configuration: {{err}}", err).Error()) + } + + if !c.seal.RecoveryKeySupported() { + return logical.CodedError(http.StatusBadRequest, "recovery keys not supported") + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Prevent multiple concurrent re-keys + if c.recoveryRekeyConfig != nil { + return logical.CodedError(http.StatusBadRequest, "rekey already in progress") + } + + // Copy the configuration + c.recoveryRekeyConfig = config.Clone() + + // Initialize the nonce + nonce, err := uuid.GenerateUUID() + if err != nil { + c.recoveryRekeyConfig = nil + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error generating nonce for procedure: {{err}}", err).Error()) + } + c.recoveryRekeyConfig.Nonce = nonce + + if c.logger.IsInfo() { + c.logger.Info("rekey initialized", "nonce", c.recoveryRekeyConfig.Nonce, "shares", c.recoveryRekeyConfig.SecretShares, "threshold", c.recoveryRekeyConfig.SecretThreshold, "validation_required", c.recoveryRekeyConfig.VerificationRequired) + } + return nil +} + +// RekeyUpdate is used to provide a new key part for the barrier or recovery key. +func (c *Core) RekeyUpdate(ctx context.Context, key []byte, nonce string, recovery bool) (*RekeyResult, logical.HTTPCodedError) { + if recovery { + return c.RecoveryRekeyUpdate(ctx, key, nonce) + } + return c.BarrierRekeyUpdate(ctx, key, nonce) +} + +// BarrierRekeyUpdate is used to provide a new key part. Barrier rekey can be done +// with unseal keys, or recovery keys if that's supported and we are storing the barrier +// key. +// +// N.B.: If recovery keys are used to rekey, the new barrier key shares are not returned. +func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string) (*RekeyResult, logical.HTTPCodedError) { + // Ensure we are already unsealed + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return nil, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + // Verify the key length + min, max := c.barrier.KeyLength() + max += shamir.ShareOverhead + if len(key) < min { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is shorter than minimum %d bytes", min)) + } + if len(key) > max { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is longer than maximum %d bytes", max)) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Get the seal configuration + var existingConfig *SealConfig + var err error + var useRecovery bool // Determines whether recovery key is being used to rekey the master key + if c.seal.StoredKeysSupported() && c.seal.RecoveryKeySupported() { + existingConfig, err = c.seal.RecoveryConfig(ctx) + useRecovery = true + } else { + existingConfig, err = c.seal.BarrierConfig(ctx) + } + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to fetch existing config: {{err}}", err).Error()) + } + // Ensure the barrier is initialized + if existingConfig == nil { + return nil, logical.CodedError(http.StatusBadRequest, ErrNotInit.Error()) + } + + // Ensure a rekey is in progress + if c.barrierRekeyConfig == nil { + return nil, logical.CodedError(http.StatusBadRequest, "no barrier rekey in progress") + } + + if len(c.barrierRekeyConfig.VerificationKey) > 0 { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("rekey operation already finished; verification must be performed; nonce for the verification operation is %q", c.barrierRekeyConfig.VerificationNonce)) + } + + if nonce != c.barrierRekeyConfig.Nonce { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("incorrect nonce supplied; nonce for this rekey operation is %q", c.barrierRekeyConfig.Nonce)) + } + + // Check if we already have this piece + for _, existing := range c.barrierRekeyConfig.RekeyProgress { + if subtle.ConstantTimeCompare(existing, key) == 1 { + return nil, logical.CodedError(http.StatusBadRequest, "given key has already been provided during this generation operation") + } + } + + // Store this key + c.barrierRekeyConfig.RekeyProgress = append(c.barrierRekeyConfig.RekeyProgress, key) + + // Check if we don't have enough keys to unlock + if len(c.barrierRekeyConfig.RekeyProgress) < existingConfig.SecretThreshold { + if c.logger.IsDebug() { + c.logger.Debug("cannot rekey yet, not enough keys", "keys", len(c.barrierRekeyConfig.RekeyProgress), "threshold", existingConfig.SecretThreshold) + } + return nil, nil + } + + // Recover the master key or recovery key + var recoveredKey []byte + if existingConfig.SecretThreshold == 1 { + recoveredKey = c.barrierRekeyConfig.RekeyProgress[0] + } else { + recoveredKey, err = shamir.Combine(c.barrierRekeyConfig.RekeyProgress) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to compute master key: {{err}}", err).Error()) + } + } + + if useRecovery { + if err := c.seal.VerifyRecoveryKey(ctx, recoveredKey); err != nil { + c.logger.Error("rekey recovery key verification failed", "error", err) + return nil, logical.CodedError(http.StatusBadRequest, errwrap.Wrapf("recovery key verification failed: {{err}}", err).Error()) + } + } else { + if err := c.barrier.VerifyMaster(recoveredKey); err != nil { + c.logger.Error("master key verification failed", "error", err) + return nil, logical.CodedError(http.StatusBadRequest, errwrap.Wrapf("master key verification failed: {{err}}", err).Error()) + } + } + + // Generate a new master key + newMasterKey, err := c.barrier.GenerateKey() + if err != nil { + c.logger.Error("failed to generate master key", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("master key generation failed: {{err}}", err).Error()) + } + + results := &RekeyResult{ + Backup: c.barrierRekeyConfig.Backup, + } + // Set result.SecretShares to the master key if only a single key + // part is used -- no Shamir split required. + if c.barrierRekeyConfig.SecretShares == 1 { + results.SecretShares = append(results.SecretShares, newMasterKey) + } else { + // Split the master key using the Shamir algorithm + shares, err := shamir.Split(newMasterKey, c.barrierRekeyConfig.SecretShares, c.barrierRekeyConfig.SecretThreshold) + if err != nil { + c.logger.Error("failed to generate shares", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to generate shares: {{err}}", err).Error()) + } + results.SecretShares = shares + } + + // If we are storing any shares, add them to the shares to store and remove + // from the returned keys + var keysToStore [][]byte + if c.seal.StoredKeysSupported() && c.barrierRekeyConfig.StoredShares > 0 { + for i := 0; i < c.barrierRekeyConfig.StoredShares; i++ { + keysToStore = append(keysToStore, results.SecretShares[0]) + results.SecretShares = results.SecretShares[1:] + } + } + + // If PGP keys are passed in, encrypt shares with corresponding PGP keys. + if len(c.barrierRekeyConfig.PGPKeys) > 0 { + hexEncodedShares := make([][]byte, len(results.SecretShares)) + for i, _ := range results.SecretShares { + hexEncodedShares[i] = []byte(hex.EncodeToString(results.SecretShares[i])) + } + results.PGPFingerprints, results.SecretShares, err = pgpkeys.EncryptShares(hexEncodedShares, c.barrierRekeyConfig.PGPKeys) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to encrypt shares: {{err}}", err).Error()) + } + + // If backup is enabled, store backup info in vault.coreBarrierUnsealKeysBackupPath + if c.barrierRekeyConfig.Backup { + backupInfo := map[string][]string{} + for i := 0; i < len(results.PGPFingerprints); i++ { + encShare := bytes.NewBuffer(results.SecretShares[i]) + if backupInfo[results.PGPFingerprints[i]] == nil { + backupInfo[results.PGPFingerprints[i]] = []string{hex.EncodeToString(encShare.Bytes())} + } else { + backupInfo[results.PGPFingerprints[i]] = append(backupInfo[results.PGPFingerprints[i]], hex.EncodeToString(encShare.Bytes())) + } + } + + backupVals := &RekeyBackup{ + Nonce: c.barrierRekeyConfig.Nonce, + Keys: backupInfo, + } + buf, err := json.Marshal(backupVals) + if err != nil { + c.logger.Error("failed to marshal unseal key backup", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to marshal unseal key backup: {{err}}", err).Error()) + } + pe := &physical.Entry{ + Key: coreBarrierUnsealKeysBackupPath, + Value: buf, + } + if err = c.physical.Put(ctx, pe); err != nil { + c.logger.Error("failed to save unseal key backup", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save unseal key backup: {{err}}", err).Error()) + } + } + } + + if keysToStore != nil { + if err := c.seal.SetStoredKeys(ctx, keysToStore); err != nil { + c.logger.Error("failed to store keys", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to store keys: {{err}}", err).Error()) + } + } + + // If we are requiring validation, return now; otherwise rekey the barrier + if c.barrierRekeyConfig.VerificationRequired { + nonce, err := uuid.GenerateUUID() + if err != nil { + c.barrierRekeyConfig = nil + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to generate verification nonce: {{err}}", err).Error()) + } + c.barrierRekeyConfig.VerificationNonce = nonce + c.barrierRekeyConfig.VerificationKey = newMasterKey + + results.VerificationRequired = true + results.VerificationNonce = nonce + return results, nil + } + + if err := c.performBarrierRekey(ctx, newMasterKey); err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to perform barrier rekey: {{err}}", err).Error()) + } + + c.barrierRekeyConfig = nil + return results, nil +} + +func (c *Core) performBarrierRekey(ctx context.Context, newMasterKey []byte) logical.HTTPCodedError { + // Rekey the barrier + if err := c.barrier.Rekey(ctx, newMasterKey); err != nil { + c.logger.Error("failed to rekey barrier", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to rekey barrier: {{err}}", err).Error()) + } + if c.logger.IsInfo() { + c.logger.Info("security barrier rekeyed", "shares", c.barrierRekeyConfig.SecretShares, "threshold", c.barrierRekeyConfig.SecretThreshold) + } + + c.barrierRekeyConfig.VerificationKey = nil + + if err := c.seal.SetBarrierConfig(ctx, c.barrierRekeyConfig); err != nil { + c.logger.Error("error saving rekey seal configuration", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save rekey seal configuration: {{err}}", err).Error()) + } + + // Write to the canary path, which will force a synchronous truing during + // replication + if err := c.barrier.Put(ctx, &Entry{ + Key: coreKeyringCanaryPath, + Value: []byte(c.barrierRekeyConfig.Nonce), + }); err != nil { + c.logger.Error("error saving keyring canary", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save keyring canary: {{err}}", err).Error()) + } + + c.barrierRekeyConfig.RekeyProgress = nil + + return nil +} + +// RecoveryRekeyUpdate is used to provide a new key part +func (c *Core) RecoveryRekeyUpdate(ctx context.Context, key []byte, nonce string) (*RekeyResult, logical.HTTPCodedError) { + // Ensure we are already unsealed + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return nil, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + // Verify the key length + min, max := c.barrier.KeyLength() + max += shamir.ShareOverhead + if len(key) < min { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is shorter than minimum %d bytes", min)) + } + if len(key) > max { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is longer than maximum %d bytes", max)) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Get the seal configuration + existingConfig, err := c.seal.RecoveryConfig(ctx) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to fetch existing recovery config: {{err}}", err).Error()) + } + // Ensure the seal is initialized + if existingConfig == nil { + return nil, logical.CodedError(http.StatusBadRequest, ErrNotInit.Error()) + } + + // Ensure a rekey is in progress + if c.recoveryRekeyConfig == nil { + return nil, logical.CodedError(http.StatusBadRequest, "no recovery rekey in progress") + } + + if len(c.recoveryRekeyConfig.VerificationKey) > 0 { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("rekey operation already finished; verification must be performed; nonce for the verification operation is %q", c.recoveryRekeyConfig.VerificationNonce)) + } + + if nonce != c.recoveryRekeyConfig.Nonce { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("incorrect nonce supplied; nonce for this rekey operation is %q", c.recoveryRekeyConfig.Nonce)) + } + + // Check if we already have this piece + for _, existing := range c.recoveryRekeyConfig.RekeyProgress { + if subtle.ConstantTimeCompare(existing, key) == 1 { + return nil, logical.CodedError(http.StatusBadRequest, "given key has already been provided during this rekey operation") + } + } + + // Store this key + c.recoveryRekeyConfig.RekeyProgress = append(c.recoveryRekeyConfig.RekeyProgress, key) + + // Check if we don't have enough keys to unlock + if len(c.recoveryRekeyConfig.RekeyProgress) < existingConfig.SecretThreshold { + if c.logger.IsDebug() { + c.logger.Debug("cannot rekey yet, not enough keys", "keys", len(c.recoveryRekeyConfig.RekeyProgress), "threshold", existingConfig.SecretThreshold) + } + return nil, nil + } + + // Recover the master key + var recoveryKey []byte + if existingConfig.SecretThreshold == 1 { + recoveryKey = c.recoveryRekeyConfig.RekeyProgress[0] + } else { + recoveryKey, err = shamir.Combine(c.recoveryRekeyConfig.RekeyProgress) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to compute recovery key: {{err}}", err).Error()) + } + } + + // Verify the recovery key + if err := c.seal.VerifyRecoveryKey(ctx, recoveryKey); err != nil { + c.logger.Error("recovery key verification failed", "error", err) + return nil, logical.CodedError(http.StatusBadRequest, errwrap.Wrapf("recovery key verification failed: {{err}}", err).Error()) + } + + // Generate a new master key + newMasterKey, err := c.barrier.GenerateKey() + if err != nil { + c.logger.Error("failed to generate recovery key", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("recovery key generation failed: {{err}}", err).Error()) + } + + // Return the master key if only a single key part is used + results := &RekeyResult{ + Backup: c.recoveryRekeyConfig.Backup, + } + + if c.recoveryRekeyConfig.SecretShares == 1 { + results.SecretShares = append(results.SecretShares, newMasterKey) + } else { + // Split the master key using the Shamir algorithm + shares, err := shamir.Split(newMasterKey, c.recoveryRekeyConfig.SecretShares, c.recoveryRekeyConfig.SecretThreshold) + if err != nil { + c.logger.Error("failed to generate shares", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to generate shares: {{err}}", err).Error()) + } + results.SecretShares = shares + } + + if len(c.recoveryRekeyConfig.PGPKeys) > 0 { + hexEncodedShares := make([][]byte, len(results.SecretShares)) + for i, _ := range results.SecretShares { + hexEncodedShares[i] = []byte(hex.EncodeToString(results.SecretShares[i])) + } + results.PGPFingerprints, results.SecretShares, err = pgpkeys.EncryptShares(hexEncodedShares, c.recoveryRekeyConfig.PGPKeys) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to encrypt shares: {{err}}", err).Error()) + } + + if c.recoveryRekeyConfig.Backup { + backupInfo := map[string][]string{} + for i := 0; i < len(results.PGPFingerprints); i++ { + encShare := bytes.NewBuffer(results.SecretShares[i]) + if backupInfo[results.PGPFingerprints[i]] == nil { + backupInfo[results.PGPFingerprints[i]] = []string{hex.EncodeToString(encShare.Bytes())} + } else { + backupInfo[results.PGPFingerprints[i]] = append(backupInfo[results.PGPFingerprints[i]], hex.EncodeToString(encShare.Bytes())) + } + } + + backupVals := &RekeyBackup{ + Nonce: c.recoveryRekeyConfig.Nonce, + Keys: backupInfo, + } + buf, err := json.Marshal(backupVals) + if err != nil { + c.logger.Error("failed to marshal recovery key backup", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to marshal recovery key backup: {{err}}", err).Error()) + } + pe := &physical.Entry{ + Key: coreRecoveryUnsealKeysBackupPath, + Value: buf, + } + if err = c.physical.Put(ctx, pe); err != nil { + c.logger.Error("failed to save unseal key backup", "error", err) + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save unseal key backup: {{err}}", err).Error()) + } + } + } + + // If we are requiring validation, return now; otherwise save the recovery + // key + if c.recoveryRekeyConfig.VerificationRequired { + nonce, err := uuid.GenerateUUID() + if err != nil { + c.recoveryRekeyConfig = nil + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to generate verification nonce: {{err}}", err).Error()) + } + c.recoveryRekeyConfig.VerificationNonce = nonce + c.recoveryRekeyConfig.VerificationKey = newMasterKey + + results.VerificationRequired = true + results.VerificationNonce = nonce + return results, nil + } + + if err := c.performRecoveryRekey(ctx, newMasterKey); err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to perform recovery rekey: {{err}}", err).Error()) + } + + c.recoveryRekeyConfig = nil + return results, nil +} + +func (c *Core) performRecoveryRekey(ctx context.Context, newMasterKey []byte) logical.HTTPCodedError { + if err := c.seal.SetRecoveryKey(ctx, newMasterKey); err != nil { + c.logger.Error("failed to set recovery key", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to set recovery key: {{err}}", err).Error()) + } + + c.recoveryRekeyConfig.VerificationKey = nil + + if err := c.seal.SetRecoveryConfig(ctx, c.recoveryRekeyConfig); err != nil { + c.logger.Error("error saving rekey seal configuration", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save rekey seal configuration: {{err}}", err).Error()) + } + + // Write to the canary path, which will force a synchronous truing during + // replication + if err := c.barrier.Put(ctx, &Entry{ + Key: coreKeyringCanaryPath, + Value: []byte(c.recoveryRekeyConfig.Nonce), + }); err != nil { + c.logger.Error("error saving keyring canary", "error", err) + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to save keyring canary: {{err}}", err).Error()) + } + + c.recoveryRekeyConfig.RekeyProgress = nil + + return nil +} + +func (c *Core) RekeyVerify(ctx context.Context, key []byte, nonce string, recovery bool) (ret *RekeyVerifyResult, retErr logical.HTTPCodedError) { + // Ensure we are already unsealed + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return nil, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + // Verify the key length + min, max := c.barrier.KeyLength() + max += shamir.ShareOverhead + if len(key) < min { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is shorter than minimum %d bytes", min)) + } + if len(key) > max { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("key is longer than maximum %d bytes", max)) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + config := c.barrierRekeyConfig + if recovery { + config = c.recoveryRekeyConfig + } + + // Ensure a rekey is in progress + if config == nil { + return nil, logical.CodedError(http.StatusBadRequest, "no rekey in progress") + } + + if len(config.VerificationKey) == 0 { + return nil, logical.CodedError(http.StatusBadRequest, "no rekey verification in progress") + } + + if nonce != config.VerificationNonce { + return nil, logical.CodedError(http.StatusBadRequest, fmt.Sprintf("incorrect nonce supplied; nonce for this verify operation is %q", config.VerificationNonce)) + } + + // Check if we already have this piece + for _, existing := range config.VerificationProgress { + if subtle.ConstantTimeCompare(existing, key) == 1 { + return nil, logical.CodedError(http.StatusBadRequest, "given key has already been provided during this verify operation") + } + } + + // Store this key + config.VerificationProgress = append(config.VerificationProgress, key) + + // Check if we don't have enough keys to unlock + if len(config.VerificationProgress) < config.SecretThreshold { + if c.logger.IsDebug() { + c.logger.Debug("cannot verify yet, not enough keys", "keys", len(config.VerificationProgress), "threshold", config.SecretThreshold) + } + return nil, nil + } + + // Schedule the progress for forgetting and rotate the nonce if possible + defer func() { + config.VerificationProgress = nil + if ret != nil && ret.Complete { + return + } + // Not complete, so rotate nonce + nonce, err := uuid.GenerateUUID() + if err == nil { + config.VerificationNonce = nonce + if ret != nil { + ret.Nonce = nonce + } + } + }() + + // Recover the master key or recovery key + var recoveredKey []byte + if config.SecretThreshold == 1 { + recoveredKey = config.VerificationProgress[0] + } else { + var err error + recoveredKey, err = shamir.Combine(config.VerificationProgress) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to compute key for verification: {{err}}", err).Error()) + } + } + + if subtle.ConstantTimeCompare(recoveredKey, config.VerificationKey) != 1 { + c.logger.Error("rekey verification failed") + return nil, logical.CodedError(http.StatusBadRequest, "rekey verification failed; incorrect key shares supplied") + } + + switch recovery { + case false: + if err := c.performBarrierRekey(ctx, recoveredKey); err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to perform rekey: {{err}}", err).Error()) + } + c.barrierRekeyConfig = nil + default: + if err := c.performRecoveryRekey(ctx, recoveredKey); err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to perform recovery key rekey: {{err}}", err).Error()) + } + c.recoveryRekeyConfig = nil + } + + res := &RekeyVerifyResult{ + Nonce: config.VerificationNonce, + Complete: true, + } + + return res, nil +} + +// RekeyCancel is used to cancel an in-progress rekey +func (c *Core) RekeyCancel(recovery bool) logical.HTTPCodedError { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Clear any progress or config + if recovery { + c.recoveryRekeyConfig = nil + } else { + c.barrierRekeyConfig = nil + } + return nil +} + +// RekeyVerifyRestart is used to start the verification process over +func (c *Core) RekeyVerifyRestart(recovery bool) logical.HTTPCodedError { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + // Attempt to generate a new nonce, but don't bail if it doesn't succeed + // (which is extraordinarily unlikely) + nonce, nonceErr := uuid.GenerateUUID() + + // Clear any progress or config + if recovery { + c.recoveryRekeyConfig.VerificationProgress = nil + if nonceErr == nil { + c.recoveryRekeyConfig.VerificationNonce = nonce + } + } else { + c.barrierRekeyConfig.VerificationProgress = nil + if nonceErr == nil { + c.barrierRekeyConfig.VerificationNonce = nonce + } + } + + return nil +} + +// RekeyRetrieveBackup is used to retrieve any backed-up PGP-encrypted unseal +// keys +func (c *Core) RekeyRetrieveBackup(ctx context.Context, recovery bool) (*RekeyBackup, logical.HTTPCodedError) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return nil, logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.RLock() + defer c.rekeyLock.RUnlock() + + var entry *physical.Entry + var err error + if recovery { + entry, err = c.physical.Get(ctx, coreRecoveryUnsealKeysBackupPath) + } else { + entry, err = c.physical.Get(ctx, coreBarrierUnsealKeysBackupPath) + } + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error getting keys from backup: {{err}}", err).Error()) + } + if entry == nil { + return nil, nil + } + + ret := &RekeyBackup{} + err = jsonutil.DecodeJSON(entry.Value, ret) + if err != nil { + return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error decoding backup keys: {{err}}", err).Error()) + } + + return ret, nil +} + +// RekeyDeleteBackup is used to delete any backed-up PGP-encrypted unseal keys +func (c *Core) RekeyDeleteBackup(ctx context.Context, recovery bool) logical.HTTPCodedError { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return logical.CodedError(http.StatusServiceUnavailable, consts.ErrSealed.Error()) + } + if c.standby { + return logical.CodedError(http.StatusBadRequest, consts.ErrStandby.Error()) + } + + c.rekeyLock.Lock() + defer c.rekeyLock.Unlock() + + if recovery { + err := c.physical.Delete(ctx, coreRecoveryUnsealKeysBackupPath) + if err != nil { + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error deleting backup keys: {{err}}", err).Error()) + } + return nil + } + err := c.physical.Delete(ctx, coreBarrierUnsealKeysBackupPath) + if err != nil { + return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("error deleting backup keys: {{err}}", err).Error()) + } + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/request_forwarding.go b/vendor/github.com/hashicorp/vault/vault/request_forwarding.go new file mode 100644 index 0000000..472ed6c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_forwarding.go @@ -0,0 +1,488 @@ +package vault + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + math "math" + "net" + "net/http" + "net/url" + "runtime" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/forwarding" + "golang.org/x/net/http2" + "google.golang.org/grpc" + "google.golang.org/grpc/keepalive" +) + +const ( + clusterListenerAcceptDeadline = 500 * time.Millisecond + requestForwardingALPN = "req_fw_sb-act_v1" +) + +var ( + // Making this a package var allows tests to modify + HeartbeatInterval = 5 * time.Second +) + +// Starts the listeners and servers necessary to handle forwarded requests +func (c *Core) startForwarding(ctx context.Context) error { + c.logger.Debug("cluster listener setup function") + defer c.logger.Debug("leaving cluster listener setup function") + + // Clean up in case we have transitioned from a client to a server + c.requestForwardingConnectionLock.Lock() + c.clearForwardingClients() + c.requestForwardingConnectionLock.Unlock() + + // Resolve locally to avoid races + ha := c.ha != nil + + // Get our TLS config + tlsConfig, err := c.ClusterTLSConfig(ctx, nil) + if err != nil { + c.logger.Error("failed to get tls configuration when starting forwarding", "error", err) + return err + } + + // The server supports all of the possible protos + tlsConfig.NextProtos = []string{"h2", requestForwardingALPN} + + if !atomic.CompareAndSwapUint32(c.rpcServerActive, 0, 1) { + c.logger.Warn("forwarding rpc server already running") + return nil + } + + fwRPCServer := grpc.NewServer( + grpc.KeepaliveParams(keepalive.ServerParameters{ + Time: 2 * HeartbeatInterval, + }), + ) + + if ha && c.clusterHandler != nil { + RegisterRequestForwardingServer(fwRPCServer, &forwardedRequestRPCServer{ + core: c, + handler: c.clusterHandler, + }) + } + + // Create the HTTP/2 server that will be shared by both RPC and regular + // duties. Doing it this way instead of listening via the server and gRPC + // allows us to re-use the same port via ALPN. We can just tell the server + // to serve a given conn and which handler to use. + fws := &http2.Server{} + + // Shutdown coordination logic + var shutdown uint32 + shutdownWg := &sync.WaitGroup{} + + for _, addr := range c.clusterListenerAddrs { + shutdownWg.Add(1) + + // Force a local resolution to avoid data races + laddr := addr + + // Start our listening loop + go func() { + defer shutdownWg.Done() + + // closeCh is used to shutdown the spawned goroutines once this + // function returns + closeCh := make(chan struct{}) + defer func() { + close(closeCh) + }() + + if c.logger.IsInfo() { + c.logger.Info("core/startClusterListener: starting listener", "listener_address", laddr) + } + + // Create a TCP listener. We do this separately and specifically + // with TCP so that we can set deadlines. + tcpLn, err := net.ListenTCP("tcp", laddr) + if err != nil { + c.logger.Error("core/startClusterListener: error starting listener", "error", err) + return + } + + // Wrap the listener with TLS + tlsLn := tls.NewListener(tcpLn, tlsConfig) + defer tlsLn.Close() + + if c.logger.IsInfo() { + c.logger.Info("core/startClusterListener: serving cluster requests", "cluster_listen_address", tlsLn.Addr()) + } + + for { + if atomic.LoadUint32(&shutdown) > 0 { + return + } + + // Set the deadline for the accept call. If it passes we'll get + // an error, causing us to check the condition at the top + // again. + tcpLn.SetDeadline(time.Now().Add(clusterListenerAcceptDeadline)) + + // Accept the connection + conn, err := tlsLn.Accept() + if err != nil { + if err, ok := err.(net.Error); ok && !err.Timeout() { + c.logger.Debug("non-timeout error accepting on cluster port", "error", err) + } + if conn != nil { + conn.Close() + } + continue + } + if conn == nil { + continue + } + + // Type assert to TLS connection and handshake to populate the + // connection state + tlsConn := conn.(*tls.Conn) + err = tlsConn.Handshake() + if err != nil { + if c.logger.IsDebug() { + c.logger.Debug("error handshaking cluster connection", "error", err) + } + tlsConn.Close() + continue + } + + switch tlsConn.ConnectionState().NegotiatedProtocol { + case requestForwardingALPN: + if !ha { + tlsConn.Close() + continue + } + + c.logger.Debug("got request forwarding connection") + + shutdownWg.Add(2) + // quitCh is used to close the connection and the second + // goroutine if the server closes before closeCh. + quitCh := make(chan struct{}) + go func() { + select { + case <-quitCh: + case <-closeCh: + } + tlsConn.Close() + shutdownWg.Done() + }() + + go func() { + fws.ServeConn(tlsConn, &http2.ServeConnOpts{ + Handler: fwRPCServer, + }) + // close the quitCh which will close the connection and + // the other goroutine. + close(quitCh) + shutdownWg.Done() + }() + + default: + c.logger.Debug("unknown negotiated protocol on cluster port") + tlsConn.Close() + continue + } + } + }() + } + + // This is in its own goroutine so that we don't block the main thread, and + // thus we use atomic and channels to coordinate + // However, because you can't query the status of a channel, we set a bool + // here while we have the state lock to know whether to actually send a + // shutdown (e.g. whether the channel will block). See issue #2083. + c.clusterListenersRunning = true + go func() { + // If we get told to shut down... + <-c.clusterListenerShutdownCh + + // Stop the RPC server + c.logger.Info("shutting down forwarding rpc listeners") + fwRPCServer.Stop() + + // Set the shutdown flag. This will cause the listeners to shut down + // within the deadline in clusterListenerAcceptDeadline + atomic.StoreUint32(&shutdown, 1) + c.logger.Info("forwarding rpc listeners stopped") + + // Wait for them all to shut down + shutdownWg.Wait() + c.logger.Info("rpc listeners successfully shut down") + + // Clear us up to run this function again + atomic.StoreUint32(c.rpcServerActive, 0) + + // Tell the main thread that shutdown is done. + c.clusterListenerShutdownSuccessCh <- struct{}{} + }() + + return nil +} + +// refreshRequestForwardingConnection ensures that the client/transport are +// alive and that the current active address value matches the most +// recently-known address. +func (c *Core) refreshRequestForwardingConnection(ctx context.Context, clusterAddr string) error { + c.logger.Debug("refreshing forwarding connection") + defer c.logger.Debug("done refreshing forwarding connection") + + c.requestForwardingConnectionLock.Lock() + defer c.requestForwardingConnectionLock.Unlock() + + // Clean things up first + c.clearForwardingClients() + + // If we don't have anything to connect to, just return + if clusterAddr == "" { + return nil + } + + clusterURL, err := url.Parse(clusterAddr) + if err != nil { + c.logger.Error("error parsing cluster address attempting to refresh forwarding connection", "error", err) + return err + } + + // Set up grpc forwarding handling + // It's not really insecure, but we have to dial manually to get the + // ALPN header right. It's just "insecure" because GRPC isn't managing + // the TLS state. + dctx, cancelFunc := context.WithCancel(ctx) + c.rpcClientConn, err = grpc.DialContext(dctx, clusterURL.Host, + grpc.WithDialer(c.getGRPCDialer(ctx, requestForwardingALPN, "", nil, nil)), + grpc.WithInsecure(), // it's not, we handle it in the dialer + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 2 * HeartbeatInterval, + }), + grpc.WithDefaultCallOptions( + grpc.MaxCallRecvMsgSize(math.MaxInt32), + grpc.MaxCallSendMsgSize(math.MaxInt32), + )) + if err != nil { + cancelFunc() + c.logger.Error("err setting up forwarding rpc client", "error", err) + return err + } + c.rpcClientConnContext = dctx + c.rpcClientConnCancelFunc = cancelFunc + c.rpcForwardingClient = &forwardingClient{ + RequestForwardingClient: NewRequestForwardingClient(c.rpcClientConn), + core: c, + echoTicker: time.NewTicker(HeartbeatInterval), + echoContext: dctx, + } + c.rpcForwardingClient.startHeartbeat() + + return nil +} + +func (c *Core) clearForwardingClients() { + c.logger.Debug("clearing forwarding clients") + defer c.logger.Debug("done clearing forwarding clients") + + if c.rpcClientConnCancelFunc != nil { + c.rpcClientConnCancelFunc() + c.rpcClientConnCancelFunc = nil + } + if c.rpcClientConn != nil { + c.rpcClientConn.Close() + c.rpcClientConn = nil + } + + c.rpcClientConnContext = nil + c.rpcForwardingClient = nil +} + +// ForwardRequest forwards a given request to the active node and returns the +// response. +func (c *Core) ForwardRequest(req *http.Request) (int, http.Header, []byte, error) { + c.requestForwardingConnectionLock.RLock() + defer c.requestForwardingConnectionLock.RUnlock() + + if c.rpcForwardingClient == nil { + return 0, nil, nil, ErrCannotForward + } + + freq, err := forwarding.GenerateForwardedRequest(req) + if err != nil { + c.logger.Error("error creating forwarding RPC request", "error", err) + return 0, nil, nil, fmt.Errorf("error creating forwarding RPC request") + } + if freq == nil { + c.logger.Error("got nil forwarding RPC request") + return 0, nil, nil, fmt.Errorf("got nil forwarding RPC request") + } + resp, err := c.rpcForwardingClient.ForwardRequest(c.rpcClientConnContext, freq) + if err != nil { + c.logger.Error("error during forwarded RPC request", "error", err) + return 0, nil, nil, fmt.Errorf("error during forwarding RPC request") + } + + var header http.Header + if resp.HeaderEntries != nil { + header = make(http.Header) + for k, v := range resp.HeaderEntries { + header[k] = v.Values + } + } + + return int(resp.StatusCode), header, resp.Body, nil +} + +// getGRPCDialer is used to return a dialer that has the correct TLS +// configuration. Otherwise gRPC tries to be helpful and stomps all over our +// NextProtos. +func (c *Core) getGRPCDialer(ctx context.Context, alpnProto, serverName string, caCert *x509.Certificate, repClusters *ReplicatedClusters) func(string, time.Duration) (net.Conn, error) { + return func(addr string, timeout time.Duration) (net.Conn, error) { + tlsConfig, err := c.ClusterTLSConfig(ctx, repClusters) + if err != nil { + c.logger.Error("failed to get tls configuration", "error", err) + return nil, err + } + if serverName != "" { + tlsConfig.ServerName = serverName + } + if caCert != nil { + pool := x509.NewCertPool() + pool.AddCert(caCert) + tlsConfig.RootCAs = pool + tlsConfig.ClientCAs = pool + } + c.logger.Debug("creating rpc dialer", "host", tlsConfig.ServerName) + + tlsConfig.NextProtos = []string{alpnProto} + dialer := &net.Dialer{ + Timeout: timeout, + } + return tls.DialWithDialer(dialer, "tcp", addr, tlsConfig) + } +} + +type forwardedRequestRPCServer struct { + core *Core + handler http.Handler +} + +func (s *forwardedRequestRPCServer) ForwardRequest(ctx context.Context, freq *forwarding.Request) (*forwarding.Response, error) { + //s.core.logger.Debug("forwarding: serving rpc forwarded request") + + // Parse an http.Request out of it + req, err := forwarding.ParseForwardedRequest(freq) + if err != nil { + return nil, err + } + + // A very dummy response writer that doesn't follow normal semantics, just + // lets you write a status code (last written wins) and a body. But it + // meets the interface requirements. + w := forwarding.NewRPCResponseWriter() + + resp := &forwarding.Response{} + + runRequest := func() { + defer func() { + // Logic here comes mostly from the Go source code + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + s.core.logger.Error("forwarding: panic serving request", "path", req.URL.Path, "error", err, "stacktrace", string(buf)) + } + }() + s.handler.ServeHTTP(w, req) + } + runRequest() + resp.StatusCode = uint32(w.StatusCode()) + resp.Body = w.Body().Bytes() + + header := w.Header() + if header != nil { + resp.HeaderEntries = make(map[string]*forwarding.HeaderEntry, len(header)) + for k, v := range header { + resp.HeaderEntries[k] = &forwarding.HeaderEntry{ + Values: v, + } + } + } + + return resp, nil +} + +func (s *forwardedRequestRPCServer) Echo(ctx context.Context, in *EchoRequest) (*EchoReply, error) { + if in.ClusterAddr != "" { + s.core.clusterPeerClusterAddrsCache.Set(in.ClusterAddr, nil, 0) + } + return &EchoReply{ + Message: "pong", + ReplicationState: uint32(s.core.ReplicationState()), + }, nil +} + +type forwardingClient struct { + RequestForwardingClient + + core *Core + + echoTicker *time.Ticker + echoContext context.Context +} + +// NOTE: we also take advantage of gRPC's keepalive bits, but as we send data +// with these requests it's useful to keep this as well +func (c *forwardingClient) startHeartbeat() { + go func() { + tick := func() { + c.core.stateLock.RLock() + clusterAddr := c.core.clusterAddr + c.core.stateLock.RUnlock() + + ctx, cancel := context.WithTimeout(c.echoContext, 2*time.Second) + resp, err := c.RequestForwardingClient.Echo(ctx, &EchoRequest{ + Message: "ping", + ClusterAddr: clusterAddr, + }) + cancel() + if err != nil { + c.core.logger.Debug("forwarding: error sending echo request to active node", "error", err) + return + } + if resp == nil { + c.core.logger.Debug("forwarding: empty echo response from active node") + return + } + if resp.Message != "pong" { + c.core.logger.Debug("forwarding: unexpected echo response from active node", "message", resp.Message) + return + } + // Store the active node's replication state to display in + // sys/health calls + atomic.StoreUint32(c.core.activeNodeReplicationState, resp.ReplicationState) + //c.core.logger.Debug("forwarding: successful heartbeat") + } + + tick() + + for { + select { + case <-c.echoContext.Done(): + c.echoTicker.Stop() + c.core.logger.Debug("forwarding: stopping heartbeating") + atomic.StoreUint32(c.core.activeNodeReplicationState, uint32(consts.ReplicationUnknown)) + return + case <-c.echoTicker.C: + tick() + } + } + }() +} diff --git a/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.pb.go b/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.pb.go new file mode 100644 index 0000000..cfe1024 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.pb.go @@ -0,0 +1,274 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: vault/request_forwarding_service.proto + +package vault // import "github.com/hashicorp/vault/vault" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import forwarding "github.com/hashicorp/vault/helper/forwarding" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type EchoRequest struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + // ClusterAddr is used to send up a standby node's address to the active + // node upon heartbeat + ClusterAddr string `protobuf:"bytes,2,opt,name=cluster_addr,json=clusterAddr" json:"cluster_addr,omitempty"` + // ClusterAddrs is used to send up a list of cluster addresses to a dr + // primary from a dr secondary + ClusterAddrs []string `protobuf:"bytes,3,rep,name=cluster_addrs,json=clusterAddrs" json:"cluster_addrs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EchoRequest) Reset() { *m = EchoRequest{} } +func (m *EchoRequest) String() string { return proto.CompactTextString(m) } +func (*EchoRequest) ProtoMessage() {} +func (*EchoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_request_forwarding_service_2fdb694b57983716, []int{0} +} +func (m *EchoRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EchoRequest.Unmarshal(m, b) +} +func (m *EchoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EchoRequest.Marshal(b, m, deterministic) +} +func (dst *EchoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EchoRequest.Merge(dst, src) +} +func (m *EchoRequest) XXX_Size() int { + return xxx_messageInfo_EchoRequest.Size(m) +} +func (m *EchoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EchoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EchoRequest proto.InternalMessageInfo + +func (m *EchoRequest) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *EchoRequest) GetClusterAddr() string { + if m != nil { + return m.ClusterAddr + } + return "" +} + +func (m *EchoRequest) GetClusterAddrs() []string { + if m != nil { + return m.ClusterAddrs + } + return nil +} + +type EchoReply struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + ClusterAddrs []string `protobuf:"bytes,2,rep,name=cluster_addrs,json=clusterAddrs" json:"cluster_addrs,omitempty"` + ReplicationState uint32 `protobuf:"varint,3,opt,name=replication_state,json=replicationState" json:"replication_state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EchoReply) Reset() { *m = EchoReply{} } +func (m *EchoReply) String() string { return proto.CompactTextString(m) } +func (*EchoReply) ProtoMessage() {} +func (*EchoReply) Descriptor() ([]byte, []int) { + return fileDescriptor_request_forwarding_service_2fdb694b57983716, []int{1} +} +func (m *EchoReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EchoReply.Unmarshal(m, b) +} +func (m *EchoReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EchoReply.Marshal(b, m, deterministic) +} +func (dst *EchoReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_EchoReply.Merge(dst, src) +} +func (m *EchoReply) XXX_Size() int { + return xxx_messageInfo_EchoReply.Size(m) +} +func (m *EchoReply) XXX_DiscardUnknown() { + xxx_messageInfo_EchoReply.DiscardUnknown(m) +} + +var xxx_messageInfo_EchoReply proto.InternalMessageInfo + +func (m *EchoReply) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *EchoReply) GetClusterAddrs() []string { + if m != nil { + return m.ClusterAddrs + } + return nil +} + +func (m *EchoReply) GetReplicationState() uint32 { + if m != nil { + return m.ReplicationState + } + return 0 +} + +func init() { + proto.RegisterType((*EchoRequest)(nil), "vault.EchoRequest") + proto.RegisterType((*EchoReply)(nil), "vault.EchoReply") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// RequestForwardingClient is the client API for RequestForwarding service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RequestForwardingClient interface { + ForwardRequest(ctx context.Context, in *forwarding.Request, opts ...grpc.CallOption) (*forwarding.Response, error) + Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoReply, error) +} + +type requestForwardingClient struct { + cc *grpc.ClientConn +} + +func NewRequestForwardingClient(cc *grpc.ClientConn) RequestForwardingClient { + return &requestForwardingClient{cc} +} + +func (c *requestForwardingClient) ForwardRequest(ctx context.Context, in *forwarding.Request, opts ...grpc.CallOption) (*forwarding.Response, error) { + out := new(forwarding.Response) + err := c.cc.Invoke(ctx, "/vault.RequestForwarding/ForwardRequest", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *requestForwardingClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoReply, error) { + out := new(EchoReply) + err := c.cc.Invoke(ctx, "/vault.RequestForwarding/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RequestForwardingServer is the server API for RequestForwarding service. +type RequestForwardingServer interface { + ForwardRequest(context.Context, *forwarding.Request) (*forwarding.Response, error) + Echo(context.Context, *EchoRequest) (*EchoReply, error) +} + +func RegisterRequestForwardingServer(s *grpc.Server, srv RequestForwardingServer) { + s.RegisterService(&_RequestForwarding_serviceDesc, srv) +} + +func _RequestForwarding_ForwardRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(forwarding.Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RequestForwardingServer).ForwardRequest(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vault.RequestForwarding/ForwardRequest", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RequestForwardingServer).ForwardRequest(ctx, req.(*forwarding.Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _RequestForwarding_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EchoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RequestForwardingServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vault.RequestForwarding/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RequestForwardingServer).Echo(ctx, req.(*EchoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _RequestForwarding_serviceDesc = grpc.ServiceDesc{ + ServiceName: "vault.RequestForwarding", + HandlerType: (*RequestForwardingServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ForwardRequest", + Handler: _RequestForwarding_ForwardRequest_Handler, + }, + { + MethodName: "Echo", + Handler: _RequestForwarding_Echo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "vault/request_forwarding_service.proto", +} + +func init() { + proto.RegisterFile("vault/request_forwarding_service.proto", fileDescriptor_request_forwarding_service_2fdb694b57983716) +} + +var fileDescriptor_request_forwarding_service_2fdb694b57983716 = []byte{ + // 297 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xfb, 0x40, + 0x10, 0xc5, 0x9b, 0xf6, 0xff, 0x57, 0xba, 0x6d, 0xa5, 0x5d, 0x3d, 0x84, 0x82, 0x10, 0x23, 0x48, + 0x40, 0xd8, 0x80, 0x9e, 0x3d, 0x28, 0xe8, 0x07, 0x88, 0x37, 0x2f, 0x61, 0xbb, 0x19, 0x93, 0x85, + 0x6d, 0x76, 0xdd, 0xd9, 0xb4, 0xe4, 0xea, 0x27, 0x97, 0x26, 0xa9, 0x4d, 0x29, 0x78, 0x19, 0x98, + 0x37, 0x8f, 0x37, 0xcc, 0x6f, 0xc8, 0xdd, 0x86, 0x57, 0xca, 0xc5, 0x16, 0xbe, 0x2a, 0x40, 0x97, + 0x7e, 0x6a, 0xbb, 0xe5, 0x36, 0x93, 0x65, 0x9e, 0x22, 0xd8, 0x8d, 0x14, 0xc0, 0x8c, 0xd5, 0x4e, + 0xd3, 0xff, 0x8d, 0x6f, 0x79, 0x5d, 0x80, 0x32, 0x60, 0xe3, 0x83, 0x2f, 0x76, 0xb5, 0x01, 0x6c, + 0x5d, 0xa1, 0x26, 0x93, 0x57, 0x51, 0xe8, 0xa4, 0x4d, 0xa3, 0x3e, 0x39, 0x5f, 0x03, 0x22, 0xcf, + 0xc1, 0xf7, 0x02, 0x2f, 0x1a, 0x27, 0xfb, 0x96, 0xde, 0x90, 0xa9, 0x50, 0x15, 0x3a, 0xb0, 0x29, + 0xcf, 0x32, 0xeb, 0x0f, 0x9b, 0xf1, 0xa4, 0xd3, 0x9e, 0xb3, 0xcc, 0xd2, 0x5b, 0x32, 0xeb, 0x5b, + 0xd0, 0x1f, 0x05, 0xa3, 0x68, 0x9c, 0x4c, 0x7b, 0x1e, 0x0c, 0xb7, 0x64, 0xdc, 0x2e, 0x34, 0xaa, + 0xfe, 0x63, 0xdd, 0x49, 0xd6, 0xf0, 0x34, 0x8b, 0xde, 0x93, 0x85, 0x05, 0xa3, 0xa4, 0xe0, 0x4e, + 0xea, 0x32, 0x45, 0xc7, 0x1d, 0xf8, 0xa3, 0xc0, 0x8b, 0x66, 0xc9, 0xbc, 0x37, 0x78, 0xdf, 0xe9, + 0x0f, 0xdf, 0x1e, 0x59, 0x74, 0x67, 0xbe, 0xfd, 0xb2, 0xa0, 0x4f, 0xe4, 0xa2, 0xeb, 0xf6, 0x08, + 0x2e, 0xd9, 0x01, 0x15, 0xeb, 0xc4, 0xe5, 0xd5, 0xb1, 0x88, 0x46, 0x97, 0x08, 0xe1, 0x80, 0x32, + 0xf2, 0x6f, 0x77, 0x0d, 0xa5, 0xac, 0xa1, 0xcd, 0x7a, 0x2c, 0x97, 0xf3, 0x23, 0xcd, 0xa8, 0x3a, + 0x1c, 0xbc, 0x84, 0x1f, 0x41, 0x2e, 0x5d, 0x51, 0xad, 0x98, 0xd0, 0xeb, 0xb8, 0xe0, 0x58, 0x48, + 0xa1, 0xad, 0x89, 0xdb, 0x9f, 0x36, 0x75, 0x75, 0xd6, 0x7c, 0xe6, 0xf1, 0x27, 0x00, 0x00, 0xff, + 0xff, 0xfe, 0x9f, 0x88, 0xc6, 0xe9, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.proto b/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.proto new file mode 100644 index 0000000..ba32f7d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_forwarding_service.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +option go_package = "github.com/hashicorp/vault/vault"; + +import "helper/forwarding/types.proto"; + +package vault; + +message EchoRequest { + string message = 1; + // ClusterAddr is used to send up a standby node's address to the active + // node upon heartbeat + string cluster_addr = 2; + // ClusterAddrs is used to send up a list of cluster addresses to a dr + // primary from a dr secondary + repeated string cluster_addrs = 3; +} + +message EchoReply { + string message = 1; + repeated string cluster_addrs = 2; + uint32 replication_state = 3; +} + +service RequestForwarding { + rpc ForwardRequest(forwarding.Request) returns (forwarding.Response) {} + rpc Echo(EchoRequest) returns (EchoReply) {} +} diff --git a/vendor/github.com/hashicorp/vault/vault/request_handling.go b/vendor/github.com/hashicorp/vault/vault/request_handling.go new file mode 100644 index 0000000..cfde6f4 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_handling.go @@ -0,0 +1,830 @@ +package vault + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/armon/go-metrics" + "github.com/hashicorp/go-multierror" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/policyutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/helper/wrapping" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +const ( + replTimeout = 10 * time.Second +) + +// fetchEntityAndDerivedPolicies returns the entity object for the given entity +// ID. If the entity is merged into a different entity object, the entity into +// which the given entity ID is merged into will be returned. This function +// also returns the cumulative list of policies that the entity is entitled to. +// This list includes the policies from the entity itself and from all the +// groups in which the given entity ID is a member of. +func (c *Core) fetchEntityAndDerivedPolicies(entityID string) (*identity.Entity, []string, error) { + if entityID == "" || c.identityStore == nil { + return nil, nil, nil + } + + //c.logger.Debug("entity set on the token", "entity_id", te.EntityID) + + // Fetch the entity + entity, err := c.identityStore.MemDBEntityByID(entityID, false) + if err != nil { + c.logger.Error("failed to lookup entity using its ID", "error", err) + return nil, nil, err + } + + if entity == nil { + // If there was no corresponding entity object found, it is + // possible that the entity got merged into another entity. Try + // finding entity based on the merged entity index. + entity, err = c.identityStore.MemDBEntityByMergedEntityID(entityID, false) + if err != nil { + c.logger.Error("failed to lookup entity in merged entity ID index", "error", err) + return nil, nil, err + } + } + + var policies []string + if entity != nil { + //c.logger.Debug("entity successfully fetched; adding entity policies to token's policies to create ACL") + + // Attach the policies on the entity + policies = append(policies, entity.Policies...) + + groupPolicies, err := c.identityStore.groupPoliciesByEntityID(entity.ID) + if err != nil { + c.logger.Error("failed to fetch group policies", "error", err) + return nil, nil, err + } + + // Attach the policies from all the groups + policies = append(policies, groupPolicies...) + } + + return entity, policies, err +} + +func (c *Core) fetchACLTokenEntryAndEntity(req *logical.Request) (*ACL, *TokenEntry, *identity.Entity, error) { + defer metrics.MeasureSince([]string{"core", "fetch_acl_and_token"}, time.Now()) + + // Ensure there is a client token + if req.ClientToken == "" { + return nil, nil, nil, fmt.Errorf("missing client token") + } + + if c.tokenStore == nil { + c.logger.Error("token store is unavailable") + return nil, nil, nil, ErrInternalError + } + + // Resolve the token policy + te, err := c.tokenStore.Lookup(c.activeContext, req.ClientToken) + if err != nil { + c.logger.Error("failed to lookup token", "error", err) + return nil, nil, nil, ErrInternalError + } + + // Ensure the token is valid + if te == nil { + return nil, nil, nil, logical.ErrPermissionDenied + } + + // CIDR checks bind all tokens except non-expiring root tokens + if te.TTL != 0 && len(te.BoundCIDRs) > 0 { + var valid bool + remoteSockAddr, err := sockaddr.NewSockAddr(req.Connection.RemoteAddr) + if err != nil { + if c.Logger().IsDebug() { + c.Logger().Debug("could not parse remote addr into sockaddr", "error", err, "remote_addr", req.Connection.RemoteAddr) + } + return nil, nil, nil, logical.ErrPermissionDenied + } + for _, cidr := range te.BoundCIDRs { + if cidr.Contains(remoteSockAddr) { + valid = true + break + } + } + if !valid { + return nil, nil, nil, logical.ErrPermissionDenied + } + } + + tokenPolicies := te.Policies + + entity, derivedPolicies, err := c.fetchEntityAndDerivedPolicies(te.EntityID) + if err != nil { + return nil, nil, nil, ErrInternalError + } + + tokenPolicies = append(tokenPolicies, derivedPolicies...) + + // Construct the corresponding ACL object + acl, err := c.policyStore.ACL(c.activeContext, tokenPolicies...) + if err != nil { + c.logger.Error("failed to construct ACL", "error", err) + return nil, nil, nil, ErrInternalError + } + + return acl, te, entity, nil +} + +func (c *Core) checkToken(ctx context.Context, req *logical.Request, unauth bool) (*logical.Auth, *TokenEntry, error) { + defer metrics.MeasureSince([]string{"core", "check_token"}, time.Now()) + + var acl *ACL + var te *TokenEntry + var entity *identity.Entity + var err error + + // Even if unauth, if a token is provided, there's little reason not to + // gather as much info as possible for the audit log and to e.g. control + // trace mode for EGPs. + if !unauth || (unauth && req.ClientToken != "") { + acl, te, entity, err = c.fetchACLTokenEntryAndEntity(req) + // In the unauth case we don't want to fail the command, since it's + // unauth, we just have no information to attach to the request, so + // ignore errors...this was best-effort anyways + if err != nil && !unauth { + return nil, te, err + } + } + + if entity != nil && entity.Disabled { + return nil, te, logical.ErrPermissionDenied + } + + // Check if this is a root protected path + rootPath := c.router.RootPath(req.Path) + + if rootPath && unauth { + return nil, nil, errors.New("cannot access root path in unauthenticated request") + } + + // When we receive a write of either type, rather than require clients to + // PUT/POST and trust the operation, we ask the backend to give us the real + // skinny -- if the backend implements an existence check, it can tell us + // whether a particular resource exists. Then we can mark it as an update + // or creation as appropriate. + if req.Operation == logical.CreateOperation || req.Operation == logical.UpdateOperation { + checkExists, resourceExists, err := c.router.RouteExistenceCheck(ctx, req) + switch err { + case logical.ErrUnsupportedPath: + // fail later via bad path to avoid confusing items in the log + checkExists = false + case nil: + // Continue on + default: + c.logger.Error("failed to run existence check", "error", err) + if _, ok := err.(errutil.UserError); ok { + return nil, nil, err + } else { + return nil, nil, ErrInternalError + } + } + + switch { + case checkExists == false: + // No existence check, so always treat it as an update operation, which is how it is pre 0.5 + req.Operation = logical.UpdateOperation + case resourceExists == true: + // It exists, so force an update operation + req.Operation = logical.UpdateOperation + case resourceExists == false: + // It doesn't exist, force a create operation + req.Operation = logical.CreateOperation + default: + panic("unreachable code") + } + } + // Create the auth response + auth := &logical.Auth{ + ClientToken: req.ClientToken, + Accessor: req.ClientTokenAccessor, + } + + if te != nil { + auth.Policies = te.Policies + auth.Metadata = te.Meta + auth.DisplayName = te.DisplayName + auth.EntityID = te.EntityID + // Store the entity ID in the request object + req.EntityID = te.EntityID + } + + // Check the standard non-root ACLs. Return the token entry if it's not + // allowed so we can decrement the use count. + authResults := c.performPolicyChecks(ctx, acl, te, req, entity, &PolicyCheckOpts{ + Unauth: unauth, + RootPrivsRequired: rootPath, + }) + if authResults.Error.ErrorOrNil() != nil { + return auth, te, authResults.Error + } + if !authResults.Allowed { + // Return auth for audit logging even if not allowed + return auth, te, logical.ErrPermissionDenied + } + + return auth, te, nil +} + +// HandleRequest is used to handle a new incoming request +func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err error) { + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, consts.ErrSealed + } + if c.standby { + return nil, consts.ErrStandby + } + + ctx, cancel := context.WithCancel(c.activeContext) + defer cancel() + + // Allowing writing to a path ending in / makes it extremely difficult to + // understand user intent for the filesystem-like backends (kv, + // cubbyhole) -- did they want a key named foo/ or did they want to write + // to a directory foo/ with no (or forgotten) key, or...? It also affects + // lookup, because paths ending in / are considered prefixes by some + // backends. Basically, it's all just terrible, so don't allow it. + if strings.HasSuffix(req.Path, "/") && + (req.Operation == logical.UpdateOperation || + req.Operation == logical.CreateOperation) { + return logical.ErrorResponse("cannot write to a path ending in '/'"), nil + } + + var auth *logical.Auth + if c.router.LoginPath(req.Path) { + resp, auth, err = c.handleLoginRequest(ctx, req) + } else { + resp, auth, err = c.handleRequest(ctx, req) + } + + // Ensure we don't leak internal data + if resp != nil { + if resp.Secret != nil { + resp.Secret.InternalData = nil + } + if resp.Auth != nil { + resp.Auth.InternalData = nil + } + } + + // We are wrapping if there is anything to wrap (not a nil response) and a + // TTL was specified for the token. Errors on a call should be returned to + // the caller, so wrapping is turned off if an error is hit and the error + // is logged to the audit log. + wrapping := resp != nil && + err == nil && + !resp.IsError() && + resp.WrapInfo != nil && + resp.WrapInfo.TTL != 0 && + resp.WrapInfo.Token == "" + + if wrapping { + cubbyResp, cubbyErr := c.wrapInCubbyhole(ctx, req, resp, auth) + // If not successful, returns either an error response from the + // cubbyhole backend or an error; if either is set, set resp and err to + // those and continue so that that's what we audit log. Otherwise + // finish the wrapping and audit log that. + if cubbyResp != nil || cubbyErr != nil { + resp = cubbyResp + err = cubbyErr + } else { + wrappingResp := &logical.Response{ + WrapInfo: resp.WrapInfo, + Warnings: resp.Warnings, + } + resp = wrappingResp + } + } + + auditResp := resp + // When unwrapping we want to log the actual response that will be written + // out. We still want to return the raw value to avoid automatic updating + // to any of it. + if req.Path == "sys/wrapping/unwrap" && + resp != nil && + resp.Data != nil && + resp.Data[logical.HTTPRawBody] != nil { + + // Decode the JSON + if resp.Data[logical.HTTPRawBodyAlreadyJSONDecoded] != nil { + delete(resp.Data, logical.HTTPRawBodyAlreadyJSONDecoded) + } else { + httpResp := &logical.HTTPResponse{} + err := jsonutil.DecodeJSON(resp.Data[logical.HTTPRawBody].([]byte), httpResp) + if err != nil { + c.logger.Error("failed to unmarshal wrapped HTTP response for audit logging", "error", err) + return nil, ErrInternalError + } + + auditResp = logical.HTTPResponseToLogicalResponse(httpResp) + } + } + + var nonHMACReqDataKeys []string + var nonHMACRespDataKeys []string + entry := c.router.MatchingMountEntry(req.Path) + if entry != nil { + // Get and set ignored HMAC'd value. Reset those back to empty afterwards. + if rawVals, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + nonHMACReqDataKeys = rawVals.([]string) + } + + // Get and set ignored HMAC'd value. Reset those back to empty afterwards. + if auditResp != nil { + if rawVals, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + nonHMACRespDataKeys = rawVals.([]string) + } + } + } + + // Create an audit trail of the response + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + Response: auditResp, + OuterErr: err, + NonHMACReqDataKeys: nonHMACReqDataKeys, + NonHMACRespDataKeys: nonHMACRespDataKeys, + } + if auditErr := c.auditBroker.LogResponse(ctx, logInput, c.auditedHeaders); auditErr != nil { + c.logger.Error("failed to audit response", "request_path", req.Path, "error", auditErr) + return nil, ErrInternalError + } + + return +} + +func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp *logical.Response, retAuth *logical.Auth, retErr error) { + defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now()) + + var nonHMACReqDataKeys []string + entry := c.router.MatchingMountEntry(req.Path) + if entry != nil { + // Get and set ignored HMAC'd value. + if rawVals, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + nonHMACReqDataKeys = rawVals.([]string) + } + } + + // Validate the token + auth, te, ctErr := c.checkToken(ctx, req, false) + // We run this logic first because we want to decrement the use count even in the case of an error + if te != nil { + // Attempt to use the token (decrement NumUses) + var err error + te, err = c.tokenStore.UseToken(ctx, te) + if err != nil { + c.logger.Error("failed to use token", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, nil, retErr + } + if te == nil { + // Token has been revoked by this point + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + return nil, nil, retErr + } + if te.NumUses == tokenRevocationPending { + // We defer a revocation until after logic has run, since this is a + // valid request (this is the token's final use). We pass the ID in + // directly just to be safe in case something else modifies te later. + defer func(id string) { + leaseID, err := c.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err == nil { + err = c.expiration.Revoke(leaseID) + } + if err != nil { + c.logger.Error("failed to revoke token", "error", err) + retResp = nil + retAuth = nil + retErr = multierror.Append(retErr, ErrInternalError) + } + if retResp != nil && retResp.Secret != nil && + // Some backends return a TTL even without a Lease ID + retResp.Secret.LeaseID != "" { + retResp = logical.ErrorResponse("Secret cannot be returned; token had one use left, so leased credentials were immediately revoked.") + return + } + }(te.ID) + } + } + if ctErr != nil { + // If it is an internal error we return that, otherwise we + // return invalid request so that the status codes can be correct + errType := logical.ErrInvalidRequest + switch ctErr { + case ErrInternalError, logical.ErrPermissionDenied: + errType = ctErr + } + + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + OuterErr: ctErr, + NonHMACReqDataKeys: nonHMACReqDataKeys, + } + if err := c.auditBroker.LogRequest(ctx, logInput, c.auditedHeaders); err != nil { + c.logger.Error("failed to audit request", "path", req.Path, "error", err) + } + + if errType != nil { + retErr = multierror.Append(retErr, errType) + } + if ctErr == ErrInternalError { + return nil, auth, retErr + } + return logical.ErrorResponse(ctErr.Error()), auth, retErr + } + + // Attach the display name + req.DisplayName = auth.DisplayName + + // Create an audit trail of the request + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + NonHMACReqDataKeys: nonHMACReqDataKeys, + } + if err := c.auditBroker.LogRequest(ctx, logInput, c.auditedHeaders); err != nil { + c.logger.Error("failed to audit request", "path", req.Path, "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + + // Route the request + resp, routeErr := c.router.Route(ctx, req) + if resp != nil { + // If wrapping is used, use the shortest between the request and response + var wrapTTL time.Duration + var wrapFormat, creationPath string + var sealWrap bool + + // Ensure no wrap info information is set other than, possibly, the TTL + if resp.WrapInfo != nil { + if resp.WrapInfo.TTL > 0 { + wrapTTL = resp.WrapInfo.TTL + } + wrapFormat = resp.WrapInfo.Format + creationPath = resp.WrapInfo.CreationPath + sealWrap = resp.WrapInfo.SealWrap + resp.WrapInfo = nil + } + + if req.WrapInfo != nil { + if req.WrapInfo.TTL > 0 { + switch { + case wrapTTL == 0: + wrapTTL = req.WrapInfo.TTL + case req.WrapInfo.TTL < wrapTTL: + wrapTTL = req.WrapInfo.TTL + } + } + // If the wrap format hasn't been set by the response, set it to + // the request format + if req.WrapInfo.Format != "" && wrapFormat == "" { + wrapFormat = req.WrapInfo.Format + } + } + + if wrapTTL > 0 { + resp.WrapInfo = &wrapping.ResponseWrapInfo{ + TTL: wrapTTL, + Format: wrapFormat, + CreationPath: creationPath, + SealWrap: sealWrap, + } + } + } + + // If there is a secret, we must register it with the expiration manager. + // We exclude renewal of a lease, since it does not need to be re-registered + if resp != nil && resp.Secret != nil && !strings.HasPrefix(req.Path, "sys/renew") && + !strings.HasPrefix(req.Path, "sys/leases/renew") { + // KV mounts should return the TTL but not register + // for a lease as this provides a massive slowdown + registerLease := true + + matchingMountEntry := c.router.MatchingMountEntry(req.Path) + if matchingMountEntry == nil { + c.logger.Error("unable to retrieve kv mount entry from router") + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + + switch matchingMountEntry.Type { + case "kv", "generic": + // If we are kv type, first see if we are an older passthrough + // backend, and otherwise check the mount entry options. + matchingBackend := c.router.MatchingBackend(req.Path) + if matchingBackend == nil { + c.logger.Error("unable to retrieve kv backend from router") + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + + if ptbe, ok := matchingBackend.(*PassthroughBackend); ok { + if !ptbe.GeneratesLeases() { + registerLease = false + resp.Secret.Renewable = false + } + } else if matchingMountEntry.Options == nil || matchingMountEntry.Options["leased_passthrough"] != "true" { + registerLease = false + resp.Secret.Renewable = false + } + + case "plugin": + // If we are a plugin type and the plugin name is "kv" check the + // mount entry options. + if matchingMountEntry.Config.PluginName == "kv" && (matchingMountEntry.Options == nil || matchingMountEntry.Options["leased_passthrough"] != "true") { + registerLease = false + resp.Secret.Renewable = false + } + } + + if registerLease { + sysView := c.router.MatchingSystemView(req.Path) + if sysView == nil { + c.logger.Error("unable to look up sys view for login path", "request_path", req.Path) + return nil, nil, ErrInternalError + } + + ttl, warnings, err := framework.CalculateTTL(sysView, 0, resp.Secret.TTL, 0, resp.Secret.MaxTTL, 0, time.Time{}) + if err != nil { + return nil, nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) + } + resp.Secret.TTL = ttl + + leaseID, err := c.expiration.Register(req, resp) + if err != nil { + c.logger.Error("failed to register lease", "request_path", req.Path, "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + resp.Secret.LeaseID = leaseID + } + } + + // If the request was to renew a token, and if there are group aliases set + // in the auth object, then the group memberships should be refreshed + if strings.HasPrefix(req.Path, "auth/token/renew") && + resp != nil && + resp.Auth != nil && + resp.Auth.EntityID != "" && + resp.Auth.GroupAliases != nil && + c.identityStore != nil { + err := c.identityStore.refreshExternalGroupMembershipsByEntityID(resp.Auth.EntityID, resp.Auth.GroupAliases) + if err != nil { + c.logger.Error("failed to refresh external group memberships", "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + } + + // Only the token store is allowed to return an auth block, for any + // other request this is an internal error. We exclude renewal of a token, + // since it does not need to be re-registered + if resp != nil && resp.Auth != nil && !strings.HasPrefix(req.Path, "auth/token/renew") { + if !strings.HasPrefix(req.Path, "auth/token/") { + c.logger.Error("unexpected Auth response for non-token backend", "request_path", req.Path) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + + if err := c.expiration.RegisterAuth(resp.Auth.CreationPath, resp.Auth); err != nil { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to register token lease", "request_path", req.Path, "error", err) + retErr = multierror.Append(retErr, ErrInternalError) + return nil, auth, retErr + } + } + + if resp != nil && + req.Path == "cubbyhole/response" && + len(te.Policies) == 1 && + te.Policies[0] == responseWrappingPolicyName { + resp.AddWarning("Reading from 'cubbyhole/response' is deprecated. Please use sys/wrapping/unwrap to unwrap responses, as it provides additional security checks and other benefits.") + } + + // Return the response and error + if routeErr != nil { + retErr = multierror.Append(retErr, routeErr) + } + + return resp, auth, retErr +} + +// handleLoginRequest is used to handle a login request, which is an +// unauthenticated request to the backend. +func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (retResp *logical.Response, retAuth *logical.Auth, retErr error) { + defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now()) + + req.Unauthenticated = true + + var auth *logical.Auth + // Create an audit trail of the request, auth is not available on login requests + // Create an audit trail of the request. Attach auth if it was returned, + // e.g. if a token was provided. + logInput := &audit.LogInput{ + Auth: auth, + Request: req, + } + if err := c.auditBroker.LogRequest(ctx, logInput, c.auditedHeaders); err != nil { + c.logger.Error("failed to audit request", "path", req.Path, "error", err) + return nil, nil, ErrInternalError + } + + // The token store uses authentication even when creating a new token, + // so it's handled in handleRequest. It should not be reached here. + if strings.HasPrefix(req.Path, "auth/token/") { + c.logger.Error("unexpected login request for token backend", "request_path", req.Path) + return nil, nil, ErrInternalError + } + + // Route the request + resp, routeErr := c.router.Route(ctx, req) + if resp != nil { + // If wrapping is used, use the shortest between the request and response + var wrapTTL time.Duration + var wrapFormat, creationPath string + var sealWrap bool + + // Ensure no wrap info information is set other than, possibly, the TTL + if resp.WrapInfo != nil { + if resp.WrapInfo.TTL > 0 { + wrapTTL = resp.WrapInfo.TTL + } + wrapFormat = resp.WrapInfo.Format + creationPath = resp.WrapInfo.CreationPath + sealWrap = resp.WrapInfo.SealWrap + resp.WrapInfo = nil + } + + if req.WrapInfo != nil { + if req.WrapInfo.TTL > 0 { + switch { + case wrapTTL == 0: + wrapTTL = req.WrapInfo.TTL + case req.WrapInfo.TTL < wrapTTL: + wrapTTL = req.WrapInfo.TTL + } + } + if req.WrapInfo.Format != "" && wrapFormat == "" { + wrapFormat = req.WrapInfo.Format + } + } + + if wrapTTL > 0 { + resp.WrapInfo = &wrapping.ResponseWrapInfo{ + TTL: wrapTTL, + Format: wrapFormat, + CreationPath: creationPath, + SealWrap: sealWrap, + } + } + } + + // A login request should never return a secret! + if resp != nil && resp.Secret != nil { + c.logger.Error("unexpected Secret response for login path", "request_path", req.Path) + return nil, nil, ErrInternalError + } + + // If the response generated an authentication, then generate the token + if resp != nil && resp.Auth != nil { + + var entity *identity.Entity + auth = resp.Auth + + mEntry := c.router.MatchingMountEntry(req.Path) + + if auth.Alias != nil && + mEntry != nil && + !mEntry.Local && + c.identityStore != nil { + // Overwrite the mount type and mount path in the alias + // information + auth.Alias.MountType = req.MountType + auth.Alias.MountAccessor = req.MountAccessor + + if auth.Alias.Name == "" { + return nil, nil, fmt.Errorf("missing name in alias") + } + + var err error + + // Fetch the entity for the alias, or create an entity if one + // doesn't exist. + entity, err = c.identityStore.CreateOrFetchEntity(auth.Alias) + if err != nil { + return nil, nil, err + } + + if entity == nil { + return nil, nil, fmt.Errorf("failed to create an entity for the authenticated alias") + } + + if entity.Disabled { + return nil, nil, logical.ErrPermissionDenied + } + + auth.EntityID = entity.ID + if auth.GroupAliases != nil { + err = c.identityStore.refreshExternalGroupMembershipsByEntityID(auth.EntityID, auth.GroupAliases) + if err != nil { + return nil, nil, err + } + } + } + + if strutil.StrListSubset(auth.Policies, []string{"root"}) { + return logical.ErrorResponse("auth methods cannot create root tokens"), nil, logical.ErrInvalidRequest + } + + // Determine the source of the login + source := c.router.MatchingMount(req.Path) + source = strings.TrimPrefix(source, credentialRoutePrefix) + source = strings.Replace(source, "/", "-", -1) + + // Prepend the source to the display name + auth.DisplayName = strings.TrimSuffix(source+auth.DisplayName, "-") + + sysView := c.router.MatchingSystemView(req.Path) + if sysView == nil { + c.logger.Error("unable to look up sys view for login path", "request_path", req.Path) + return nil, nil, ErrInternalError + } + + tokenTTL, warnings, err := framework.CalculateTTL(sysView, 0, auth.TTL, auth.Period, auth.MaxTTL, auth.ExplicitMaxTTL, time.Time{}) + if err != nil { + return nil, nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) + } + + // Generate a token + te := TokenEntry{ + Path: req.Path, + Policies: auth.Policies, + Meta: auth.Metadata, + DisplayName: auth.DisplayName, + CreationTime: time.Now().Unix(), + TTL: tokenTTL, + NumUses: auth.NumUses, + EntityID: auth.EntityID, + BoundCIDRs: auth.BoundCIDRs, + } + + te.Policies = policyutil.SanitizePolicies(te.Policies, true) + + // Prevent internal policies from being assigned to tokens + for _, policy := range te.Policies { + if strutil.StrListContains(nonAssignablePolicies, policy) { + return logical.ErrorResponse(fmt.Sprintf("cannot assign policy %q", policy)), nil, logical.ErrInvalidRequest + } + } + + if err := c.tokenStore.create(ctx, &te); err != nil { + c.logger.Error("failed to create token", "error", err) + return nil, auth, ErrInternalError + } + + // Populate the client token, accessor, and TTL + auth.ClientToken = te.ID + auth.Accessor = te.Accessor + auth.Policies = te.Policies + auth.TTL = te.TTL + + // Register with the expiration manager + if err := c.expiration.RegisterAuth(te.Path, auth); err != nil { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to register token lease", "request_path", req.Path, "error", err) + return nil, auth, ErrInternalError + } + + // Attach the display name, might be used by audit backends + req.DisplayName = auth.DisplayName + } + + return resp, auth, routeErr +} diff --git a/vendor/github.com/hashicorp/vault/vault/rollback.go b/vendor/github.com/hashicorp/vault/vault/rollback.go new file mode 100644 index 0000000..9954246 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/rollback.go @@ -0,0 +1,244 @@ +package vault + +import ( + "context" + "strings" + "sync" + "time" + + log "github.com/hashicorp/go-hclog" + + "github.com/armon/go-metrics" + "github.com/hashicorp/vault/logical" +) + +const ( + // rollbackPeriod is how often we attempt rollbacks for all the backends + rollbackPeriod = time.Minute +) + +// RollbackManager is responsible for performing rollbacks of partial +// secrets within logical backends. +// +// During normal operations, it is possible for logical backends to +// error partially through an operation. These are called "partial secrets": +// they are never sent back to a user, but they do need to be cleaned up. +// This manager handles that by periodically (on a timer) requesting that the +// backends clean up. +// +// The RollbackManager periodically initiates a logical.RollbackOperation +// on every mounted logical backend. It ensures that only one rollback operation +// is in-flight at any given time within a single seal/unseal phase. +type RollbackManager struct { + logger log.Logger + + // This gives the current mount table of both logical and credential backends, + // plus a RWMutex that is locked for reading. It is up to the caller to RUnlock + // it when done with the mount table. + backends func() []*MountEntry + + router *Router + period time.Duration + + inflightAll sync.WaitGroup + inflight map[string]*rollbackState + inflightLock sync.RWMutex + + doneCh chan struct{} + shutdown bool + shutdownCh chan struct{} + shutdownLock sync.Mutex + quitContext context.Context +} + +// rollbackState is used to track the state of a single rollback attempt +type rollbackState struct { + lastError error + sync.WaitGroup +} + +// NewRollbackManager is used to create a new rollback manager +func NewRollbackManager(logger log.Logger, backendsFunc func() []*MountEntry, router *Router, ctx context.Context) *RollbackManager { + r := &RollbackManager{ + logger: logger, + backends: backendsFunc, + router: router, + period: rollbackPeriod, + inflight: make(map[string]*rollbackState), + doneCh: make(chan struct{}), + shutdownCh: make(chan struct{}), + quitContext: ctx, + } + return r +} + +// Start starts the rollback manager +func (m *RollbackManager) Start() { + go m.run() +} + +// Stop stops the running manager. This will wait for any in-flight +// rollbacks to complete. +func (m *RollbackManager) Stop() { + m.shutdownLock.Lock() + defer m.shutdownLock.Unlock() + if !m.shutdown { + m.shutdown = true + close(m.shutdownCh) + <-m.doneCh + } + m.inflightAll.Wait() +} + +// run is a long running routine to periodically invoke rollback +func (m *RollbackManager) run() { + m.logger.Info("starting rollback manager") + tick := time.NewTicker(m.period) + defer tick.Stop() + defer close(m.doneCh) + for { + select { + case <-tick.C: + m.triggerRollbacks() + + case <-m.shutdownCh: + m.logger.Info("stopping rollback manager") + return + } + } +} + +// triggerRollbacks is used to trigger the rollbacks across all the backends +func (m *RollbackManager) triggerRollbacks() { + + backends := m.backends() + + for _, e := range backends { + path := e.Path + if e.Table == credentialTableType { + path = credentialRoutePrefix + path + } + + // When the mount is filtered, the backend will be nil + backend := m.router.MatchingBackend(path) + if backend == nil { + continue + } + + m.inflightLock.RLock() + _, ok := m.inflight[path] + m.inflightLock.RUnlock() + if !ok { + m.startRollback(path) + } + } +} + +// startRollback is used to start an async rollback attempt. +// This must be called with the inflightLock held. +func (m *RollbackManager) startRollback(path string) *rollbackState { + rs := &rollbackState{} + rs.Add(1) + m.inflightAll.Add(1) + m.inflightLock.Lock() + m.inflight[path] = rs + m.inflightLock.Unlock() + go m.attemptRollback(m.quitContext, path, rs) + return rs +} + +// attemptRollback invokes a RollbackOperation for the given path +func (m *RollbackManager) attemptRollback(ctx context.Context, path string, rs *rollbackState) (err error) { + defer metrics.MeasureSince([]string{"rollback", "attempt", strings.Replace(path, "/", "-", -1)}, time.Now()) + if m.logger.IsDebug() { + m.logger.Debug("attempting rollback", "path", path) + } + + defer func() { + rs.lastError = err + rs.Done() + m.inflightAll.Done() + m.inflightLock.Lock() + delete(m.inflight, path) + m.inflightLock.Unlock() + }() + + // Invoke a RollbackOperation + req := &logical.Request{ + Operation: logical.RollbackOperation, + Path: path, + } + _, err = m.router.Route(ctx, req) + + // If the error is an unsupported operation, then it doesn't + // matter, the backend doesn't support it. + if err == logical.ErrUnsupportedOperation { + err = nil + } + // If we failed due to read-only storage, we can't do anything; ignore + if err != nil && strings.Contains(err.Error(), logical.ErrReadOnly.Error()) { + err = nil + } + if err != nil { + m.logger.Error("error rolling back", "path", path, "error", err) + } + return +} + +// Rollback is used to trigger an immediate rollback of the path, +// or to join an existing rollback operation if in flight. +func (m *RollbackManager) Rollback(path string) error { + // Check for an existing attempt and start one if none + m.inflightLock.RLock() + rs, ok := m.inflight[path] + m.inflightLock.RUnlock() + if !ok { + rs = m.startRollback(path) + } + + // Wait for the attempt to finish + rs.Wait() + + // Return the last error + return rs.lastError +} + +// The methods below are the hooks from core that are called pre/post seal. + +// startRollback is used to start the rollback manager after unsealing +func (c *Core) startRollback() error { + backendsFunc := func() []*MountEntry { + ret := []*MountEntry{} + c.mountsLock.RLock() + defer c.mountsLock.RUnlock() + // During teardown/setup after a leader change or unseal there could be + // something racy here so make sure the table isn't nil + if c.mounts != nil { + for _, entry := range c.mounts.Entries { + ret = append(ret, entry) + } + } + c.authLock.RLock() + defer c.authLock.RUnlock() + // During teardown/setup after a leader change or unseal there could be + // something racy here so make sure the table isn't nil + if c.auth != nil { + for _, entry := range c.auth.Entries { + ret = append(ret, entry) + } + } + return ret + } + c.rollback = NewRollbackManager(c.logger.ResetNamed("rollback"), backendsFunc, c.router, c.activeContext) + c.rollback.Start() + return nil +} + +// stopRollback is used to stop running the rollback manager before sealing +func (c *Core) stopRollback() error { + if c.rollback != nil { + c.rollback.Stop() + c.rollback = nil + } + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/router.go b/vendor/github.com/hashicorp/vault/vault/router.go new file mode 100644 index 0000000..249cce3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/router.go @@ -0,0 +1,648 @@ +package vault + +import ( + "context" + "fmt" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/armon/go-metrics" + "github.com/armon/go-radix" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" +) + +// Router is used to do prefix based routing of a request to a logical backend +type Router struct { + l sync.RWMutex + root *radix.Tree + mountUUIDCache *radix.Tree + mountAccessorCache *radix.Tree + tokenStoreSaltFunc func(context.Context) (*salt.Salt, error) + // storagePrefix maps the prefix used for storage (ala the BarrierView) + // to the backend. This is used to map a key back into the backend that owns it. + // For example, logical/uuid1/foobar -> secrets/ (kv backend) + foobar + storagePrefix *radix.Tree +} + +// NewRouter returns a new router +func NewRouter() *Router { + r := &Router{ + root: radix.New(), + storagePrefix: radix.New(), + mountUUIDCache: radix.New(), + mountAccessorCache: radix.New(), + } + return r +} + +// routeEntry is used to represent a mount point in the router +type routeEntry struct { + tainted bool + backend logical.Backend + mountEntry *MountEntry + storageView logical.Storage + storagePrefix string + rootPaths atomic.Value + loginPaths atomic.Value + l sync.RWMutex +} + +type validateMountResponse struct { + MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type"` + MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor"` + MountPath string `json:"mount_path" structs:"mount_path" mapstructure:"mount_path"` + MountLocal bool `json:"mount_local" structs:"mount_local" mapstructure:"mount_local"` +} + +// validateMountByAccessor returns the mount type and ID for a given mount +// accessor +func (r *Router) validateMountByAccessor(accessor string) *validateMountResponse { + if accessor == "" { + return nil + } + + mountEntry := r.MatchingMountByAccessor(accessor) + if mountEntry == nil { + return nil + } + + mountPath := mountEntry.Path + if mountEntry.Table == credentialTableType { + mountPath = credentialRoutePrefix + mountPath + } + + return &validateMountResponse{ + MountAccessor: mountEntry.Accessor, + MountType: mountEntry.Type, + MountPath: mountPath, + MountLocal: mountEntry.Local, + } +} + +// SaltID is used to apply a salt and hash to an ID to make sure its not reversible +func (re *routeEntry) SaltID(id string) string { + return salt.SaltID(re.mountEntry.UUID, id, salt.SHA1Hash) +} + +// Mount is used to expose a logical backend at a given prefix, using a unique salt, +// and the barrier view for that path. +func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *MountEntry, storageView *BarrierView) error { + r.l.Lock() + defer r.l.Unlock() + + // Check if this is a nested mount + if existing, _, ok := r.root.LongestPrefix(prefix); ok && existing != "" { + return fmt.Errorf("cannot mount under existing mount %q", existing) + } + + // Build the paths + paths := new(logical.Paths) + if backend != nil { + specialPaths := backend.SpecialPaths() + if specialPaths != nil { + paths = specialPaths + } + } + + // Create a mount entry + re := &routeEntry{ + tainted: false, + backend: backend, + mountEntry: mountEntry, + storagePrefix: storageView.prefix, + storageView: storageView, + } + re.rootPaths.Store(pathsToRadix(paths.Root)) + re.loginPaths.Store(pathsToRadix(paths.Unauthenticated)) + + switch { + case prefix == "": + return fmt.Errorf("missing prefix to be used for router entry; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type) + case re.storagePrefix == "": + return fmt.Errorf("missing storage view prefix; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type) + case re.mountEntry.UUID == "": + return fmt.Errorf("missing mount identifier; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type) + case re.mountEntry.Accessor == "": + return fmt.Errorf("missing mount accessor; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type) + } + + r.root.Insert(prefix, re) + r.storagePrefix.Insert(re.storagePrefix, re) + r.mountUUIDCache.Insert(re.mountEntry.UUID, re.mountEntry) + r.mountAccessorCache.Insert(re.mountEntry.Accessor, re.mountEntry) + + return nil +} + +// Unmount is used to remove a logical backend from a given prefix +func (r *Router) Unmount(ctx context.Context, prefix string) error { + r.l.Lock() + defer r.l.Unlock() + + // Fast-path out if the backend doesn't exist + raw, ok := r.root.Get(prefix) + if !ok { + return nil + } + + // Call backend's Cleanup routine + re := raw.(*routeEntry) + if re.backend != nil { + re.backend.Cleanup(ctx) + } + + // Purge from the radix trees + r.root.Delete(prefix) + r.storagePrefix.Delete(re.storagePrefix) + r.mountUUIDCache.Delete(re.mountEntry.UUID) + r.mountAccessorCache.Delete(re.mountEntry.Accessor) + + return nil +} + +// Remount is used to change the mount location of a logical backend +func (r *Router) Remount(src, dst string) error { + r.l.Lock() + defer r.l.Unlock() + + // Check for existing mount + raw, ok := r.root.Get(src) + if !ok { + return fmt.Errorf("no mount at %q", src) + } + + // Update the mount point + r.root.Delete(src) + r.root.Insert(dst, raw) + return nil +} + +// Taint is used to mark a path as tainted. This means only RollbackOperation +// RevokeOperation requests are allowed to proceed +func (r *Router) Taint(path string) error { + r.l.Lock() + defer r.l.Unlock() + _, raw, ok := r.root.LongestPrefix(path) + if ok { + raw.(*routeEntry).tainted = true + } + return nil +} + +// Untaint is used to unmark a path as tainted. +func (r *Router) Untaint(path string) error { + r.l.Lock() + defer r.l.Unlock() + _, raw, ok := r.root.LongestPrefix(path) + if ok { + raw.(*routeEntry).tainted = false + } + return nil +} + +func (r *Router) MatchingMountByUUID(mountID string) *MountEntry { + if mountID == "" { + return nil + } + + r.l.RLock() + defer r.l.RUnlock() + + _, raw, ok := r.mountUUIDCache.LongestPrefix(mountID) + if !ok { + return nil + } + + return raw.(*MountEntry) +} + +// MatchingMountByAccessor returns the MountEntry by accessor lookup +func (r *Router) MatchingMountByAccessor(mountAccessor string) *MountEntry { + if mountAccessor == "" { + return nil + } + + r.l.RLock() + defer r.l.RUnlock() + + _, raw, ok := r.mountAccessorCache.LongestPrefix(mountAccessor) + if !ok { + return nil + } + + return raw.(*MountEntry) +} + +// MatchingMount returns the mount prefix that would be used for a path +func (r *Router) MatchingMount(path string) string { + r.l.RLock() + defer r.l.RUnlock() + var mount = r.matchingMountInternal(path) + return mount +} + +func (r *Router) matchingMountInternal(path string) string { + mount, _, ok := r.root.LongestPrefix(path) + if !ok { + return "" + } + return mount +} + +// matchingPrefixInternal returns a mount prefix that a path may be a part of +func (r *Router) matchingPrefixInternal(path string) string { + var existing string = "" + fn := func(existing_path string, _v interface{}) bool { + if strings.HasPrefix(existing_path, path) { + existing = existing_path + return true + } + return false + } + r.root.WalkPrefix(path, fn) + return existing +} + +// MountConflict determines if there are potential path conflicts +func (r *Router) MountConflict(path string) string { + r.l.RLock() + defer r.l.RUnlock() + if exact_match := r.matchingMountInternal(path); exact_match != "" { + return exact_match + } + if prefix_match := r.matchingPrefixInternal(path); prefix_match != "" { + return prefix_match + } + return "" +} + +// MatchingStorageByAPIPath/StoragePath returns the storage used for +// API/Storage paths respectively +func (r *Router) MatchingStorageByAPIPath(path string) logical.Storage { + return r.matchingStorage(path, true) +} +func (r *Router) MatchingStorageByStoragePath(path string) logical.Storage { + return r.matchingStorage(path, false) +} +func (r *Router) matchingStorage(path string, apiPath bool) logical.Storage { + var raw interface{} + var ok bool + r.l.RLock() + if apiPath { + _, raw, ok = r.root.LongestPrefix(path) + } else { + _, raw, ok = r.storagePrefix.LongestPrefix(path) + } + r.l.RUnlock() + if !ok { + return nil + } + return raw.(*routeEntry).storageView +} + +// MatchingMountEntry returns the MountEntry used for a path +func (r *Router) MatchingMountEntry(path string) *MountEntry { + r.l.RLock() + _, raw, ok := r.root.LongestPrefix(path) + r.l.RUnlock() + if !ok { + return nil + } + return raw.(*routeEntry).mountEntry +} + +// MatchingBackend returns the backend used for a path +func (r *Router) MatchingBackend(path string) logical.Backend { + r.l.RLock() + _, raw, ok := r.root.LongestPrefix(path) + r.l.RUnlock() + if !ok { + return nil + } + return raw.(*routeEntry).backend +} + +// MatchingSystemView returns the SystemView used for a path +func (r *Router) MatchingSystemView(path string) logical.SystemView { + r.l.RLock() + _, raw, ok := r.root.LongestPrefix(path) + r.l.RUnlock() + if !ok { + return nil + } + return raw.(*routeEntry).backend.System() +} + +// MatchingStoragePrefixByAPIPath/StoragePath returns the mount path matching +// and storage prefix matching the given API/Storage path respectively +func (r *Router) MatchingStoragePrefixByAPIPath(path string) (string, string, bool) { + return r.matchingStoragePrefix(path, true) +} +func (r *Router) MatchingStoragePrefixByStoragePath(path string) (string, string, bool) { + return r.matchingStoragePrefix(path, false) +} +func (r *Router) matchingStoragePrefix(path string, apiPath bool) (string, string, bool) { + var raw interface{} + var ok bool + r.l.RLock() + if apiPath { + _, raw, ok = r.root.LongestPrefix(path) + } else { + _, raw, ok = r.storagePrefix.LongestPrefix(path) + } + r.l.RUnlock() + if !ok { + return "", "", false + } + + // Extract the mount path and storage prefix + re := raw.(*routeEntry) + mountPath := re.mountEntry.Path + prefix := re.storagePrefix + + // Add back the prefix for credential backends + if !apiPath && strings.HasPrefix(path, credentialBarrierPrefix) { + mountPath = credentialRoutePrefix + mountPath + } + + return mountPath, prefix, true +} + +// Route is used to route a given request +func (r *Router) Route(ctx context.Context, req *logical.Request) (*logical.Response, error) { + resp, _, _, err := r.routeCommon(ctx, req, false) + return resp, err +} + +// Route is used to route a given existence check request +func (r *Router) RouteExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) { + _, ok, exists, err := r.routeCommon(ctx, req, true) + return ok, exists, err +} + +func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenceCheck bool) (*logical.Response, bool, bool, error) { + // Find the mount point + r.l.RLock() + adjustedPath := req.Path + mount, raw, ok := r.root.LongestPrefix(adjustedPath) + if !ok && !strings.HasSuffix(adjustedPath, "/") { + // Re-check for a backend by appending a slash. This lets "foo" mean + // "foo/" at the root level which is almost always what we want. + adjustedPath += "/" + mount, raw, ok = r.root.LongestPrefix(adjustedPath) + } + r.l.RUnlock() + if !ok { + return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + } + req.Path = adjustedPath + defer metrics.MeasureSince([]string{"route", string(req.Operation), + strings.Replace(mount, "/", "-", -1)}, time.Now()) + re := raw.(*routeEntry) + + // Grab a read lock on the route entry, this protects against the backend + // being reloaded during a request. + re.l.RLock() + defer re.l.RUnlock() + + // Filtered mounts will have a nil backend + if re.backend == nil { + return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + } + + // If the path is tainted, we reject any operation except for + // Rollback and Revoke + if re.tainted { + switch req.Operation { + case logical.RevokeOperation, logical.RollbackOperation: + default: + return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + } + } + + // Adjust the path to exclude the routing prefix + originalPath := req.Path + req.Path = strings.TrimPrefix(req.Path, mount) + req.MountPoint = mount + req.MountType = re.mountEntry.Type + if req.Path == "/" { + req.Path = "" + } + + // Attach the storage view for the request + req.Storage = re.storageView + + originalEntityID := req.EntityID + + // Hash the request token unless the request is being routed to the token + // or system backend. + clientToken := req.ClientToken + switch { + case strings.HasPrefix(originalPath, "auth/token/"): + case strings.HasPrefix(originalPath, "sys/"): + case strings.HasPrefix(originalPath, "cubbyhole/"): + // In order for the token store to revoke later, we need to have the same + // salted ID, so we double-salt what's going to the cubbyhole backend + salt, err := r.tokenStoreSaltFunc(ctx) + if err != nil { + return nil, false, false, err + } + req.ClientToken = re.SaltID(salt.SaltID(req.ClientToken)) + default: + req.ClientToken = re.SaltID(req.ClientToken) + } + + // Cache the pointer to the original connection object + originalConn := req.Connection + + // Cache the identifier of the request + originalReqID := req.ID + + // Cache the client token's number of uses in the request + originalClientTokenRemainingUses := req.ClientTokenRemainingUses + req.ClientTokenRemainingUses = 0 + + // Cache the headers + headers := req.Headers + + // Filter and add passthrough headers to the backend + var passthroughRequestHeaders []string + if rawVal, ok := re.mountEntry.synthesizedConfigCache.Load("passthrough_request_headers"); ok { + passthroughRequestHeaders = rawVal.([]string) + } + req.Headers = filteredPassthroughHeaders(headers, passthroughRequestHeaders) + + // Cache the wrap info of the request + var wrapInfo *logical.RequestWrapInfo + if req.WrapInfo != nil { + wrapInfo = &logical.RequestWrapInfo{ + TTL: req.WrapInfo.TTL, + Format: req.WrapInfo.Format, + SealWrap: req.WrapInfo.SealWrap, + } + } + + // Reset the request before returning + defer func() { + req.Path = originalPath + req.MountPoint = mount + req.MountType = re.mountEntry.Type + req.Connection = originalConn + req.ID = originalReqID + req.Storage = nil + req.ClientToken = clientToken + req.ClientTokenRemainingUses = originalClientTokenRemainingUses + req.WrapInfo = wrapInfo + req.Headers = headers + // This is only set in one place, after routing, so should never be set + // by a backend + req.SetLastRemoteWAL(0) + + // This will be used for attaching the mount accessor for the identities + // returned by the authentication backends + req.MountAccessor = re.mountEntry.Accessor + + req.EntityID = originalEntityID + }() + + // Invoke the backend + if existenceCheck { + ok, exists, err := re.backend.HandleExistenceCheck(ctx, req) + return nil, ok, exists, err + } else { + resp, err := re.backend.HandleRequest(ctx, req) + // When a token gets renewed, the request hits this path and reaches + // token store. Token store delegates the renewal to the expiration + // manager. Expiration manager in-turn creates a different logical + // request and forwards the request to the auth backend that had + // initially authenticated the login request. The forwarding to auth + // backend will make this code path hit for the second time for the + // same renewal request. The accessors in the Alias structs should be + // of the auth backend and not of the token store. Therefore, avoiding + // the overwriting of accessors by having a check for path prefix + // having "renew". This gets applied for "renew" and "renew-self" + // requests. + if resp != nil && + resp.Auth != nil && + !strings.HasPrefix(req.Path, "renew") { + if resp.Auth.Alias != nil { + resp.Auth.Alias.MountAccessor = re.mountEntry.Accessor + } + for _, alias := range resp.Auth.GroupAliases { + alias.MountAccessor = re.mountEntry.Accessor + } + } + return resp, false, false, err + } +} + +// RootPath checks if the given path requires root privileges +func (r *Router) RootPath(path string) bool { + r.l.RLock() + mount, raw, ok := r.root.LongestPrefix(path) + r.l.RUnlock() + if !ok { + return false + } + re := raw.(*routeEntry) + + // Trim to get remaining path + remain := strings.TrimPrefix(path, mount) + + // Check the rootPaths of this backend + rootPaths := re.rootPaths.Load().(*radix.Tree) + match, raw, ok := rootPaths.LongestPrefix(remain) + if !ok { + return false + } + prefixMatch := raw.(bool) + + // Handle the prefix match case + if prefixMatch { + return strings.HasPrefix(remain, match) + } + + // Handle the exact match case + return match == remain +} + +// LoginPath checks if the given path is used for logins +func (r *Router) LoginPath(path string) bool { + r.l.RLock() + mount, raw, ok := r.root.LongestPrefix(path) + r.l.RUnlock() + if !ok { + return false + } + re := raw.(*routeEntry) + + // Trim to get remaining path + remain := strings.TrimPrefix(path, mount) + + // Check the loginPaths of this backend + loginPaths := re.loginPaths.Load().(*radix.Tree) + match, raw, ok := loginPaths.LongestPrefix(remain) + if !ok { + return false + } + prefixMatch := raw.(bool) + + // Handle the prefix match case + if prefixMatch { + return strings.HasPrefix(remain, match) + } + + // Handle the exact match case + return match == remain +} + +// pathsToRadix converts a the mapping of special paths to a mapping +// of special paths to radix trees. +func pathsToRadix(paths []string) *radix.Tree { + tree := radix.New() + for _, path := range paths { + // Check if this is a prefix or exact match + prefixMatch := len(path) >= 1 && path[len(path)-1] == '*' + if prefixMatch { + path = path[:len(path)-1] + } + + tree.Insert(path, prefixMatch) + } + + return tree +} + +// filteredPassthroughHeaders returns a headers map[string][]string that +// contains the filtered values contained in passthroughHeaders, as well as the +// values in whitelistedHeaders. Filtering of passthroughHeaders from the +// origHeaders is done is a case-insensitive manner. +func filteredPassthroughHeaders(origHeaders map[string][]string, passthroughHeaders []string) map[string][]string { + retHeaders := make(map[string][]string) + + // Short-circuit if there's nothing to filter + if len(passthroughHeaders) == 0 { + return retHeaders + } + + // Create a map that uses lowercased header values as the key and the original + // header naming as the value for comparison down below. + lowerHeadersRef := make(map[string]string, len(origHeaders)) + for key := range origHeaders { + lowerHeadersRef[strings.ToLower(key)] = key + } + + // Case-insensitive compare of passthrough headers against originating + // headers. The returned headers will be the same casing as the originating + // header name. + for _, ph := range passthroughHeaders { + if header, ok := lowerHeadersRef[strings.ToLower(ph)]; ok { + retHeaders[header] = origHeaders[header] + } + } + + return retHeaders +} diff --git a/vendor/github.com/hashicorp/vault/vault/router_access.go b/vendor/github.com/hashicorp/vault/vault/router_access.go new file mode 100644 index 0000000..fc6790f --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/router_access.go @@ -0,0 +1,14 @@ +package vault + +// RouterAccess provides access into some things necessary for testing +type RouterAccess struct { + c *Core +} + +func NewRouterAccess(c *Core) *RouterAccess { + return &RouterAccess{c: c} +} + +func (r *RouterAccess) StoragePrefixByAPIPath(path string) (string, string, bool) { + return r.c.router.MatchingStoragePrefixByAPIPath(path) +} diff --git a/vendor/github.com/hashicorp/vault/vault/seal.go b/vendor/github.com/hashicorp/vault/vault/seal.go new file mode 100644 index 0000000..363a47d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/seal.go @@ -0,0 +1,383 @@ +package vault + +import ( + "bytes" + "context" + "crypto/subtle" + "encoding/base64" + "encoding/json" + "fmt" + "sync/atomic" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/physical" + + "github.com/keybase/go-crypto/openpgp" + "github.com/keybase/go-crypto/openpgp/packet" +) + +const ( + // barrierSealConfigPath is the path used to store our seal configuration. + // This value is stored in plaintext, since we must be able to read it even + // with the Vault sealed. This is required so that we know how many secret + // parts must be used to reconstruct the master key. + barrierSealConfigPath = "core/seal-config" + + // recoverySealConfigPath is the path to the recovery key seal + // configuration. It lives inside the barrier. + // DEPRECATED: Use recoverySealConfigPlaintextPath instead. + recoverySealConfigPath = "core/recovery-seal-config" + + // recoverySealConfigPlaintextPath is the path to the recovery key seal + // configuration. This is stored in plaintext so that we can perform + // auto-unseal. + recoverySealConfigPlaintextPath = "core/recovery-config" + + // recoveryKeyPath is the path to the recovery key + recoveryKeyPath = "core/recovery-key" + + // storedBarrierKeysPath is the path used for storing HSM-encrypted unseal keys + storedBarrierKeysPath = "core/hsm/barrier-unseal-keys" + + // hsmStoredIVPath is the path to the initialization vector for stored keys + hsmStoredIVPath = "core/hsm/iv" +) + +const ( + SealTypeShamir = "shamir" + SealTypePKCS11 = "pkcs11" + SealTypeAWSKMS = "awskms" + SealTypeTest = "test-auto" + + RecoveryTypeUnsupported = "unsupported" + RecoveryTypeShamir = "shamir" +) + +type KeyNotFoundError struct { + Err error +} + +func (e *KeyNotFoundError) WrappedErrors() []error { + return []error{e.Err} +} + +func (e *KeyNotFoundError) Error() string { + return e.Err.Error() +} + +type Seal interface { + SetCore(*Core) + Init(context.Context) error + Finalize(context.Context) error + + StoredKeysSupported() bool + SetStoredKeys(context.Context, [][]byte) error + GetStoredKeys(context.Context) ([][]byte, error) + + BarrierType() string + BarrierConfig(context.Context) (*SealConfig, error) + SetBarrierConfig(context.Context, *SealConfig) error + + RecoveryKeySupported() bool + RecoveryType() string + RecoveryConfig(context.Context) (*SealConfig, error) + SetRecoveryConfig(context.Context, *SealConfig) error + SetRecoveryKey(context.Context, []byte) error + VerifyRecoveryKey(context.Context, []byte) error +} + +type defaultSeal struct { + config atomic.Value + core *Core + PretendToAllowStoredShares bool + PretendToAllowRecoveryKeys bool + PretendRecoveryKey []byte +} + +func NewDefaultSeal() Seal { + ret := &defaultSeal{} + ret.config.Store((*SealConfig)(nil)) + return ret +} + +func (d *defaultSeal) checkCore() error { + if d.core == nil { + return fmt.Errorf("seal does not have a core set") + } + return nil +} + +func (d *defaultSeal) SetCore(core *Core) { + d.core = core +} + +func (d *defaultSeal) Init(ctx context.Context) error { + return nil +} + +func (d *defaultSeal) Finalize(ctx context.Context) error { + return nil +} + +func (d *defaultSeal) BarrierType() string { + return SealTypeShamir +} + +func (d *defaultSeal) StoredKeysSupported() bool { + return d.PretendToAllowStoredShares +} + +func (d *defaultSeal) RecoveryKeySupported() bool { + return d.PretendToAllowRecoveryKeys +} + +func (d *defaultSeal) SetStoredKeys(ctx context.Context, keys [][]byte) error { + return fmt.Errorf("stored keys are not supported") +} + +func (d *defaultSeal) GetStoredKeys(ctx context.Context) ([][]byte, error) { + return nil, fmt.Errorf("stored keys are not supported") +} + +func (d *defaultSeal) BarrierConfig(ctx context.Context) (*SealConfig, error) { + if d.config.Load().(*SealConfig) != nil { + return d.config.Load().(*SealConfig).Clone(), nil + } + + if err := d.checkCore(); err != nil { + return nil, err + } + + // Fetch the core configuration + pe, err := d.core.physical.Get(ctx, barrierSealConfigPath) + if err != nil { + d.core.logger.Error("failed to read seal configuration", "error", err) + return nil, errwrap.Wrapf("failed to check seal configuration: {{err}}", err) + } + + // If the seal configuration is missing, we are not initialized + if pe == nil { + d.core.logger.Info("seal configuration missing, not initialized") + return nil, nil + } + + var conf SealConfig + + // Decode the barrier entry + if err := jsonutil.DecodeJSON(pe.Value, &conf); err != nil { + d.core.logger.Error("failed to decode seal configuration", "error", err) + return nil, errwrap.Wrapf("failed to decode seal configuration: {{err}}", err) + } + + switch conf.Type { + // This case should not be valid for other types as only this is the default + case "": + conf.Type = d.BarrierType() + case d.BarrierType(): + default: + d.core.logger.Error("barrier seal type does not match loaded type", "barrier_seal_type", conf.Type, "loaded_seal_type", d.BarrierType()) + return nil, fmt.Errorf("barrier seal type of %q does not match loaded type of %q", conf.Type, d.BarrierType()) + } + + // Check for a valid seal configuration + if err := conf.Validate(); err != nil { + d.core.logger.Error("invalid seal configuration", "error", err) + return nil, errwrap.Wrapf("seal validation failed: {{err}}", err) + } + + d.config.Store(&conf) + return conf.Clone(), nil +} + +func (d *defaultSeal) SetBarrierConfig(ctx context.Context, config *SealConfig) error { + if err := d.checkCore(); err != nil { + return err + } + + // Provide a way to wipe out the cached value (also prevents actually + // saving a nil config) + if config == nil { + d.config.Store((*SealConfig)(nil)) + return nil + } + + config.Type = d.BarrierType() + + // Encode the seal configuration + buf, err := json.Marshal(config) + if err != nil { + return errwrap.Wrapf("failed to encode seal configuration: {{err}}", err) + } + + // Store the seal configuration + pe := &physical.Entry{ + Key: barrierSealConfigPath, + Value: buf, + } + + if err := d.core.physical.Put(ctx, pe); err != nil { + d.core.logger.Error("failed to write seal configuration", "error", err) + return errwrap.Wrapf("failed to write seal configuration: {{err}}", err) + } + + d.config.Store(config.Clone()) + + return nil +} + +func (d *defaultSeal) RecoveryType() string { + if d.PretendToAllowRecoveryKeys { + return RecoveryTypeShamir + } + return RecoveryTypeUnsupported +} + +func (d *defaultSeal) RecoveryConfig(ctx context.Context) (*SealConfig, error) { + if d.PretendToAllowRecoveryKeys { + return &SealConfig{ + SecretShares: 5, + SecretThreshold: 3, + }, nil + } + return nil, fmt.Errorf("recovery not supported") +} + +func (d *defaultSeal) SetRecoveryConfig(ctx context.Context, config *SealConfig) error { + if d.PretendToAllowRecoveryKeys { + return nil + } + return fmt.Errorf("recovery not supported") +} + +func (d *defaultSeal) VerifyRecoveryKey(ctx context.Context, key []byte) error { + if d.PretendToAllowRecoveryKeys { + if subtle.ConstantTimeCompare(key, d.PretendRecoveryKey) == 1 { + return nil + } + return fmt.Errorf("mismatch") + } + return fmt.Errorf("recovery not supported") +} + +func (d *defaultSeal) SetRecoveryKey(ctx context.Context, key []byte) error { + if d.PretendToAllowRecoveryKeys { + d.PretendRecoveryKey = key + return nil + } + return fmt.Errorf("recovery not supported") +} + +// SealConfig is used to describe the seal configuration +type SealConfig struct { + // The type, for sanity checking + Type string `json:"type"` + + // SecretShares is the number of shares the secret is split into. This is + // the N value of Shamir. + SecretShares int `json:"secret_shares"` + + // SecretThreshold is the number of parts required to open the vault. This + // is the T value of Shamir. + SecretThreshold int `json:"secret_threshold"` + + // PGPKeys is the array of public PGP keys used, if requested, to encrypt + // the output unseal tokens. If provided, it sets the value of + // SecretShares. Ordering is important. + PGPKeys []string `json:"pgp_keys"` + + // Nonce is a nonce generated by Vault used to ensure that when unseal keys + // are submitted for a rekey operation, the rekey operation itself is the + // one intended. This prevents hijacking of the rekey operation, since it + // is unauthenticated. + Nonce string `json:"nonce"` + + // Backup indicates whether or not a backup of PGP-encrypted unseal keys + // should be stored at coreUnsealKeysBackupPath after successful rekeying. + Backup bool `json:"backup"` + + // How many keys to store, for seals that support storage. + StoredShares int `json:"stored_shares"` + + // Stores the progress of the rekey operation (key shares) + RekeyProgress [][]byte `json:"-"` + + // VerificationRequired indicates that after a rekey validation must be + // performed (via providing shares from the new key) before the new key is + // actually installed. This is omitted from JSON as we don't persist the + // new key, it lives only in memory. + VerificationRequired bool `json:"-"` + + // VerificationKey is the new key that we will roll to after successful + // validation + VerificationKey []byte `json:"-"` + + // VerificationNonce stores the current operation nonce for verification + VerificationNonce string `json:"-"` + + // Stores the progress of the verification operation (key shares) + VerificationProgress [][]byte `json:"-"` +} + +// Validate is used to sanity check the seal configuration +func (s *SealConfig) Validate() error { + if s.SecretShares < 1 { + return fmt.Errorf("shares must be at least one") + } + if s.SecretThreshold < 1 { + return fmt.Errorf("threshold must be at least one") + } + if s.SecretShares > 1 && s.SecretThreshold == 1 { + return fmt.Errorf("threshold must be greater than one for multiple shares") + } + if s.SecretShares > 255 { + return fmt.Errorf("shares must be less than 256") + } + if s.SecretThreshold > 255 { + return fmt.Errorf("threshold must be less than 256") + } + if s.SecretThreshold > s.SecretShares { + return fmt.Errorf("threshold cannot be larger than shares") + } + if s.StoredShares > s.SecretShares { + return fmt.Errorf("stored keys cannot be larger than shares") + } + if len(s.PGPKeys) > 0 && len(s.PGPKeys) != s.SecretShares-s.StoredShares { + return fmt.Errorf("count mismatch between number of provided PGP keys and number of shares") + } + if len(s.PGPKeys) > 0 { + for _, keystring := range s.PGPKeys { + data, err := base64.StdEncoding.DecodeString(keystring) + if err != nil { + return errwrap.Wrapf("error decoding given PGP key: {{err}}", err) + } + _, err = openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) + if err != nil { + return errwrap.Wrapf("error parsing given PGP key: {{err}}", err) + } + } + } + return nil +} + +func (s *SealConfig) Clone() *SealConfig { + ret := &SealConfig{ + Type: s.Type, + SecretShares: s.SecretShares, + SecretThreshold: s.SecretThreshold, + Nonce: s.Nonce, + Backup: s.Backup, + StoredShares: s.StoredShares, + VerificationRequired: s.VerificationRequired, + VerificationNonce: s.VerificationNonce, + } + if len(s.PGPKeys) > 0 { + ret.PGPKeys = make([]string, len(s.PGPKeys)) + copy(ret.PGPKeys, s.PGPKeys) + } + if len(s.VerificationKey) > 0 { + ret.VerificationKey = make([]byte, len(s.VerificationKey)) + copy(ret.VerificationKey, s.VerificationKey) + } + return ret +} diff --git a/vendor/github.com/hashicorp/vault/vault/seal_access.go b/vendor/github.com/hashicorp/vault/vault/seal_access.go new file mode 100644 index 0000000..5c44bd1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/seal_access.go @@ -0,0 +1,63 @@ +package vault + +import ( + "context" + "fmt" +) + +// SealAccess is a wrapper around Seal that exposes accessor methods +// through Core.SealAccess() while restricting the ability to modify +// Core.seal itself. +type SealAccess struct { + seal Seal +} + +func NewSealAccess(seal Seal) *SealAccess { + return &SealAccess{seal: seal} +} + +func (s *SealAccess) StoredKeysSupported() bool { + return s.seal.StoredKeysSupported() +} + +func (s *SealAccess) BarrierConfig(ctx context.Context) (*SealConfig, error) { + return s.seal.BarrierConfig(ctx) +} + +func (s *SealAccess) RecoveryKeySupported() bool { + return s.seal.RecoveryKeySupported() +} + +func (s *SealAccess) RecoveryConfig(ctx context.Context) (*SealConfig, error) { + return s.seal.RecoveryConfig(ctx) +} + +func (s *SealAccess) VerifyRecoveryKey(ctx context.Context, key []byte) error { + return s.seal.VerifyRecoveryKey(ctx, key) +} + +func (s *SealAccess) ClearCaches(ctx context.Context) { + s.seal.SetBarrierConfig(ctx, nil) + if s.RecoveryKeySupported() { + s.seal.SetRecoveryConfig(ctx, nil) + } +} + +type SealAccessTestingParams struct { + PretendToAllowStoredShares bool + PretendToAllowRecoveryKeys bool + PretendRecoveryKey []byte +} + +func (s *SealAccess) SetTestingParams(params *SealAccessTestingParams) error { + d, ok := s.seal.(*defaultSeal) + if !ok { + return fmt.Errorf("not a defaultseal") + } + d.PretendToAllowRecoveryKeys = params.PretendToAllowRecoveryKeys + d.PretendToAllowStoredShares = params.PretendToAllowStoredShares + if params.PretendRecoveryKey != nil { + d.PretendRecoveryKey = params.PretendRecoveryKey + } + return nil +} diff --git a/vendor/github.com/hashicorp/vault/vault/seal_testing.go b/vendor/github.com/hashicorp/vault/vault/seal_testing.go new file mode 100644 index 0000000..a3d4abf --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/seal_testing.go @@ -0,0 +1,88 @@ +package vault + +import ( + "context" + + "github.com/mitchellh/go-testing-interface" +) + +var ( + TestCoreUnsealedWithConfigs = testCoreUnsealedWithConfigs + TestSealDefConfigs = testSealDefConfigs +) + +type TestSealOpts struct { + StoredKeysDisabled bool + RecoveryKeysDisabled bool +} + +func NewTestSeal(t testing.T, opts *TestSealOpts) Seal { + return NewDefaultSeal() +} + +func testCoreUnsealedWithConfigs(t testing.T, barrierConf, recoveryConf *SealConfig) (*Core, [][]byte, [][]byte, string) { + seal := NewTestSeal(t, nil) + core := TestCoreWithSeal(t, seal, false) + result, err := core.Initialize(context.Background(), &InitParams{ + BarrierConfig: barrierConf, + RecoveryConfig: recoveryConf, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + err = core.UnsealWithStoredKeys(context.Background()) + if err != nil { + t.Fatalf("err: %s", err) + } + if sealed, _ := core.Sealed(); sealed { + for _, key := range result.SecretShares { + if _, err := core.Unseal(TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + sealed, err = core.Sealed() + if err != nil { + t.Fatalf("err checking seal status: %s", err) + } + if sealed { + t.Fatal("should not be sealed") + } + } + + return core, result.SecretShares, result.RecoveryShares, result.RootToken +} + +func testSealDefConfigs() (*SealConfig, *SealConfig) { + return &SealConfig{ + SecretShares: 5, + SecretThreshold: 3, + }, nil +} + +func TestCoreUnsealedWithConfigSealOpts(t testing.T, barrierConf, recoveryConf *SealConfig, sealOpts *TestSealOpts) (*Core, [][]byte, [][]byte, string) { + seal := NewTestSeal(t, sealOpts) + core := TestCoreWithSeal(t, seal, false) + result, err := core.Initialize(context.Background(), &InitParams{ + BarrierConfig: barrierConf, + RecoveryConfig: recoveryConf, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + for _, key := range result.SecretShares { + if _, err := core.Unseal(TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + sealed, err := core.Sealed() + if err != nil { + t.Fatalf("err checking seal status: %s", err) + } + if sealed { + t.Fatal("should not be sealed") + } + + return core, result.SecretShares, result.RecoveryShares, result.RootToken +} diff --git a/vendor/github.com/hashicorp/vault/vault/sealunwrapper.go b/vendor/github.com/hashicorp/vault/vault/sealunwrapper.go new file mode 100644 index 0000000..a7e6fc2 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/sealunwrapper.go @@ -0,0 +1,183 @@ +// +build !ent +// +build !prem +// +build !pro +// +build !hsm + +package vault + +import ( + "context" + "fmt" + "sync/atomic" + + proto "github.com/golang/protobuf/proto" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/physical" +) + +// NewSealUnwrapper creates a new seal unwrapper +func NewSealUnwrapper(underlying physical.Backend, logger log.Logger) physical.Backend { + ret := &sealUnwrapper{ + underlying: underlying, + logger: logger, + locks: locksutil.CreateLocks(), + allowUnwraps: new(uint32), + } + + if underTxn, ok := underlying.(physical.Transactional); ok { + return &transactionalSealUnwrapper{ + sealUnwrapper: ret, + Transactional: underTxn, + } + } + + return ret +} + +var _ physical.Backend = (*sealUnwrapper)(nil) +var _ physical.Transactional = (*transactionalSealUnwrapper)(nil) + +type sealUnwrapper struct { + underlying physical.Backend + logger log.Logger + locks []*locksutil.LockEntry + allowUnwraps *uint32 +} + +// transactionalSealUnwrapper is a seal unwrapper that wraps a physical that is transactional +type transactionalSealUnwrapper struct { + *sealUnwrapper + physical.Transactional +} + +func (d *sealUnwrapper) Put(ctx context.Context, entry *physical.Entry) error { + if entry == nil { + return nil + } + + locksutil.LockForKey(d.locks, entry.Key).Lock() + defer locksutil.LockForKey(d.locks, entry.Key).Unlock() + + return d.underlying.Put(ctx, entry) +} + +func (d *sealUnwrapper) Get(ctx context.Context, key string) (*physical.Entry, error) { + entry, err := d.underlying.Get(ctx, key) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var performUnwrap bool + se := &physical.SealWrapEntry{} + // If the value ends in our canary value, try to decode the bytes. + eLen := len(entry.Value) + if eLen > 0 && entry.Value[eLen-1] == 's' { + if err := proto.Unmarshal(entry.Value[:eLen-1], se); err == nil { + // We unmarshaled successfully which means we need to store it as a + // non-proto message + performUnwrap = true + } + } + if !performUnwrap { + return entry, nil + } + // It's actually encrypted and we can't read it + if se.Wrapped { + return nil, fmt.Errorf("cannot decode sealwrapped storage entry %q", entry.Key) + } + if atomic.LoadUint32(d.allowUnwraps) != 1 { + return &physical.Entry{ + Key: entry.Key, + Value: se.Ciphertext, + }, nil + } + + locksutil.LockForKey(d.locks, key).Lock() + defer locksutil.LockForKey(d.locks, key).Unlock() + + // At this point we need to re-read and re-check + entry, err = d.underlying.Get(ctx, key) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + performUnwrap = false + se = &physical.SealWrapEntry{} + // If the value ends in our canary value, try to decode the bytes. + eLen = len(entry.Value) + if eLen > 0 && entry.Value[eLen-1] == 's' { + // We ignore an error because the canary is not a guarantee; if it + // doesn't decode, proceed normally + if err := proto.Unmarshal(entry.Value[:eLen-1], se); err == nil { + // We unmarshaled successfully which means we need to store it as a + // non-proto message + performUnwrap = true + } + } + if !performUnwrap { + return entry, nil + } + if se.Wrapped { + return nil, fmt.Errorf("cannot decode sealwrapped storage entry %q", entry.Key) + } + + entry = &physical.Entry{ + Key: entry.Key, + Value: se.Ciphertext, + } + + if atomic.LoadUint32(d.allowUnwraps) != 1 { + return entry, nil + } + return entry, d.underlying.Put(ctx, entry) +} + +func (d *sealUnwrapper) Delete(ctx context.Context, key string) error { + locksutil.LockForKey(d.locks, key).Lock() + defer locksutil.LockForKey(d.locks, key).Unlock() + + return d.underlying.Delete(ctx, key) +} + +func (d *sealUnwrapper) List(ctx context.Context, prefix string) ([]string, error) { + return d.underlying.List(ctx, prefix) +} + +func (d *transactionalSealUnwrapper) Transaction(ctx context.Context, txns []*physical.TxnEntry) error { + // Collect keys that need to be locked + var keys []string + for _, curr := range txns { + keys = append(keys, curr.Entry.Key) + } + // Lock the keys + for _, l := range locksutil.LocksForKeys(d.locks, keys) { + l.Lock() + defer l.Unlock() + } + + if err := d.Transactional.Transaction(ctx, txns); err != nil { + return err + } + + return nil +} + +// This should only run during preSeal which ensures that it can't be run +// concurrently and that it will be run only by the active node +func (d *sealUnwrapper) stopUnwraps() { + atomic.StoreUint32(d.allowUnwraps, 0) +} + +func (d *sealUnwrapper) runUnwraps() { + // Allow key unwraps on key gets. This gets set only when running on the + // active node to prevent standbys from changing data underneath the + // primary + atomic.StoreUint32(d.allowUnwraps, 1) +} diff --git a/vendor/github.com/hashicorp/vault/vault/testing.go b/vendor/github.com/hashicorp/vault/vault/testing.go new file mode 100644 index 0000000..da8985e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/testing.go @@ -0,0 +1,1435 @@ +package vault + +import ( + "bytes" + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "io" + "io/ioutil" + "math/big" + mathrand "math/rand" + "net" + "net/http" + "os" + "os/exec" + "path/filepath" + "sync" + "time" + + log "github.com/hashicorp/go-hclog" + "github.com/mitchellh/copystructure" + + "golang.org/x/crypto/ssh" + "golang.org/x/net/http2" + + cleanhttp "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/logging" + "github.com/hashicorp/vault/helper/reload" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "github.com/hashicorp/vault/physical" + "github.com/mitchellh/go-testing-interface" + + physInmem "github.com/hashicorp/vault/physical/inmem" +) + +// This file contains a number of methods that are useful for unit +// tests within other packages. + +const ( + testSharedPublicKey = ` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9i+hFxZHGo6KblVme4zrAcJstR6I0PTJozW286X4WyvPnkMYDQ5mnhEYC7UWCvjoTWbPEXPX7NjhRtwQTGD67bV+lrxgfyzK1JZbUXK4PwgKJvQD+XyyWYMzDgGSQY61KUSqCxymSm/9NZkPU3ElaQ9xQuTzPpztM4ROfb8f2Yv6/ZESZsTo0MTAkp8Pcy+WkioI/uJ1H7zqs0EA4OMY4aDJRu0UtP4rTVeYNEAuRXdX+eH4aW3KMvhzpFTjMbaJHJXlEeUm2SaX5TNQyTOvghCeQILfYIL/Ca2ij8iwCmulwdV6eQGfd4VDu40PvSnmfoaE38o6HaPnX0kUcnKiT +` + testSharedPrivateKey = ` +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAvYvoRcWRxqOim5VZnuM6wHCbLUeiND0yaM1tvOl+Fsrz55DG +A0OZp4RGAu1Fgr46E1mzxFz1+zY4UbcEExg+u21fpa8YH8sytSWW1FyuD8ICib0A +/l8slmDMw4BkkGOtSlEqgscpkpv/TWZD1NxJWkPcULk8z6c7TOETn2/H9mL+v2RE +mbE6NDEwJKfD3MvlpIqCP7idR+86rNBAODjGOGgyUbtFLT+K01XmDRALkV3V/nh+ +GltyjL4c6RU4zG2iRyV5RHlJtkml+UzUMkzr4IQnkCC32CC/wmtoo/IsAprpcHVe +nkBn3eFQ7uND70p5n6GhN/KOh2j519JFHJyokwIDAQABAoIBAHX7VOvBC3kCN9/x ++aPdup84OE7Z7MvpX6w+WlUhXVugnmsAAVDczhKoUc/WktLLx2huCGhsmKvyVuH+ +MioUiE+vx75gm3qGx5xbtmOfALVMRLopjCnJYf6EaFA0ZeQ+NwowNW7Lu0PHmAU8 +Z3JiX8IwxTz14DU82buDyewO7v+cEr97AnERe3PUcSTDoUXNaoNxjNpEJkKREY6h +4hAY676RT/GsRcQ8tqe/rnCqPHNd7JGqL+207FK4tJw7daoBjQyijWuB7K5chSal +oPInylM6b13ASXuOAOT/2uSUBWmFVCZPDCmnZxy2SdnJGbsJAMl7Ma3MUlaGvVI+ +Tfh1aQkCgYEA4JlNOabTb3z42wz6mz+Nz3JRwbawD+PJXOk5JsSnV7DtPtfgkK9y +6FTQdhnozGWShAvJvc+C4QAihs9AlHXoaBY5bEU7R/8UK/pSqwzam+MmxmhVDV7G +IMQPV0FteoXTaJSikhZ88mETTegI2mik+zleBpVxvfdhE5TR+lq8Br0CgYEA2AwJ +CUD5CYUSj09PluR0HHqamWOrJkKPFPwa+5eiTTCzfBBxImYZh7nXnWuoviXC0sg2 +AuvCW+uZ48ygv/D8gcz3j1JfbErKZJuV+TotK9rRtNIF5Ub7qysP7UjyI7zCssVM +kuDd9LfRXaB/qGAHNkcDA8NxmHW3gpln4CFdSY8CgYANs4xwfercHEWaJ1qKagAe +rZyrMpffAEhicJ/Z65lB0jtG4CiE6w8ZeUMWUVJQVcnwYD+4YpZbX4S7sJ0B8Ydy +AhkSr86D/92dKTIt2STk6aCN7gNyQ1vW198PtaAWH1/cO2UHgHOy3ZUt5X/Uwxl9 +cex4flln+1Viumts2GgsCQKBgCJH7psgSyPekK5auFdKEr5+Gc/jB8I/Z3K9+g4X +5nH3G1PBTCJYLw7hRzw8W/8oALzvddqKzEFHphiGXK94Lqjt/A4q1OdbCrhiE68D +My21P/dAKB1UYRSs9Y8CNyHCjuZM9jSMJ8vv6vG/SOJPsnVDWVAckAbQDvlTHC9t +O98zAoGAcbW6uFDkrv0XMCpB9Su3KaNXOR0wzag+WIFQRXCcoTvxVi9iYfUReQPi +oOyBJU/HMVvBfv4g+OVFLVgSwwm6owwsouZ0+D/LasbuHqYyqYqdyPJQYzWA2Y+F ++B6f4RoPdSXj24JHPg/ioRxjaj094UXJxua2yfkcecGNEuBQHSs= +-----END RSA PRIVATE KEY----- +` +) + +// TestCore returns a pure in-memory, uninitialized core for testing. +func TestCore(t testing.T) *Core { + return TestCoreWithSeal(t, nil, false) +} + +// TestCoreRaw returns a pure in-memory, uninitialized core for testing. The raw +// storage endpoints are enabled with this core. +func TestCoreRaw(t testing.T) *Core { + return TestCoreWithSeal(t, nil, true) +} + +// TestCoreNewSeal returns a pure in-memory, uninitialized core with +// the new seal configuration. +func TestCoreNewSeal(t testing.T) *Core { + seal := NewTestSeal(t, nil) + return TestCoreWithSeal(t, seal, false) +} + +// TestCoreWithSeal returns a pure in-memory, uninitialized core with the +// specified seal for testing. +func TestCoreWithSeal(t testing.T, testSeal Seal, enableRaw bool) *Core { + logger := logging.NewVaultLogger(log.Trace) + physicalBackend, err := physInmem.NewInmem(nil, logger) + if err != nil { + t.Fatal(err) + } + + conf := testCoreConfig(t, physicalBackend, logger) + + if enableRaw { + conf.EnableRaw = true + } + + if testSeal != nil { + conf.Seal = testSeal + } + + c, err := NewCore(conf) + if err != nil { + t.Fatalf("err: %s", err) + } + + return c +} + +func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Logger) *CoreConfig { + t.Helper() + noopAudits := map[string]audit.Factory{ + "noop": func(_ context.Context, config *audit.BackendConfig) (audit.Backend, error) { + view := &logical.InmemStorage{} + view.Put(context.Background(), &logical.StorageEntry{ + Key: "salt", + Value: []byte("foo"), + }) + config.SaltConfig = &salt.Config{ + HMAC: sha256.New, + HMACType: "hmac-sha256", + } + config.SaltView = view + return &noopAudit{ + Config: config, + }, nil + }, + } + + noopBackends := make(map[string]logical.Factory) + noopBackends["noop"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + b := new(framework.Backend) + b.Setup(ctx, config) + return b, nil + } + noopBackends["http"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + return new(rawHTTP), nil + } + + credentialBackends := make(map[string]logical.Factory) + for backendName, backendFactory := range noopBackends { + credentialBackends[backendName] = backendFactory + } + for backendName, backendFactory := range testCredentialBackends { + credentialBackends[backendName] = backendFactory + } + + logicalBackends := make(map[string]logical.Factory) + for backendName, backendFactory := range noopBackends { + logicalBackends[backendName] = backendFactory + } + + logicalBackends["kv"] = LeasedPassthroughBackendFactory + for backendName, backendFactory := range testLogicalBackends { + logicalBackends[backendName] = backendFactory + } + + conf := &CoreConfig{ + Physical: physicalBackend, + AuditBackends: noopAudits, + LogicalBackends: logicalBackends, + CredentialBackends: credentialBackends, + DisableMlock: true, + Logger: logger, + } + + return conf +} + +// TestCoreInit initializes the core with a single key, and returns +// the key that must be used to unseal the core and a root token. +func TestCoreInit(t testing.T, core *Core) ([][]byte, string) { + t.Helper() + secretShares, _, root := TestCoreInitClusterWrapperSetup(t, core, nil, nil) + return secretShares, root +} + +func TestCoreInitClusterWrapperSetup(t testing.T, core *Core, clusterAddrs []*net.TCPAddr, handler http.Handler) ([][]byte, [][]byte, string) { + t.Helper() + core.SetClusterListenerAddrs(clusterAddrs) + core.SetClusterHandler(handler) + + barrierConfig := &SealConfig{ + SecretShares: 3, + SecretThreshold: 3, + } + + // If we support storing barrier keys, then set that to equal the min threshold to unseal + if core.seal.StoredKeysSupported() { + barrierConfig.StoredShares = barrierConfig.SecretThreshold + } + + recoveryConfig := &SealConfig{ + SecretShares: 3, + SecretThreshold: 3, + } + + result, err := core.Initialize(context.Background(), &InitParams{ + BarrierConfig: barrierConfig, + RecoveryConfig: recoveryConfig, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + return result.SecretShares, result.RecoveryShares, result.RootToken +} + +func TestCoreUnseal(core *Core, key []byte) (bool, error) { + return core.Unseal(key) +} + +func TestCoreUnsealWithRecoveryKeys(core *Core, key []byte) (bool, error) { + return core.UnsealWithRecoveryKeys(context.Background(), key) +} + +// TestCoreUnsealed returns a pure in-memory core that is already +// initialized and unsealed. +func TestCoreUnsealed(t testing.T) (*Core, [][]byte, string) { + t.Helper() + core := TestCore(t) + return testCoreUnsealed(t, core) +} + +// TestCoreUnsealedRaw returns a pure in-memory core that is already +// initialized, unsealed, and with raw endpoints enabled. +func TestCoreUnsealedRaw(t testing.T) (*Core, [][]byte, string) { + t.Helper() + core := TestCoreRaw(t) + return testCoreUnsealed(t, core) +} + +func testCoreUnsealed(t testing.T, core *Core) (*Core, [][]byte, string) { + t.Helper() + keys, token := TestCoreInit(t, core) + for _, key := range keys { + if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + sealed, err := core.Sealed() + if err != nil { + t.Fatalf("err checking seal status: %s", err) + } + if sealed { + t.Fatal("should not be sealed") + } + + return core, keys, token +} + +func TestCoreUnsealedBackend(t testing.T, backend physical.Backend) (*Core, [][]byte, string) { + t.Helper() + logger := logging.NewVaultLogger(log.Trace) + conf := testCoreConfig(t, backend, logger) + conf.Seal = NewTestSeal(t, nil) + + core, err := NewCore(conf) + if err != nil { + t.Fatalf("err: %s", err) + } + + keys, token := TestCoreInit(t, core) + for _, key := range keys { + if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + if err := core.UnsealWithStoredKeys(context.Background()); err != nil { + t.Fatal(err) + } + + sealed, err := core.Sealed() + if err != nil { + t.Fatalf("err checking seal status: %s", err) + } + if sealed { + t.Fatal("should not be sealed") + } + + return core, keys, token +} + +// TestKeyCopy is a silly little function to just copy the key so that +// it can be used with Unseal easily. +func TestKeyCopy(key []byte) []byte { + result := make([]byte, len(key)) + copy(result, key) + return result +} + +func TestDynamicSystemView(c *Core) *dynamicSystemView { + me := &MountEntry{ + Config: MountConfig{ + DefaultLeaseTTL: 24 * time.Hour, + MaxLeaseTTL: 2 * 24 * time.Hour, + }, + } + + return &dynamicSystemView{c, me} +} + +// TestAddTestPlugin registers the testFunc as part of the plugin command to the +// plugin catalog. +func TestAddTestPlugin(t testing.T, c *Core, name, testFunc string) { + file, err := os.Open(os.Args[0]) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + hash := sha256.New() + + _, err = io.Copy(hash, file) + if err != nil { + t.Fatal(err) + } + + sum := hash.Sum(nil) + + // Determine plugin directory path + fullPath, err := filepath.EvalSymlinks(os.Args[0]) + if err != nil { + t.Fatal(err) + } + directoryPath := filepath.Dir(fullPath) + + // Set core's plugin directory and plugin catalog directory + c.pluginDirectory = directoryPath + c.pluginCatalog.directory = directoryPath + + command := fmt.Sprintf("%s", filepath.Base(os.Args[0])) + args := []string{fmt.Sprintf("--test.run=%s", testFunc)} + err = c.pluginCatalog.Set(context.Background(), name, command, args, sum) + if err != nil { + t.Fatal(err) + } +} + +// TestAddTestPluginTempDir registers the testFunc as part of the plugin command to the +// plugin catalog. It uses tmpDir as the plugin directory. +func TestAddTestPluginTempDir(t testing.T, c *Core, name, testFunc, tempDir string) { + file, err := os.Open(os.Args[0]) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + fi, err := file.Stat() + if err != nil { + t.Fatal(err) + } + + // Copy over the file to the temp dir + dst := filepath.Join(tempDir, filepath.Base(os.Args[0])) + out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode()) + if err != nil { + t.Fatal(err) + } + defer out.Close() + + if _, err = io.Copy(out, file); err != nil { + t.Fatal(err) + } + err = out.Sync() + if err != nil { + t.Fatal(err) + } + + // Determine plugin directory full path + fullPath, err := filepath.EvalSymlinks(tempDir) + if err != nil { + t.Fatal(err) + } + + reader, err := os.Open(filepath.Join(fullPath, filepath.Base(os.Args[0]))) + if err != nil { + t.Fatal(err) + } + defer reader.Close() + + // Find out the sha256 + hash := sha256.New() + + _, err = io.Copy(hash, reader) + if err != nil { + t.Fatal(err) + } + + sum := hash.Sum(nil) + + // Set core's plugin directory and plugin catalog directory + c.pluginDirectory = fullPath + c.pluginCatalog.directory = fullPath + + command := fmt.Sprintf("%s", filepath.Base(os.Args[0])) + args := []string{fmt.Sprintf("--test.run=%s", testFunc)} + err = c.pluginCatalog.Set(context.Background(), name, command, args, sum) + if err != nil { + t.Fatal(err) + } +} + +var testLogicalBackends = map[string]logical.Factory{} +var testCredentialBackends = map[string]logical.Factory{} + +// StartSSHHostTestServer starts the test server which responds to SSH +// authentication. Used to test the SSH secret backend. +func StartSSHHostTestServer() (string, error) { + pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(testSharedPublicKey)) + if err != nil { + return "", fmt.Errorf("error parsing public key") + } + serverConfig := &ssh.ServerConfig{ + PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { + if bytes.Compare(pubKey.Marshal(), key.Marshal()) == 0 { + return &ssh.Permissions{}, nil + } else { + return nil, fmt.Errorf("key does not match") + } + }, + } + signer, err := ssh.ParsePrivateKey([]byte(testSharedPrivateKey)) + if err != nil { + panic("Error parsing private key") + } + serverConfig.AddHostKey(signer) + + soc, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return "", fmt.Errorf("error listening to connection") + } + + go func() { + for { + conn, err := soc.Accept() + if err != nil { + panic(fmt.Sprintf("Error accepting incoming connection: %s", err)) + } + defer conn.Close() + sshConn, chanReqs, _, err := ssh.NewServerConn(conn, serverConfig) + if err != nil { + panic(fmt.Sprintf("Handshaking error: %v", err)) + } + + go func() { + for chanReq := range chanReqs { + go func(chanReq ssh.NewChannel) { + if chanReq.ChannelType() != "session" { + chanReq.Reject(ssh.UnknownChannelType, "unknown channel type") + return + } + + ch, requests, err := chanReq.Accept() + if err != nil { + panic(fmt.Sprintf("Error accepting channel: %s", err)) + } + + go func(ch ssh.Channel, in <-chan *ssh.Request) { + for req := range in { + executeServerCommand(ch, req) + } + }(ch, requests) + }(chanReq) + } + sshConn.Close() + }() + } + }() + return soc.Addr().String(), nil +} + +// This executes the commands requested to be run on the server. +// Used to test the SSH secret backend. +func executeServerCommand(ch ssh.Channel, req *ssh.Request) { + command := string(req.Payload[4:]) + cmd := exec.Command("/bin/bash", []string{"-c", command}...) + req.Reply(true, nil) + + cmd.Stdout = ch + cmd.Stderr = ch + cmd.Stdin = ch + + err := cmd.Start() + if err != nil { + panic(fmt.Sprintf("Error starting the command: '%s'", err)) + } + + go func() { + _, err := cmd.Process.Wait() + if err != nil { + panic(fmt.Sprintf("Error while waiting for command to finish:'%s'", err)) + } + ch.Close() + }() +} + +// This adds a credential backend for the test core. This needs to be +// invoked before the test core is created. +func AddTestCredentialBackend(name string, factory logical.Factory) error { + if name == "" { + return fmt.Errorf("missing backend name") + } + if factory == nil { + return fmt.Errorf("missing backend factory function") + } + testCredentialBackends[name] = factory + return nil +} + +// This adds a logical backend for the test core. This needs to be +// invoked before the test core is created. +func AddTestLogicalBackend(name string, factory logical.Factory) error { + if name == "" { + return fmt.Errorf("missing backend name") + } + if factory == nil { + return fmt.Errorf("missing backend factory function") + } + testLogicalBackends[name] = factory + return nil +} + +type noopAudit struct { + Config *audit.BackendConfig + salt *salt.Salt + saltMutex sync.RWMutex +} + +func (n *noopAudit) GetHash(ctx context.Context, data string) (string, error) { + salt, err := n.Salt(ctx) + if err != nil { + return "", err + } + return salt.GetIdentifiedHMAC(data), nil +} + +func (n *noopAudit) LogRequest(_ context.Context, _ *audit.LogInput) error { + return nil +} + +func (n *noopAudit) LogResponse(_ context.Context, _ *audit.LogInput) error { + return nil +} + +func (n *noopAudit) Reload(_ context.Context) error { + return nil +} + +func (n *noopAudit) Invalidate(_ context.Context) { + n.saltMutex.Lock() + defer n.saltMutex.Unlock() + n.salt = nil +} + +func (n *noopAudit) Salt(ctx context.Context) (*salt.Salt, error) { + n.saltMutex.RLock() + if n.salt != nil { + defer n.saltMutex.RUnlock() + return n.salt, nil + } + n.saltMutex.RUnlock() + n.saltMutex.Lock() + defer n.saltMutex.Unlock() + if n.salt != nil { + return n.salt, nil + } + salt, err := salt.NewSalt(ctx, n.Config.SaltView, n.Config.SaltConfig) + if err != nil { + return nil, err + } + n.salt = salt + return salt, nil +} + +type rawHTTP struct{} + +func (n *rawHTTP) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { + return &logical.Response{ + Data: map[string]interface{}{ + logical.HTTPStatusCode: 200, + logical.HTTPContentType: "plain/text", + logical.HTTPRawBody: []byte("hello world"), + }, + }, nil +} + +func (n *rawHTTP) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) { + return false, false, nil +} + +func (n *rawHTTP) SpecialPaths() *logical.Paths { + return &logical.Paths{Unauthenticated: []string{"*"}} +} + +func (n *rawHTTP) System() logical.SystemView { + return logical.StaticSystemView{ + DefaultLeaseTTLVal: time.Hour * 24, + MaxLeaseTTLVal: time.Hour * 24 * 32, + } +} + +func (n *rawHTTP) Logger() log.Logger { + return logging.NewVaultLogger(log.Trace) +} + +func (n *rawHTTP) Cleanup(ctx context.Context) { + // noop +} + +func (n *rawHTTP) Initialize(ctx context.Context) error { + // noop + return nil +} + +func (n *rawHTTP) InvalidateKey(context.Context, string) { + // noop +} + +func (n *rawHTTP) Setup(ctx context.Context, config *logical.BackendConfig) error { + // noop + return nil +} + +func (n *rawHTTP) Type() logical.BackendType { + return logical.TypeUnknown +} + +func GenerateRandBytes(length int) ([]byte, error) { + if length < 0 { + return nil, fmt.Errorf("length must be >= 0") + } + + buf := make([]byte, length) + if length == 0 { + return buf, nil + } + + n, err := rand.Read(buf) + if err != nil { + return nil, err + } + if n != length { + return nil, fmt.Errorf("unable to read %d bytes; only read %d", length, n) + } + + return buf, nil +} + +func TestWaitActive(t testing.T, core *Core) { + t.Helper() + if err := TestWaitActiveWithError(core); err != nil { + t.Fatal(err) + } +} + +func TestWaitActiveWithError(core *Core) error { + start := time.Now() + var standby bool + var err error + for time.Now().Sub(start) < time.Second { + standby, err = core.Standby() + if err != nil { + return err + } + if !standby { + break + } + } + if standby { + return errors.New("should not be in standby mode") + } + return nil +} + +type TestCluster struct { + BarrierKeys [][]byte + RecoveryKeys [][]byte + CACert *x509.Certificate + CACertBytes []byte + CACertPEM []byte + CACertPEMFile string + CAKey *ecdsa.PrivateKey + CAKeyPEM []byte + Cores []*TestClusterCore + ID string + RootToken string + RootCAs *x509.CertPool + TempDir string +} + +func (c *TestCluster) Start() { + for _, core := range c.Cores { + if core.Server != nil { + for _, ln := range core.Listeners { + go core.Server.Serve(ln) + } + } + } +} + +// UnsealCores uses the cluster barrier keys to unseal the test cluster cores +func (c *TestCluster) UnsealCores(t testing.T) { + if err := c.UnsealCoresWithError(); err != nil { + t.Fatal(err) + } +} + +func (c *TestCluster) UnsealCoresWithError() error { + numCores := len(c.Cores) + + // Unseal first core + for _, key := range c.BarrierKeys { + if _, err := c.Cores[0].Unseal(TestKeyCopy(key)); err != nil { + return fmt.Errorf("unseal err: %s", err) + } + } + + // Verify unsealed + sealed, err := c.Cores[0].Sealed() + if err != nil { + return fmt.Errorf("err checking seal status: %s", err) + } + if sealed { + return fmt.Errorf("should not be sealed") + } + + if err := TestWaitActiveWithError(c.Cores[0].Core); err != nil { + return err + } + + // Unseal other cores + for i := 1; i < numCores; i++ { + for _, key := range c.BarrierKeys { + if _, err := c.Cores[i].Core.Unseal(TestKeyCopy(key)); err != nil { + return fmt.Errorf("unseal err: %s", err) + } + } + } + + // Let them come fully up to standby + time.Sleep(2 * time.Second) + + // Ensure cluster connection info is populated. + // Other cores should not come up as leaders. + for i := 1; i < numCores; i++ { + isLeader, _, _, err := c.Cores[i].Leader() + if err != nil { + return err + } + if isLeader { + return fmt.Errorf("core[%d] should not be leader", i) + } + } + + return nil +} + +func (c *TestCluster) EnsureCoresSealed(t testing.T) { + t.Helper() + if err := c.ensureCoresSealed(); err != nil { + t.Fatal(err) + } +} + +func (c *TestCluster) Cleanup() { + // Close listeners + for _, core := range c.Cores { + if core.Listeners != nil { + for _, ln := range core.Listeners { + ln.Close() + } + } + } + + // Seal the cores + c.ensureCoresSealed() + + // Remove any temp dir that exists + if c.TempDir != "" { + os.RemoveAll(c.TempDir) + } + + // Give time to actually shut down/clean up before the next test + time.Sleep(time.Second) +} + +func (c *TestCluster) ensureCoresSealed() error { + for _, core := range c.Cores { + if err := core.Shutdown(); err != nil { + return err + } + timeout := time.Now().Add(60 * time.Second) + for { + if time.Now().After(timeout) { + return fmt.Errorf("timeout waiting for core to seal") + } + sealed, err := core.Sealed() + if err != nil { + return err + } + if sealed { + break + } + time.Sleep(250 * time.Millisecond) + } + } + return nil +} + +// UnsealWithStoredKeys uses stored keys to unseal the test cluster cores +func (c *TestCluster) UnsealWithStoredKeys(t testing.T) error { + for _, core := range c.Cores { + if err := core.UnsealWithStoredKeys(context.Background()); err != nil { + return err + } + timeout := time.Now().Add(60 * time.Second) + for { + if time.Now().After(timeout) { + return fmt.Errorf("timeout waiting for core to unseal") + } + sealed, err := core.Sealed() + if err != nil { + return err + } + if !sealed { + break + } + time.Sleep(250 * time.Millisecond) + } + } + return nil +} + +type TestListener struct { + net.Listener + Address *net.TCPAddr +} + +type TestClusterCore struct { + *Core + Client *api.Client + Handler http.Handler + Listeners []*TestListener + ReloadFuncs *map[string][]reload.ReloadFunc + ReloadFuncsLock *sync.RWMutex + Server *http.Server + ServerCert *x509.Certificate + ServerCertBytes []byte + ServerCertPEM []byte + ServerKey *ecdsa.PrivateKey + ServerKeyPEM []byte + TLSConfig *tls.Config + UnderlyingStorage physical.Backend +} + +type TestClusterOptions struct { + KeepStandbysSealed bool + SkipInit bool + HandlerFunc func(*Core) http.Handler + BaseListenAddress string + NumCores int + SealFunc func() Seal + Logger log.Logger + TempDir string + CACert []byte + CAKey *ecdsa.PrivateKey +} + +var DefaultNumCores = 3 + +type certInfo struct { + cert *x509.Certificate + certPEM []byte + certBytes []byte + key *ecdsa.PrivateKey + keyPEM []byte +} + +// NewTestCluster creates a new test cluster based on the provided core config +// and test cluster options. +// +// N.B. Even though a single base CoreConfig is provided, NewTestCluster will instantiate a +// core config for each core it creates. If separate seal per core is desired, opts.SealFunc +// can be provided to generate a seal for each one. Otherwise, the provided base.Seal will be +// shared among cores. NewCore's default behavior is to generate a new DefaultSeal if the +// provided Seal in coreConfig (i.e. base.Seal) is nil. +func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *TestCluster { + var err error + + var numCores int + if opts == nil || opts.NumCores == 0 { + numCores = DefaultNumCores + } else { + numCores = opts.NumCores + } + + certIPs := []net.IP{ + net.IPv6loopback, + net.ParseIP("127.0.0.1"), + } + var baseAddr *net.TCPAddr + if opts != nil && opts.BaseListenAddress != "" { + baseAddr, err = net.ResolveTCPAddr("tcp", opts.BaseListenAddress) + if err != nil { + t.Fatal("could not parse given base IP") + } + certIPs = append(certIPs, baseAddr.IP) + } + + var testCluster TestCluster + if opts != nil && opts.TempDir != "" { + if _, err := os.Stat(opts.TempDir); os.IsNotExist(err) { + if err := os.MkdirAll(opts.TempDir, 0700); err != nil { + t.Fatal(err) + } + } + testCluster.TempDir = opts.TempDir + } else { + tempDir, err := ioutil.TempDir("", "vault-test-cluster-") + if err != nil { + t.Fatal(err) + } + testCluster.TempDir = tempDir + } + + var caKey *ecdsa.PrivateKey + if opts != nil && opts.CAKey != nil { + caKey = opts.CAKey + } else { + caKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + } + testCluster.CAKey = caKey + var caBytes []byte + if opts != nil && len(opts.CACert) > 0 { + caBytes = opts.CACert + } else { + caCertTemplate := &x509.Certificate{ + Subject: pkix.Name{ + CommonName: "localhost", + }, + DNSNames: []string{"localhost"}, + IPAddresses: certIPs, + KeyUsage: x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign), + SerialNumber: big.NewInt(mathrand.Int63()), + NotBefore: time.Now().Add(-30 * time.Second), + NotAfter: time.Now().Add(262980 * time.Hour), + BasicConstraintsValid: true, + IsCA: true, + } + caBytes, err = x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey) + if err != nil { + t.Fatal(err) + } + } + caCert, err := x509.ParseCertificate(caBytes) + if err != nil { + t.Fatal(err) + } + testCluster.CACert = caCert + testCluster.CACertBytes = caBytes + testCluster.RootCAs = x509.NewCertPool() + testCluster.RootCAs.AddCert(caCert) + caCertPEMBlock := &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + } + testCluster.CACertPEM = pem.EncodeToMemory(caCertPEMBlock) + testCluster.CACertPEMFile = filepath.Join(testCluster.TempDir, "ca_cert.pem") + err = ioutil.WriteFile(testCluster.CACertPEMFile, testCluster.CACertPEM, 0755) + if err != nil { + t.Fatal(err) + } + marshaledCAKey, err := x509.MarshalECPrivateKey(caKey) + if err != nil { + t.Fatal(err) + } + caKeyPEMBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: marshaledCAKey, + } + testCluster.CAKeyPEM = pem.EncodeToMemory(caKeyPEMBlock) + err = ioutil.WriteFile(filepath.Join(testCluster.TempDir, "ca_key.pem"), testCluster.CAKeyPEM, 0755) + if err != nil { + t.Fatal(err) + } + + var certInfoSlice []*certInfo + + // + // Certs generation + // + for i := 0; i < numCores; i++ { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + certTemplate := &x509.Certificate{ + Subject: pkix.Name{ + CommonName: "localhost", + }, + DNSNames: []string{"localhost"}, + IPAddresses: certIPs, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement, + SerialNumber: big.NewInt(mathrand.Int63()), + NotBefore: time.Now().Add(-30 * time.Second), + NotAfter: time.Now().Add(262980 * time.Hour), + } + certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, caCert, key.Public(), caKey) + if err != nil { + t.Fatal(err) + } + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + t.Fatal(err) + } + certPEMBlock := &pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + } + certPEM := pem.EncodeToMemory(certPEMBlock) + marshaledKey, err := x509.MarshalECPrivateKey(key) + if err != nil { + t.Fatal(err) + } + keyPEMBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: marshaledKey, + } + keyPEM := pem.EncodeToMemory(keyPEMBlock) + + certInfoSlice = append(certInfoSlice, &certInfo{ + cert: cert, + certPEM: certPEM, + certBytes: certBytes, + key: key, + keyPEM: keyPEM, + }) + } + + // + // Listener setup + // + logger := logging.NewVaultLogger(log.Trace) + ports := make([]int, numCores) + if baseAddr != nil { + for i := 0; i < numCores; i++ { + ports[i] = baseAddr.Port + i + } + } else { + baseAddr = &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 0, + } + } + + listeners := [][]*TestListener{} + servers := []*http.Server{} + handlers := []http.Handler{} + tlsConfigs := []*tls.Config{} + certGetters := []*reload.CertificateGetter{} + for i := 0; i < numCores; i++ { + baseAddr.Port = ports[i] + ln, err := net.ListenTCP("tcp", baseAddr) + if err != nil { + t.Fatal(err) + } + certFile := filepath.Join(testCluster.TempDir, fmt.Sprintf("node%d_port_%d_cert.pem", i+1, ln.Addr().(*net.TCPAddr).Port)) + keyFile := filepath.Join(testCluster.TempDir, fmt.Sprintf("node%d_port_%d_key.pem", i+1, ln.Addr().(*net.TCPAddr).Port)) + err = ioutil.WriteFile(certFile, certInfoSlice[i].certPEM, 0755) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(keyFile, certInfoSlice[i].keyPEM, 0755) + if err != nil { + t.Fatal(err) + } + tlsCert, err := tls.X509KeyPair(certInfoSlice[i].certPEM, certInfoSlice[i].keyPEM) + if err != nil { + t.Fatal(err) + } + certGetter := reload.NewCertificateGetter(certFile, keyFile, "") + certGetters = append(certGetters, certGetter) + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{tlsCert}, + RootCAs: testCluster.RootCAs, + ClientCAs: testCluster.RootCAs, + ClientAuth: tls.RequestClientCert, + NextProtos: []string{"h2", "http/1.1"}, + GetCertificate: certGetter.GetCertificate, + } + tlsConfig.BuildNameToCertificate() + tlsConfigs = append(tlsConfigs, tlsConfig) + lns := []*TestListener{&TestListener{ + Listener: tls.NewListener(ln, tlsConfig), + Address: ln.Addr().(*net.TCPAddr), + }, + } + listeners = append(listeners, lns) + var handler http.Handler = http.NewServeMux() + handlers = append(handlers, handler) + server := &http.Server{ + Handler: handler, + } + servers = append(servers, server) + } + + // Create three cores with the same physical and different redirect/cluster + // addrs. + // N.B.: On OSX, instead of random ports, it assigns new ports to new + // listeners sequentially. Aside from being a bad idea in a security sense, + // it also broke tests that assumed it was OK to just use the port above + // the redirect addr. This has now been changed to 105 ports above, but if + // we ever do more than three nodes in a cluster it may need to be bumped. + // Note: it's 105 so that we don't conflict with a running Consul by + // default. + coreConfig := &CoreConfig{ + LogicalBackends: make(map[string]logical.Factory), + CredentialBackends: make(map[string]logical.Factory), + AuditBackends: make(map[string]audit.Factory), + RedirectAddr: fmt.Sprintf("https://127.0.0.1:%d", listeners[0][0].Address.Port), + ClusterAddr: fmt.Sprintf("https://127.0.0.1:%d", listeners[0][0].Address.Port+105), + DisableMlock: true, + EnableUI: true, + EnableRaw: true, + } + + if base != nil { + coreConfig.DisableCache = base.DisableCache + coreConfig.EnableUI = base.EnableUI + coreConfig.DefaultLeaseTTL = base.DefaultLeaseTTL + coreConfig.MaxLeaseTTL = base.MaxLeaseTTL + coreConfig.CacheSize = base.CacheSize + coreConfig.PluginDirectory = base.PluginDirectory + coreConfig.Seal = base.Seal + coreConfig.DevToken = base.DevToken + coreConfig.EnableRaw = base.EnableRaw + + if !coreConfig.DisableMlock { + base.DisableMlock = false + } + + if base.Physical != nil { + coreConfig.Physical = base.Physical + } + + if base.HAPhysical != nil { + coreConfig.HAPhysical = base.HAPhysical + } + + // Used to set something non-working to test fallback + switch base.ClusterAddr { + case "empty": + coreConfig.ClusterAddr = "" + case "": + default: + coreConfig.ClusterAddr = base.ClusterAddr + } + + if base.LogicalBackends != nil { + for k, v := range base.LogicalBackends { + coreConfig.LogicalBackends[k] = v + } + } + if base.CredentialBackends != nil { + for k, v := range base.CredentialBackends { + coreConfig.CredentialBackends[k] = v + } + } + if base.AuditBackends != nil { + for k, v := range base.AuditBackends { + coreConfig.AuditBackends[k] = v + } + } + if base.Logger != nil { + coreConfig.Logger = base.Logger + } + + coreConfig.ClusterCipherSuites = base.ClusterCipherSuites + + coreConfig.DisableCache = base.DisableCache + + coreConfig.DevToken = base.DevToken + } + + if coreConfig.Physical == nil { + coreConfig.Physical, err = physInmem.NewInmem(nil, logger) + if err != nil { + t.Fatal(err) + } + } + if coreConfig.HAPhysical == nil { + haPhys, err := physInmem.NewInmemHA(nil, logger) + if err != nil { + t.Fatal(err) + } + coreConfig.HAPhysical = haPhys.(physical.HABackend) + } + + cores := []*Core{} + for i := 0; i < numCores; i++ { + coreConfig.RedirectAddr = fmt.Sprintf("https://127.0.0.1:%d", listeners[i][0].Address.Port) + if coreConfig.ClusterAddr != "" { + coreConfig.ClusterAddr = fmt.Sprintf("https://127.0.0.1:%d", listeners[i][0].Address.Port+105) + } + + // if opts.SealFunc is provided, use that to generate a seal for the config instead + if opts != nil && opts.SealFunc != nil { + coreConfig.Seal = opts.SealFunc() + } + + if opts != nil && opts.Logger != nil { + coreConfig.Logger = opts.Logger.Named(fmt.Sprintf("core%d", i)) + } + + c, err := NewCore(coreConfig) + if err != nil { + t.Fatalf("err: %v", err) + } + cores = append(cores, c) + if opts != nil && opts.HandlerFunc != nil { + handlers[i] = opts.HandlerFunc(c) + servers[i].Handler = handlers[i] + } + } + + // + // Clustering setup + // + clusterAddrGen := func(lns []*TestListener) []*net.TCPAddr { + ret := make([]*net.TCPAddr, len(lns)) + for i, ln := range lns { + ret[i] = &net.TCPAddr{ + IP: ln.Address.IP, + Port: ln.Address.Port + 105, + } + } + return ret + } + + if numCores > 1 { + for i := 1; i < numCores; i++ { + cores[i].SetClusterListenerAddrs(clusterAddrGen(listeners[i])) + cores[i].SetClusterHandler(handlers[i]) + } + } + + if opts == nil || !opts.SkipInit { + bKeys, rKeys, root := TestCoreInitClusterWrapperSetup(t, cores[0], clusterAddrGen(listeners[0]), handlers[0]) + barrierKeys, _ := copystructure.Copy(bKeys) + testCluster.BarrierKeys = barrierKeys.([][]byte) + recoveryKeys, _ := copystructure.Copy(rKeys) + testCluster.RecoveryKeys = recoveryKeys.([][]byte) + testCluster.RootToken = root + + // Write root token and barrier keys + err = ioutil.WriteFile(filepath.Join(testCluster.TempDir, "root_token"), []byte(root), 0755) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + for i, key := range testCluster.BarrierKeys { + buf.Write([]byte(base64.StdEncoding.EncodeToString(key))) + if i < len(testCluster.BarrierKeys)-1 { + buf.WriteRune('\n') + } + } + err = ioutil.WriteFile(filepath.Join(testCluster.TempDir, "barrier_keys"), buf.Bytes(), 0755) + if err != nil { + t.Fatal(err) + } + for i, key := range testCluster.RecoveryKeys { + buf.Write([]byte(base64.StdEncoding.EncodeToString(key))) + if i < len(testCluster.RecoveryKeys)-1 { + buf.WriteRune('\n') + } + } + err = ioutil.WriteFile(filepath.Join(testCluster.TempDir, "recovery_keys"), buf.Bytes(), 0755) + if err != nil { + t.Fatal(err) + } + + // Unseal first core + for _, key := range bKeys { + if _, err := cores[0].Unseal(TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + ctx := context.Background() + + // If stored keys is supported, the above will no no-op, so trigger auto-unseal + // using stored keys to try to unseal + if err := cores[0].UnsealWithStoredKeys(ctx); err != nil { + t.Fatal(err) + } + + // Verify unsealed + sealed, err := cores[0].Sealed() + if err != nil { + t.Fatalf("err checking seal status: %s", err) + } + if sealed { + t.Fatal("should not be sealed") + } + + TestWaitActive(t, cores[0]) + + // Unseal other cores unless otherwise specified + if (opts == nil || !opts.KeepStandbysSealed) && numCores > 1 { + for i := 1; i < numCores; i++ { + for _, key := range bKeys { + if _, err := cores[i].Unseal(TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + } + + // If stored keys is supported, the above will no no-op, so trigger auto-unseal + // using stored keys + if err := cores[i].UnsealWithStoredKeys(ctx); err != nil { + t.Fatal(err) + } + } + + // Let them come fully up to standby + time.Sleep(2 * time.Second) + + // Ensure cluster connection info is populated. + // Other cores should not come up as leaders. + for i := 1; i < numCores; i++ { + isLeader, _, _, err := cores[i].Leader() + if err != nil { + t.Fatal(err) + } + if isLeader { + t.Fatalf("core[%d] should not be leader", i) + } + } + } + + // + // Set test cluster core(s) and test cluster + // + cluster, err := cores[0].Cluster(context.Background()) + if err != nil { + t.Fatal(err) + } + testCluster.ID = cluster.ID + } + + getAPIClient := func(port int, tlsConfig *tls.Config) *api.Client { + transport := cleanhttp.DefaultPooledTransport() + transport.TLSClientConfig = tlsConfig.Clone() + if err := http2.ConfigureTransport(transport); err != nil { + t.Fatal(err) + } + client := &http.Client{ + Transport: transport, + CheckRedirect: func(*http.Request, []*http.Request) error { + // This can of course be overridden per-test by using its own client + return fmt.Errorf("redirects not allowed in these tests") + }, + } + config := api.DefaultConfig() + if config.Error != nil { + t.Fatal(config.Error) + } + config.Address = fmt.Sprintf("https://127.0.0.1:%d", port) + config.HttpClient = client + apiClient, err := api.NewClient(config) + if err != nil { + t.Fatal(err) + } + if opts == nil || !opts.SkipInit { + apiClient.SetToken(testCluster.RootToken) + } + return apiClient + } + + var ret []*TestClusterCore + for i := 0; i < numCores; i++ { + tcc := &TestClusterCore{ + Core: cores[i], + ServerKey: certInfoSlice[i].key, + ServerKeyPEM: certInfoSlice[i].keyPEM, + ServerCert: certInfoSlice[i].cert, + ServerCertBytes: certInfoSlice[i].certBytes, + ServerCertPEM: certInfoSlice[i].certPEM, + Listeners: listeners[i], + Handler: handlers[i], + Server: servers[i], + TLSConfig: tlsConfigs[i], + Client: getAPIClient(listeners[i][0].Address.Port, tlsConfigs[i]), + } + tcc.ReloadFuncs = &cores[i].reloadFuncs + tcc.ReloadFuncsLock = &cores[i].reloadFuncsLock + tcc.ReloadFuncsLock.Lock() + (*tcc.ReloadFuncs)["listener|tcp"] = []reload.ReloadFunc{certGetters[i].Reload} + tcc.ReloadFuncsLock.Unlock() + ret = append(ret, tcc) + } + + testCluster.Cores = ret + return &testCluster +} diff --git a/vendor/github.com/hashicorp/vault/vault/token_store.go b/vendor/github.com/hashicorp/vault/vault/token_store.go new file mode 100644 index 0000000..349a869 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/token_store.go @@ -0,0 +1,2700 @@ +package vault + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "sync" + "sync/atomic" + + "regexp" + "strings" + "time" + + "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" + sockaddr "github.com/hashicorp/go-sockaddr" + + "github.com/armon/go-metrics" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/identity" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/locksutil" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/helper/policyutil" + "github.com/hashicorp/vault/helper/salt" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "github.com/mitchellh/mapstructure" +) + +const ( + // lookupPrefix is the prefix used to store tokens for their + // primary ID based index + lookupPrefix = "id/" + + // accessorPrefix is the prefix used to store the index from + // Accessor to Token ID + accessorPrefix = "accessor/" + + // parentPrefix is the prefix used to store tokens for their + // secondar parent based index + parentPrefix = "parent/" + + // tokenSubPath is the sub-path used for the token store + // view. This is nested under the system view. + tokenSubPath = "token/" + + // rolesPrefix is the prefix used to store role information + rolesPrefix = "roles/" + + // tokenRevocationPending indicates that the token should not be used + // again. If this is encountered during an existing request flow, it means + // that the token is but is currently fulfilling its final use; after this + // request it will not be able to be looked up as being valid. + tokenRevocationPending = -1 +) + +var ( + // displayNameSanitize is used to sanitize a display name given to a token. + displayNameSanitize = regexp.MustCompile("[^a-zA-Z0-9-]") + + // pathSuffixSanitize is used to ensure a path suffix in a role is valid. + pathSuffixSanitize = regexp.MustCompile("\\w[\\w-.]+\\w") + + destroyCubbyhole = func(ctx context.Context, ts *TokenStore, saltedID string) error { + if ts.cubbyholeBackend == nil { + // Should only ever happen in testing + return nil + } + return ts.cubbyholeBackend.revoke(ctx, salt.SaltID(ts.cubbyholeBackend.saltUUID, saltedID, salt.SHA1Hash)) + } +) + +// LookupToken returns the properties of the token from the token store. This +// is particularly useful to fetch the accessor of the client token and get it +// populated in the logical request along with the client token. The accessor +// of the client token can get audit logged. +func (c *Core) LookupToken(token string) (*TokenEntry, error) { + if token == "" { + return nil, fmt.Errorf("missing client token") + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return nil, consts.ErrSealed + } + if c.standby { + return nil, consts.ErrStandby + } + + // Many tests don't have a token store running + if c.tokenStore == nil { + return nil, nil + } + + return c.tokenStore.Lookup(c.activeContext, token) +} + +// TokenStore is used to manage client tokens. Tokens are used for +// clients to authenticate, and each token is mapped to an applicable +// set of policy which is used for authorization. +type TokenStore struct { + *framework.Backend + + view *BarrierView + + expiration *ExpirationManager + + cubbyholeBackend *CubbyholeBackend + + policyLookupFunc func(string) (*Policy, error) + + tokenLocks []*locksutil.LockEntry + + // tokenPendingDeletion stores tokens that are being revoked. If the token is + // not in the map, it means that there's no deletion in progress. If the value + // is true it means deletion is in progress, and if false it means deletion + // failed. Revocation needs to handle these states accordingly. + tokensPendingDeletion *sync.Map + + cubbyholeDestroyer func(context.Context, *TokenStore, string) error + + logger log.Logger + + saltLock sync.RWMutex + salt *salt.Salt + + tidyLock int64 + + identityPoliciesDeriverFunc func(string) (*identity.Entity, []string, error) +} + +// NewTokenStore is used to construct a token store that is +// backed by the given barrier view. +func NewTokenStore(ctx context.Context, logger log.Logger, c *Core, config *logical.BackendConfig) (*TokenStore, error) { + // Create a sub-view + view := c.systemBarrierView.SubView(tokenSubPath) + + // Initialize the store + t := &TokenStore{ + view: view, + cubbyholeDestroyer: destroyCubbyhole, + logger: logger, + tokenLocks: locksutil.CreateLocks(), + tokensPendingDeletion: &sync.Map{}, + saltLock: sync.RWMutex{}, + identityPoliciesDeriverFunc: c.fetchEntityAndDerivedPolicies, + } + + if c.policyStore != nil { + t.policyLookupFunc = func(name string) (*Policy, error) { + return c.policyStore.GetPolicy(ctx, name, PolicyTypeToken) + } + } + + // Setup the framework endpoints + t.Backend = &framework.Backend{ + AuthRenew: t.authRenew, + + PathsSpecial: &logical.Paths{ + Root: []string{ + "revoke-orphan/*", + "accessors*", + }, + + // Most token store items are local since tokens are local, but a + // notable exception is roles + LocalStorage: []string{ + lookupPrefix, + accessorPrefix, + parentPrefix, + salt.DefaultLocation, + }, + }, + + Paths: []*framework.Path{ + &framework.Path{ + Pattern: "roles/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: t.tokenStoreRoleList, + }, + + HelpSynopsis: tokenListRolesHelp, + HelpDescription: tokenListRolesHelp, + }, + + &framework.Path{ + Pattern: "accessors/$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: t.tokenStoreAccessorList, + }, + + HelpSynopsis: tokenListAccessorsHelp, + HelpDescription: tokenListAccessorsHelp, + }, + + &framework.Path{ + Pattern: "roles/" + framework.GenericNameRegex("role_name"), + Fields: map[string]*framework.FieldSchema{ + "role_name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Name of the role", + }, + + "allowed_policies": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: tokenAllowedPoliciesHelp, + }, + + "disallowed_policies": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: tokenDisallowedPoliciesHelp, + }, + + "orphan": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: tokenOrphanHelp, + }, + + "period": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Default: 0, + Description: tokenPeriodHelp, + }, + + "path_suffix": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "", + Description: tokenPathSuffixHelp + pathSuffixSanitize.String(), + }, + + "explicit_max_ttl": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Default: 0, + Description: tokenExplicitMaxTTLHelp, + }, + + "renewable": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: tokenRenewableHelp, + }, + + "bound_cidrs": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Comma separated string or JSON list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: t.tokenStoreRoleRead, + logical.CreateOperation: t.tokenStoreRoleCreateUpdate, + logical.UpdateOperation: t.tokenStoreRoleCreateUpdate, + logical.DeleteOperation: t.tokenStoreRoleDelete, + }, + + ExistenceCheck: t.tokenStoreRoleExistenceCheck, + + HelpSynopsis: tokenPathRolesHelp, + HelpDescription: tokenPathRolesHelp, + }, + + &framework.Path{ + Pattern: "create-orphan$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleCreateOrphan, + }, + + HelpSynopsis: strings.TrimSpace(tokenCreateOrphanHelp), + HelpDescription: strings.TrimSpace(tokenCreateOrphanHelp), + }, + + &framework.Path{ + Pattern: "create/" + framework.GenericNameRegex("role_name"), + + Fields: map[string]*framework.FieldSchema{ + "role_name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Name of the role", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleCreateAgainstRole, + }, + + HelpSynopsis: strings.TrimSpace(tokenCreateRoleHelp), + HelpDescription: strings.TrimSpace(tokenCreateRoleHelp), + }, + + &framework.Path{ + Pattern: "create$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleCreate, + }, + + HelpSynopsis: strings.TrimSpace(tokenCreateHelp), + HelpDescription: strings.TrimSpace(tokenCreateHelp), + }, + + &framework.Path{ + Pattern: "lookup" + framework.OptionalParamRegex("urltoken"), + + Fields: map[string]*framework.FieldSchema{ + "urltoken": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Token to lookup (URL parameter). Do not use this; use the POST version instead with the token in the body.", + }, + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to lookup (POST request body)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: t.handleLookup, + logical.UpdateOperation: t.handleLookup, + }, + + HelpSynopsis: strings.TrimSpace(tokenLookupHelp), + HelpDescription: strings.TrimSpace(tokenLookupHelp), + }, + + &framework.Path{ + Pattern: "lookup-accessor" + framework.OptionalParamRegex("urlaccessor"), + + Fields: map[string]*framework.FieldSchema{ + "urlaccessor": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Accessor of the token to lookup (URL parameter). Do not use this; use the POST version instead with the accessor in the body.", + }, + "accessor": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Accessor of the token to look up (request body)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleUpdateLookupAccessor, + }, + + HelpSynopsis: strings.TrimSpace(tokenLookupAccessorHelp), + HelpDescription: strings.TrimSpace(tokenLookupAccessorHelp), + }, + + &framework.Path{ + Pattern: "lookup-self$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to look up (unused, does not need to be set)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleLookupSelf, + logical.ReadOperation: t.handleLookupSelf, + }, + + HelpSynopsis: strings.TrimSpace(tokenLookupHelp), + HelpDescription: strings.TrimSpace(tokenLookupHelp), + }, + + &framework.Path{ + Pattern: "revoke-accessor" + framework.OptionalParamRegex("urlaccessor"), + + Fields: map[string]*framework.FieldSchema{ + "urlaccessor": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Accessor of the token to revoke (URL parameter). Do not use this; use the POST version instead with the accessor in the body.", + }, + "accessor": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Accessor of the token (request body)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleUpdateRevokeAccessor, + }, + + HelpSynopsis: strings.TrimSpace(tokenRevokeAccessorHelp), + HelpDescription: strings.TrimSpace(tokenRevokeAccessorHelp), + }, + + &framework.Path{ + Pattern: "revoke-self$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleRevokeSelf, + }, + + HelpSynopsis: strings.TrimSpace(tokenRevokeSelfHelp), + HelpDescription: strings.TrimSpace(tokenRevokeSelfHelp), + }, + + &framework.Path{ + Pattern: "revoke" + framework.OptionalParamRegex("urltoken"), + + Fields: map[string]*framework.FieldSchema{ + "urltoken": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Token to revoke (URL parameter). Do not use this; use the POST version instead with the token in the body.", + }, + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to revoke (request body)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleRevokeTree, + }, + + HelpSynopsis: strings.TrimSpace(tokenRevokeHelp), + HelpDescription: strings.TrimSpace(tokenRevokeHelp), + }, + + &framework.Path{ + Pattern: "revoke-orphan" + framework.OptionalParamRegex("urltoken"), + + Fields: map[string]*framework.FieldSchema{ + "urltoken": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Token to revoke (URL parameter). Do not use this; use the POST version instead with the token in the body.", + }, + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to revoke (request body)", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleRevokeOrphan, + }, + + HelpSynopsis: strings.TrimSpace(tokenRevokeOrphanHelp), + HelpDescription: strings.TrimSpace(tokenRevokeOrphanHelp), + }, + + &framework.Path{ + Pattern: "renew-self$", + + Fields: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to renew (unused, does not need to be set)", + }, + "increment": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Default: 0, + Description: "The desired increment in seconds to the token expiration", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleRenewSelf, + }, + + HelpSynopsis: strings.TrimSpace(tokenRenewSelfHelp), + HelpDescription: strings.TrimSpace(tokenRenewSelfHelp), + }, + + &framework.Path{ + Pattern: "renew" + framework.OptionalParamRegex("urltoken"), + + Fields: map[string]*framework.FieldSchema{ + "urltoken": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "DEPRECATED: Token to renew (URL parameter). Do not use this; use the POST version instead with the token in the body.", + }, + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to renew (request body)", + }, + "increment": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Default: 0, + Description: "The desired increment in seconds to the token expiration", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleRenew, + }, + + HelpSynopsis: strings.TrimSpace(tokenRenewHelp), + HelpDescription: strings.TrimSpace(tokenRenewHelp), + }, + + &framework.Path{ + Pattern: "tidy$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: t.handleTidy, + }, + + HelpSynopsis: strings.TrimSpace(tokenTidyHelp), + HelpDescription: strings.TrimSpace(tokenTidyDesc), + }, + }, + } + + t.Backend.Setup(ctx, config) + + return t, nil +} + +func (ts *TokenStore) Invalidate(ctx context.Context, key string) { + //ts.logger.Debug("invalidating key", "key", key) + + switch key { + case tokenSubPath + salt.DefaultLocation: + ts.saltLock.Lock() + ts.salt = nil + ts.saltLock.Unlock() + } +} + +func (ts *TokenStore) Salt(ctx context.Context) (*salt.Salt, error) { + ts.saltLock.RLock() + if ts.salt != nil { + defer ts.saltLock.RUnlock() + return ts.salt, nil + } + ts.saltLock.RUnlock() + ts.saltLock.Lock() + defer ts.saltLock.Unlock() + if ts.salt != nil { + return ts.salt, nil + } + salt, err := salt.NewSalt(ctx, ts.view, &salt.Config{ + HashFunc: salt.SHA1Hash, + Location: salt.DefaultLocation, + }) + if err != nil { + return nil, err + } + ts.salt = salt + return salt, nil +} + +// TokenEntry is used to represent a given token +type TokenEntry struct { + // ID of this entry, generally a random UUID + ID string `json:"id" mapstructure:"id" structs:"id" sentinel:""` + + // Accessor for this token, a random UUID + Accessor string `json:"accessor" mapstructure:"accessor" structs:"accessor" sentinel:""` + + // Parent token, used for revocation trees + Parent string `json:"parent" mapstructure:"parent" structs:"parent" sentinel:""` + + // Which named policies should be used + Policies []string `json:"policies" mapstructure:"policies" structs:"policies"` + + // Used for audit trails, this is something like "auth/user/login" + Path string `json:"path" mapstructure:"path" structs:"path"` + + // Used for auditing. This could include things like "source", "user", "ip" + Meta map[string]string `json:"meta" mapstructure:"meta" structs:"meta" sentinel:"meta"` + + // Used for operators to be able to associate with the source + DisplayName string `json:"display_name" mapstructure:"display_name" structs:"display_name"` + + // Used to restrict the number of uses (zero is unlimited). This is to + // support one-time-tokens (generalized). There are a few special values: + // if it's -1 it has run through its use counts and is executing its final + // use; if it's -2 it is tainted, which means revocation is currently + // running on it; and if it's -3 it's also tainted but revocation + // previously ran and failed, so this hints the tidy function to try it + // again. + NumUses int `json:"num_uses" mapstructure:"num_uses" structs:"num_uses"` + + // Time of token creation + CreationTime int64 `json:"creation_time" mapstructure:"creation_time" structs:"creation_time" sentinel:""` + + // Duration set when token was created + TTL time.Duration `json:"ttl" mapstructure:"ttl" structs:"ttl" sentinel:""` + + // Explicit maximum TTL on the token + ExplicitMaxTTL time.Duration `json:"explicit_max_ttl" mapstructure:"explicit_max_ttl" structs:"explicit_max_ttl" sentinel:""` + + // If set, the role that was used for parameters at creation time + Role string `json:"role" mapstructure:"role" structs:"role"` + + // If set, the period of the token. This is only used when created directly + // through the create endpoint; periods managed by roles or other auth + // backends are subject to those renewal rules. + Period time.Duration `json:"period" mapstructure:"period" structs:"period" sentinel:""` + + // These are the deprecated fields + DisplayNameDeprecated string `json:"DisplayName" mapstructure:"DisplayName" structs:"DisplayName" sentinel:""` + NumUsesDeprecated int `json:"NumUses" mapstructure:"NumUses" structs:"NumUses" sentinel:""` + CreationTimeDeprecated int64 `json:"CreationTime" mapstructure:"CreationTime" structs:"CreationTime" sentinel:""` + ExplicitMaxTTLDeprecated time.Duration `json:"ExplicitMaxTTL" mapstructure:"ExplicitMaxTTL" structs:"ExplicitMaxTTL" sentinel:""` + + EntityID string `json:"entity_id" mapstructure:"entity_id" structs:"entity_id"` + + // The set of CIDRs that this token can be used with + BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"` +} + +func (te *TokenEntry) SentinelGet(key string) (interface{}, error) { + if te == nil { + return nil, nil + } + switch key { + case "period": + return te.Period, nil + + case "period_seconds": + return int64(te.Period.Seconds()), nil + + case "explicit_max_ttl": + return te.ExplicitMaxTTL, nil + + case "explicit_max_ttl_seconds": + return int64(te.ExplicitMaxTTL.Seconds()), nil + + case "creation_ttl": + return te.TTL, nil + + case "creation_ttl_seconds": + return int64(te.TTL.Seconds()), nil + + case "creation_time": + return time.Unix(te.CreationTime, 0).Format(time.RFC3339Nano), nil + + case "creation_time_unix": + return time.Unix(te.CreationTime, 0), nil + + case "meta", "metadata": + return te.Meta, nil + } + + return nil, nil +} + +func (te *TokenEntry) SentinelKeys() []string { + return []string{ + "period", + "period_seconds", + "explicit_max_ttl", + "explicit_max_ttl_seconds", + "creation_ttl", + "creation_ttl_seconds", + "creation_time", + "creation_time_unix", + "meta", + "metadata", + } +} + +// tsRoleEntry contains token store role information +type tsRoleEntry struct { + // The name of the role. Embedded so it can be used for pathing + Name string `json:"name" mapstructure:"name" structs:"name"` + + // The policies that creation functions using this role can assign to a token, + // escaping or further locking down normal subset checking + AllowedPolicies []string `json:"allowed_policies" mapstructure:"allowed_policies" structs:"allowed_policies"` + + // List of policies to be not allowed during token creation using this role + DisallowedPolicies []string `json:"disallowed_policies" mapstructure:"disallowed_policies" structs:"disallowed_policies"` + + // If true, tokens created using this role will be orphans + Orphan bool `json:"orphan" mapstructure:"orphan" structs:"orphan"` + + // If non-zero, tokens created using this role will be able to be renewed + // forever, but will have a fixed renewal period of this value + Period time.Duration `json:"period" mapstructure:"period" structs:"period"` + + // If set, a suffix will be set on the token path, making it easier to + // revoke using 'revoke-prefix' + PathSuffix string `json:"path_suffix" mapstructure:"path_suffix" structs:"path_suffix"` + + // If set, controls whether created tokens are marked as being renewable + Renewable bool `json:"renewable" mapstructure:"renewable" structs:"renewable"` + + // If set, the token entry will have an explicit maximum TTL set, rather + // than deferring to role/mount values + ExplicitMaxTTL time.Duration `json:"explicit_max_ttl" mapstructure:"explicit_max_ttl" structs:"explicit_max_ttl"` + + // The set of CIDRs that tokens generated using this role will be bound to + BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"` +} + +type accessorEntry struct { + TokenID string `json:"token_id"` + AccessorID string `json:"accessor_id"` +} + +// SetExpirationManager is used to provide the token store with +// an expiration manager. This is used to manage prefix based revocation +// of tokens and to tidy entries when removed from the token store. +func (ts *TokenStore) SetExpirationManager(exp *ExpirationManager) { + ts.expiration = exp +} + +// SaltID is used to apply a salt and hash to an ID to make sure its not reversible +func (ts *TokenStore) SaltID(ctx context.Context, id string) (string, error) { + s, err := ts.Salt(ctx) + if err != nil { + return "", err + } + + return s.SaltID(id), nil +} + +// RootToken is used to generate a new token with root privileges and no parent +func (ts *TokenStore) rootToken(ctx context.Context) (*TokenEntry, error) { + te := &TokenEntry{ + Policies: []string{"root"}, + Path: "auth/token/root", + DisplayName: "root", + CreationTime: time.Now().Unix(), + } + if err := ts.create(ctx, te); err != nil { + return nil, err + } + return te, nil +} + +func (ts *TokenStore) tokenStoreAccessorList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := ts.view.List(ctx, accessorPrefix) + if err != nil { + return nil, err + } + + resp := &logical.Response{} + + ret := make([]string, 0, len(entries)) + for _, entry := range entries { + aEntry, err := ts.lookupBySaltedAccessor(ctx, entry, false) + if err != nil { + resp.AddWarning("Found an accessor entry that could not be successfully decoded") + continue + } + if aEntry.TokenID == "" { + resp.AddWarning(fmt.Sprintf("Found an accessor entry missing a token: %v", aEntry.AccessorID)) + } else { + ret = append(ret, aEntry.AccessorID) + } + } + + resp.Data = map[string]interface{}{ + "keys": ret, + } + return resp, nil +} + +// createAccessor is used to create an identifier for the token ID. +// A storage index, mapping the accessor to the token ID is also created. +func (ts *TokenStore) createAccessor(ctx context.Context, entry *TokenEntry) error { + defer metrics.MeasureSince([]string{"token", "createAccessor"}, time.Now()) + + // Create a random accessor + accessorUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.Accessor = accessorUUID + + // Create index entry, mapping the accessor to the token ID + saltID, err := ts.SaltID(ctx, entry.Accessor) + if err != nil { + return err + } + + path := accessorPrefix + saltID + aEntry := &accessorEntry{ + TokenID: entry.ID, + AccessorID: entry.Accessor, + } + aEntryBytes, err := jsonutil.EncodeJSON(aEntry) + if err != nil { + return errwrap.Wrapf("failed to marshal accessor index entry: {{err}}", err) + } + + le := &logical.StorageEntry{Key: path, Value: aEntryBytes} + if err := ts.view.Put(ctx, le); err != nil { + return errwrap.Wrapf("failed to persist accessor index entry: {{err}}", err) + } + return nil +} + +// Create is used to create a new token entry. The entry is assigned +// a newly generated ID if not provided. +func (ts *TokenStore) create(ctx context.Context, entry *TokenEntry) error { + defer metrics.MeasureSince([]string{"token", "create"}, time.Now()) + // Generate an ID if necessary + if entry.ID == "" { + entryUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.ID = entryUUID + } + + saltedID, err := ts.SaltID(ctx, entry.ID) + if err != nil { + return err + } + exist, _ := ts.lookupSalted(ctx, saltedID, true) + if exist != nil { + return fmt.Errorf("cannot create a token with a duplicate ID") + } + + entry.Policies = policyutil.SanitizePolicies(entry.Policies, policyutil.DoNotAddDefaultPolicy) + + err = ts.createAccessor(ctx, entry) + if err != nil { + return err + } + + return ts.storeCommon(ctx, entry, true) +} + +// Store is used to store an updated token entry without writing the +// secondary index. +func (ts *TokenStore) store(ctx context.Context, entry *TokenEntry) error { + defer metrics.MeasureSince([]string{"token", "store"}, time.Now()) + return ts.storeCommon(ctx, entry, false) +} + +// storeCommon handles the actual storage of an entry, possibly generating +// secondary indexes +func (ts *TokenStore) storeCommon(ctx context.Context, entry *TokenEntry, writeSecondary bool) error { + saltedID, err := ts.SaltID(ctx, entry.ID) + if err != nil { + return err + } + + // Marshal the entry + enc, err := json.Marshal(entry) + if err != nil { + return errwrap.Wrapf("failed to encode entry: {{err}}", err) + } + + if writeSecondary { + // Write the secondary index if necessary. This is done before the + // primary index because we'd rather have a dangling pointer with + // a missing primary instead of missing the parent index and potentially + // escaping the revocation chain. + if entry.Parent != "" { + // Ensure the parent exists + parent, err := ts.Lookup(ctx, entry.Parent) + if err != nil { + return errwrap.Wrapf("failed to lookup parent: {{err}}", err) + } + if parent == nil { + return fmt.Errorf("parent token not found") + } + + // Create the index entry + parentSaltedID, err := ts.SaltID(ctx, entry.Parent) + if err != nil { + return err + } + path := parentPrefix + parentSaltedID + "/" + saltedID + le := &logical.StorageEntry{Key: path} + if err := ts.view.Put(ctx, le); err != nil { + return errwrap.Wrapf("failed to persist entry: {{err}}", err) + } + } + } + + // Write the primary ID + path := lookupPrefix + saltedID + le := &logical.StorageEntry{Key: path, Value: enc} + if len(entry.Policies) == 1 && entry.Policies[0] == "root" { + le.SealWrap = true + } + if err := ts.view.Put(ctx, le); err != nil { + return errwrap.Wrapf("failed to persist entry: {{err}}", err) + } + return nil +} + +// UseToken is used to manage restricted use tokens and decrement their +// available uses. Returns two values: a potentially updated entry or, if the +// token has been revoked, nil; and whether an error was encountered. The +// locking here isn't perfect, as other parts of the code may update an entry, +// but usually none after the entry is already created...so this is pretty +// good. +func (ts *TokenStore) UseToken(ctx context.Context, te *TokenEntry) (*TokenEntry, error) { + if te == nil { + return nil, fmt.Errorf("invalid token entry provided for use count decrementing") + } + + // This case won't be hit with a token with restricted uses because we go + // from 1 to -1. So it's a nice optimization to check this without a read + // lock. + if te.NumUses == 0 { + return te, nil + } + + // If we are attempting to unwrap a control group request, don't use the token. + // It will be manually revoked by the handler. + if len(te.Policies) == 1 && te.Policies[0] == controlGroupPolicyName { + return te, nil + } + + lock := locksutil.LockForKey(ts.tokenLocks, te.ID) + lock.Lock() + defer lock.Unlock() + + // Call lookupSalted instead of Lookup to avoid deadlocking since Lookup grabs a read lock + saltedID, err := ts.SaltID(ctx, te.ID) + if err != nil { + return nil, err + } + + te, err = ts.lookupSalted(ctx, saltedID, false) + if err != nil { + return nil, errwrap.Wrapf("failed to refresh entry: {{err}}", err) + } + // If it can't be found we shouldn't be trying to use it, so if we get nil + // back, it is because it has been revoked in the interim or will be + // revoked (NumUses is -1) + if te == nil { + return nil, fmt.Errorf("token not found or fully used already") + } + + // Decrement the count. If this is our last use count, we need to indicate + // that this is no longer valid, but revocation is deferred to the end of + // the call, so this will make sure that any Lookup that happens doesn't + // return an entry. This essentially acts as a write-ahead lock and is + // especially useful since revocation can end up (via the expiration + // manager revoking children) attempting to acquire the same lock + // repeatedly. + if te.NumUses == 1 { + te.NumUses = tokenRevocationPending + } else { + te.NumUses-- + } + + err = ts.store(ctx, te) + if err != nil { + return nil, err + } + + return te, nil +} + +func (ts *TokenStore) UseTokenByID(ctx context.Context, id string) (*TokenEntry, error) { + te, err := ts.Lookup(ctx, id) + if err != nil { + return te, err + } + + return ts.UseToken(ctx, te) +} + +// Lookup is used to find a token given its ID. It acquires a read lock, then calls lookupSalted. +func (ts *TokenStore) Lookup(ctx context.Context, id string) (*TokenEntry, error) { + defer metrics.MeasureSince([]string{"token", "lookup"}, time.Now()) + if id == "" { + return nil, fmt.Errorf("cannot lookup blank token") + } + + lock := locksutil.LockForKey(ts.tokenLocks, id) + lock.RLock() + defer lock.RUnlock() + + saltedID, err := ts.SaltID(ctx, id) + if err != nil { + return nil, err + } + return ts.lookupSalted(ctx, saltedID, false) +} + +// lookupTainted is used to find a token that may or maynot be tainted given its +// ID. It acquires a read lock, then calls lookupSalted. +func (ts *TokenStore) lookupTainted(ctx context.Context, id string) (*TokenEntry, error) { + defer metrics.MeasureSince([]string{"token", "lookup"}, time.Now()) + if id == "" { + return nil, fmt.Errorf("cannot lookup blank token") + } + + lock := locksutil.LockForKey(ts.tokenLocks, id) + lock.RLock() + defer lock.RUnlock() + + saltedID, err := ts.SaltID(ctx, id) + if err != nil { + return nil, err + } + return ts.lookupSalted(ctx, saltedID, true) +} + +// lookupSalted is used to find a token given its salted ID. If tainted is +// true, entries that are in some revocation state (currently, indicated by num +// uses < 0), the entry will be returned anyways +func (ts *TokenStore) lookupSalted(ctx context.Context, saltedID string, tainted bool) (*TokenEntry, error) { + // Lookup token + path := lookupPrefix + saltedID + raw, err := ts.view.Get(ctx, path) + if err != nil { + return nil, errwrap.Wrapf("failed to read entry: {{err}}", err) + } + + // Bail if not found + if raw == nil { + return nil, nil + } + + // Unmarshal the token + entry := new(TokenEntry) + if err := jsonutil.DecodeJSON(raw.Value, entry); err != nil { + return nil, errwrap.Wrapf("failed to decode entry: {{err}}", err) + } + + // This is a token that is awaiting deferred revocation or tainted + if entry.NumUses < 0 && !tainted { + return nil, nil + } + + persistNeeded := false + + // Upgrade the deprecated fields + if entry.DisplayNameDeprecated != "" { + if entry.DisplayName == "" { + entry.DisplayName = entry.DisplayNameDeprecated + } + entry.DisplayNameDeprecated = "" + persistNeeded = true + } + + if entry.CreationTimeDeprecated != 0 { + if entry.CreationTime == 0 { + entry.CreationTime = entry.CreationTimeDeprecated + } + entry.CreationTimeDeprecated = 0 + persistNeeded = true + } + + if entry.ExplicitMaxTTLDeprecated != 0 { + if entry.ExplicitMaxTTL == 0 { + entry.ExplicitMaxTTL = entry.ExplicitMaxTTLDeprecated + } + entry.ExplicitMaxTTLDeprecated = 0 + persistNeeded = true + } + + if entry.NumUsesDeprecated != 0 { + if entry.NumUses == 0 || entry.NumUsesDeprecated < entry.NumUses { + entry.NumUses = entry.NumUsesDeprecated + } + entry.NumUsesDeprecated = 0 + persistNeeded = true + } + + // Perform these checks on upgraded fields, but before persisting + + // If we are still restoring the expiration manager, we want to ensure the + // token is not expired + if ts.expiration == nil { + return nil, errors.New("expiration manager is nil on tokenstore") + } + le, err := ts.expiration.FetchLeaseTimesByToken(entry.Path, entry.ID) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch lease times: {{err}}", err) + } + + var ret *TokenEntry + + switch { + // It's a root token with unlimited creation TTL (so never had an + // expiration); this may or may not have a lease (based on when it was + // generated, for later revocation purposes) but it doesn't matter, it's + // allowed + case len(entry.Policies) == 1 && entry.Policies[0] == "root" && entry.TTL == 0: + ret = entry + + // It's any kind of expiring token with no lease, immediately delete it + case le == nil: + leaseID, err := ts.expiration.CreateOrFetchRevocationLeaseByToken(entry) + if err != nil { + return nil, err + } + + err = ts.expiration.Revoke(leaseID) + if err != nil { + return nil, err + } + + // Only return if we're not past lease expiration (or if tainted is true), + // otherwise assume expmgr is working on revocation + default: + if !le.ExpireTime.Before(time.Now()) || tainted { + ret = entry + } + } + + // If fields are getting upgraded, store the changes + if persistNeeded { + if err := ts.store(ctx, entry); err != nil { + return nil, errwrap.Wrapf("failed to persist token upgrade: {{err}}", err) + } + } + + return ret, nil +} + +// Revoke is used to invalidate a given token, any child tokens +// will be orphaned. +func (ts *TokenStore) revokeOrphan(ctx context.Context, id string) error { + defer metrics.MeasureSince([]string{"token", "revoke"}, time.Now()) + if id == "" { + return fmt.Errorf("cannot revoke blank token") + } + + saltedID, err := ts.SaltID(ctx, id) + if err != nil { + return err + } + return ts.revokeSalted(ctx, saltedID, false) +} + +// revokeSalted is used to invalidate a given salted token, any child tokens +// will be orphaned unless otherwise specified. skipOrphan should be used +// whenever we are revoking the entire tree starting from a particular parent +// (e.g. revokeTreeSalted). +func (ts *TokenStore) revokeSalted(ctx context.Context, saltedID string, skipOrphan bool) (ret error) { + // Check and set the token deletion state. We only proceed with the deletion + // if we don't have a pending deletion (empty), or if the deletion previously + // failed (state is false) + state, loaded := ts.tokensPendingDeletion.LoadOrStore(saltedID, true) + + // If the entry was loaded and its state is true, we short-circuit + if loaded && state == true { + return nil + } + + // The map check above should protect use from any concurrent revocations, so + // doing a bare lookup here should be fine. + entry, err := ts.lookupSalted(ctx, saltedID, true) + if err != nil { + return err + } + if entry == nil { + return nil + } + + if entry.NumUses != tokenRevocationPending { + entry.NumUses = tokenRevocationPending + if err := ts.store(ctx, entry); err != nil { + // The only real reason for this is an underlying storage error + // which also means that nothing else in this func or expmgr will + // really work either. So we clear revocation state so the user can + // try again. + ts.logger.Error("failed to mark token as revoked") + ts.tokensPendingDeletion.Store(saltedID, false) + return err + } + } + + defer func() { + // If we succeeded in all other revocation operations after this defer and + // before we return, we can remove the token store entry + if ret == nil { + path := lookupPrefix + saltedID + if err := ts.view.Delete(ctx, path); err != nil { + ret = errwrap.Wrapf("failed to delete entry: {{err}}", err) + } + } + + // Check on ret again and update the sync.Map accordingly + if ret != nil { + // If we failed on any of the calls within, we store the state as false + // so that the next call to revokeSalted will retry + ts.tokensPendingDeletion.Store(saltedID, false) + } else { + ts.tokensPendingDeletion.Delete(saltedID) + } + }() + + // Destroy the token's cubby. This should go first as it's a + // security-sensitive item. + err = ts.cubbyholeDestroyer(ctx, ts, saltedID) + if err != nil { + return err + } + + // Revoke all secrets under this token. This should go first as it's a + // security-sensitive item. + if err := ts.expiration.RevokeByToken(entry); err != nil { + return err + } + + // Clear the secondary index if any + if entry.Parent != "" { + parentSaltedID, err := ts.SaltID(ctx, entry.Parent) + if err != nil { + return err + } + + path := parentPrefix + parentSaltedID + "/" + saltedID + if err = ts.view.Delete(ctx, path); err != nil { + return errwrap.Wrapf("failed to delete entry: {{err}}", err) + } + } + + // Clear the accessor index if any + if entry.Accessor != "" { + accessorSaltedID, err := ts.SaltID(ctx, entry.Accessor) + if err != nil { + return err + } + + path := accessorPrefix + accessorSaltedID + if err = ts.view.Delete(ctx, path); err != nil { + return errwrap.Wrapf("failed to delete entry: {{err}}", err) + } + } + + if !skipOrphan { + // Mark all children token as orphan by removing + // their parent index, and clear the parent entry. + // + // Marking the token as orphan should be skipped if it's called by + // revokeTreeSalted to avoid unnecessary view.List operations. Since + // the deletion occurs in a DFS fashion we don't need to perform a delete + // on child prefixes as there will be none (as saltedID entry is a leaf node). + parentPath := parentPrefix + saltedID + "/" + children, err := ts.view.List(ctx, parentPath) + if err != nil { + return errwrap.Wrapf("failed to scan for children: {{err}}", err) + } + for _, child := range children { + entry, err := ts.lookupSalted(ctx, child, true) + if err != nil { + return errwrap.Wrapf("failed to get child token: {{err}}", err) + } + lock := locksutil.LockForKey(ts.tokenLocks, entry.ID) + lock.Lock() + + entry.Parent = "" + err = ts.store(ctx, entry) + if err != nil { + lock.Unlock() + return errwrap.Wrapf("failed to update child token: {{err}}", err) + } + lock.Unlock() + + // Delete the the child storage entry after we update the token entry Since + // paths are not deeply nested (i.e. they are simply + // parenPrefix//), we can simply call view.Delete instead + // of logical.ClearView + index := parentPath + child + err = ts.view.Delete(ctx, index) + if err != nil { + return errwrap.Wrapf("failed to delete child entry: {{err}}", err) + } + } + } + + return nil +} + +// revokeTree is used to invalidate a given token and all +// child tokens. +func (ts *TokenStore) revokeTree(ctx context.Context, id string) error { + defer metrics.MeasureSince([]string{"token", "revoke-tree"}, time.Now()) + // Verify the token is not blank + if id == "" { + return fmt.Errorf("cannot tree-revoke blank token") + } + + // Get the salted ID + saltedID, err := ts.SaltID(ctx, id) + if err != nil { + return err + } + + // Nuke the entire tree recursively + return ts.revokeTreeSalted(ctx, saltedID) +} + +// revokeTreeSalted is used to invalidate a given token and all +// child tokens using a saltedID. +// Updated to be non-recursive and revoke child tokens +// before parent tokens(DFS). +func (ts *TokenStore) revokeTreeSalted(ctx context.Context, saltedID string) error { + var dfs []string + dfs = append(dfs, saltedID) + + for l := len(dfs); l > 0; l = len(dfs) { + id := dfs[0] + path := parentPrefix + id + "/" + children, err := ts.view.List(ctx, path) + if err != nil { + return errwrap.Wrapf("failed to scan for children: {{err}}", err) + } + // If the length of the children array is zero, + // then we are at a leaf node. + if len(children) == 0 { + // Whenever revokeSalted is called, the token will be removed immediately and + // any underlying secrets will be handed off to the expiration manager which will + // take care of expiring them. If Vault is restarted, any revoked tokens + // would have been deleted, and any pending leases for deletion will be restored + // by the expiration manager. + if err := ts.revokeSalted(ctx, id, true); err != nil { + + return errwrap.Wrapf("failed to revoke entry: {{err}}", err) + } + // If the length of l is equal to 1, then the last token has been deleted + if l == 1 { + return nil + } + dfs = dfs[1:] + } else { + // If we make it here, there are children and they must + // be prepended. + dfs = append(children, dfs...) + } + } + + return nil +} + +// handleCreateAgainstRole handles the auth/token/create path for a role +func (ts *TokenStore) handleCreateAgainstRole(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("role_name").(string) + roleEntry, err := ts.tokenStoreRole(ctx, name) + if err != nil { + return nil, err + } + if roleEntry == nil { + return logical.ErrorResponse(fmt.Sprintf("unknown role %s", name)), nil + } + + return ts.handleCreateCommon(ctx, req, d, false, roleEntry) +} + +func (ts *TokenStore) lookupByAccessor(ctx context.Context, accessor string, tainted bool) (accessorEntry, error) { + saltedID, err := ts.SaltID(ctx, accessor) + if err != nil { + return accessorEntry{}, err + } + return ts.lookupBySaltedAccessor(ctx, saltedID, tainted) +} + +func (ts *TokenStore) lookupBySaltedAccessor(ctx context.Context, saltedAccessor string, tainted bool) (accessorEntry, error) { + entry, err := ts.view.Get(ctx, accessorPrefix+saltedAccessor) + var aEntry accessorEntry + + if err != nil { + return aEntry, errwrap.Wrapf("failed to read index using accessor: {{err}}", err) + } + if entry == nil { + return aEntry, &logical.StatusBadRequest{Err: "invalid accessor"} + } + + err = jsonutil.DecodeJSON(entry.Value, &aEntry) + // If we hit an error, assume it's a pre-struct straight token ID + if err != nil { + saltedID, err := ts.SaltID(ctx, string(entry.Value)) + if err != nil { + return accessorEntry{}, err + } + + te, err := ts.lookupSalted(ctx, saltedID, tainted) + if err != nil { + return accessorEntry{}, errwrap.Wrapf("failed to look up token using accessor index: {{err}}", err) + } + // It's hard to reason about what to do here -- it may be that the + // token was revoked async, or that it's an old accessor index entry + // that was somehow not cleared up, or or or. A nonexistent token entry + // on lookup is nil, not an error, so we keep that behavior here to be + // safe...the token ID is simply not filled in. + if te != nil { + aEntry.TokenID = te.ID + aEntry.AccessorID = te.Accessor + } + } + + return aEntry, nil +} + +// handleTidy handles the cleaning up of leaked accessor storage entries and +// cleaning up of leases that are associated to tokens that are expired. +func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var tidyErrors *multierror.Error + + if !atomic.CompareAndSwapInt64(&ts.tidyLock, 0, 1) { + ts.logger.Warn("tidy operation on tokens is already in progress") + return nil, fmt.Errorf("tidy operation on tokens is already in progress") + } + + defer atomic.CompareAndSwapInt64(&ts.tidyLock, 1, 0) + + ts.logger.Info("beginning tidy operation on tokens") + defer ts.logger.Info("finished tidy operation on tokens") + + // List out all the accessors + saltedAccessorList, err := ts.view.List(ctx, accessorPrefix) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch accessor index entries: {{err}}", err) + } + + // First, clean up secondary index entries that are no longer valid + parentList, err := ts.view.List(ctx, parentPrefix) + if err != nil { + return nil, errwrap.Wrapf("failed to fetch secondary index entries: {{err}}", err) + } + + var countParentEntries, deletedCountParentEntries, countParentList, deletedCountParentList int64 + + // Scan through the secondary index entries; if there is an entry + // with the token's salt ID at the end, remove it + for _, parent := range parentList { + countParentEntries++ + + // Get the children + children, err := ts.view.List(ctx, parentPrefix+parent) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to read secondary index: {{err}}", err)) + continue + } + + // First check if the salt ID of the parent exists, and if not mark this so + // that deletion of children later with this loop below applies to all + // children + originalChildrenCount := int64(len(children)) + exists, _ := ts.lookupSalted(ctx, strings.TrimSuffix(parent, "/"), true) + if exists == nil { + ts.logger.Debug("deleting invalid parent prefix entry", "index", parentPrefix+parent) + } + + var deletedChildrenCount int64 + for _, child := range children { + countParentList++ + if countParentList%500 == 0 { + ts.logger.Info("checking validity of tokens in secondary index list", "progress", countParentList) + } + + // Look up tainted entries so we can be sure that if this isn't + // found, it doesn't exist. Doing the following without locking + // since appropriate locks cannot be held with salted token IDs. + // Also perform deletion if the parent doesn't exist any more. + te, _ := ts.lookupSalted(ctx, child, true) + // If the child entry is not nil, but the parent doesn't exist, then turn + // that child token into an orphan token. Theres no deletion in this case. + if te != nil && exists == nil { + lock := locksutil.LockForKey(ts.tokenLocks, te.ID) + lock.Lock() + + te.Parent = "" + err = ts.store(ctx, te) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to convert child token into an orphan token: {{err}}", err)) + } + lock.Unlock() + continue + } + // Otherwise, if the entry doesn't exist, or if the parent doesn't exist go + // on with the delete on the secondary index + if te == nil || exists == nil { + index := parentPrefix + parent + child + ts.logger.Debug("deleting invalid secondary index", "index", index) + err = ts.view.Delete(ctx, index) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to delete secondary index: {{err}}", err)) + continue + } + deletedChildrenCount++ + } + } + // Add current children deleted count to the total count + deletedCountParentList += deletedChildrenCount + // N.B.: We don't call delete on the parent prefix since physical.Backend.Delete + // implementations should be in charge of deleting empty prefixes. + // If we deleted all the children, then add that to our deleted parent entries count. + if originalChildrenCount == deletedChildrenCount { + deletedCountParentEntries++ + } + } + + var countAccessorList, + deletedCountAccessorEmptyToken, + deletedCountAccessorInvalidToken, + deletedCountInvalidTokenInAccessor int64 + + // For each of the accessor, see if the token ID associated with it is + // a valid one. If not, delete the leases associated with that token + // and delete the accessor as well. + for _, saltedAccessor := range saltedAccessorList { + countAccessorList++ + if countAccessorList%500 == 0 { + ts.logger.Info("checking if accessors contain valid tokens", "progress", countAccessorList) + } + + accessorEntry, err := ts.lookupBySaltedAccessor(ctx, saltedAccessor, true) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to read the accessor index: {{err}}", err)) + continue + } + + // A valid accessor storage entry should always have a token ID + // in it. If not, it is an invalid accessor entry and needs to + // be deleted. + if accessorEntry.TokenID == "" { + index := accessorPrefix + saltedAccessor + // If deletion of accessor fails, move on to the next + // item since this is just a best-effort operation + err = ts.view.Delete(ctx, index) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to delete the accessor index: {{err}}", err)) + continue + } + deletedCountAccessorEmptyToken++ + } + + lock := locksutil.LockForKey(ts.tokenLocks, accessorEntry.TokenID) + lock.RLock() + + // Look up tainted variants so we only find entries that truly don't + // exist + saltedID, err := ts.SaltID(ctx, accessorEntry.TokenID) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to read salt id: {{err}}", err)) + lock.RUnlock() + continue + } + te, err := ts.lookupSalted(ctx, saltedID, true) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to lookup tainted ID: {{err}}", err)) + lock.RUnlock() + continue + } + + lock.RUnlock() + + // If token entry is not found assume that the token is not valid any + // more and conclude that accessor, leases, and secondary index entries + // for this token should not exist as well. + if te == nil { + ts.logger.Info("deleting token with nil entry", "salted_token", saltedID) + + // RevokeByToken expects a '*TokenEntry'. For the + // purposes of tidying, it is sufficient if the token + // entry only has ID set. + tokenEntry := &TokenEntry{ + ID: accessorEntry.TokenID, + } + + // Attempt to revoke the token. This will also revoke + // the leases associated with the token. + err := ts.expiration.RevokeByToken(tokenEntry) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to revoke leases of expired token: {{err}}", err)) + continue + } + deletedCountInvalidTokenInAccessor++ + + index := accessorPrefix + saltedAccessor + + // If deletion of accessor fails, move on to the next item since + // this is just a best-effort operation. We do this last so that on + // next run if something above failed we still have the accessor + // entry to try again. + err = ts.view.Delete(ctx, index) + if err != nil { + tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to delete accessor entry: {{err}}", err)) + continue + } + deletedCountAccessorInvalidToken++ + } + } + + ts.logger.Info("number of entries scanned in parent prefix", "count", countParentEntries) + ts.logger.Info("number of entries deleted in parent prefix", "count", deletedCountParentEntries) + ts.logger.Info("number of tokens scanned in parent index list", "count", countParentList) + ts.logger.Info("number of tokens revoked in parent index list", "count", deletedCountParentList) + ts.logger.Info("number of accessors scanned", "count", countAccessorList) + ts.logger.Info("number of deleted accessors which had empty tokens", "count", deletedCountAccessorEmptyToken) + ts.logger.Info("number of revoked tokens which were invalid but present in accessors", "count", deletedCountInvalidTokenInAccessor) + ts.logger.Info("number of deleted accessors which had invalid tokens", "count", deletedCountAccessorInvalidToken) + + return nil, tidyErrors.ErrorOrNil() +} + +// handleUpdateLookupAccessor handles the auth/token/lookup-accessor path for returning +// the properties of the token associated with the accessor +func (ts *TokenStore) handleUpdateLookupAccessor(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urlaccessor bool + accessor := data.Get("accessor").(string) + if accessor == "" { + accessor = data.Get("urlaccessor").(string) + if accessor == "" { + return nil, &logical.StatusBadRequest{Err: "missing accessor"} + } + urlaccessor = true + } + + aEntry, err := ts.lookupByAccessor(ctx, accessor, false) + if err != nil { + return nil, err + } + + // Prepare the field data required for a lookup call + d := &framework.FieldData{ + Raw: map[string]interface{}{ + "token": aEntry.TokenID, + }, + Schema: map[string]*framework.FieldSchema{ + "token": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Token to lookup", + }, + }, + } + resp, err := ts.handleLookup(ctx, req, d) + if err != nil { + return nil, err + } + if resp == nil { + return nil, fmt.Errorf("failed to lookup the token") + } + if resp.IsError() { + return resp, nil + + } + + // Remove the token ID from the response + if resp.Data != nil { + resp.Data["id"] = "" + } + + if urlaccessor { + resp.AddWarning(`Using an accessor in the path is unsafe as the accessor can be logged in many places. Please use POST or PUT with the accessor passed in via the "accessor" parameter.`) + } + + return resp, nil +} + +// handleUpdateRevokeAccessor handles the auth/token/revoke-accessor path for revoking +// the token associated with the accessor +func (ts *TokenStore) handleUpdateRevokeAccessor(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urlaccessor bool + accessor := data.Get("accessor").(string) + if accessor == "" { + accessor = data.Get("urlaccessor").(string) + if accessor == "" { + return nil, &logical.StatusBadRequest{Err: "missing accessor"} + } + urlaccessor = true + } + + aEntry, err := ts.lookupByAccessor(ctx, accessor, true) + if err != nil { + return nil, err + } + + te, err := ts.Lookup(ctx, aEntry.TokenID) + if err != nil { + return nil, err + } + + if te == nil { + return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest + } + + leaseID, err := ts.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err != nil { + return nil, err + } + + err = ts.expiration.Revoke(leaseID) + if err != nil { + return nil, err + } + + if urlaccessor { + resp := &logical.Response{} + resp.AddWarning(`Using an accessor in the path is unsafe as the accessor can be logged in many places. Please use POST or PUT with the accessor passed in via the "accessor" parameter.`) + return resp, nil + } + + return nil, nil +} + +// handleCreate handles the auth/token/create path for creation of new orphan +// tokens +func (ts *TokenStore) handleCreateOrphan(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + return ts.handleCreateCommon(ctx, req, d, true, nil) +} + +// handleCreate handles the auth/token/create path for creation of new non-orphan +// tokens +func (ts *TokenStore) handleCreate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + return ts.handleCreateCommon(ctx, req, d, false, nil) +} + +// handleCreateCommon handles the auth/token/create path for creation of new tokens +func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Request, d *framework.FieldData, orphan bool, role *tsRoleEntry) (*logical.Response, error) { + // Read the parent policy + parent, err := ts.Lookup(ctx, req.ClientToken) + if err != nil { + return nil, errwrap.Wrapf("parent token lookup failed: {{err}}", err) + } + if parent == nil { + return logical.ErrorResponse("parent token lookup failed: no parent found"), logical.ErrInvalidRequest + } + + // A token with a restricted number of uses cannot create a new token + // otherwise it could escape the restriction count. + if parent.NumUses > 0 { + return logical.ErrorResponse("restricted use token cannot generate child tokens"), + logical.ErrInvalidRequest + } + + // Check if the client token has sudo/root privileges for the requested path + isSudo := ts.System().SudoPrivilege(ctx, req.MountPoint+req.Path, req.ClientToken) + + // Read and parse the fields + var data struct { + ID string + Policies []string + Metadata map[string]string `mapstructure:"meta"` + NoParent bool `mapstructure:"no_parent"` + NoDefaultPolicy bool `mapstructure:"no_default_policy"` + Lease string + TTL string + Renewable *bool + ExplicitMaxTTL string `mapstructure:"explicit_max_ttl"` + DisplayName string `mapstructure:"display_name"` + NumUses int `mapstructure:"num_uses"` + Period string + } + if err := mapstructure.WeakDecode(req.Data, &data); err != nil { + return logical.ErrorResponse(fmt.Sprintf( + "Error decoding request: %s", err)), logical.ErrInvalidRequest + } + + // Verify the number of uses is positive + if data.NumUses < 0 { + return logical.ErrorResponse("number of uses cannot be negative"), + logical.ErrInvalidRequest + } + + // Setup the token entry + te := TokenEntry{ + Parent: req.ClientToken, + + // The mount point is always the same since we have only one token + // store; using req.MountPoint causes trouble in tests since they don't + // have an official mount + Path: fmt.Sprintf("auth/token/%s", req.Path), + + Meta: data.Metadata, + DisplayName: "token", + NumUses: data.NumUses, + CreationTime: time.Now().Unix(), + } + + renewable := true + if data.Renewable != nil { + renewable = *data.Renewable + } + + // If the role is not nil, we add the role name as part of the token's + // path. This makes it much easier to later revoke tokens that were issued + // by a role (using revoke-prefix). Users can further specify a PathSuffix + // in the role; that way they can use something like "v1", "v2" to indicate + // role revisions, and revoke only tokens issued with a previous revision. + if role != nil { + te.Role = role.Name + + // If renewable hasn't been disabled in the call and the role has + // renewability disabled, set renewable false + if renewable && !role.Renewable { + renewable = false + } + + if role.PathSuffix != "" { + te.Path = fmt.Sprintf("%s/%s", te.Path, role.PathSuffix) + } + } + + // Attach the given display name if any + if data.DisplayName != "" { + full := "token-" + data.DisplayName + full = displayNameSanitize.ReplaceAllString(full, "-") + full = strings.TrimSuffix(full, "-") + te.DisplayName = full + } + + // Allow specifying the ID of the token if the client has root or sudo privileges + if data.ID != "" { + if !isSudo { + return logical.ErrorResponse("root or sudo privileges required to specify token id"), + logical.ErrInvalidRequest + } + te.ID = data.ID + } + + resp := &logical.Response{} + + var addDefault bool + + // N.B.: The logic here uses various calculations as to whether default + // should be added. In the end we decided that if NoDefaultPolicy is set it + // should be stripped out regardless, *but*, the logic of when it should + // and shouldn't be added is kept because we want to do subset comparisons + // based on adding default when it's correct to do so. + switch { + case role != nil && (len(role.AllowedPolicies) > 0 || len(role.DisallowedPolicies) > 0): + // Holds the final set of policies as they get munged + var finalPolicies []string + + // We don't make use of the global one because roles with allowed or + // disallowed set do their own policy rules + var localAddDefault bool + + // If the request doesn't say not to add "default" and if "default" + // isn't in the disallowed list, add it. This is in line with the idea + // that roles, when allowed/disallowed ar set, allow a subset of + // policies to be set disjoint from the parent token's policies. + if !data.NoDefaultPolicy && !strutil.StrListContains(role.DisallowedPolicies, "default") { + localAddDefault = true + } + + // Start with passed-in policies as a baseline, if they exist + if len(data.Policies) > 0 { + finalPolicies = policyutil.SanitizePolicies(data.Policies, localAddDefault) + } + + var sanitizedRolePolicies []string + + // First check allowed policies; if policies are specified they will be + // checked, otherwise if an allowed set exists that will be the set + // that is used + if len(role.AllowedPolicies) > 0 { + // Note that if "default" is already in allowed, and also in + // disallowed, this will still result in an error later since this + // doesn't strip out default + sanitizedRolePolicies = policyutil.SanitizePolicies(role.AllowedPolicies, localAddDefault) + + if len(finalPolicies) == 0 { + finalPolicies = sanitizedRolePolicies + } else { + if !strutil.StrListSubset(sanitizedRolePolicies, finalPolicies) { + return logical.ErrorResponse(fmt.Sprintf("token policies (%v) must be subset of the role's allowed policies (%v)", finalPolicies, sanitizedRolePolicies)), logical.ErrInvalidRequest + } + } + } else { + // Assign parent policies if none have been requested. As this is a + // role, add default unless explicitly disabled. + if len(finalPolicies) == 0 { + finalPolicies = policyutil.SanitizePolicies(parent.Policies, localAddDefault) + } + } + + if len(role.DisallowedPolicies) > 0 { + // We don't add the default here because we only want to disallow it if it's explicitly set + sanitizedRolePolicies = strutil.RemoveDuplicates(role.DisallowedPolicies, true) + + for _, finalPolicy := range finalPolicies { + if strutil.StrListContains(sanitizedRolePolicies, finalPolicy) { + return logical.ErrorResponse(fmt.Sprintf("token policy %q is disallowed by this role", finalPolicy)), logical.ErrInvalidRequest + } + } + } + + data.Policies = finalPolicies + + // No policies specified, inherit parent + case len(data.Policies) == 0: + // Only inherit "default" if the parent already has it, so don't touch addDefault here + data.Policies = policyutil.SanitizePolicies(parent.Policies, policyutil.DoNotAddDefaultPolicy) + + // When a role is not in use or does not specify allowed/disallowed, only + // permit policies to be a subset unless the client has root or sudo + // privileges. Default is added in this case if the parent has it, unless + // the client specified for it not to be added. + case !isSudo: + // Sanitize passed-in and parent policies before comparison + sanitizedInputPolicies := policyutil.SanitizePolicies(data.Policies, policyutil.DoNotAddDefaultPolicy) + sanitizedParentPolicies := policyutil.SanitizePolicies(parent.Policies, policyutil.DoNotAddDefaultPolicy) + + if !strutil.StrListSubset(sanitizedParentPolicies, sanitizedInputPolicies) { + return logical.ErrorResponse("child policies must be subset of parent"), logical.ErrInvalidRequest + } + + // If the parent has default, and they haven't requested not to get it, + // add it. Note that if they have explicitly put "default" in + // data.Policies it will still be added because NoDefaultPolicy + // controls *automatic* adding. + if !data.NoDefaultPolicy && strutil.StrListContains(parent.Policies, "default") { + addDefault = true + } + + // Add default by default in this case unless requested not to + case isSudo: + addDefault = !data.NoDefaultPolicy + } + + te.Policies = policyutil.SanitizePolicies(data.Policies, addDefault) + + // Yes, this is a little inefficient to do it like this, but meh + if data.NoDefaultPolicy { + te.Policies = strutil.StrListDelete(te.Policies, "default") + } + + // Prevent internal policies from being assigned to tokens + for _, policy := range te.Policies { + if strutil.StrListContains(nonAssignablePolicies, policy) { + return logical.ErrorResponse(fmt.Sprintf("cannot assign policy %q", policy)), nil + } + } + + // Prevent attempts to create a root token without an actual root token as parent. + // This is to thwart privilege escalation by tokens having 'sudo' privileges. + if strutil.StrListContains(data.Policies, "root") && !strutil.StrListContains(parent.Policies, "root") { + return logical.ErrorResponse("root tokens may not be created without parent token being root"), logical.ErrInvalidRequest + } + + // + // NOTE: Do not modify policies below this line. We need the checks above + // to be the last checks as they must look at the final policy set. + // + + switch { + case role != nil: + if role.Orphan { + te.Parent = "" + } + + if len(role.BoundCIDRs) > 0 { + te.BoundCIDRs = role.BoundCIDRs + } + + case data.NoParent: + // Only allow an orphan token if the client has sudo policy + if !isSudo { + return logical.ErrorResponse("root or sudo privileges required to create orphan token"), + logical.ErrInvalidRequest + } + + te.Parent = "" + + default: + // This comes from create-orphan, which can be properly ACLd + if orphan { + te.Parent = "" + } + } + + // At this point, it is clear whether the token is going to be an orphan or + // not. If the token is not going to be an orphan, inherit the parent's + // entity identifier into the child token. + if te.Parent != "" { + te.EntityID = parent.EntityID + } + + var explicitMaxTTLToUse time.Duration + if data.ExplicitMaxTTL != "" { + dur, err := parseutil.ParseDurationSecond(data.ExplicitMaxTTL) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + if dur < 0 { + return logical.ErrorResponse("explicit_max_ttl must be positive"), logical.ErrInvalidRequest + } + te.ExplicitMaxTTL = dur + explicitMaxTTLToUse = dur + } + + var periodToUse time.Duration + if data.Period != "" { + dur, err := parseutil.ParseDurationSecond(data.Period) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + + switch { + case dur < 0: + return logical.ErrorResponse("period must be positive"), logical.ErrInvalidRequest + case dur == 0: + default: + if !isSudo { + return logical.ErrorResponse("root or sudo privileges required to create periodic token"), + logical.ErrInvalidRequest + } + te.Period = dur + periodToUse = dur + } + } + + // Parse the TTL/lease if any + if data.TTL != "" { + dur, err := parseutil.ParseDurationSecond(data.TTL) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + if dur < 0 { + return logical.ErrorResponse("ttl must be positive"), logical.ErrInvalidRequest + } + te.TTL = dur + } else if data.Lease != "" { + // This block is compatibility + dur, err := time.ParseDuration(data.Lease) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + if dur < 0 { + return logical.ErrorResponse("lease must be positive"), logical.ErrInvalidRequest + } + te.TTL = dur + } + + // Set the lesser period/explicit max TTL if defined both in arguments and in role + if role != nil { + if role.ExplicitMaxTTL != 0 { + switch { + case explicitMaxTTLToUse == 0: + explicitMaxTTLToUse = role.ExplicitMaxTTL + default: + if role.ExplicitMaxTTL < explicitMaxTTLToUse { + explicitMaxTTLToUse = role.ExplicitMaxTTL + } + resp.AddWarning(fmt.Sprintf("Explicit max TTL specified both during creation call and in role; using the lesser value of %d seconds", int64(explicitMaxTTLToUse.Seconds()))) + } + } + if role.Period != 0 { + switch { + case periodToUse == 0: + periodToUse = role.Period + default: + if role.Period < periodToUse { + periodToUse = role.Period + } + resp.AddWarning(fmt.Sprintf("Period specified both during creation call and in role; using the lesser value of %d seconds", int64(periodToUse.Seconds()))) + } + } + } + + sysView := ts.System() + + // Only calculate a TTL if you are A) periodic, B) have a TTL, C) do not have a TTL and are not a root token + if periodToUse > 0 || te.TTL > 0 || (te.TTL == 0 && !strutil.StrListContains(te.Policies, "root")) { + ttl, warnings, err := framework.CalculateTTL(sysView, 0, te.TTL, periodToUse, 0, explicitMaxTTLToUse, time.Unix(te.CreationTime, 0)) + if err != nil { + return nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) + } + te.TTL = ttl + } + + // Root tokens are still bound by explicit max TTL + if te.TTL == 0 && explicitMaxTTLToUse > 0 { + te.TTL = explicitMaxTTLToUse + } + + // Don't advertise non-expiring root tokens as renewable, as attempts to + // renew them are denied. Don't CIDR-restrict these either. + if te.TTL == 0 { + if parent.TTL != 0 { + return logical.ErrorResponse("expiring root tokens cannot create non-expiring root tokens"), logical.ErrInvalidRequest + } + renewable = false + te.BoundCIDRs = nil + } + + // Create the token + if err := ts.create(ctx, &te); err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + + // Generate the response + resp.Auth = &logical.Auth{ + NumUses: te.NumUses, + DisplayName: te.DisplayName, + Policies: te.Policies, + Metadata: te.Meta, + LeaseOptions: logical.LeaseOptions{ + TTL: te.TTL, + Renewable: renewable, + }, + ClientToken: te.ID, + Accessor: te.Accessor, + EntityID: te.EntityID, + Period: periodToUse, + ExplicitMaxTTL: explicitMaxTTLToUse, + CreationPath: te.Path, + } + + if ts.policyLookupFunc != nil { + for _, p := range te.Policies { + policy, err := ts.policyLookupFunc(p) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("could not look up policy %s", p)), nil + } + if policy == nil { + resp.AddWarning(fmt.Sprintf("Policy %q does not exist", p)) + } + } + } + + return resp, nil +} + +// handleRevokeSelf handles the auth/token/revoke-self path for revocation of tokens +// in a way that revokes all child tokens. Normally, using sys/revoke/leaseID will revoke +// the token and all children anyways, but that is only available when there is a lease. +func (ts *TokenStore) handleRevokeSelf(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + te, err := ts.Lookup(ctx, req.ClientToken) + if err != nil { + return nil, err + } + + if te == nil { + return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest + } + + leaseID, err := ts.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err != nil { + return nil, err + } + + err = ts.expiration.Revoke(leaseID) + if err != nil { + return nil, err + } + + return nil, nil +} + +// handleRevokeTree handles the auth/token/revoke/id path for revocation of tokens +// in a way that revokes all child tokens. Normally, using sys/revoke/leaseID will revoke +// the token and all children anyways, but that is only available when there is a lease. +func (ts *TokenStore) handleRevokeTree(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urltoken bool + id := data.Get("token").(string) + if id == "" { + id = data.Get("urltoken").(string) + if id == "" { + return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest + } + urltoken = true + } + + te, err := ts.Lookup(ctx, id) + if err != nil { + return nil, err + } + + if te == nil { + return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest + } + + leaseID, err := ts.expiration.CreateOrFetchRevocationLeaseByToken(te) + if err != nil { + return nil, err + } + + err = ts.expiration.Revoke(leaseID) + if err != nil { + return nil, err + } + + if urltoken { + resp := &logical.Response{} + resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) + return resp, nil + } + + return nil, nil +} + +// handleRevokeOrphan handles the auth/token/revoke-orphan/id path for revocation of tokens +// in a way that leaves child tokens orphaned. Normally, using sys/revoke/leaseID will revoke +// the token and all children. +func (ts *TokenStore) handleRevokeOrphan(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urltoken bool + // Parse the id + id := data.Get("token").(string) + if id == "" { + id = data.Get("urltoken").(string) + if id == "" { + return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest + } + urltoken = true + } + + parent, err := ts.Lookup(ctx, req.ClientToken) + if err != nil { + return nil, errwrap.Wrapf("parent token lookup failed: {{err}}", err) + } + if parent == nil { + return logical.ErrorResponse("parent token lookup failed: no parent found"), logical.ErrInvalidRequest + } + + // Check if the client token has sudo/root privileges for the requested path + isSudo := ts.System().SudoPrivilege(ctx, req.MountPoint+req.Path, req.ClientToken) + + if !isSudo { + return logical.ErrorResponse("root or sudo privileges required to revoke and orphan"), + logical.ErrInvalidRequest + } + + // Revoke and orphan + if err := ts.revokeOrphan(ctx, id); err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + + if urltoken { + resp := &logical.Response{} + resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) + return resp, nil + } + + return nil, nil +} + +func (ts *TokenStore) handleLookupSelf(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + data.Raw["token"] = req.ClientToken + return ts.handleLookup(ctx, req, data) +} + +// handleLookup handles the auth/token/lookup/id path for querying information about +// a particular token. This can be used to see which policies are applicable. +func (ts *TokenStore) handleLookup(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urltoken bool + id := data.Get("token").(string) + if id == "" { + id = data.Get("urltoken").(string) + if id != "" { + urltoken = true + } + } + if id == "" { + id = req.ClientToken + } + if id == "" { + return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest + } + + lock := locksutil.LockForKey(ts.tokenLocks, id) + lock.RLock() + defer lock.RUnlock() + + // Lookup the token + saltedID, err := ts.SaltID(ctx, id) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + out, err := ts.lookupSalted(ctx, saltedID, true) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + + if out == nil { + return logical.ErrorResponse("bad token"), logical.ErrPermissionDenied + } + + // Generate a response. We purposely omit the parent reference otherwise + // you could escalate your privileges. + resp := &logical.Response{ + Data: map[string]interface{}{ + "id": out.ID, + "accessor": out.Accessor, + "policies": out.Policies, + "path": out.Path, + "meta": out.Meta, + "display_name": out.DisplayName, + "num_uses": out.NumUses, + "orphan": false, + "creation_time": int64(out.CreationTime), + "creation_ttl": int64(out.TTL.Seconds()), + "expire_time": nil, + "ttl": int64(0), + "explicit_max_ttl": int64(out.ExplicitMaxTTL.Seconds()), + "entity_id": out.EntityID, + }, + } + + if out.Parent == "" { + resp.Data["orphan"] = true + } + + if out.Role != "" { + resp.Data["role"] = out.Role + } + + if out.Period != 0 { + resp.Data["period"] = int64(out.Period.Seconds()) + } + + if len(out.BoundCIDRs) > 0 { + resp.Data["bound_cidrs"] = out.BoundCIDRs + } + + // Fetch the last renewal time + leaseTimes, err := ts.expiration.FetchLeaseTimesByToken(out.Path, out.ID) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + if leaseTimes != nil { + if !leaseTimes.LastRenewalTime.IsZero() { + resp.Data["last_renewal_time"] = leaseTimes.LastRenewalTime.Unix() + resp.Data["last_renewal"] = leaseTimes.LastRenewalTime + } + if !leaseTimes.ExpireTime.IsZero() { + resp.Data["expire_time"] = leaseTimes.ExpireTime + resp.Data["ttl"] = leaseTimes.ttl() + } + renewable, _ := leaseTimes.renewable() + resp.Data["renewable"] = renewable + resp.Data["issue_time"] = leaseTimes.IssueTime + } + + if out.EntityID != "" { + _, identityPolicies, err := ts.identityPoliciesDeriverFunc(out.EntityID) + if err != nil { + return nil, err + } + if len(identityPolicies) != 0 { + resp.Data["identity_policies"] = identityPolicies + } + } + + if urltoken { + resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) + } + + return resp, nil +} + +func (ts *TokenStore) handleRenewSelf(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + data.Raw["token"] = req.ClientToken + return ts.handleRenew(ctx, req, data) +} + +// handleRenew handles the auth/token/renew/id path for renewal of tokens. +// This is used to prevent token expiration and revocation. +func (ts *TokenStore) handleRenew(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var urltoken bool + id := data.Get("token").(string) + if id == "" { + id = data.Get("urltoken").(string) + if id == "" { + return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest + } + urltoken = true + } + incrementRaw := data.Get("increment").(int) + + // Convert the increment + increment := time.Duration(incrementRaw) * time.Second + + // Lookup the token + te, err := ts.Lookup(ctx, id) + if err != nil { + return nil, errwrap.Wrapf("error looking up token: {{err}}", err) + } + + // Verify the token exists + if te == nil { + return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest + } + + // Renew the token and its children + resp, err := ts.expiration.RenewToken(req, te.Path, te.ID, increment) + + if urltoken { + resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) + } + + return resp, err +} + +func (ts *TokenStore) destroyCubbyhole(ctx context.Context, saltedID string) error { + if ts.cubbyholeBackend == nil { + // Should only ever happen in testing + return nil + } + return ts.cubbyholeBackend.revoke(ctx, salt.SaltID(ts.cubbyholeBackend.saltUUID, saltedID, salt.SHA1Hash)) +} + +func (ts *TokenStore) authRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + if req.Auth == nil { + return nil, fmt.Errorf("request auth is nil") + } + + te, err := ts.Lookup(ctx, req.Auth.ClientToken) + if err != nil { + return nil, errwrap.Wrapf("error looking up token: {{err}}", err) + } + if te == nil { + return nil, fmt.Errorf("no token entry found during lookup") + } + + if te.Role == "" { + req.Auth.Period = te.Period + req.Auth.ExplicitMaxTTL = te.ExplicitMaxTTL + return &logical.Response{Auth: req.Auth}, nil + } + + role, err := ts.tokenStoreRole(ctx, te.Role) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("error looking up role %q: {{err}}", te.Role), err) + } + if role == nil { + return nil, fmt.Errorf("original token role %q could not be found, not renewing", te.Role) + } + + req.Auth.Period = role.Period + req.Auth.ExplicitMaxTTL = role.ExplicitMaxTTL + return &logical.Response{Auth: req.Auth}, nil +} + +func (ts *TokenStore) tokenStoreRole(ctx context.Context, name string) (*tsRoleEntry, error) { + entry, err := ts.view.Get(ctx, fmt.Sprintf("%s%s", rolesPrefix, name)) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var result tsRoleEntry + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + + return &result, nil +} + +func (ts *TokenStore) tokenStoreRoleList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := ts.view.List(ctx, rolesPrefix) + if err != nil { + return nil, err + } + + ret := make([]string, len(entries)) + for i, entry := range entries { + ret[i] = strings.TrimPrefix(entry, rolesPrefix) + } + + return logical.ListResponse(ret), nil +} + +func (ts *TokenStore) tokenStoreRoleDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := ts.view.Delete(ctx, fmt.Sprintf("%s%s", rolesPrefix, data.Get("role_name").(string))) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (ts *TokenStore) tokenStoreRoleRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + role, err := ts.tokenStoreRole(ctx, data.Get("role_name").(string)) + if err != nil { + return nil, err + } + if role == nil { + return nil, nil + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "period": int64(role.Period.Seconds()), + "explicit_max_ttl": int64(role.ExplicitMaxTTL.Seconds()), + "disallowed_policies": role.DisallowedPolicies, + "allowed_policies": role.AllowedPolicies, + "name": role.Name, + "orphan": role.Orphan, + "path_suffix": role.PathSuffix, + "renewable": role.Renewable, + }, + } + + if len(role.BoundCIDRs) > 0 { + resp.Data["bound_cidrs"] = role.BoundCIDRs + } + + return resp, nil +} + +func (ts *TokenStore) tokenStoreRoleExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + name := data.Get("role_name").(string) + if name == "" { + return false, fmt.Errorf("role name cannot be empty") + } + role, err := ts.tokenStoreRole(ctx, name) + if err != nil { + return false, err + } + + return role != nil, nil +} + +func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + name := data.Get("role_name").(string) + if name == "" { + return logical.ErrorResponse("role name cannot be empty"), nil + } + entry, err := ts.tokenStoreRole(ctx, name) + if err != nil { + return nil, err + } + + // Due to the existence check, entry will only be nil if it's a create + // operation, so just create a new one + if entry == nil { + entry = &tsRoleEntry{ + Name: name, + } + } + + // In this series of blocks, if we do not find a user-provided value and + // it's a creation operation, we call data.Get to get the appropriate + // default + + orphanInt, ok := data.GetOk("orphan") + if ok { + entry.Orphan = orphanInt.(bool) + } else if req.Operation == logical.CreateOperation { + entry.Orphan = data.Get("orphan").(bool) + } + + periodInt, ok := data.GetOk("period") + if ok { + entry.Period = time.Second * time.Duration(periodInt.(int)) + } else if req.Operation == logical.CreateOperation { + entry.Period = time.Second * time.Duration(data.Get("period").(int)) + } + + renewableInt, ok := data.GetOk("renewable") + if ok { + entry.Renewable = renewableInt.(bool) + } else if req.Operation == logical.CreateOperation { + entry.Renewable = data.Get("renewable").(bool) + } + + boundCIDRsRaw, ok := data.GetOk("bound_cidrs") + if ok { + boundCIDRs := boundCIDRsRaw.([]string) + if len(boundCIDRs) > 0 { + var parsedCIDRs []*sockaddr.SockAddrMarshaler + for _, v := range boundCIDRs { + parsedCIDR, err := sockaddr.NewSockAddr(v) + if err != nil { + return logical.ErrorResponse(errwrap.Wrapf(fmt.Sprintf("invalid value %q when parsing bound cidrs: {{err}}", v), err).Error()), nil + } + parsedCIDRs = append(parsedCIDRs, &sockaddr.SockAddrMarshaler{parsedCIDR}) + } + entry.BoundCIDRs = parsedCIDRs + } + } + + var resp *logical.Response + + explicitMaxTTLInt, ok := data.GetOk("explicit_max_ttl") + if ok { + entry.ExplicitMaxTTL = time.Second * time.Duration(explicitMaxTTLInt.(int)) + } else if req.Operation == logical.CreateOperation { + entry.ExplicitMaxTTL = time.Second * time.Duration(data.Get("explicit_max_ttl").(int)) + } + if entry.ExplicitMaxTTL != 0 { + sysView := ts.System() + + if sysView.MaxLeaseTTL() != time.Duration(0) && entry.ExplicitMaxTTL > sysView.MaxLeaseTTL() { + if resp == nil { + resp = &logical.Response{} + } + resp.AddWarning(fmt.Sprintf( + "Given explicit max TTL of %d is greater than system/mount allowed value of %d seconds; until this is fixed attempting to create tokens against this role will result in an error", + int64(entry.ExplicitMaxTTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds()))) + } + } + + pathSuffixInt, ok := data.GetOk("path_suffix") + if ok { + pathSuffix := pathSuffixInt.(string) + if pathSuffix != "" { + matched := pathSuffixSanitize.MatchString(pathSuffix) + if !matched { + return logical.ErrorResponse(fmt.Sprintf( + "given role path suffix contains invalid characters; must match %s", + pathSuffixSanitize.String())), nil + } + entry.PathSuffix = pathSuffix + } + } else if req.Operation == logical.CreateOperation { + entry.PathSuffix = data.Get("path_suffix").(string) + } + + if strings.Contains(entry.PathSuffix, "..") { + return logical.ErrorResponse(fmt.Sprintf("error registering path suffix: %s", consts.ErrPathContainsParentReferences)), nil + } + + allowedPoliciesRaw, ok := data.GetOk("allowed_policies") + if ok { + entry.AllowedPolicies = policyutil.SanitizePolicies(allowedPoliciesRaw.([]string), policyutil.DoNotAddDefaultPolicy) + } else if req.Operation == logical.CreateOperation { + entry.AllowedPolicies = policyutil.SanitizePolicies(data.Get("allowed_policies").([]string), policyutil.DoNotAddDefaultPolicy) + } + + disallowedPoliciesRaw, ok := data.GetOk("disallowed_policies") + if ok { + entry.DisallowedPolicies = strutil.RemoveDuplicates(disallowedPoliciesRaw.([]string), true) + } else if req.Operation == logical.CreateOperation { + entry.DisallowedPolicies = strutil.RemoveDuplicates(data.Get("disallowed_policies").([]string), true) + } + + // Store it + jsonEntry, err := logical.StorageEntryJSON(fmt.Sprintf("%s%s", rolesPrefix, name), entry) + if err != nil { + return nil, err + } + if err := ts.view.Put(ctx, jsonEntry); err != nil { + return nil, err + } + + return resp, nil +} + +const ( + tokenTidyHelp = ` +This endpoint performs cleanup tasks that can be run if certain error +conditions have occurred. +` + tokenTidyDesc = ` +This endpoint performs cleanup tasks that can be run to clean up token and +lease entries after certain error conditions. Usually running this is not +necessary, and is only required if upgrade notes or support personnel suggest +it. +` + tokenBackendHelp = `The token credential backend is always enabled and builtin to Vault. +Client tokens are used to identify a client and to allow Vault to associate policies and ACLs +which are enforced on every request. This backend also allows for generating sub-tokens as well +as revocation of tokens. The tokens are renewable if associated with a lease.` + tokenCreateHelp = `The token create path is used to create new tokens.` + tokenCreateOrphanHelp = `The token create path is used to create new orphan tokens.` + tokenCreateRoleHelp = `This token create path is used to create new tokens adhering to the given role.` + tokenListRolesHelp = `This endpoint lists configured roles.` + tokenLookupAccessorHelp = `This endpoint will lookup a token associated with the given accessor and its properties. Response will not contain the token ID.` + tokenLookupHelp = `This endpoint will lookup a token and its properties.` + tokenPathRolesHelp = `This endpoint allows creating, reading, and deleting roles.` + tokenRevokeAccessorHelp = `This endpoint will delete the token associated with the accessor and all of its child tokens.` + tokenRevokeHelp = `This endpoint will delete the given token and all of its child tokens.` + tokenRevokeSelfHelp = `This endpoint will delete the token used to call it and all of its child tokens.` + tokenRevokeOrphanHelp = `This endpoint will delete the token and orphan its child tokens.` + tokenRenewHelp = `This endpoint will renew the given token and prevent expiration.` + tokenRenewSelfHelp = `This endpoint will renew the token used to call it and prevent expiration.` + tokenAllowedPoliciesHelp = `If set, tokens can be created with any subset of the policies in this +list, rather than the normal semantics of tokens being a subset of the +calling token's policies. The parameter is a comma-delimited string of +policy names.` + tokenDisallowedPoliciesHelp = `If set, successful token creation via this role will require that +no policies in the given list are requested. The parameter is a comma-delimited string of policy names.` + tokenOrphanHelp = `If true, tokens created via this role +will be orphan tokens (have no parent)` + tokenPeriodHelp = `If set, tokens created via this role +will have no max lifetime; instead, their +renewal period will be fixed to this value. +This takes an integer number of seconds, +or a string duration (e.g. "24h").` + tokenPathSuffixHelp = `If set, tokens created via this role +will contain the given suffix as a part of +their path. This can be used to assist use +of the 'revoke-prefix' endpoint later on. +The given suffix must match the regular +expression.` + tokenExplicitMaxTTLHelp = `If set, tokens created via this role +carry an explicit maximum TTL. During renewal, +the current maximum TTL values of the role +and the mount are not checked for changes, +and any updates to these values will have +no effect on the token being renewed.` + tokenRenewableHelp = `Tokens created via this role will be +renewable or not according to this value. +Defaults to "true".` + tokenListAccessorsHelp = `List token accessors, which can then be +be used to iterate and discover their properties +or revoke them. Because this can be used to +cause a denial of service, this endpoint +requires 'sudo' capability in addition to +'list'.` +) diff --git a/vendor/github.com/hashicorp/vault/vault/ui.go b/vendor/github.com/hashicorp/vault/vault/ui.go new file mode 100644 index 0000000..7a637f2 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/ui.go @@ -0,0 +1,217 @@ +package vault + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "strings" + "sync" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/physical" +) + +const ( + uiConfigKey = "config" + uiConfigPlaintextKey = "config_plaintext" +) + +// UIConfig contains UI configuration. This takes both a physical view and a barrier view +// because it is stored in both plaintext and encrypted to allow for getting the header +// values before the barrier is unsealed +type UIConfig struct { + l sync.RWMutex + physicalStorage physical.Backend + barrierStorage logical.Storage + + enabled bool + defaultHeaders http.Header +} + +// NewUIConfig creates a new UI config +func NewUIConfig(enabled bool, physicalStorage physical.Backend, barrierStorage logical.Storage) *UIConfig { + defaultHeaders := http.Header{} + defaultHeaders.Set("Content-Security-Policy", "default-src 'none'; connect-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'unsafe-inline' 'self'; form-action 'none'; frame-ancestors 'none'") + + return &UIConfig{ + physicalStorage: physicalStorage, + barrierStorage: barrierStorage, + enabled: enabled, + defaultHeaders: defaultHeaders, + } +} + +// Enabled returns if the UI is enabled +func (c *UIConfig) Enabled() bool { + c.l.RLock() + defer c.l.RUnlock() + return c.enabled +} + +// Headers returns the response headers that should be returned in the UI +func (c *UIConfig) Headers(ctx context.Context) (http.Header, error) { + c.l.RLock() + defer c.l.RUnlock() + + config, err := c.get(ctx) + if err != nil { + return nil, err + } + headers := make(http.Header) + if config != nil { + headers = config.Headers + } + + for k := range c.defaultHeaders { + if headers.Get(k) == "" { + v := c.defaultHeaders.Get(k) + headers.Set(k, v) + } + } + return headers, nil +} + +// HeaderKeys returns the list of the configured headers +func (c *UIConfig) HeaderKeys(ctx context.Context) ([]string, error) { + c.l.RLock() + defer c.l.RUnlock() + + config, err := c.get(ctx) + if err != nil { + return nil, err + } + if config == nil { + return nil, nil + } + var keys []string + for k := range config.Headers { + keys = append(keys, k) + } + return keys, nil +} + +// GetHeader retrieves the configured value for the given header +func (c *UIConfig) GetHeader(ctx context.Context, header string) (string, error) { + c.l.RLock() + defer c.l.RUnlock() + + config, err := c.get(ctx) + if err != nil { + return "", err + } + if config == nil { + return "", nil + } + + value := config.Headers.Get(header) + return value, nil +} + +// SetHeader sets the value for the given header +func (c *UIConfig) SetHeader(ctx context.Context, header, value string) error { + c.l.Lock() + defer c.l.Unlock() + + config, err := c.get(ctx) + if err != nil { + return err + } + if config == nil { + config = &uiConfigEntry{ + Headers: http.Header{}, + } + } + config.Headers.Set(header, value) + return c.save(ctx, config) +} + +// DeleteHeader deletes the header configuration for the given header +func (c *UIConfig) DeleteHeader(ctx context.Context, header string) error { + c.l.Lock() + defer c.l.Unlock() + + config, err := c.get(ctx) + if err != nil { + return err + } + if config == nil { + return nil + } + + config.Headers.Del(header) + return c.save(ctx, config) +} + +func (c *UIConfig) get(ctx context.Context) (*uiConfigEntry, error) { + // Read plaintext always to ensure in sync with barrier value + plaintextConfigRaw, err := c.physicalStorage.Get(ctx, uiConfigPlaintextKey) + if err != nil { + return nil, err + } + + configRaw, err := c.barrierStorage.Get(ctx, uiConfigKey) + if err == nil { + if configRaw == nil { + return nil, nil + } + config := new(uiConfigEntry) + if err := json.Unmarshal(configRaw.Value, config); err != nil { + return nil, err + } + // Check that plaintext value matches barrier value, if not sync values + if plaintextConfigRaw == nil || bytes.Compare(plaintextConfigRaw.Value, configRaw.Value) != 0 { + if err := c.save(ctx, config); err != nil { + return nil, err + } + } + return config, nil + } + + // Respond with error if not sealed + if !strings.Contains(err.Error(), ErrBarrierSealed.Error()) { + return nil, err + } + + // Respond with plaintext value + if configRaw == nil { + return nil, nil + } + config := new(uiConfigEntry) + if err := json.Unmarshal(plaintextConfigRaw.Value, config); err != nil { + return nil, err + } + return config, nil +} + +func (c *UIConfig) save(ctx context.Context, config *uiConfigEntry) error { + if len(config.Headers) == 0 { + if err := c.physicalStorage.Delete(ctx, uiConfigPlaintextKey); err != nil { + return err + } + return c.barrierStorage.Delete(ctx, uiConfigKey) + } + + configRaw, err := json.Marshal(config) + if err != nil { + return err + } + + entry := &physical.Entry{ + Key: uiConfigPlaintextKey, + Value: configRaw, + } + if err := c.physicalStorage.Put(ctx, entry); err != nil { + return err + } + + barrEntry := &logical.StorageEntry{ + Key: uiConfigKey, + Value: configRaw, + } + return c.barrierStorage.Put(ctx, barrEntry) +} + +type uiConfigEntry struct { + Headers http.Header `json:"headers"` +} diff --git a/vendor/github.com/hashicorp/vault/vault/util.go b/vendor/github.com/hashicorp/vault/vault/util.go new file mode 100644 index 0000000..9e03afd --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/util.go @@ -0,0 +1,42 @@ +package vault + +import ( + "crypto/rand" + "fmt" +) + +// memzero is used to zero out a byte buffer. This specific format is optimized +// by the compiler to use memclr to improve performance. See this code review: +// https://codereview.appspot.com/137880043 +// +// Use of memzero is not a guarantee against memory analysis as described in +// the Vault threat model: +// https://www.vaultproject.io/docs/internals/security.html . Vault does not +// provide guarantees against memory analysis or raw memory dumping by +// operators, however it does minimize this exposure by zeroing out buffers +// that contain secrets as soon as they are no longer used. Starting with Go +// 1.5, the garbage collector was changed to become a "generational copying +// garbage collector." This change to the garbage collector makes it +// impossible for Vault to guarantee a buffer with a secret has not been +// copied during a garbage collection. It is therefore possible that secrets +// may be exist in memory that have not been wiped despite a pending memzero +// call. Over time any copied data with a secret will be reused and the +// memory overwritten thereby mitigating some of the risk from this threat +// vector. +func memzero(b []byte) { + if b == nil { + return + } + for i := range b { + b[i] = 0 + } +} + +// randbytes is used to create a buffer of size n filled with random bytes +func randbytes(n int) []byte { + buf := make([]byte, n) + if _, err := rand.Read(buf); err != nil { + panic(fmt.Sprintf("failed to generate %d random bytes: %v", n, err)) + } + return buf +} diff --git a/vendor/github.com/hashicorp/vault/vault/wrapping.go b/vendor/github.com/hashicorp/vault/vault/wrapping.go new file mode 100644 index 0000000..6c43613 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/wrapping.go @@ -0,0 +1,348 @@ +package vault + +import ( + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/SermoDigital/jose/crypto" + "github.com/SermoDigital/jose/jws" + "github.com/SermoDigital/jose/jwt" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/logical" +) + +const ( + // The location of the key used to generate response-wrapping JWTs + coreWrappingJWTKeyPath = "core/wrapping/jwtkey" +) + +func (c *Core) ensureWrappingKey(ctx context.Context) error { + entry, err := c.barrier.Get(ctx, coreWrappingJWTKeyPath) + if err != nil { + return err + } + + var keyParams clusterKeyParams + + if entry == nil { + key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + return errwrap.Wrapf("failed to generate wrapping key: {{err}}", err) + } + keyParams.D = key.D + keyParams.X = key.X + keyParams.Y = key.Y + keyParams.Type = corePrivateKeyTypeP521 + val, err := jsonutil.EncodeJSON(keyParams) + if err != nil { + return errwrap.Wrapf("failed to encode wrapping key: {{err}}", err) + } + entry = &Entry{ + Key: coreWrappingJWTKeyPath, + Value: val, + } + if err = c.barrier.Put(ctx, entry); err != nil { + return errwrap.Wrapf("failed to store wrapping key: {{err}}", err) + } + } + + // Redundant if we just created it, but in this case serves as a check anyways + if err = jsonutil.DecodeJSON(entry.Value, &keyParams); err != nil { + return errwrap.Wrapf("failed to decode wrapping key parameters: {{err}}", err) + } + + c.wrappingJWTKey = &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: elliptic.P521(), + X: keyParams.X, + Y: keyParams.Y, + }, + D: keyParams.D, + } + + c.logger.Info("loaded wrapping token key") + + return nil +} + +func (c *Core) wrapInCubbyhole(ctx context.Context, req *logical.Request, resp *logical.Response, auth *logical.Auth) (*logical.Response, error) { + // Before wrapping, obey special rules for listing: if no entries are + // found, 404. This prevents unwrapping only to find empty data. + if req.Operation == logical.ListOperation { + if resp == nil || (len(resp.Data) == 0 && len(resp.Warnings) == 0) { + return nil, logical.ErrUnsupportedPath + } + + keysRaw, ok := resp.Data["keys"] + if !ok || keysRaw == nil { + if len(resp.Data) > 0 || len(resp.Warnings) > 0 { + // We could be returning extra metadata on a list, or returning + // warnings with no data, so handle these cases + goto DONELISTHANDLING + } + return nil, logical.ErrUnsupportedPath + } + + keys, ok := keysRaw.([]string) + if !ok { + return nil, logical.ErrUnsupportedPath + } + if len(keys) == 0 { + return nil, logical.ErrUnsupportedPath + } + } + +DONELISTHANDLING: + var err error + sealWrap := resp.WrapInfo.SealWrap + + // If we are wrapping, the first part (performed in this functions) happens + // before auditing so that resp.WrapInfo.Token can contain the HMAC'd + // wrapping token ID in the audit logs, so that it can be determined from + // the audit logs whether the token was ever actually used. + creationTime := time.Now() + te := TokenEntry{ + Path: req.Path, + Policies: []string{"response-wrapping"}, + CreationTime: creationTime.Unix(), + TTL: resp.WrapInfo.TTL, + NumUses: 1, + ExplicitMaxTTL: resp.WrapInfo.TTL, + } + + if err := c.tokenStore.create(ctx, &te); err != nil { + c.logger.Error("failed to create wrapping token", "error", err) + return nil, ErrInternalError + } + + resp.WrapInfo.Token = te.ID + resp.WrapInfo.Accessor = te.Accessor + resp.WrapInfo.CreationTime = creationTime + // If this is not a rewrap, store the request path as creation_path + if req.Path != "sys/wrapping/rewrap" { + resp.WrapInfo.CreationPath = req.Path + } + + if auth != nil && auth.EntityID != "" { + resp.WrapInfo.WrappedEntityID = auth.EntityID + } + + // This will only be non-nil if this response contains a token, so in that + // case put the accessor in the wrap info. + if resp.Auth != nil { + resp.WrapInfo.WrappedAccessor = resp.Auth.Accessor + } + + switch resp.WrapInfo.Format { + case "jwt": + // Create the JWT + claims := jws.Claims{} + // Map the JWT ID to the token ID for ease of use + claims.SetJWTID(te.ID) + // Set the issue time to the creation time + claims.SetIssuedAt(creationTime) + // Set the expiration to the TTL + claims.SetExpiration(creationTime.Add(resp.WrapInfo.TTL)) + if resp.Auth != nil { + claims.Set("accessor", resp.Auth.Accessor) + } + claims.Set("type", "wrapping") + claims.Set("addr", c.redirectAddr) + jwt := jws.NewJWT(claims, crypto.SigningMethodES512) + serWebToken, err := jwt.Serialize(c.wrappingJWTKey) + if err != nil { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to serialize JWT", "error", err) + return nil, ErrInternalError + } + resp.WrapInfo.Token = string(serWebToken) + if c.redirectAddr == "" { + resp.AddWarning("No redirect address set in Vault so none could be encoded in the token. You may need to supply Vault's API address when unwrapping the token.") + } + } + + cubbyReq := &logical.Request{ + Operation: logical.CreateOperation, + Path: "cubbyhole/response", + ClientToken: te.ID, + } + if sealWrap { + cubbyReq.WrapInfo = &logical.RequestWrapInfo{ + SealWrap: true, + } + } + + // During a rewrap, store the original response, don't wrap it again. + if req.Path == "sys/wrapping/rewrap" { + cubbyReq.Data = map[string]interface{}{ + "response": resp.Data["response"], + } + } else { + httpResponse := logical.LogicalResponseToHTTPResponse(resp) + + // Add the unique identifier of the original request to the response + httpResponse.RequestID = req.ID + + // Because of the way that JSON encodes (likely just in Go) we actually get + // mixed-up values for ints if we simply put this object in the response + // and encode the whole thing; so instead we marshal it first, then store + // the string response. This actually ends up making it easier on the + // client side, too, as it becomes a straight read-string-pass-to-unmarshal + // operation. + + marshaledResponse, err := json.Marshal(httpResponse) + if err != nil { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to marshal wrapped response", "error", err) + return nil, ErrInternalError + } + + cubbyReq.Data = map[string]interface{}{ + "response": string(marshaledResponse), + } + } + + cubbyResp, err := c.router.Route(ctx, cubbyReq) + if err != nil { + // Revoke since it's not yet being tracked for expiration + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to store wrapped response information", "error", err) + return nil, ErrInternalError + } + if cubbyResp != nil && cubbyResp.IsError() { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to store wrapped response information", "error", cubbyResp.Data["error"]) + return cubbyResp, nil + } + + // Store info for lookup + cubbyReq.WrapInfo = nil + cubbyReq.Path = "cubbyhole/wrapinfo" + cubbyReq.Data = map[string]interface{}{ + "creation_ttl": resp.WrapInfo.TTL, + "creation_time": creationTime, + } + // Store creation_path if not a rewrap + if req.Path != "sys/wrapping/rewrap" { + cubbyReq.Data["creation_path"] = req.Path + } else { + cubbyReq.Data["creation_path"] = resp.WrapInfo.CreationPath + } + cubbyResp, err = c.router.Route(ctx, cubbyReq) + if err != nil { + // Revoke since it's not yet being tracked for expiration + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to store wrapping information", "error", err) + return nil, ErrInternalError + } + if cubbyResp != nil && cubbyResp.IsError() { + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to store wrapping information", "error", cubbyResp.Data["error"]) + return cubbyResp, nil + } + + wAuth := &logical.Auth{ + ClientToken: te.ID, + Policies: []string{"response-wrapping"}, + LeaseOptions: logical.LeaseOptions{ + TTL: te.TTL, + Renewable: false, + }, + } + + // Register the wrapped token with the expiration manager + if err := c.expiration.RegisterAuth(te.Path, wAuth); err != nil { + // Revoke since it's not yet being tracked for expiration + c.tokenStore.revokeOrphan(ctx, te.ID) + c.logger.Error("failed to register cubbyhole wrapping token lease", "request_path", req.Path, "error", err) + return nil, ErrInternalError + } + + return nil, nil +} + +// ValidateWrappingToken checks whether a token is a wrapping token. +func (c *Core) ValidateWrappingToken(req *logical.Request) (bool, error) { + if req == nil { + return false, fmt.Errorf("invalid request") + } + + var err error + + var token string + var thirdParty bool + if req.Data != nil && req.Data["token"] != nil { + thirdParty = true + if tokenStr, ok := req.Data["token"].(string); !ok { + return false, fmt.Errorf("could not decode token in request body") + } else if tokenStr == "" { + return false, fmt.Errorf("empty token in request body") + } else { + token = tokenStr + } + } else { + token = req.ClientToken + } + + // Check for it being a JWT. If it is, and it is valid, we extract the + // internal client token from it and use that during lookup. + if strings.Count(token, ".") == 2 { + wt, err := jws.ParseJWT([]byte(token)) + // If there's an error we simply fall back to attempting to use it as a regular token + if err == nil && wt != nil { + validator := &jwt.Validator{} + validator.SetClaim("type", "wrapping") + if err = wt.Validate(&c.wrappingJWTKey.PublicKey, crypto.SigningMethodES512, []*jwt.Validator{validator}...); err != nil { + return false, errwrap.Wrapf("wrapping token signature could not be validated: {{err}}", err) + } + token, _ = wt.Claims().JWTID() + // We override the given request client token so that the rest of + // Vault sees the real value. This also ensures audit logs are + // consistent with the actual token that was issued. + if !thirdParty { + req.ClientToken = token + } else { + req.Data["token"] = token + } + } + } + + if token == "" { + return false, fmt.Errorf("token is empty") + } + + c.stateLock.RLock() + defer c.stateLock.RUnlock() + if c.sealed { + return false, consts.ErrSealed + } + if c.standby { + return false, consts.ErrStandby + } + + te, err := c.tokenStore.Lookup(c.activeContext, token) + if err != nil { + return false, err + } + if te == nil { + return false, nil + } + + if len(te.Policies) != 1 { + return false, nil + } + + if te.Policies[0] != responseWrappingPolicyName && te.Policies[0] != controlGroupPolicyName { + return false, nil + } + + return true, nil +} diff --git a/vendor/github.com/hashicorp/vault/version/cgo.go b/vendor/github.com/hashicorp/vault/version/cgo.go new file mode 100644 index 0000000..2ed493a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/version/cgo.go @@ -0,0 +1,7 @@ +// +build cgo + +package version + +func init() { + CgoEnabled = true +} diff --git a/vendor/github.com/hashicorp/vault/version/version.go b/vendor/github.com/hashicorp/vault/version/version.go new file mode 100644 index 0000000..0f81933 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/version/version.go @@ -0,0 +1,87 @@ +package version + +import ( + "bytes" + "fmt" +) + +var ( + // The git commit that was compiled. This will be filled in by the compiler. + GitCommit string + GitDescribe string + + // Whether cgo is enabled or not; set at build time + CgoEnabled bool + + Version = "unknown" + VersionPrerelease = "unknown" + VersionMetadata = "" +) + +// VersionInfo +type VersionInfo struct { + Revision string + Version string + VersionPrerelease string + VersionMetadata string +} + +func GetVersion() *VersionInfo { + ver := Version + rel := VersionPrerelease + md := VersionMetadata + if GitDescribe != "" { + ver = GitDescribe + } + if GitDescribe == "" && rel == "" && VersionPrerelease != "" { + rel = "dev" + } + + return &VersionInfo{ + Revision: GitCommit, + Version: ver, + VersionPrerelease: rel, + VersionMetadata: md, + } +} + +func (c *VersionInfo) VersionNumber() string { + if Version == "unknown" && VersionPrerelease == "unknown" { + return "(version unknown)" + } + + version := fmt.Sprintf("%s", c.Version) + + if c.VersionPrerelease != "" { + version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease) + } + + if c.VersionMetadata != "" { + version = fmt.Sprintf("%s+%s", version, c.VersionMetadata) + } + + return version +} + +func (c *VersionInfo) FullVersionNumber(rev bool) string { + var versionString bytes.Buffer + + if Version == "unknown" && VersionPrerelease == "unknown" { + return "Vault (version unknown)" + } + + fmt.Fprintf(&versionString, "Vault v%s", c.Version) + if c.VersionPrerelease != "" { + fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease) + } + + if c.VersionMetadata != "" { + fmt.Fprintf(&versionString, "+%s", c.VersionMetadata) + } + + if rev && c.Revision != "" { + fmt.Fprintf(&versionString, " (%s)", c.Revision) + } + + return versionString.String() +} diff --git a/vendor/github.com/hashicorp/vault/version/version_base.go b/vendor/github.com/hashicorp/vault/version/version_base.go new file mode 100644 index 0000000..dfc6734 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/version/version_base.go @@ -0,0 +1,11 @@ +package version + +func init() { + // The main version number that is being run at the moment. + Version = "0.10.2" + + // A pre-release marker for the version. If this is "" (empty string) + // then it means that it is a final release. Otherwise, this is a pre-release + // such as "dev" (in development), "beta", "rc1", etc. + VersionPrerelease = "" +} diff --git a/vendor/github.com/hashicorp/vault/website/LICENSE.md b/vendor/github.com/hashicorp/vault/website/LICENSE.md new file mode 100644 index 0000000..3189f43 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/website/LICENSE.md @@ -0,0 +1,10 @@ +# Proprietary License + +This license is temporary while a more official one is drafted. However, +this should make it clear: + +The text contents of this website are MPL 2.0 licensed. + +The design contents of this website are proprietary and may not be reproduced +or reused in any way other than to run the website locally. The license for +the design is owned solely by HashiCorp, Inc. diff --git a/vendor/github.com/hashicorp/vault/website/source/api/system/license.html.md b/vendor/github.com/hashicorp/vault/website/source/api/system/license.html.md new file mode 100644 index 0000000..933d277 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/website/source/api/system/license.html.md @@ -0,0 +1,87 @@ +--- +layout: "api" +page_title: "/sys/license - HTTP API" +sidebar_current: "docs-http-system-license" +description: |- + The `/sys/license` endpoint is used to view and update the license used in + Vault. +--- + +# `/sys/license` + +~> **Enterprise Only** – These endpoints require Vault Enterprise. + +The `/sys/license` endpoint is used to view and update the license used in +Vault. + +## Read License + +This endpoint returns information about the currently installed license. + +| Method | Path | Produces | +| :------- | :--------------------------- | :--------------------- | +| `GET` | `/sys/license` | `200 application/json` | + +### Sample Request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + http://127.0.0.1:8200/v1/sys/license +``` + +### Sample Response + +```json +{ + "data": { + "expiration_time": "2017-11-14T16:34:36.546753-05:00", + "features": [ + "UI", + "HSM", + "Performance Replication", + "DR Replication" + ], + "license_id": "temporary", + "start_time": "2017-11-14T16:04:36.546753-05:00" + }, + "warnings": [ + "time left on license is 29m33s" + ] +} +``` + +## Install License + +This endpoint is used to install a license into Vault. + +| Method | Path | Produces | +| :------- | :--------------------------- | :--------------------- | +| `PUT` | `/sys/license` | `204 (empty body)` | + +### Parameters + +- `text` `(string: )` – The text of the license. + +*DR Secondary Specific Parameters* + + - `dr_operation_token` `(string: )` - DR operation token used to authorize this request. + + +### Sample Payload + +```json +{ + "text": "01ABCDEFG..." +} +``` + +### Sample Request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + --request PUT \ + --data @payload.json \ + http://127.0.0.1:8200/v1/sys/license +``` diff --git a/vendor/github.com/hashicorp/yamux/.gitignore b/vendor/github.com/hashicorp/yamux/.gitignore new file mode 100644 index 0000000..8365624 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/hashicorp/yamux/LICENSE b/vendor/github.com/hashicorp/yamux/LICENSE new file mode 100644 index 0000000..f0e5c79 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/vendor/github.com/hashicorp/yamux/README.md b/vendor/github.com/hashicorp/yamux/README.md new file mode 100644 index 0000000..d4db7fc --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/README.md @@ -0,0 +1,86 @@ +# Yamux + +Yamux (Yet another Multiplexer) is a multiplexing library for Golang. +It relies on an underlying connection to provide reliability +and ordering, such as TCP or Unix domain sockets, and provides +stream-oriented multiplexing. It is inspired by SPDY but is not +interoperable with it. + +Yamux features include: + +* Bi-directional streams + * Streams can be opened by either client or server + * Useful for NAT traversal + * Server-side push support +* Flow control + * Avoid starvation + * Back-pressure to prevent overwhelming a receiver +* Keep Alives + * Enables persistent connections over a load balancer +* Efficient + * Enables thousands of logical streams with low overhead + +## Documentation + +For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/yamux). + +## Specification + +The full specification for Yamux is provided in the `spec.md` file. +It can be used as a guide to implementors of interoperable libraries. + +## Usage + +Using Yamux is remarkably simple: + +```go + +func client() { + // Get a TCP connection + conn, err := net.Dial(...) + if err != nil { + panic(err) + } + + // Setup client side of yamux + session, err := yamux.Client(conn, nil) + if err != nil { + panic(err) + } + + // Open a new stream + stream, err := session.Open() + if err != nil { + panic(err) + } + + // Stream implements net.Conn + stream.Write([]byte("ping")) +} + +func server() { + // Accept a TCP connection + conn, err := listener.Accept() + if err != nil { + panic(err) + } + + // Setup server side of yamux + session, err := yamux.Server(conn, nil) + if err != nil { + panic(err) + } + + // Accept a stream + stream, err := session.Accept() + if err != nil { + panic(err) + } + + // Listen for a message + buf := make([]byte, 4) + stream.Read(buf) +} + +``` + diff --git a/vendor/github.com/hashicorp/yamux/addr.go b/vendor/github.com/hashicorp/yamux/addr.go new file mode 100644 index 0000000..be6ebca --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/addr.go @@ -0,0 +1,60 @@ +package yamux + +import ( + "fmt" + "net" +) + +// hasAddr is used to get the address from the underlying connection +type hasAddr interface { + LocalAddr() net.Addr + RemoteAddr() net.Addr +} + +// yamuxAddr is used when we cannot get the underlying address +type yamuxAddr struct { + Addr string +} + +func (*yamuxAddr) Network() string { + return "yamux" +} + +func (y *yamuxAddr) String() string { + return fmt.Sprintf("yamux:%s", y.Addr) +} + +// Addr is used to get the address of the listener. +func (s *Session) Addr() net.Addr { + return s.LocalAddr() +} + +// LocalAddr is used to get the local address of the +// underlying connection. +func (s *Session) LocalAddr() net.Addr { + addr, ok := s.conn.(hasAddr) + if !ok { + return &yamuxAddr{"local"} + } + return addr.LocalAddr() +} + +// RemoteAddr is used to get the address of remote end +// of the underlying connection +func (s *Session) RemoteAddr() net.Addr { + addr, ok := s.conn.(hasAddr) + if !ok { + return &yamuxAddr{"remote"} + } + return addr.RemoteAddr() +} + +// LocalAddr returns the local address +func (s *Stream) LocalAddr() net.Addr { + return s.session.LocalAddr() +} + +// LocalAddr returns the remote address +func (s *Stream) RemoteAddr() net.Addr { + return s.session.RemoteAddr() +} diff --git a/vendor/github.com/hashicorp/yamux/const.go b/vendor/github.com/hashicorp/yamux/const.go new file mode 100644 index 0000000..4f52938 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/const.go @@ -0,0 +1,157 @@ +package yamux + +import ( + "encoding/binary" + "fmt" +) + +var ( + // ErrInvalidVersion means we received a frame with an + // invalid version + ErrInvalidVersion = fmt.Errorf("invalid protocol version") + + // ErrInvalidMsgType means we received a frame with an + // invalid message type + ErrInvalidMsgType = fmt.Errorf("invalid msg type") + + // ErrSessionShutdown is used if there is a shutdown during + // an operation + ErrSessionShutdown = fmt.Errorf("session shutdown") + + // ErrStreamsExhausted is returned if we have no more + // stream ids to issue + ErrStreamsExhausted = fmt.Errorf("streams exhausted") + + // ErrDuplicateStream is used if a duplicate stream is + // opened inbound + ErrDuplicateStream = fmt.Errorf("duplicate stream initiated") + + // ErrReceiveWindowExceeded indicates the window was exceeded + ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded") + + // ErrTimeout is used when we reach an IO deadline + ErrTimeout = fmt.Errorf("i/o deadline reached") + + // ErrStreamClosed is returned when using a closed stream + ErrStreamClosed = fmt.Errorf("stream closed") + + // ErrUnexpectedFlag is set when we get an unexpected flag + ErrUnexpectedFlag = fmt.Errorf("unexpected flag") + + // ErrRemoteGoAway is used when we get a go away from the other side + ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections") + + // ErrConnectionReset is sent if a stream is reset. This can happen + // if the backlog is exceeded, or if there was a remote GoAway. + ErrConnectionReset = fmt.Errorf("connection reset") + + // ErrConnectionWriteTimeout indicates that we hit the "safety valve" + // timeout writing to the underlying stream connection. + ErrConnectionWriteTimeout = fmt.Errorf("connection write timeout") + + // ErrKeepAliveTimeout is sent if a missed keepalive caused the stream close + ErrKeepAliveTimeout = fmt.Errorf("keepalive timeout") +) + +const ( + // protoVersion is the only version we support + protoVersion uint8 = 0 +) + +const ( + // Data is used for data frames. They are followed + // by length bytes worth of payload. + typeData uint8 = iota + + // WindowUpdate is used to change the window of + // a given stream. The length indicates the delta + // update to the window. + typeWindowUpdate + + // Ping is sent as a keep-alive or to measure + // the RTT. The StreamID and Length value are echoed + // back in the response. + typePing + + // GoAway is sent to terminate a session. The StreamID + // should be 0 and the length is an error code. + typeGoAway +) + +const ( + // SYN is sent to signal a new stream. May + // be sent with a data payload + flagSYN uint16 = 1 << iota + + // ACK is sent to acknowledge a new stream. May + // be sent with a data payload + flagACK + + // FIN is sent to half-close the given stream. + // May be sent with a data payload. + flagFIN + + // RST is used to hard close a given stream. + flagRST +) + +const ( + // initialStreamWindow is the initial stream window size + initialStreamWindow uint32 = 256 * 1024 +) + +const ( + // goAwayNormal is sent on a normal termination + goAwayNormal uint32 = iota + + // goAwayProtoErr sent on a protocol error + goAwayProtoErr + + // goAwayInternalErr sent on an internal error + goAwayInternalErr +) + +const ( + sizeOfVersion = 1 + sizeOfType = 1 + sizeOfFlags = 2 + sizeOfStreamID = 4 + sizeOfLength = 4 + headerSize = sizeOfVersion + sizeOfType + sizeOfFlags + + sizeOfStreamID + sizeOfLength +) + +type header []byte + +func (h header) Version() uint8 { + return h[0] +} + +func (h header) MsgType() uint8 { + return h[1] +} + +func (h header) Flags() uint16 { + return binary.BigEndian.Uint16(h[2:4]) +} + +func (h header) StreamID() uint32 { + return binary.BigEndian.Uint32(h[4:8]) +} + +func (h header) Length() uint32 { + return binary.BigEndian.Uint32(h[8:12]) +} + +func (h header) String() string { + return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d", + h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length()) +} + +func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) { + h[0] = protoVersion + h[1] = msgType + binary.BigEndian.PutUint16(h[2:4], flags) + binary.BigEndian.PutUint32(h[4:8], streamID) + binary.BigEndian.PutUint32(h[8:12], length) +} diff --git a/vendor/github.com/hashicorp/yamux/mux.go b/vendor/github.com/hashicorp/yamux/mux.go new file mode 100644 index 0000000..7abc7c7 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/mux.go @@ -0,0 +1,87 @@ +package yamux + +import ( + "fmt" + "io" + "os" + "time" +) + +// Config is used to tune the Yamux session +type Config struct { + // AcceptBacklog is used to limit how many streams may be + // waiting an accept. + AcceptBacklog int + + // EnableKeepalive is used to do a period keep alive + // messages using a ping. + EnableKeepAlive bool + + // KeepAliveInterval is how often to perform the keep alive + KeepAliveInterval time.Duration + + // ConnectionWriteTimeout is meant to be a "safety valve" timeout after + // we which will suspect a problem with the underlying connection and + // close it. This is only applied to writes, where's there's generally + // an expectation that things will move along quickly. + ConnectionWriteTimeout time.Duration + + // MaxStreamWindowSize is used to control the maximum + // window size that we allow for a stream. + MaxStreamWindowSize uint32 + + // LogOutput is used to control the log destination + LogOutput io.Writer +} + +// DefaultConfig is used to return a default configuration +func DefaultConfig() *Config { + return &Config{ + AcceptBacklog: 256, + EnableKeepAlive: true, + KeepAliveInterval: 30 * time.Second, + ConnectionWriteTimeout: 10 * time.Second, + MaxStreamWindowSize: initialStreamWindow, + LogOutput: os.Stderr, + } +} + +// VerifyConfig is used to verify the sanity of configuration +func VerifyConfig(config *Config) error { + if config.AcceptBacklog <= 0 { + return fmt.Errorf("backlog must be positive") + } + if config.KeepAliveInterval == 0 { + return fmt.Errorf("keep-alive interval must be positive") + } + if config.MaxStreamWindowSize < initialStreamWindow { + return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow) + } + return nil +} + +// Server is used to initialize a new server-side connection. +// There must be at most one server-side connection. If a nil config is +// provided, the DefaultConfiguration will be used. +func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) { + if config == nil { + config = DefaultConfig() + } + if err := VerifyConfig(config); err != nil { + return nil, err + } + return newSession(config, conn, false), nil +} + +// Client is used to initialize a new client-side connection. +// There must be at most one client-side connection. +func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) { + if config == nil { + config = DefaultConfig() + } + + if err := VerifyConfig(config); err != nil { + return nil, err + } + return newSession(config, conn, true), nil +} diff --git a/vendor/github.com/hashicorp/yamux/session.go b/vendor/github.com/hashicorp/yamux/session.go new file mode 100644 index 0000000..32ba02e --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/session.go @@ -0,0 +1,648 @@ +package yamux + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "log" + "math" + "net" + "strings" + "sync" + "sync/atomic" + "time" +) + +// Session is used to wrap a reliable ordered connection and to +// multiplex it into multiple streams. +type Session struct { + // remoteGoAway indicates the remote side does + // not want futher connections. Must be first for alignment. + remoteGoAway int32 + + // localGoAway indicates that we should stop + // accepting futher connections. Must be first for alignment. + localGoAway int32 + + // nextStreamID is the next stream we should + // send. This depends if we are a client/server. + nextStreamID uint32 + + // config holds our configuration + config *Config + + // logger is used for our logs + logger *log.Logger + + // conn is the underlying connection + conn io.ReadWriteCloser + + // bufRead is a buffered reader + bufRead *bufio.Reader + + // pings is used to track inflight pings + pings map[uint32]chan struct{} + pingID uint32 + pingLock sync.Mutex + + // streams maps a stream id to a stream, and inflight has an entry + // for any outgoing stream that has not yet been established. Both are + // protected by streamLock. + streams map[uint32]*Stream + inflight map[uint32]struct{} + streamLock sync.Mutex + + // synCh acts like a semaphore. It is sized to the AcceptBacklog which + // is assumed to be symmetric between the client and server. This allows + // the client to avoid exceeding the backlog and instead blocks the open. + synCh chan struct{} + + // acceptCh is used to pass ready streams to the client + acceptCh chan *Stream + + // sendCh is used to mark a stream as ready to send, + // or to send a header out directly. + sendCh chan sendReady + + // recvDoneCh is closed when recv() exits to avoid a race + // between stream registration and stream shutdown + recvDoneCh chan struct{} + + // shutdown is used to safely close a session + shutdown bool + shutdownErr error + shutdownCh chan struct{} + shutdownLock sync.Mutex +} + +// sendReady is used to either mark a stream as ready +// or to directly send a header +type sendReady struct { + Hdr []byte + Body io.Reader + Err chan error +} + +// newSession is used to construct a new session +func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { + s := &Session{ + config: config, + logger: log.New(config.LogOutput, "", log.LstdFlags), + conn: conn, + bufRead: bufio.NewReader(conn), + pings: make(map[uint32]chan struct{}), + streams: make(map[uint32]*Stream), + inflight: make(map[uint32]struct{}), + synCh: make(chan struct{}, config.AcceptBacklog), + acceptCh: make(chan *Stream, config.AcceptBacklog), + sendCh: make(chan sendReady, 64), + recvDoneCh: make(chan struct{}), + shutdownCh: make(chan struct{}), + } + if client { + s.nextStreamID = 1 + } else { + s.nextStreamID = 2 + } + go s.recv() + go s.send() + if config.EnableKeepAlive { + go s.keepalive() + } + return s +} + +// IsClosed does a safe check to see if we have shutdown +func (s *Session) IsClosed() bool { + select { + case <-s.shutdownCh: + return true + default: + return false + } +} + +// CloseChan returns a read-only channel which is closed as +// soon as the session is closed. +func (s *Session) CloseChan() <-chan struct{} { + return s.shutdownCh +} + +// NumStreams returns the number of currently open streams +func (s *Session) NumStreams() int { + s.streamLock.Lock() + num := len(s.streams) + s.streamLock.Unlock() + return num +} + +// Open is used to create a new stream as a net.Conn +func (s *Session) Open() (net.Conn, error) { + conn, err := s.OpenStream() + if err != nil { + return nil, err + } + return conn, nil +} + +// OpenStream is used to create a new stream +func (s *Session) OpenStream() (*Stream, error) { + if s.IsClosed() { + return nil, ErrSessionShutdown + } + if atomic.LoadInt32(&s.remoteGoAway) == 1 { + return nil, ErrRemoteGoAway + } + + // Block if we have too many inflight SYNs + select { + case s.synCh <- struct{}{}: + case <-s.shutdownCh: + return nil, ErrSessionShutdown + } + +GET_ID: + // Get an ID, and check for stream exhaustion + id := atomic.LoadUint32(&s.nextStreamID) + if id >= math.MaxUint32-1 { + return nil, ErrStreamsExhausted + } + if !atomic.CompareAndSwapUint32(&s.nextStreamID, id, id+2) { + goto GET_ID + } + + // Register the stream + stream := newStream(s, id, streamInit) + s.streamLock.Lock() + s.streams[id] = stream + s.inflight[id] = struct{}{} + s.streamLock.Unlock() + + // Send the window update to create + if err := stream.sendWindowUpdate(); err != nil { + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: aborted stream open without inflight syn semaphore") + } + return nil, err + } + return stream, nil +} + +// Accept is used to block until the next available stream +// is ready to be accepted. +func (s *Session) Accept() (net.Conn, error) { + conn, err := s.AcceptStream() + if err != nil { + return nil, err + } + return conn, err +} + +// AcceptStream is used to block until the next available stream +// is ready to be accepted. +func (s *Session) AcceptStream() (*Stream, error) { + select { + case stream := <-s.acceptCh: + if err := stream.sendWindowUpdate(); err != nil { + return nil, err + } + return stream, nil + case <-s.shutdownCh: + return nil, s.shutdownErr + } +} + +// Close is used to close the session and all streams. +// Attempts to send a GoAway before closing the connection. +func (s *Session) Close() error { + s.shutdownLock.Lock() + defer s.shutdownLock.Unlock() + + if s.shutdown { + return nil + } + s.shutdown = true + if s.shutdownErr == nil { + s.shutdownErr = ErrSessionShutdown + } + close(s.shutdownCh) + s.conn.Close() + <-s.recvDoneCh + + s.streamLock.Lock() + defer s.streamLock.Unlock() + for _, stream := range s.streams { + stream.forceClose() + } + return nil +} + +// exitErr is used to handle an error that is causing the +// session to terminate. +func (s *Session) exitErr(err error) { + s.shutdownLock.Lock() + if s.shutdownErr == nil { + s.shutdownErr = err + } + s.shutdownLock.Unlock() + s.Close() +} + +// GoAway can be used to prevent accepting further +// connections. It does not close the underlying conn. +func (s *Session) GoAway() error { + return s.waitForSend(s.goAway(goAwayNormal), nil) +} + +// goAway is used to send a goAway message +func (s *Session) goAway(reason uint32) header { + atomic.SwapInt32(&s.localGoAway, 1) + hdr := header(make([]byte, headerSize)) + hdr.encode(typeGoAway, 0, 0, reason) + return hdr +} + +// Ping is used to measure the RTT response time +func (s *Session) Ping() (time.Duration, error) { + // Get a channel for the ping + ch := make(chan struct{}) + + // Get a new ping id, mark as pending + s.pingLock.Lock() + id := s.pingID + s.pingID++ + s.pings[id] = ch + s.pingLock.Unlock() + + // Send the ping request + hdr := header(make([]byte, headerSize)) + hdr.encode(typePing, flagSYN, 0, id) + if err := s.waitForSend(hdr, nil); err != nil { + return 0, err + } + + // Wait for a response + start := time.Now() + select { + case <-ch: + case <-time.After(s.config.ConnectionWriteTimeout): + s.pingLock.Lock() + delete(s.pings, id) // Ignore it if a response comes later. + s.pingLock.Unlock() + return 0, ErrTimeout + case <-s.shutdownCh: + return 0, ErrSessionShutdown + } + + // Compute the RTT + return time.Now().Sub(start), nil +} + +// keepalive is a long running goroutine that periodically does +// a ping to keep the connection alive. +func (s *Session) keepalive() { + for { + select { + case <-time.After(s.config.KeepAliveInterval): + _, err := s.Ping() + if err != nil { + if err != ErrSessionShutdown { + s.logger.Printf("[ERR] yamux: keepalive failed: %v", err) + s.exitErr(ErrKeepAliveTimeout) + } + return + } + case <-s.shutdownCh: + return + } + } +} + +// waitForSendErr waits to send a header, checking for a potential shutdown +func (s *Session) waitForSend(hdr header, body io.Reader) error { + errCh := make(chan error, 1) + return s.waitForSendErr(hdr, body, errCh) +} + +// waitForSendErr waits to send a header with optional data, checking for a +// potential shutdown. Since there's the expectation that sends can happen +// in a timely manner, we enforce the connection write timeout here. +func (s *Session) waitForSendErr(hdr header, body io.Reader, errCh chan error) error { + t := timerPool.Get() + timer := t.(*time.Timer) + timer.Reset(s.config.ConnectionWriteTimeout) + defer func() { + timer.Stop() + select { + case <-timer.C: + default: + } + timerPool.Put(t) + }() + + ready := sendReady{Hdr: hdr, Body: body, Err: errCh} + select { + case s.sendCh <- ready: + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } + + select { + case err := <-errCh: + return err + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } +} + +// sendNoWait does a send without waiting. Since there's the expectation that +// the send happens right here, we enforce the connection write timeout if we +// can't queue the header to be sent. +func (s *Session) sendNoWait(hdr header) error { + t := timerPool.Get() + timer := t.(*time.Timer) + timer.Reset(s.config.ConnectionWriteTimeout) + defer func() { + timer.Stop() + select { + case <-timer.C: + default: + } + timerPool.Put(t) + }() + + select { + case s.sendCh <- sendReady{Hdr: hdr}: + return nil + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } +} + +// send is a long running goroutine that sends data +func (s *Session) send() { + for { + select { + case ready := <-s.sendCh: + // Send a header if ready + if ready.Hdr != nil { + sent := 0 + for sent < len(ready.Hdr) { + n, err := s.conn.Write(ready.Hdr[sent:]) + if err != nil { + s.logger.Printf("[ERR] yamux: Failed to write header: %v", err) + asyncSendErr(ready.Err, err) + s.exitErr(err) + return + } + sent += n + } + } + + // Send data from a body if given + if ready.Body != nil { + _, err := io.Copy(s.conn, ready.Body) + if err != nil { + s.logger.Printf("[ERR] yamux: Failed to write body: %v", err) + asyncSendErr(ready.Err, err) + s.exitErr(err) + return + } + } + + // No error, successful send + asyncSendErr(ready.Err, nil) + case <-s.shutdownCh: + return + } + } +} + +// recv is a long running goroutine that accepts new data +func (s *Session) recv() { + if err := s.recvLoop(); err != nil { + s.exitErr(err) + } +} + +// Ensure that the index of the handler (typeData/typeWindowUpdate/etc) matches the message type +var ( + handlers = []func(*Session, header) error{ + typeData: (*Session).handleStreamMessage, + typeWindowUpdate: (*Session).handleStreamMessage, + typePing: (*Session).handlePing, + typeGoAway: (*Session).handleGoAway, + } +) + +// recvLoop continues to receive data until a fatal error is encountered +func (s *Session) recvLoop() error { + defer close(s.recvDoneCh) + hdr := header(make([]byte, headerSize)) + for { + // Read the header + if _, err := io.ReadFull(s.bufRead, hdr); err != nil { + if err != io.EOF && !strings.Contains(err.Error(), "closed") && !strings.Contains(err.Error(), "reset by peer") { + s.logger.Printf("[ERR] yamux: Failed to read header: %v", err) + } + return err + } + + // Verify the version + if hdr.Version() != protoVersion { + s.logger.Printf("[ERR] yamux: Invalid protocol version: %d", hdr.Version()) + return ErrInvalidVersion + } + + mt := hdr.MsgType() + if mt < typeData || mt > typeGoAway { + return ErrInvalidMsgType + } + + if err := handlers[mt](s, hdr); err != nil { + return err + } + } +} + +// handleStreamMessage handles either a data or window update frame +func (s *Session) handleStreamMessage(hdr header) error { + // Check for a new stream creation + id := hdr.StreamID() + flags := hdr.Flags() + if flags&flagSYN == flagSYN { + if err := s.incomingStream(id); err != nil { + return err + } + } + + // Get the stream + s.streamLock.Lock() + stream := s.streams[id] + s.streamLock.Unlock() + + // If we do not have a stream, likely we sent a RST + if stream == nil { + // Drain any data on the wire + if hdr.MsgType() == typeData && hdr.Length() > 0 { + s.logger.Printf("[WARN] yamux: Discarding data for stream: %d", id) + if _, err := io.CopyN(ioutil.Discard, s.bufRead, int64(hdr.Length())); err != nil { + s.logger.Printf("[ERR] yamux: Failed to discard data: %v", err) + return nil + } + } else { + s.logger.Printf("[WARN] yamux: frame for missing stream: %v", hdr) + } + return nil + } + + // Check if this is a window update + if hdr.MsgType() == typeWindowUpdate { + if err := stream.incrSendWindow(hdr, flags); err != nil { + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return err + } + return nil + } + + // Read the new data + if err := stream.readData(hdr, flags, s.bufRead); err != nil { + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return err + } + return nil +} + +// handlePing is invokde for a typePing frame +func (s *Session) handlePing(hdr header) error { + flags := hdr.Flags() + pingID := hdr.Length() + + // Check if this is a query, respond back in a separate context so we + // don't interfere with the receiving thread blocking for the write. + if flags&flagSYN == flagSYN { + go func() { + hdr := header(make([]byte, headerSize)) + hdr.encode(typePing, flagACK, 0, pingID) + if err := s.sendNoWait(hdr); err != nil { + s.logger.Printf("[WARN] yamux: failed to send ping reply: %v", err) + } + }() + return nil + } + + // Handle a response + s.pingLock.Lock() + ch := s.pings[pingID] + if ch != nil { + delete(s.pings, pingID) + close(ch) + } + s.pingLock.Unlock() + return nil +} + +// handleGoAway is invokde for a typeGoAway frame +func (s *Session) handleGoAway(hdr header) error { + code := hdr.Length() + switch code { + case goAwayNormal: + atomic.SwapInt32(&s.remoteGoAway, 1) + case goAwayProtoErr: + s.logger.Printf("[ERR] yamux: received protocol error go away") + return fmt.Errorf("yamux protocol error") + case goAwayInternalErr: + s.logger.Printf("[ERR] yamux: received internal error go away") + return fmt.Errorf("remote yamux internal error") + default: + s.logger.Printf("[ERR] yamux: received unexpected go away") + return fmt.Errorf("unexpected go away received") + } + return nil +} + +// incomingStream is used to create a new incoming stream +func (s *Session) incomingStream(id uint32) error { + // Reject immediately if we are doing a go away + if atomic.LoadInt32(&s.localGoAway) == 1 { + hdr := header(make([]byte, headerSize)) + hdr.encode(typeWindowUpdate, flagRST, id, 0) + return s.sendNoWait(hdr) + } + + // Allocate a new stream + stream := newStream(s, id, streamSYNReceived) + + s.streamLock.Lock() + defer s.streamLock.Unlock() + + // Check if stream already exists + if _, ok := s.streams[id]; ok { + s.logger.Printf("[ERR] yamux: duplicate stream declared") + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return ErrDuplicateStream + } + + // Register the stream + s.streams[id] = stream + + // Check if we've exceeded the backlog + select { + case s.acceptCh <- stream: + return nil + default: + // Backlog exceeded! RST the stream + s.logger.Printf("[WARN] yamux: backlog exceeded, forcing connection reset") + delete(s.streams, id) + stream.sendHdr.encode(typeWindowUpdate, flagRST, id, 0) + return s.sendNoWait(stream.sendHdr) + } +} + +// closeStream is used to close a stream once both sides have +// issued a close. If there was an in-flight SYN and the stream +// was not yet established, then this will give the credit back. +func (s *Session) closeStream(id uint32) { + s.streamLock.Lock() + if _, ok := s.inflight[id]; ok { + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: SYN tracking out of sync") + } + } + delete(s.streams, id) + s.streamLock.Unlock() +} + +// establishStream is used to mark a stream that was in the +// SYN Sent state as established. +func (s *Session) establishStream(id uint32) { + s.streamLock.Lock() + if _, ok := s.inflight[id]; ok { + delete(s.inflight, id) + } else { + s.logger.Printf("[ERR] yamux: established stream without inflight SYN (no tracking entry)") + } + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: established stream without inflight SYN (didn't have semaphore)") + } + s.streamLock.Unlock() +} diff --git a/vendor/github.com/hashicorp/yamux/spec.md b/vendor/github.com/hashicorp/yamux/spec.md new file mode 100644 index 0000000..183d797 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/spec.md @@ -0,0 +1,140 @@ +# Specification + +We use this document to detail the internal specification of Yamux. +This is used both as a guide for implementing Yamux, but also for +alternative interoperable libraries to be built. + +# Framing + +Yamux uses a streaming connection underneath, but imposes a message +framing so that it can be shared between many logical streams. Each +frame contains a header like: + +* Version (8 bits) +* Type (8 bits) +* Flags (16 bits) +* StreamID (32 bits) +* Length (32 bits) + +This means that each header has a 12 byte overhead. +All fields are encoded in network order (big endian). +Each field is described below: + +## Version Field + +The version field is used for future backward compatibility. At the +current time, the field is always set to 0, to indicate the initial +version. + +## Type Field + +The type field is used to switch the frame message type. The following +message types are supported: + +* 0x0 Data - Used to transmit data. May transmit zero length payloads + depending on the flags. + +* 0x1 Window Update - Used to updated the senders receive window size. + This is used to implement per-session flow control. + +* 0x2 Ping - Used to measure RTT. It can also be used to heart-beat + and do keep-alives over TCP. + +* 0x3 Go Away - Used to close a session. + +## Flag Field + +The flags field is used to provide additional information related +to the message type. The following flags are supported: + +* 0x1 SYN - Signals the start of a new stream. May be sent with a data or + window update message. Also sent with a ping to indicate outbound. + +* 0x2 ACK - Acknowledges the start of a new stream. May be sent with a data + or window update message. Also sent with a ping to indicate response. + +* 0x4 FIN - Performs a half-close of a stream. May be sent with a data + message or window update. + +* 0x8 RST - Reset a stream immediately. May be sent with a data or + window update message. + +## StreamID Field + +The StreamID field is used to identify the logical stream the frame +is addressing. The client side should use odd ID's, and the server even. +This prevents any collisions. Additionally, the 0 ID is reserved to represent +the session. + +Both Ping and Go Away messages should always use the 0 StreamID. + +## Length Field + +The meaning of the length field depends on the message type: + +* Data - provides the length of bytes following the header +* Window update - provides a delta update to the window size +* Ping - Contains an opaque value, echoed back +* Go Away - Contains an error code + +# Message Flow + +There is no explicit connection setup, as Yamux relies on an underlying +transport to be provided. However, there is a distinction between client +and server side of the connection. + +## Opening a stream + +To open a stream, an initial data or window update frame is sent +with a new StreamID. The SYN flag should be set to signal a new stream. + +The receiver must then reply with either a data or window update frame +with the StreamID along with the ACK flag to accept the stream or with +the RST flag to reject the stream. + +Because we are relying on the reliable stream underneath, a connection +can begin sending data once the SYN flag is sent. The corresponding +ACK does not need to be received. This is particularly well suited +for an RPC system where a client wants to open a stream and immediately +fire a request without waiting for the RTT of the ACK. + +This does introduce the possibility of a connection being rejected +after data has been sent already. This is a slight semantic difference +from TCP, where the conection cannot be refused after it is opened. +Clients should be prepared to handle this by checking for an error +that indicates a RST was received. + +## Closing a stream + +To close a stream, either side sends a data or window update frame +along with the FIN flag. This does a half-close indicating the sender +will send no further data. + +Once both sides have closed the connection, the stream is closed. + +Alternatively, if an error occurs, the RST flag can be used to +hard close a stream immediately. + +## Flow Control + +When Yamux is initially starts each stream with a 256KB window size. +There is no window size for the session. + +To prevent the streams from stalling, window update frames should be +sent regularly. Yamux can be configured to provide a larger limit for +windows sizes. Both sides assume the initial 256KB window, but can +immediately send a window update as part of the SYN/ACK indicating a +larger window. + +Both sides should track the number of bytes sent in Data frames +only, as only they are tracked as part of the window size. + +## Session termination + +When a session is being terminated, the Go Away message should +be sent. The Length should be set to one of the following to +provide an error code: + +* 0x0 Normal termination +* 0x1 Protocol error +* 0x2 Internal error diff --git a/vendor/github.com/hashicorp/yamux/stream.go b/vendor/github.com/hashicorp/yamux/stream.go new file mode 100644 index 0000000..aa23919 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/stream.go @@ -0,0 +1,470 @@ +package yamux + +import ( + "bytes" + "io" + "sync" + "sync/atomic" + "time" +) + +type streamState int + +const ( + streamInit streamState = iota + streamSYNSent + streamSYNReceived + streamEstablished + streamLocalClose + streamRemoteClose + streamClosed + streamReset +) + +// Stream is used to represent a logical stream +// within a session. +type Stream struct { + recvWindow uint32 + sendWindow uint32 + + id uint32 + session *Session + + state streamState + stateLock sync.Mutex + + recvBuf *bytes.Buffer + recvLock sync.Mutex + + controlHdr header + controlErr chan error + controlHdrLock sync.Mutex + + sendHdr header + sendErr chan error + sendLock sync.Mutex + + recvNotifyCh chan struct{} + sendNotifyCh chan struct{} + + readDeadline atomic.Value // time.Time + writeDeadline atomic.Value // time.Time +} + +// newStream is used to construct a new stream within +// a given session for an ID +func newStream(session *Session, id uint32, state streamState) *Stream { + s := &Stream{ + id: id, + session: session, + state: state, + controlHdr: header(make([]byte, headerSize)), + controlErr: make(chan error, 1), + sendHdr: header(make([]byte, headerSize)), + sendErr: make(chan error, 1), + recvWindow: initialStreamWindow, + sendWindow: initialStreamWindow, + recvNotifyCh: make(chan struct{}, 1), + sendNotifyCh: make(chan struct{}, 1), + } + s.readDeadline.Store(time.Time{}) + s.writeDeadline.Store(time.Time{}) + return s +} + +// Session returns the associated stream session +func (s *Stream) Session() *Session { + return s.session +} + +// StreamID returns the ID of this stream +func (s *Stream) StreamID() uint32 { + return s.id +} + +// Read is used to read from the stream +func (s *Stream) Read(b []byte) (n int, err error) { + defer asyncNotify(s.recvNotifyCh) +START: + s.stateLock.Lock() + switch s.state { + case streamLocalClose: + fallthrough + case streamRemoteClose: + fallthrough + case streamClosed: + s.recvLock.Lock() + if s.recvBuf == nil || s.recvBuf.Len() == 0 { + s.recvLock.Unlock() + s.stateLock.Unlock() + return 0, io.EOF + } + s.recvLock.Unlock() + case streamReset: + s.stateLock.Unlock() + return 0, ErrConnectionReset + } + s.stateLock.Unlock() + + // If there is no data available, block + s.recvLock.Lock() + if s.recvBuf == nil || s.recvBuf.Len() == 0 { + s.recvLock.Unlock() + goto WAIT + } + + // Read any bytes + n, _ = s.recvBuf.Read(b) + s.recvLock.Unlock() + + // Send a window update potentially + err = s.sendWindowUpdate() + return n, err + +WAIT: + var timeout <-chan time.Time + var timer *time.Timer + readDeadline := s.readDeadline.Load().(time.Time) + if !readDeadline.IsZero() { + delay := readDeadline.Sub(time.Now()) + timer = time.NewTimer(delay) + timeout = timer.C + } + select { + case <-s.recvNotifyCh: + if timer != nil { + timer.Stop() + } + goto START + case <-timeout: + return 0, ErrTimeout + } +} + +// Write is used to write to the stream +func (s *Stream) Write(b []byte) (n int, err error) { + s.sendLock.Lock() + defer s.sendLock.Unlock() + total := 0 + for total < len(b) { + n, err := s.write(b[total:]) + total += n + if err != nil { + return total, err + } + } + return total, nil +} + +// write is used to write to the stream, may return on +// a short write. +func (s *Stream) write(b []byte) (n int, err error) { + var flags uint16 + var max uint32 + var body io.Reader +START: + s.stateLock.Lock() + switch s.state { + case streamLocalClose: + fallthrough + case streamClosed: + s.stateLock.Unlock() + return 0, ErrStreamClosed + case streamReset: + s.stateLock.Unlock() + return 0, ErrConnectionReset + } + s.stateLock.Unlock() + + // If there is no data available, block + window := atomic.LoadUint32(&s.sendWindow) + if window == 0 { + goto WAIT + } + + // Determine the flags if any + flags = s.sendFlags() + + // Send up to our send window + max = min(window, uint32(len(b))) + body = bytes.NewReader(b[:max]) + + // Send the header + s.sendHdr.encode(typeData, flags, s.id, max) + if err = s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil { + return 0, err + } + + // Reduce our send window + atomic.AddUint32(&s.sendWindow, ^uint32(max-1)) + + // Unlock + return int(max), err + +WAIT: + var timeout <-chan time.Time + writeDeadline := s.writeDeadline.Load().(time.Time) + if !writeDeadline.IsZero() { + delay := writeDeadline.Sub(time.Now()) + timeout = time.After(delay) + } + select { + case <-s.sendNotifyCh: + goto START + case <-timeout: + return 0, ErrTimeout + } + return 0, nil +} + +// sendFlags determines any flags that are appropriate +// based on the current stream state +func (s *Stream) sendFlags() uint16 { + s.stateLock.Lock() + defer s.stateLock.Unlock() + var flags uint16 + switch s.state { + case streamInit: + flags |= flagSYN + s.state = streamSYNSent + case streamSYNReceived: + flags |= flagACK + s.state = streamEstablished + } + return flags +} + +// sendWindowUpdate potentially sends a window update enabling +// further writes to take place. Must be invoked with the lock. +func (s *Stream) sendWindowUpdate() error { + s.controlHdrLock.Lock() + defer s.controlHdrLock.Unlock() + + // Determine the delta update + max := s.session.config.MaxStreamWindowSize + var bufLen uint32 + s.recvLock.Lock() + if s.recvBuf != nil { + bufLen = uint32(s.recvBuf.Len()) + } + delta := (max - bufLen) - s.recvWindow + + // Determine the flags if any + flags := s.sendFlags() + + // Check if we can omit the update + if delta < (max/2) && flags == 0 { + s.recvLock.Unlock() + return nil + } + + // Update our window + s.recvWindow += delta + s.recvLock.Unlock() + + // Send the header + s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta) + if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { + return err + } + return nil +} + +// sendClose is used to send a FIN +func (s *Stream) sendClose() error { + s.controlHdrLock.Lock() + defer s.controlHdrLock.Unlock() + + flags := s.sendFlags() + flags |= flagFIN + s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0) + if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { + return err + } + return nil +} + +// Close is used to close the stream +func (s *Stream) Close() error { + closeStream := false + s.stateLock.Lock() + switch s.state { + // Opened means we need to signal a close + case streamSYNSent: + fallthrough + case streamSYNReceived: + fallthrough + case streamEstablished: + s.state = streamLocalClose + goto SEND_CLOSE + + case streamLocalClose: + case streamRemoteClose: + s.state = streamClosed + closeStream = true + goto SEND_CLOSE + + case streamClosed: + case streamReset: + default: + panic("unhandled state") + } + s.stateLock.Unlock() + return nil +SEND_CLOSE: + s.stateLock.Unlock() + s.sendClose() + s.notifyWaiting() + if closeStream { + s.session.closeStream(s.id) + } + return nil +} + +// forceClose is used for when the session is exiting +func (s *Stream) forceClose() { + s.stateLock.Lock() + s.state = streamClosed + s.stateLock.Unlock() + s.notifyWaiting() +} + +// processFlags is used to update the state of the stream +// based on set flags, if any. Lock must be held +func (s *Stream) processFlags(flags uint16) error { + // Close the stream without holding the state lock + closeStream := false + defer func() { + if closeStream { + s.session.closeStream(s.id) + } + }() + + s.stateLock.Lock() + defer s.stateLock.Unlock() + if flags&flagACK == flagACK { + if s.state == streamSYNSent { + s.state = streamEstablished + } + s.session.establishStream(s.id) + } + if flags&flagFIN == flagFIN { + switch s.state { + case streamSYNSent: + fallthrough + case streamSYNReceived: + fallthrough + case streamEstablished: + s.state = streamRemoteClose + s.notifyWaiting() + case streamLocalClose: + s.state = streamClosed + closeStream = true + s.notifyWaiting() + default: + s.session.logger.Printf("[ERR] yamux: unexpected FIN flag in state %d", s.state) + return ErrUnexpectedFlag + } + } + if flags&flagRST == flagRST { + s.state = streamReset + closeStream = true + s.notifyWaiting() + } + return nil +} + +// notifyWaiting notifies all the waiting channels +func (s *Stream) notifyWaiting() { + asyncNotify(s.recvNotifyCh) + asyncNotify(s.sendNotifyCh) +} + +// incrSendWindow updates the size of our send window +func (s *Stream) incrSendWindow(hdr header, flags uint16) error { + if err := s.processFlags(flags); err != nil { + return err + } + + // Increase window, unblock a sender + atomic.AddUint32(&s.sendWindow, hdr.Length()) + asyncNotify(s.sendNotifyCh) + return nil +} + +// readData is used to handle a data frame +func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error { + if err := s.processFlags(flags); err != nil { + return err + } + + // Check that our recv window is not exceeded + length := hdr.Length() + if length == 0 { + return nil + } + + // Wrap in a limited reader + conn = &io.LimitedReader{R: conn, N: int64(length)} + + // Copy into buffer + s.recvLock.Lock() + + if length > s.recvWindow { + s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, s.recvWindow, length) + return ErrRecvWindowExceeded + } + + if s.recvBuf == nil { + // Allocate the receive buffer just-in-time to fit the full data frame. + // This way we can read in the whole packet without further allocations. + s.recvBuf = bytes.NewBuffer(make([]byte, 0, length)) + } + if _, err := io.Copy(s.recvBuf, conn); err != nil { + s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err) + s.recvLock.Unlock() + return err + } + + // Decrement the receive window + s.recvWindow -= length + s.recvLock.Unlock() + + // Unblock any readers + asyncNotify(s.recvNotifyCh) + return nil +} + +// SetDeadline sets the read and write deadlines +func (s *Stream) SetDeadline(t time.Time) error { + if err := s.SetReadDeadline(t); err != nil { + return err + } + if err := s.SetWriteDeadline(t); err != nil { + return err + } + return nil +} + +// SetReadDeadline sets the deadline for future Read calls. +func (s *Stream) SetReadDeadline(t time.Time) error { + s.readDeadline.Store(t) + return nil +} + +// SetWriteDeadline sets the deadline for future Write calls +func (s *Stream) SetWriteDeadline(t time.Time) error { + s.writeDeadline.Store(t) + return nil +} + +// Shrink is used to compact the amount of buffers utilized +// This is useful when using Yamux in a connection pool to reduce +// the idle memory utilization. +func (s *Stream) Shrink() { + s.recvLock.Lock() + if s.recvBuf != nil && s.recvBuf.Len() == 0 { + s.recvBuf = nil + } + s.recvLock.Unlock() +} diff --git a/vendor/github.com/hashicorp/yamux/util.go b/vendor/github.com/hashicorp/yamux/util.go new file mode 100644 index 0000000..8a73e92 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/util.go @@ -0,0 +1,43 @@ +package yamux + +import ( + "sync" + "time" +) + +var ( + timerPool = &sync.Pool{ + New: func() interface{} { + timer := time.NewTimer(time.Hour * 1e6) + timer.Stop() + return timer + }, + } +) + +// asyncSendErr is used to try an async send of an error +func asyncSendErr(ch chan error, err error) { + if ch == nil { + return + } + select { + case ch <- err: + default: + } +} + +// asyncNotify is used to signal a waiting goroutine +func asyncNotify(ch chan struct{}) { + select { + case ch <- struct{}{}: + default: + } +} + +// min computes the minimum of two values +func min(a, b uint32) uint32 { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/howeyc/gopass/.travis.yml b/vendor/github.com/howeyc/gopass/.travis.yml new file mode 100644 index 0000000..cc5d509 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/.travis.yml @@ -0,0 +1,11 @@ +language: go + +os: + - linux + - osx + +go: + - 1.3 + - 1.4 + - 1.5 + - tip diff --git a/vendor/github.com/howeyc/gopass/LICENSE.txt b/vendor/github.com/howeyc/gopass/LICENSE.txt new file mode 100644 index 0000000..14f7470 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/LICENSE.txt @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012 Chris Howey + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE b/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE new file mode 100644 index 0000000..da23621 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE @@ -0,0 +1,384 @@ +Unless otherwise noted, all files in this distribution are released +under the Common Development and Distribution License (CDDL). +Exceptions are noted within the associated source files. + +-------------------------------------------------------------------- + + +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0 + +1. Definitions. + + 1.1. "Contributor" means each individual or entity that creates + or contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Software, prior Modifications used by a Contributor (if any), + and the Modifications made by that particular Contributor. + + 1.3. "Covered Software" means (a) the Original Software, or (b) + Modifications, or (c) the combination of files containing + Original Software with files containing Modifications, in + each case including portions thereof. + + 1.4. "Executable" means the Covered Software in any form other + than Source Code. + + 1.5. "Initial Developer" means the individual or entity that first + makes Original Software available under this License. + + 1.6. "Larger Work" means a work which combines Covered Software or + portions thereof with code not governed by the terms of this + License. + + 1.7. "License" means this document. + + 1.8. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed + herein. + + 1.9. "Modifications" means the Source Code and Executable form of + any of the following: + + A. Any file that results from an addition to, deletion from or + modification of the contents of a file containing Original + Software or previous Modifications; + + B. Any new file that contains any part of the Original + Software or previous Modifications; or + + C. Any new file that is contributed or otherwise made + available under the terms of this License. + + 1.10. "Original Software" means the Source Code and Executable + form of computer software code that is originally released + under this License. + + 1.11. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, + process, and apparatus claims, in any patent Licensable by + grantor. + + 1.12. "Source Code" means (a) the common form of computer software + code in which modifications are made and (b) associated + documentation included in or with such code. + + 1.13. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms + of, this License. For legal entities, "You" includes any + entity which controls, is controlled by, or is under common + control with You. For purposes of this definition, + "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty + percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, the Initial + Developer hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer, to use, + reproduce, modify, display, perform, sublicense and + distribute the Original Software (or portions thereof), + with or without Modifications, and/or as part of a Larger + Work; and + + (b) under Patent Claims infringed by the making, using or + selling of Original Software, to make, have made, use, + practice, sell, and offer for sale, and/or otherwise + dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are + effective on the date Initial Developer first distributes + or otherwise makes the Original Software available to a + third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: (1) for code that You delete from the Original + Software, or (2) for infringements caused by: (i) the + modification of the Original Software, or (ii) the + combination of the Original Software with other software + or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, each + Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor to use, reproduce, + modify, display, perform, sublicense and distribute the + Modifications created by such Contributor (or portions + thereof), either on an unmodified basis, with other + Modifications, as Covered Software and/or as part of a + Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either + alone and/or in combination with its Contributor Version + (or portions of such combination), to make, use, sell, + offer for sale, have made, and/or otherwise dispose of: + (1) Modifications made by that Contributor (or portions + thereof); and (2) the combination of Modifications made by + that Contributor with its Contributor Version (or portions + of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first distributes or + otherwise makes the Modifications available to a third + party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: (1) for any code that Contributor has deleted + from the Contributor Version; (2) for infringements caused + by: (i) third party modifications of Contributor Version, + or (ii) the combination of Modifications made by that + Contributor with other software (except as part of the + Contributor Version) or other devices; or (3) under Patent + Claims infringed by Covered Software in the absence of + Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make + available in Executable form must also be made available in Source + Code form and that Source Code form must be distributed only under + the terms of this License. You must include a copy of this + License with every copy of the Source Code form of the Covered + Software You distribute or otherwise make available. You must + inform recipients of any such Covered Software in Executable form + as to how they can obtain such Covered Software in Source Code + form in a reasonable manner on or through a medium customarily + used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are + governed by the terms of this License. You represent that You + believe Your Modifications are Your original creation(s) and/or + You have sufficient rights to grant the rights conveyed by this + License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that + identifies You as the Contributor of the Modification. You may + not remove or alter any copyright, patent or trademark notices + contained within the Covered Software, or any notices of licensing + or any descriptive text giving attribution to any Contributor or + the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in + Source Code form that alters or restricts the applicable version + of this License or the recipients' rights hereunder. You may + choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of + Covered Software. However, you may do so only on Your own behalf, + and not on behalf of the Initial Developer or any Contributor. + You must make it absolutely clear that any such warranty, support, + indemnity or liability obligation is offered by You alone, and You + hereby agree to indemnify the Initial Developer and every + Contributor for any liability incurred by the Initial Developer or + such Contributor as a result of warranty, support, indemnity or + liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software + under the terms of this License or under the terms of a license of + Your choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable form does not attempt to + limit or alter the recipient's rights in the Source Code form from + the rights set forth in this License. If You distribute the + Covered Software in Executable form under a different license, You + must make it absolutely clear that any terms which differ from + this License are offered by You alone, not by the Initial + Developer or Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred + by the Initial Developer or such Contributor as a result of any + such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with + other code not governed by the terms of this License and + distribute the Larger Work as a single product. In such a case, + You must make sure the requirements of this License are fulfilled + for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Sun Microsystems, Inc. is the initial license steward and may + publish revised and/or new versions of this License from time to + time. Each version will be given a distinguishing version number. + Except as provided in Section 4.3, no one other than the license + steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the + Covered Software available under the terms of the version of the + License under which You originally received the Covered Software. + If the Initial Developer includes a notice in the Original + Software prohibiting it from being distributed or otherwise made + available under any subsequent version of the License, You must + distribute and make the Covered Software available under the terms + of the version of the License under which You originally received + the Covered Software. Otherwise, You may also choose to use, + distribute or otherwise make the Covered Software available under + the terms of any subsequent version of the License published by + the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new + license for Your Original Software, You may create and use a + modified version of this License if You: (a) rename the license + and remove any references to the name of the license steward + (except to note that the license differs from this License); and + (b) otherwise make it clear that the license contains terms which + differ from this License. + +5. DISCLAIMER OF WARRANTY. + + COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" + BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED + SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR + PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND + PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY + COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE + INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY + NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF + WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS + DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to + cure such breach within 30 days of becoming aware of the breach. + Provisions which, by their nature, must remain in effect beyond + the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding + declaratory judgment actions) against Initial Developer or a + Contributor (the Initial Developer or Contributor against whom You + assert such claim is referred to as "Participant") alleging that + the Participant Software (meaning the Contributor Version where + the Participant is a Contributor or the Original Software where + the Participant is the Initial Developer) directly or indirectly + infringes any patent, then any and all rights granted directly or + indirectly to You by such Participant, the Initial Developer (if + the Initial Developer is not the Participant) and all Contributors + under Sections 2.1 and/or 2.2 of this License shall, upon 60 days + notice from Participant terminate prospectively and automatically + at the expiration of such 60 day notice period, unless if within + such 60 day period You withdraw Your claim with respect to the + Participant Software against such Participant either unilaterally + or pursuant to a written agreement with Participant. + + 6.3. In the event of termination under Sections 6.1 or 6.2 above, + all end user licenses that have been validly granted by You or any + distributor hereunder prior to termination (excluding licenses + granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE + INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF + COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE + LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK + STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL + INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT + APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO + NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR + CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT + APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + + The Covered Software is a "commercial item," as that term is + defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial + computer software" (as that term is defined at 48 + C.F.R. 252.227-7014(a)(1)) and "commercial computer software + documentation" as such terms are used in 48 C.F.R. 12.212 + (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 + C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all + U.S. Government End Users acquire Covered Software with only those + rights set forth herein. This U.S. Government Rights clause is in + lieu of, and supersedes, any other FAR, DFAR, or other clause or + provision that addresses Government rights in computer software + under this License. + +9. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed + by the law of the jurisdiction specified in a notice contained + within the Original Software (except to the extent applicable law, + if any, provides otherwise), excluding such jurisdiction's + conflict-of-law provisions. Any litigation relating to this + License shall be subject to the jurisdiction of the courts located + in the jurisdiction and venue specified in a notice contained + within the Original Software, with the losing party responsible + for costs, including, without limitation, court costs and + reasonable attorneys' fees and expenses. The application of the + United Nations Convention on Contracts for the International Sale + of Goods is expressly excluded. Any law or regulation which + provides that the language of a contract shall be construed + against the drafter shall not apply to this License. You agree + that You alone are responsible for compliance with the United + States export administration regulations (and the export control + laws and regulation of any other countries) when You use, + distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or + indirectly, out of its utilization of rights under this License + and You agree to work with Initial Developer and Contributors to + distribute such responsibility on an equitable basis. Nothing + herein is intended or shall be deemed to constitute any admission + of liability. + +-------------------------------------------------------------------- + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND +DISTRIBUTION LICENSE (CDDL) + +For Covered Software in this distribution, this License shall +be governed by the laws of the State of California (excluding +conflict-of-law provisions). + +Any litigation relating to this License shall be subject to the +jurisdiction of the Federal Courts of the Northern District of +California and the state courts of the State of California, with +venue lying in Santa Clara County, California. diff --git a/vendor/github.com/howeyc/gopass/README.md b/vendor/github.com/howeyc/gopass/README.md new file mode 100644 index 0000000..2d6a4e7 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/README.md @@ -0,0 +1,27 @@ +# getpasswd in Go [![GoDoc](https://godoc.org/github.com/howeyc/gopass?status.svg)](https://godoc.org/github.com/howeyc/gopass) [![Build Status](https://secure.travis-ci.org/howeyc/gopass.png?branch=master)](http://travis-ci.org/howeyc/gopass) + +Retrieve password from user terminal or piped input without echo. + +Verified on BSD, Linux, and Windows. + +Example: +```go +package main + +import "fmt" +import "github.com/howeyc/gopass" + +func main() { + fmt.Printf("Password: ") + + // Silent. For printing *'s use gopass.GetPasswdMasked() + pass, err := gopass.GetPasswd() + if err != nil { + // Handle gopass.ErrInterrupted or getch() read error + } + + // Do something with pass +} +``` + +Caution: Multi-byte characters not supported! diff --git a/vendor/github.com/howeyc/gopass/pass.go b/vendor/github.com/howeyc/gopass/pass.go new file mode 100644 index 0000000..f5bd5a5 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/pass.go @@ -0,0 +1,110 @@ +package gopass + +import ( + "errors" + "fmt" + "io" + "os" +) + +type FdReader interface { + io.Reader + Fd() uintptr +} + +var defaultGetCh = func(r io.Reader) (byte, error) { + buf := make([]byte, 1) + if n, err := r.Read(buf); n == 0 || err != nil { + if err != nil { + return 0, err + } + return 0, io.EOF + } + return buf[0], nil +} + +var ( + maxLength = 512 + ErrInterrupted = errors.New("interrupted") + ErrMaxLengthExceeded = fmt.Errorf("maximum byte limit (%v) exceeded", maxLength) + + // Provide variable so that tests can provide a mock implementation. + getch = defaultGetCh +) + +// getPasswd returns the input read from terminal. +// If prompt is not empty, it will be output as a prompt to the user +// If masked is true, typing will be matched by asterisks on the screen. +// Otherwise, typing will echo nothing. +func getPasswd(prompt string, masked bool, r FdReader, w io.Writer) ([]byte, error) { + var err error + var pass, bs, mask []byte + if masked { + bs = []byte("\b \b") + mask = []byte("*") + } + + if isTerminal(r.Fd()) { + if oldState, err := makeRaw(r.Fd()); err != nil { + return pass, err + } else { + defer func() { + restore(r.Fd(), oldState) + fmt.Fprintln(w) + }() + } + } + + if prompt != "" { + fmt.Fprint(w, prompt) + } + + // Track total bytes read, not just bytes in the password. This ensures any + // errors that might flood the console with nil or -1 bytes infinitely are + // capped. + var counter int + for counter = 0; counter <= maxLength; counter++ { + if v, e := getch(r); e != nil { + err = e + break + } else if v == 127 || v == 8 { + if l := len(pass); l > 0 { + pass = pass[:l-1] + fmt.Fprint(w, string(bs)) + } + } else if v == 13 || v == 10 { + break + } else if v == 3 { + err = ErrInterrupted + break + } else if v != 0 { + pass = append(pass, v) + fmt.Fprint(w, string(mask)) + } + } + + if counter > maxLength { + err = ErrMaxLengthExceeded + } + + return pass, err +} + +// GetPasswd returns the password read from the terminal without echoing input. +// The returned byte array does not include end-of-line characters. +func GetPasswd() ([]byte, error) { + return getPasswd("", false, os.Stdin, os.Stdout) +} + +// GetPasswdMasked returns the password read from the terminal, echoing asterisks. +// The returned byte array does not include end-of-line characters. +func GetPasswdMasked() ([]byte, error) { + return getPasswd("", true, os.Stdin, os.Stdout) +} + +// GetPasswdPrompt prompts the user and returns the password read from the terminal. +// If mask is true, then asterisks are echoed. +// The returned byte array does not include end-of-line characters. +func GetPasswdPrompt(prompt string, mask bool, r FdReader, w io.Writer) ([]byte, error) { + return getPasswd(prompt, mask, r, w) +} diff --git a/vendor/github.com/howeyc/gopass/terminal.go b/vendor/github.com/howeyc/gopass/terminal.go new file mode 100644 index 0000000..0835641 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/terminal.go @@ -0,0 +1,25 @@ +// +build !solaris + +package gopass + +import "golang.org/x/crypto/ssh/terminal" + +type terminalState struct { + state *terminal.State +} + +func isTerminal(fd uintptr) bool { + return terminal.IsTerminal(int(fd)) +} + +func makeRaw(fd uintptr) (*terminalState, error) { + state, err := terminal.MakeRaw(int(fd)) + + return &terminalState{ + state: state, + }, err +} + +func restore(fd uintptr, oldState *terminalState) error { + return terminal.Restore(int(fd), oldState.state) +} diff --git a/vendor/github.com/howeyc/gopass/terminal_solaris.go b/vendor/github.com/howeyc/gopass/terminal_solaris.go new file mode 100644 index 0000000..257e1b4 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/terminal_solaris.go @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +// Below is derived from Solaris source, so CDDL license is included. + +package gopass + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +type terminalState struct { + state *unix.Termios +} + +// isTerminal returns true if there is a terminal attached to the given +// file descriptor. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +func isTerminal(fd uintptr) bool { + var termio unix.Termio + err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) + return err == nil +} + +// makeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c +func makeRaw(fd uintptr) (*terminalState, error) { + oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + if err != nil { + return nil, err + } + oldTermios := *oldTermiosPtr + + newTermios := oldTermios + newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL + if err := unix.IoctlSetTermios(int(fd), unix.TCSETS, &newTermios); err != nil { + return nil, err + } + + return &terminalState{ + state: oldTermiosPtr, + }, nil +} + +func restore(fd uintptr, oldState *terminalState) error { + return unix.IoctlSetTermios(int(fd), unix.TCSETS, oldState.state) +} diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore new file mode 100644 index 0000000..529c341 --- /dev/null +++ b/vendor/github.com/imdario/mergo/.gitignore @@ -0,0 +1,33 @@ +#### joe made this: http://goel.io/joe + +#### go #### +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +#### vim #### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml new file mode 100644 index 0000000..b13a50e --- /dev/null +++ b/vendor/github.com/imdario/mergo/.travis.yml @@ -0,0 +1,7 @@ +language: go +install: + - go get -t + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls +script: + - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..469b449 --- /dev/null +++ b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/github.com/imdario/mergo/LICENSE new file mode 100644 index 0000000..6866802 --- /dev/null +++ b/vendor/github.com/imdario/mergo/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2013 Dario Castañé. All rights reserved. +Copyright (c) 2012 The Go Authors. 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/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md new file mode 100644 index 0000000..d1cefa8 --- /dev/null +++ b/vendor/github.com/imdario/mergo/README.md @@ -0,0 +1,222 @@ +# Mergo + +A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements. + +Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche. + +## Status + +It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild). + +[![GoDoc][3]][4] +[![GoCard][5]][6] +[![Build Status][1]][2] +[![Coverage Status][7]][8] +[![Sourcegraph][9]][10] + +[1]: https://travis-ci.org/imdario/mergo.png +[2]: https://travis-ci.org/imdario/mergo +[3]: https://godoc.org/github.com/imdario/mergo?status.svg +[4]: https://godoc.org/github.com/imdario/mergo +[5]: https://goreportcard.com/badge/imdario/mergo +[6]: https://goreportcard.com/report/github.com/imdario/mergo +[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master +[8]: https://coveralls.io/github/imdario/mergo?branch=master +[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg +[10]: https://sourcegraph.com/github.com/imdario/mergo?badge + +### Latest release + +[Release v0.3.4](https://github.com/imdario/mergo/releases/tag/v0.3.4). + +### Important note + +Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code. + +If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0). + +### Donations + +If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes: + +Buy Me a Coffee at ko-fi.com +[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo) +[![Beerpay](https://beerpay.io/imdario/mergo/make-wish.svg)](https://beerpay.io/imdario/mergo) +Donate using Liberapay + +### Mergo in the wild + +- [moby/moby](https://github.com/moby/moby) +- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) +- [vmware/dispatch](https://github.com/vmware/dispatch) +- [Shopify/themekit](https://github.com/Shopify/themekit) +- [imdario/zas](https://github.com/imdario/zas) +- [matcornic/hermes](https://github.com/matcornic/hermes) +- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go) +- [kataras/iris](https://github.com/kataras/iris) +- [michaelsauter/crane](https://github.com/michaelsauter/crane) +- [go-task/task](https://github.com/go-task/task) +- [sensu/uchiwa](https://github.com/sensu/uchiwa) +- [ory/hydra](https://github.com/ory/hydra) +- [sisatech/vcli](https://github.com/sisatech/vcli) +- [dairycart/dairycart](https://github.com/dairycart/dairycart) +- [projectcalico/felix](https://github.com/projectcalico/felix) +- [resin-os/balena](https://github.com/resin-os/balena) +- [go-kivik/kivik](https://github.com/go-kivik/kivik) +- [Telefonica/govice](https://github.com/Telefonica/govice) +- [supergiant/supergiant](supergiant/supergiant) +- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce) +- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy) +- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel) +- [EagerIO/Stout](https://github.com/EagerIO/Stout) +- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api) +- [russross/canvasassignments](https://github.com/russross/canvasassignments) +- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api) +- [casualjim/exeggutor](https://github.com/casualjim/exeggutor) +- [divshot/gitling](https://github.com/divshot/gitling) +- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl) +- [andrerocker/deploy42](https://github.com/andrerocker/deploy42) +- [elwinar/rambler](https://github.com/elwinar/rambler) +- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman) +- [jfbus/impressionist](https://github.com/jfbus/impressionist) +- [Jmeyering/zealot](https://github.com/Jmeyering/zealot) +- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host) +- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go) +- [thoas/picfit](https://github.com/thoas/picfit) +- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server) +- [jnuthong/item_search](https://github.com/jnuthong/item_search) +- [bukalapak/snowboard](https://github.com/bukalapak/snowboard) + +## Installation + + go get github.com/imdario/mergo + + // use in your .go code + import ( + "github.com/imdario/mergo" + ) + +## Usage + +You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). + +```go +if err := mergo.Merge(&dst, src); err != nil { + // ... +} +``` + +Also, you can merge overwriting values using the transformer `WithOverride`. + +```go +if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil { + // ... +} +``` + +Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field. + +```go +if err := mergo.Map(&dst, srcMap); err != nil { + // ... +} +``` + +Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values. + +More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo). + +### Nice example + +```go +package main + +import ( + "fmt" + "github.com/imdario/mergo" +) + +type Foo struct { + A string + B int64 +} + +func main() { + src := Foo{ + A: "one", + B: 2, + } + dest := Foo{ + A: "two", + } + mergo.Merge(&dest, src) + fmt.Println(dest) + // Will print + // {two 2} +} +``` + +Note: if test are failing due missing package, please execute: + + go get gopkg.in/yaml.v2 + +### Transformers + +Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? + +```go +package main + +import ( + "fmt" + "github.com/imdario/mergo" + "reflect" + "time" +) + +type timeTransfomer struct { +} + +func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ == reflect.TypeOf(time.Time{}) { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + isZero := dst.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if result[0].Bool() { + dst.Set(src) + } + } + return nil + } + } + return nil +} + +type Snapshot struct { + Time time.Time + // ... +} + +func main() { + src := Snapshot{time.Now()} + dest := Snapshot{} + mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{})) + fmt.Println(dest) + // Will print + // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } +} +``` + + +## Contact me + +If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario) + +## About + +Written by [Dario Castañé](http://dario.im). + +## License + +[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE). diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go new file mode 100644 index 0000000..6e9aa7b --- /dev/null +++ b/vendor/github.com/imdario/mergo/doc.go @@ -0,0 +1,44 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// 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. + +/* +Package mergo merges same-type structs and maps by setting default values in zero-value fields. + +Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). + +Usage + +From my own work-in-progress project: + + type networkConfig struct { + Protocol string + Address string + ServerType string `json: "server_type"` + Port uint16 + } + + type FssnConfig struct { + Network networkConfig + } + + var fssnDefault = FssnConfig { + networkConfig { + "tcp", + "127.0.0.1", + "http", + 31560, + }, + } + + // Inside a function [...] + + if err := mergo.Merge(&config, fssnDefault); err != nil { + log.Fatal(err) + } + + // More code [...] + +*/ +package mergo diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go new file mode 100644 index 0000000..6ea38e6 --- /dev/null +++ b/vendor/github.com/imdario/mergo/map.go @@ -0,0 +1,174 @@ +// Copyright 2014 Dario Castañé. All rights reserved. +// 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. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "fmt" + "reflect" + "unicode" + "unicode/utf8" +) + +func changeInitialCase(s string, mapper func(rune) rune) string { + if s == "" { + return s + } + r, n := utf8.DecodeRuneInString(s) + return string(mapper(r)) + s[n:] +} + +func isExported(field reflect.StructField) bool { + r, _ := utf8.DecodeRuneInString(field.Name) + return r >= 'A' && r <= 'Z' +} + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { + overwrite := config.Overwrite + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + zeroValue := reflect.Value{} + switch dst.Kind() { + case reflect.Map: + dstMap := dst.Interface().(map[string]interface{}) + for i, n := 0, src.NumField(); i < n; i++ { + srcType := src.Type() + field := srcType.Field(i) + if !isExported(field) { + continue + } + fieldName := field.Name + fieldName = changeInitialCase(fieldName, unicode.ToLower) + if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) { + dstMap[fieldName] = src.Field(i).Interface() + } + } + case reflect.Ptr: + if dst.IsNil() { + v := reflect.New(dst.Type().Elem()) + dst.Set(v) + } + dst = dst.Elem() + fallthrough + case reflect.Struct: + srcMap := src.Interface().(map[string]interface{}) + for key := range srcMap { + srcValue := srcMap[key] + fieldName := changeInitialCase(key, unicode.ToUpper) + dstElement := dst.FieldByName(fieldName) + if dstElement == zeroValue { + // We discard it because the field doesn't exist. + continue + } + srcElement := reflect.ValueOf(srcValue) + dstKind := dstElement.Kind() + srcKind := srcElement.Kind() + if srcKind == reflect.Ptr && dstKind != reflect.Ptr { + srcElement = srcElement.Elem() + srcKind = reflect.TypeOf(srcElement.Interface()).Kind() + } else if dstKind == reflect.Ptr { + // Can this work? I guess it can't. + if srcKind != reflect.Ptr && srcElement.CanAddr() { + srcPtr := srcElement.Addr() + srcElement = reflect.ValueOf(srcPtr) + srcKind = reflect.Ptr + } + } + + if !srcElement.IsValid() { + continue + } + if srcKind == dstKind { + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { + return + } + } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface { + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { + return + } + } else if srcKind == reflect.Map { + if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil { + return + } + } else { + return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind) + } + } + } + return +} + +// Map sets fields' values in dst from src. +// src can be a map with string keys or a struct. dst must be the opposite: +// if src is a map, dst must be a valid pointer to struct. If src is a struct, +// dst must be map[string]interface{}. +// It won't merge unexported (private) fields and will do recursively +// any exported field. +// If dst is a map, keys will be src fields' names in lower camel case. +// Missing key in src that doesn't match a field in dst will be skipped. This +// doesn't apply if dst is a map. +// This is separated method from Merge because it is cleaner and it keeps sane +// semantics: merging equal types, mapping different (restricted) types. +func Map(dst, src interface{}, opts ...func(*Config)) error { + return _map(dst, src, opts...) +} + +// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by +// non-empty src attribute values. +// Deprecated: Use Map(…) with WithOverride +func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { + return _map(dst, src, append(opts, WithOverride)...) +} + +func _map(dst, src interface{}, opts ...func(*Config)) error { + var ( + vDst, vSrc reflect.Value + err error + ) + config := &Config{} + + for _, opt := range opts { + opt(config) + } + + if vDst, vSrc, err = resolveValues(dst, src); err != nil { + return err + } + // To be friction-less, we redirect equal-type arguments + // to deepMerge. Only because arguments can be anything. + if vSrc.Kind() == vDst.Kind() { + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) + } + switch vSrc.Kind() { + case reflect.Struct: + if vDst.Kind() != reflect.Map { + return ErrExpectedMapAsDestination + } + case reflect.Map: + if vDst.Kind() != reflect.Struct { + return ErrExpectedStructAsDestination + } + default: + return ErrNotSupported + } + return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config) +} diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go new file mode 100644 index 0000000..f0e1792 --- /dev/null +++ b/vendor/github.com/imdario/mergo/merge.go @@ -0,0 +1,233 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// 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. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "reflect" +) + +func hasExportedField(dst reflect.Value) (exported bool) { + for i, n := 0, dst.NumField(); i < n; i++ { + field := dst.Type().Field(i) + if field.Anonymous && dst.Field(i).Kind() == reflect.Struct { + exported = exported || hasExportedField(dst.Field(i)) + } else { + exported = exported || len(field.PkgPath) == 0 + } + } + return +} + +type Config struct { + Overwrite bool + AppendSlice bool + Transformers Transformers +} + +type Transformers interface { + Transformer(reflect.Type) func(dst, src reflect.Value) error +} + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { + overwrite := config.Overwrite + + if !src.IsValid() { + return + } + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + + if config.Transformers != nil && !isEmptyValue(dst) { + if fn := config.Transformers.Transformer(dst.Type()); fn != nil { + err = fn(dst, src) + return + } + } + + switch dst.Kind() { + case reflect.Struct: + if hasExportedField(dst) { + for i, n := 0, dst.NumField(); i < n; i++ { + if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil { + return + } + } + } else { + if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) { + dst.Set(src) + } + } + case reflect.Map: + if dst.IsNil() && !src.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + for _, key := range src.MapKeys() { + srcElement := src.MapIndex(key) + if !srcElement.IsValid() { + continue + } + dstElement := dst.MapIndex(key) + switch srcElement.Kind() { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice: + if srcElement.IsNil() { + continue + } + fallthrough + default: + if !srcElement.CanInterface() { + continue + } + switch reflect.TypeOf(srcElement.Interface()).Kind() { + case reflect.Struct: + fallthrough + case reflect.Ptr: + fallthrough + case reflect.Map: + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { + return + } + case reflect.Slice: + srcSlice := reflect.ValueOf(srcElement.Interface()) + + var dstSlice reflect.Value + if !dstElement.IsValid() || dstElement.IsNil() { + dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len()) + } else { + dstSlice = reflect.ValueOf(dstElement.Interface()) + } + + dstSlice = reflect.AppendSlice(dstSlice, srcSlice) + dst.SetMapIndex(key, dstSlice) + } + } + if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map { + continue + } + + if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) { + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + dst.SetMapIndex(key, srcElement) + } + } + case reflect.Slice: + if !dst.CanSet() { + break + } + if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice { + dst.Set(src) + } else { + dst.Set(reflect.AppendSlice(dst, src)) + } + case reflect.Ptr: + fallthrough + case reflect.Interface: + if src.IsNil() { + break + } + if src.Kind() != reflect.Interface { + if dst.IsNil() || overwrite { + if dst.CanSet() && (overwrite || isEmptyValue(dst)) { + dst.Set(src) + } + } else if src.Kind() == reflect.Ptr { + if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { + return + } + } else if dst.Elem().Type() == src.Type() { + if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil { + return + } + } else { + return ErrDifferentArgumentsTypes + } + break + } + if dst.IsNil() || overwrite { + if dst.CanSet() && (overwrite || isEmptyValue(dst)) { + dst.Set(src) + } + } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { + return + } + default: + if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) { + dst.Set(src) + } + } + return +} + +// Merge will fill any empty for value type attributes on the dst struct using corresponding +// src attributes if they themselves are not empty. dst and src must be valid same-type structs +// and dst must be a pointer to struct. +// It won't merge unexported (private) fields and will do recursively any exported field. +func Merge(dst, src interface{}, opts ...func(*Config)) error { + return merge(dst, src, opts...) +} + +// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by +// non-empty src attribute values. +// Deprecated: use Merge(…) with WithOverride +func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { + return merge(dst, src, append(opts, WithOverride)...) +} + +// WithTransformers adds transformers to merge, allowing to customize the merging of some types. +func WithTransformers(transformers Transformers) func(*Config) { + return func(config *Config) { + config.Transformers = transformers + } +} + +// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values. +func WithOverride(config *Config) { + config.Overwrite = true +} + +// WithAppendSlice will make merge append slices instead of overwriting it +func WithAppendSlice(config *Config) { + config.AppendSlice = true +} + +func merge(dst, src interface{}, opts ...func(*Config)) error { + var ( + vDst, vSrc reflect.Value + err error + ) + + config := &Config{} + + for _, opt := range opts { + opt(config) + } + + if vDst, vSrc, err = resolveValues(dst, src); err != nil { + return err + } + if vDst.Type() != vSrc.Type() { + return ErrDifferentArgumentsTypes + } + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) +} diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go new file mode 100644 index 0000000..785618c --- /dev/null +++ b/vendor/github.com/imdario/mergo/mergo.go @@ -0,0 +1,92 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// 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. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "errors" + "reflect" +) + +// Errors reported by Mergo when it finds invalid arguments. +var ( + ErrNilArguments = errors.New("src and dst must not be nil") + ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type") + ErrNotSupported = errors.New("only structs and maps are supported") + ErrExpectedMapAsDestination = errors.New("dst was expected to be a map") + ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct") +) + +// During deepMerge, must keep track of checks that are +// in progress. The comparison algorithm assumes that all +// checks in progress are true when it reencounters them. +// Visited are stored in a map indexed by 17 * a1 + a2; +type visit struct { + ptr uintptr + typ reflect.Type + next *visit +} + +// From src/pkg/encoding/json/encode.go. +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr, reflect.Func: + return v.IsNil() + case reflect.Invalid: + return true + } + return false +} + +func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) { + if dst == nil || src == nil { + err = ErrNilArguments + return + } + vDst = reflect.ValueOf(dst).Elem() + if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map { + err = ErrNotSupported + return + } + vSrc = reflect.ValueOf(src) + // We check if vSrc is a pointer to dereference it. + if vSrc.Kind() == reflect.Ptr { + vSrc = vSrc.Elem() + } + return +} + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) { + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + return // TODO refactor +} diff --git a/vendor/github.com/imdario/mergo/testdata/license.yml b/vendor/github.com/imdario/mergo/testdata/license.yml new file mode 100644 index 0000000..2f1ad00 --- /dev/null +++ b/vendor/github.com/imdario/mergo/testdata/license.yml @@ -0,0 +1,4 @@ +import: ../../../../fossene/db/schema/thing.yml +fields: + site: string + author: root diff --git a/vendor/github.com/jefferai/jsonx/LICENSE b/vendor/github.com/jefferai/jsonx/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/vendor/github.com/jefferai/jsonx/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/jefferai/jsonx/README.md b/vendor/github.com/jefferai/jsonx/README.md new file mode 100644 index 0000000..a7bb5ba --- /dev/null +++ b/vendor/github.com/jefferai/jsonx/README.md @@ -0,0 +1,12 @@ +JSONx +======== + +[![GoDoc](https://godoc.org/github.com/jefferai/jsonx?status.svg)](https://godoc.org/github.com/jefferai/jsonx) + +A Go (Golang) library to transform an object or existing JSON bytes into +[JSONx](https://www.ibm.com/support/knowledgecenter/SS9H2Y_7.5.0/com.ibm.dp.doc/json_jsonxconversionrules.html). +Because sometimes your luck runs out. + +This follows the "standard" except for the handling of special and escaped +characters. Names and values are properly XML-escaped but there is no special +handling of values already escaped in JSON if they are valid in XML. diff --git a/vendor/github.com/jefferai/jsonx/jsonx.go b/vendor/github.com/jefferai/jsonx/jsonx.go new file mode 100644 index 0000000..93d24a9 --- /dev/null +++ b/vendor/github.com/jefferai/jsonx/jsonx.go @@ -0,0 +1,132 @@ +package jsonx + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "sort" + + "github.com/Jeffail/gabs" +) + +const ( + XMLHeader = `` + Header = `` + Footer = `` +) + +// namedContainer wraps a gabs.Container to carry name information with it +type namedContainer struct { + name string + *gabs.Container +} + +// Marshal marshals the input data into JSONx. +func Marshal(input interface{}) (string, error) { + jsonBytes, err := json.Marshal(input) + if err != nil { + return "", err + } + xmlBytes, err := EncodeJSONBytes(jsonBytes) + if err != nil { + return "", err + } + return fmt.Sprintf("%s%s%s%s", XMLHeader, Header, string(xmlBytes), Footer), nil +} + +// EncodeJSONBytes encodes JSON-formatted bytes into JSONx. It is designed to +// be used for multiple entries so does not prepend the JSONx header tag or +// append the JSONx footer tag. You can use jsonx.Header and jsonx.Footer to +// easily add these when necessary. +func EncodeJSONBytes(input []byte) ([]byte, error) { + o := bytes.NewBuffer(nil) + reader := bytes.NewReader(input) + dec := json.NewDecoder(reader) + dec.UseNumber() + + cont, err := gabs.ParseJSONDecoder(dec) + if err != nil { + return nil, err + } + + if err := sortAndTransformObject(o, &namedContainer{Container: cont}); err != nil { + return nil, err + } + + return o.Bytes(), nil +} + +func transformContainer(o *bytes.Buffer, cont *namedContainer) error { + var printName string + + if cont.name != "" { + escapedNameBuf := bytes.NewBuffer(nil) + err := xml.EscapeText(escapedNameBuf, []byte(cont.name)) + if err != nil { + return err + } + printName = fmt.Sprintf(" name=\"%s\"", escapedNameBuf.String()) + } + + data := cont.Data() + switch data.(type) { + case nil: + o.WriteString(fmt.Sprintf("", printName)) + + case bool: + o.WriteString(fmt.Sprintf("%t", printName, data)) + + case json.Number: + o.WriteString(fmt.Sprintf("%v", printName, data)) + + case string: + o.WriteString(fmt.Sprintf("%v", printName, data)) + + case []interface{}: + o.WriteString(fmt.Sprintf("", printName)) + arrayChildren, err := cont.Children() + if err != nil { + return err + } + for _, child := range arrayChildren { + if err := transformContainer(o, &namedContainer{Container: child}); err != nil { + return err + } + } + o.WriteString("") + + case map[string]interface{}: + o.WriteString(fmt.Sprintf("", printName)) + + if err := sortAndTransformObject(o, cont); err != nil { + return err + } + + o.WriteString("") + } + + return nil +} + +// sortAndTransformObject sorts object keys to make the output predictable so +// the package can be tested; logic is here to prevent code duplication +func sortAndTransformObject(o *bytes.Buffer, cont *namedContainer) error { + objectChildren, err := cont.ChildrenMap() + if err != nil { + return err + } + + sortedNames := make([]string, 0, len(objectChildren)) + for name, _ := range objectChildren { + sortedNames = append(sortedNames, name) + } + sort.Strings(sortedNames) + for _, name := range sortedNames { + if err := transformContainer(o, &namedContainer{name: name, Container: objectChildren[name]}); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/json-iterator/go/.codecov.yml b/vendor/github.com/json-iterator/go/.codecov.yml new file mode 100644 index 0000000..955dc0b --- /dev/null +++ b/vendor/github.com/json-iterator/go/.codecov.yml @@ -0,0 +1,3 @@ +ignore: + - "output_tests/.*" + diff --git a/vendor/github.com/json-iterator/go/.gitignore b/vendor/github.com/json-iterator/go/.gitignore new file mode 100644 index 0000000..1555653 --- /dev/null +++ b/vendor/github.com/json-iterator/go/.gitignore @@ -0,0 +1,4 @@ +/vendor +/bug_test.go +/coverage.txt +/.idea diff --git a/vendor/github.com/json-iterator/go/.travis.yml b/vendor/github.com/json-iterator/go/.travis.yml new file mode 100644 index 0000000..449e67c --- /dev/null +++ b/vendor/github.com/json-iterator/go/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.8.x + - 1.x + +before_install: + - go get -t -v ./... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/json-iterator/go/Gopkg.lock b/vendor/github.com/json-iterator/go/Gopkg.lock new file mode 100644 index 0000000..338f1c6 --- /dev/null +++ b/vendor/github.com/json-iterator/go/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" + version = "1.0.0" + +[[projects]] + name = "github.com/modern-go/reflect2" + packages = ["."] + revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f" + version = "1.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "ac7003b5a981716353a43055ab7d4c5357403cb30a60de2dbdeb446c1544beaa" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/json-iterator/go/Gopkg.toml b/vendor/github.com/json-iterator/go/Gopkg.toml new file mode 100644 index 0000000..5801ffa --- /dev/null +++ b/vendor/github.com/json-iterator/go/Gopkg.toml @@ -0,0 +1,26 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + +ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"] + +[[constraint]] + name = "github.com/modern-go/reflect2" + version = "1.0.0" diff --git a/vendor/github.com/json-iterator/go/LICENSE b/vendor/github.com/json-iterator/go/LICENSE new file mode 100644 index 0000000..2cf4f5a --- /dev/null +++ b/vendor/github.com/json-iterator/go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 json-iterator + +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/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md new file mode 100644 index 0000000..9f404aa --- /dev/null +++ b/vendor/github.com/json-iterator/go/README.md @@ -0,0 +1,88 @@ +[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go) +[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) +[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) +[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) +[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) + +A high-performance 100% compatible drop-in replacement of "encoding/json" + +You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go) + +``` +Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com +``` + +# Benchmark + +![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) + +Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go + +Raw Result (easyjson requires static code generation) + +| | ns/op | allocation bytes | allocation times | +| --- | --- | --- | --- | +| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | +| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | +| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | +| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | +| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | +| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | + +# Usage + +100% compatibility with standard lib + +Replace + +```go +import "encoding/json" +json.Marshal(&data) +``` + +with + +```go +import "github.com/json-iterator/go" + +var json = jsoniter.ConfigCompatibleWithStandardLibrary +json.Marshal(&data) +``` + +Replace + +```go +import "encoding/json" +json.Unmarshal(input, &data) +``` + +with + +```go +import "github.com/json-iterator/go" + +var json = jsoniter.ConfigCompatibleWithStandardLibrary +json.Unmarshal(input, &data) +``` + +[More documentation](http://jsoniter.com/migrate-from-go-std.html) + +# How to get + +``` +go get github.com/json-iterator/go +``` + +# Contribution Welcomed ! + +Contributors + +* [thockin](https://github.com/thockin) +* [mattn](https://github.com/mattn) +* [cch123](https://github.com/cch123) +* [Oleg Shaldybin](https://github.com/olegshaldybin) +* [Jason Toffaletti](https://github.com/toffaletti) + +Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/adapter.go b/vendor/github.com/json-iterator/go/adapter.go new file mode 100644 index 0000000..3a494ee --- /dev/null +++ b/vendor/github.com/json-iterator/go/adapter.go @@ -0,0 +1,141 @@ +package jsoniter + +import ( + "bytes" + "io" +) + +// RawMessage to make replace json with jsoniter +type RawMessage []byte + +// Unmarshal adapts to json/encoding Unmarshal API +// +// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. +// Refer to https://godoc.org/encoding/json#Unmarshal for more information +func Unmarshal(data []byte, v interface{}) error { + return ConfigDefault.Unmarshal(data, v) +} + +// UnmarshalFromString convenient method to read from string instead of []byte +func UnmarshalFromString(str string, v interface{}) error { + return ConfigDefault.UnmarshalFromString(str, v) +} + +// Get quick method to get value from deeply nested JSON structure +func Get(data []byte, path ...interface{}) Any { + return ConfigDefault.Get(data, path...) +} + +// Marshal adapts to json/encoding Marshal API +// +// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API +// Refer to https://godoc.org/encoding/json#Marshal for more information +func Marshal(v interface{}) ([]byte, error) { + return ConfigDefault.Marshal(v) +} + +// MarshalIndent same as json.MarshalIndent. Prefix is not supported. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + return ConfigDefault.MarshalIndent(v, prefix, indent) +} + +// MarshalToString convenient method to write as string instead of []byte +func MarshalToString(v interface{}) (string, error) { + return ConfigDefault.MarshalToString(v) +} + +// NewDecoder adapts to json/stream NewDecoder API. +// +// NewDecoder returns a new decoder that reads from r. +// +// Instead of a json/encoding Decoder, an Decoder is returned +// Refer to https://godoc.org/encoding/json#NewDecoder for more information +func NewDecoder(reader io.Reader) *Decoder { + return ConfigDefault.NewDecoder(reader) +} + +// Decoder reads and decodes JSON values from an input stream. +// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) +type Decoder struct { + iter *Iterator +} + +// Decode decode JSON into interface{} +func (adapter *Decoder) Decode(obj interface{}) error { + if adapter.iter.head == adapter.iter.tail && adapter.iter.reader != nil { + if !adapter.iter.loadMore() { + return io.EOF + } + } + adapter.iter.ReadVal(obj) + err := adapter.iter.Error + if err == io.EOF { + return nil + } + return adapter.iter.Error +} + +// More is there more? +func (adapter *Decoder) More() bool { + return adapter.iter.head != adapter.iter.tail +} + +// Buffered remaining buffer +func (adapter *Decoder) Buffered() io.Reader { + remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] + return bytes.NewReader(remaining) +} + +// UseNumber causes the Decoder to unmarshal a number into an interface{} as a +// Number instead of as a float64. +func (adapter *Decoder) UseNumber() { + cfg := adapter.iter.cfg.configBeforeFrozen + cfg.UseNumber = true + adapter.iter.cfg = cfg.frozeWithCacheReuse() +} + +// DisallowUnknownFields causes the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (adapter *Decoder) DisallowUnknownFields() { + cfg := adapter.iter.cfg.configBeforeFrozen + cfg.DisallowUnknownFields = true + adapter.iter.cfg = cfg.frozeWithCacheReuse() +} + +// NewEncoder same as json.NewEncoder +func NewEncoder(writer io.Writer) *Encoder { + return ConfigDefault.NewEncoder(writer) +} + +// Encoder same as json.Encoder +type Encoder struct { + stream *Stream +} + +// Encode encode interface{} as JSON to io.Writer +func (adapter *Encoder) Encode(val interface{}) error { + adapter.stream.WriteVal(val) + adapter.stream.WriteRaw("\n") + adapter.stream.Flush() + return adapter.stream.Error +} + +// SetIndent set the indention. Prefix is not supported +func (adapter *Encoder) SetIndent(prefix, indent string) { + config := adapter.stream.cfg.configBeforeFrozen + config.IndentionStep = len(indent) + adapter.stream.cfg = config.frozeWithCacheReuse() +} + +// SetEscapeHTML escape html by default, set to false to disable +func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { + config := adapter.stream.cfg.configBeforeFrozen + config.EscapeHTML = escapeHTML + adapter.stream.cfg = config.frozeWithCacheReuse() +} + +// Valid reports whether data is a valid JSON encoding. +func Valid(data []byte) bool { + return ConfigDefault.Valid(data) +} diff --git a/vendor/github.com/json-iterator/go/any.go b/vendor/github.com/json-iterator/go/any.go new file mode 100644 index 0000000..daecfed --- /dev/null +++ b/vendor/github.com/json-iterator/go/any.go @@ -0,0 +1,321 @@ +package jsoniter + +import ( + "errors" + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "strconv" + "unsafe" +) + +// Any generic object representation. +// The lazy json implementation holds []byte and parse lazily. +type Any interface { + LastError() error + ValueType() ValueType + MustBeValid() Any + ToBool() bool + ToInt() int + ToInt32() int32 + ToInt64() int64 + ToUint() uint + ToUint32() uint32 + ToUint64() uint64 + ToFloat32() float32 + ToFloat64() float64 + ToString() string + ToVal(val interface{}) + Get(path ...interface{}) Any + Size() int + Keys() []string + GetInterface() interface{} + WriteTo(stream *Stream) +} + +type baseAny struct{} + +func (any *baseAny) Get(path ...interface{}) Any { + return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} +} + +func (any *baseAny) Size() int { + return 0 +} + +func (any *baseAny) Keys() []string { + return []string{} +} + +func (any *baseAny) ToVal(obj interface{}) { + panic("not implemented") +} + +// WrapInt32 turn int32 into Any interface +func WrapInt32(val int32) Any { + return &int32Any{baseAny{}, val} +} + +// WrapInt64 turn int64 into Any interface +func WrapInt64(val int64) Any { + return &int64Any{baseAny{}, val} +} + +// WrapUint32 turn uint32 into Any interface +func WrapUint32(val uint32) Any { + return &uint32Any{baseAny{}, val} +} + +// WrapUint64 turn uint64 into Any interface +func WrapUint64(val uint64) Any { + return &uint64Any{baseAny{}, val} +} + +// WrapFloat64 turn float64 into Any interface +func WrapFloat64(val float64) Any { + return &floatAny{baseAny{}, val} +} + +// WrapString turn string into Any interface +func WrapString(val string) Any { + return &stringAny{baseAny{}, val} +} + +// Wrap turn a go object into Any interface +func Wrap(val interface{}) Any { + if val == nil { + return &nilAny{} + } + asAny, isAny := val.(Any) + if isAny { + return asAny + } + typ := reflect2.TypeOf(val) + switch typ.Kind() { + case reflect.Slice: + return wrapArray(val) + case reflect.Struct: + return wrapStruct(val) + case reflect.Map: + return wrapMap(val) + case reflect.String: + return WrapString(val.(string)) + case reflect.Int: + if strconv.IntSize == 32 { + return WrapInt32(int32(val.(int))) + } + return WrapInt64(int64(val.(int))) + case reflect.Int8: + return WrapInt32(int32(val.(int8))) + case reflect.Int16: + return WrapInt32(int32(val.(int16))) + case reflect.Int32: + return WrapInt32(val.(int32)) + case reflect.Int64: + return WrapInt64(val.(int64)) + case reflect.Uint: + if strconv.IntSize == 32 { + return WrapUint32(uint32(val.(uint))) + } + return WrapUint64(uint64(val.(uint))) + case reflect.Uintptr: + if ptrSize == 32 { + return WrapUint32(uint32(val.(uintptr))) + } + return WrapUint64(uint64(val.(uintptr))) + case reflect.Uint8: + return WrapUint32(uint32(val.(uint8))) + case reflect.Uint16: + return WrapUint32(uint32(val.(uint16))) + case reflect.Uint32: + return WrapUint32(uint32(val.(uint32))) + case reflect.Uint64: + return WrapUint64(val.(uint64)) + case reflect.Float32: + return WrapFloat64(float64(val.(float32))) + case reflect.Float64: + return WrapFloat64(val.(float64)) + case reflect.Bool: + if val.(bool) == true { + return &trueAny{} + } + return &falseAny{} + } + return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} +} + +// ReadAny read next JSON element as an Any object. It is a better json.RawMessage. +func (iter *Iterator) ReadAny() Any { + return iter.readAny() +} + +func (iter *Iterator) readAny() Any { + c := iter.nextToken() + switch c { + case '"': + iter.unreadByte() + return &stringAny{baseAny{}, iter.ReadString()} + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + return &nilAny{} + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + return &trueAny{} + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + return &falseAny{} + case '{': + return iter.readObjectAny() + case '[': + return iter.readArrayAny() + case '-': + return iter.readNumberAny(false) + case 0: + return &invalidAny{baseAny{}, errors.New("input is empty")} + default: + return iter.readNumberAny(true) + } +} + +func (iter *Iterator) readNumberAny(positive bool) Any { + iter.startCapture(iter.head - 1) + iter.skipNumber() + lazyBuf := iter.stopCapture() + return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readObjectAny() Any { + iter.startCapture(iter.head - 1) + iter.skipObject() + lazyBuf := iter.stopCapture() + return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readArrayAny() Any { + iter.startCapture(iter.head - 1) + iter.skipArray() + lazyBuf := iter.stopCapture() + return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func locateObjectField(iter *Iterator, target string) []byte { + var found []byte + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + if field == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + return true + }) + return found +} + +func locateArrayElement(iter *Iterator, target int) []byte { + var found []byte + n := 0 + iter.ReadArrayCB(func(iter *Iterator) bool { + if n == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + n++ + return true + }) + return found +} + +func locatePath(iter *Iterator, path []interface{}) Any { + for i, pathKeyObj := range path { + switch pathKey := pathKeyObj.(type) { + case string: + valueBytes := locateObjectField(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int: + valueBytes := locateArrayElement(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int32: + if '*' == pathKey { + return iter.readAny().Get(path[i:]...) + } + return newInvalidAny(path[i:]) + default: + return newInvalidAny(path[i:]) + } + } + if iter.Error != nil && iter.Error != io.EOF { + return &invalidAny{baseAny{}, iter.Error} + } + return iter.readAny() +} + +var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem() + +func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ == anyType { + return &directAnyCodec{} + } + if typ.Implements(anyType) { + return &anyCodec{ + valType: typ, + } + } + return nil +} + +func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == anyType { + return &directAnyCodec{} + } + if typ.Implements(anyType) { + return &anyCodec{ + valType: typ, + } + } + return nil +} + +type anyCodec struct { + valType reflect2.Type +} + +func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + panic("not implemented") +} + +func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := codec.valType.UnsafeIndirect(ptr) + any := obj.(Any) + any.WriteTo(stream) +} + +func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { + obj := codec.valType.UnsafeIndirect(ptr) + any := obj.(Any) + return any.Size() == 0 +} + +type directAnyCodec struct { +} + +func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *(*Any)(ptr) = iter.readAny() +} + +func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + any := *(*Any)(ptr) + any.WriteTo(stream) +} + +func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool { + any := *(*Any)(ptr) + return any.Size() == 0 +} diff --git a/vendor/github.com/json-iterator/go/any_array.go b/vendor/github.com/json-iterator/go/any_array.go new file mode 100644 index 0000000..0449e9a --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_array.go @@ -0,0 +1,278 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type arrayLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *arrayLazyAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayLazyAny) MustBeValid() Any { + return any +} + +func (any *arrayLazyAny) LastError() error { + return any.err +} + +func (any *arrayLazyAny) ToBool() bool { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.ReadArray() +} + +func (any *arrayLazyAny) ToInt() int { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt32() int32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt64() int64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint() uint { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint32() uint32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint64() uint64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat32() float32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat64() float64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *arrayLazyAny) ToVal(val interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(val) +} + +func (any *arrayLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateArrayElement(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + arr := make([]Any, 0) + iter.ReadArrayCB(func(iter *Iterator) bool { + found := iter.readAny().Get(path[1:]...) + if found.ValueType() != InvalidValue { + arr = append(arr, found) + } + return true + }) + return wrapArray(arr) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadArrayCB(func(iter *Iterator) bool { + size++ + iter.Skip() + return true + }) + return size +} + +func (any *arrayLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *arrayLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type arrayAny struct { + baseAny + val reflect.Value +} + +func wrapArray(val interface{}) *arrayAny { + return &arrayAny{baseAny{}, reflect.ValueOf(val)} +} + +func (any *arrayAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayAny) MustBeValid() Any { + return any +} + +func (any *arrayAny) LastError() error { + return nil +} + +func (any *arrayAny) ToBool() bool { + return any.val.Len() != 0 +} + +func (any *arrayAny) ToInt() int { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt32() int32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt64() int64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint() uint { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint32() uint32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint64() uint64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat32() float32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat64() float64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToString() string { + str, _ := MarshalToString(any.val.Interface()) + return str +} + +func (any *arrayAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + if firstPath < 0 || firstPath >= any.val.Len() { + return newInvalidAny(path) + } + return Wrap(any.val.Index(firstPath).Interface()) + case int32: + if '*' == firstPath { + mappedAll := make([]Any, 0) + for i := 0; i < any.val.Len(); i++ { + mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll = append(mappedAll, mapped) + } + } + return wrapArray(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayAny) Size() int { + return any.val.Len() +} + +func (any *arrayAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *arrayAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/any_bool.go b/vendor/github.com/json-iterator/go/any_bool.go new file mode 100644 index 0000000..9452324 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_bool.go @@ -0,0 +1,137 @@ +package jsoniter + +type trueAny struct { + baseAny +} + +func (any *trueAny) LastError() error { + return nil +} + +func (any *trueAny) ToBool() bool { + return true +} + +func (any *trueAny) ToInt() int { + return 1 +} + +func (any *trueAny) ToInt32() int32 { + return 1 +} + +func (any *trueAny) ToInt64() int64 { + return 1 +} + +func (any *trueAny) ToUint() uint { + return 1 +} + +func (any *trueAny) ToUint32() uint32 { + return 1 +} + +func (any *trueAny) ToUint64() uint64 { + return 1 +} + +func (any *trueAny) ToFloat32() float32 { + return 1 +} + +func (any *trueAny) ToFloat64() float64 { + return 1 +} + +func (any *trueAny) ToString() string { + return "true" +} + +func (any *trueAny) WriteTo(stream *Stream) { + stream.WriteTrue() +} + +func (any *trueAny) Parse() *Iterator { + return nil +} + +func (any *trueAny) GetInterface() interface{} { + return true +} + +func (any *trueAny) ValueType() ValueType { + return BoolValue +} + +func (any *trueAny) MustBeValid() Any { + return any +} + +type falseAny struct { + baseAny +} + +func (any *falseAny) LastError() error { + return nil +} + +func (any *falseAny) ToBool() bool { + return false +} + +func (any *falseAny) ToInt() int { + return 0 +} + +func (any *falseAny) ToInt32() int32 { + return 0 +} + +func (any *falseAny) ToInt64() int64 { + return 0 +} + +func (any *falseAny) ToUint() uint { + return 0 +} + +func (any *falseAny) ToUint32() uint32 { + return 0 +} + +func (any *falseAny) ToUint64() uint64 { + return 0 +} + +func (any *falseAny) ToFloat32() float32 { + return 0 +} + +func (any *falseAny) ToFloat64() float64 { + return 0 +} + +func (any *falseAny) ToString() string { + return "false" +} + +func (any *falseAny) WriteTo(stream *Stream) { + stream.WriteFalse() +} + +func (any *falseAny) Parse() *Iterator { + return nil +} + +func (any *falseAny) GetInterface() interface{} { + return false +} + +func (any *falseAny) ValueType() ValueType { + return BoolValue +} + +func (any *falseAny) MustBeValid() Any { + return any +} diff --git a/vendor/github.com/json-iterator/go/any_float.go b/vendor/github.com/json-iterator/go/any_float.go new file mode 100644 index 0000000..35fdb09 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_float.go @@ -0,0 +1,83 @@ +package jsoniter + +import ( + "strconv" +) + +type floatAny struct { + baseAny + val float64 +} + +func (any *floatAny) Parse() *Iterator { + return nil +} + +func (any *floatAny) ValueType() ValueType { + return NumberValue +} + +func (any *floatAny) MustBeValid() Any { + return any +} + +func (any *floatAny) LastError() error { + return nil +} + +func (any *floatAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *floatAny) ToInt() int { + return int(any.val) +} + +func (any *floatAny) ToInt32() int32 { + return int32(any.val) +} + +func (any *floatAny) ToInt64() int64 { + return int64(any.val) +} + +func (any *floatAny) ToUint() uint { + if any.val > 0 { + return uint(any.val) + } + return 0 +} + +func (any *floatAny) ToUint32() uint32 { + if any.val > 0 { + return uint32(any.val) + } + return 0 +} + +func (any *floatAny) ToUint64() uint64 { + if any.val > 0 { + return uint64(any.val) + } + return 0 +} + +func (any *floatAny) ToFloat32() float32 { + return float32(any.val) +} + +func (any *floatAny) ToFloat64() float64 { + return any.val +} + +func (any *floatAny) ToString() string { + return strconv.FormatFloat(any.val, 'E', -1, 64) +} + +func (any *floatAny) WriteTo(stream *Stream) { + stream.WriteFloat64(any.val) +} + +func (any *floatAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_int32.go b/vendor/github.com/json-iterator/go/any_int32.go new file mode 100644 index 0000000..1b56f39 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_int32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int32Any struct { + baseAny + val int32 +} + +func (any *int32Any) LastError() error { + return nil +} + +func (any *int32Any) ValueType() ValueType { + return NumberValue +} + +func (any *int32Any) MustBeValid() Any { + return any +} + +func (any *int32Any) ToBool() bool { + return any.val != 0 +} + +func (any *int32Any) ToInt() int { + return int(any.val) +} + +func (any *int32Any) ToInt32() int32 { + return any.val +} + +func (any *int32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *int32Any) ToUint() uint { + return uint(any.val) +} + +func (any *int32Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *int32Any) WriteTo(stream *Stream) { + stream.WriteInt32(any.val) +} + +func (any *int32Any) Parse() *Iterator { + return nil +} + +func (any *int32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_int64.go b/vendor/github.com/json-iterator/go/any_int64.go new file mode 100644 index 0000000..c440d72 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_int64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int64Any struct { + baseAny + val int64 +} + +func (any *int64Any) LastError() error { + return nil +} + +func (any *int64Any) ValueType() ValueType { + return NumberValue +} + +func (any *int64Any) MustBeValid() Any { + return any +} + +func (any *int64Any) ToBool() bool { + return any.val != 0 +} + +func (any *int64Any) ToInt() int { + return int(any.val) +} + +func (any *int64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *int64Any) ToInt64() int64 { + return any.val +} + +func (any *int64Any) ToUint() uint { + return uint(any.val) +} + +func (any *int64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int64Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int64Any) ToString() string { + return strconv.FormatInt(any.val, 10) +} + +func (any *int64Any) WriteTo(stream *Stream) { + stream.WriteInt64(any.val) +} + +func (any *int64Any) Parse() *Iterator { + return nil +} + +func (any *int64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_invalid.go b/vendor/github.com/json-iterator/go/any_invalid.go new file mode 100644 index 0000000..1d859ea --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_invalid.go @@ -0,0 +1,82 @@ +package jsoniter + +import "fmt" + +type invalidAny struct { + baseAny + err error +} + +func newInvalidAny(path []interface{}) *invalidAny { + return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)} +} + +func (any *invalidAny) LastError() error { + return any.err +} + +func (any *invalidAny) ValueType() ValueType { + return InvalidValue +} + +func (any *invalidAny) MustBeValid() Any { + panic(any.err) +} + +func (any *invalidAny) ToBool() bool { + return false +} + +func (any *invalidAny) ToInt() int { + return 0 +} + +func (any *invalidAny) ToInt32() int32 { + return 0 +} + +func (any *invalidAny) ToInt64() int64 { + return 0 +} + +func (any *invalidAny) ToUint() uint { + return 0 +} + +func (any *invalidAny) ToUint32() uint32 { + return 0 +} + +func (any *invalidAny) ToUint64() uint64 { + return 0 +} + +func (any *invalidAny) ToFloat32() float32 { + return 0 +} + +func (any *invalidAny) ToFloat64() float64 { + return 0 +} + +func (any *invalidAny) ToString() string { + return "" +} + +func (any *invalidAny) WriteTo(stream *Stream) { +} + +func (any *invalidAny) Get(path ...interface{}) Any { + if any.err == nil { + return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} + } + return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)} +} + +func (any *invalidAny) Parse() *Iterator { + return nil +} + +func (any *invalidAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/any_nil.go b/vendor/github.com/json-iterator/go/any_nil.go new file mode 100644 index 0000000..d04cb54 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_nil.go @@ -0,0 +1,69 @@ +package jsoniter + +type nilAny struct { + baseAny +} + +func (any *nilAny) LastError() error { + return nil +} + +func (any *nilAny) ValueType() ValueType { + return NilValue +} + +func (any *nilAny) MustBeValid() Any { + return any +} + +func (any *nilAny) ToBool() bool { + return false +} + +func (any *nilAny) ToInt() int { + return 0 +} + +func (any *nilAny) ToInt32() int32 { + return 0 +} + +func (any *nilAny) ToInt64() int64 { + return 0 +} + +func (any *nilAny) ToUint() uint { + return 0 +} + +func (any *nilAny) ToUint32() uint32 { + return 0 +} + +func (any *nilAny) ToUint64() uint64 { + return 0 +} + +func (any *nilAny) ToFloat32() float32 { + return 0 +} + +func (any *nilAny) ToFloat64() float64 { + return 0 +} + +func (any *nilAny) ToString() string { + return "" +} + +func (any *nilAny) WriteTo(stream *Stream) { + stream.WriteNil() +} + +func (any *nilAny) Parse() *Iterator { + return nil +} + +func (any *nilAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/any_number.go b/vendor/github.com/json-iterator/go/any_number.go new file mode 100644 index 0000000..9d1e901 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_number.go @@ -0,0 +1,123 @@ +package jsoniter + +import ( + "io" + "unsafe" +) + +type numberLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *numberLazyAny) ValueType() ValueType { + return NumberValue +} + +func (any *numberLazyAny) MustBeValid() Any { + return any +} + +func (any *numberLazyAny) LastError() error { + return any.err +} + +func (any *numberLazyAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *numberLazyAny) ToInt() int { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToInt32() int32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToInt64() int64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint() uint { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint32() uint32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint64() uint64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToFloat32() float32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToFloat64() float64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *numberLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *numberLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} diff --git a/vendor/github.com/json-iterator/go/any_object.go b/vendor/github.com/json-iterator/go/any_object.go new file mode 100644 index 0000000..c44ef5c --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_object.go @@ -0,0 +1,374 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type objectLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *objectLazyAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectLazyAny) MustBeValid() Any { + return any +} + +func (any *objectLazyAny) LastError() error { + return any.err +} + +func (any *objectLazyAny) ToBool() bool { + return true +} + +func (any *objectLazyAny) ToInt() int { + return 0 +} + +func (any *objectLazyAny) ToInt32() int32 { + return 0 +} + +func (any *objectLazyAny) ToInt64() int64 { + return 0 +} + +func (any *objectLazyAny) ToUint() uint { + return 0 +} + +func (any *objectLazyAny) ToUint32() uint32 { + return 0 +} + +func (any *objectLazyAny) ToUint64() uint64 { + return 0 +} + +func (any *objectLazyAny) ToFloat32() float32 { + return 0 +} + +func (any *objectLazyAny) ToFloat64() float64 { + return 0 +} + +func (any *objectLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *objectLazyAny) ToVal(obj interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(obj) +} + +func (any *objectLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateObjectField(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + mapped := locatePath(iter, path[1:]) + if mapped.ValueType() != InvalidValue { + mappedAll[field] = mapped + } + return true + }) + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectLazyAny) Keys() []string { + keys := []string{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + iter.Skip() + keys = append(keys, field) + return true + }) + return keys +} + +func (any *objectLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + size++ + return true + }) + return size +} + +func (any *objectLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *objectLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type objectAny struct { + baseAny + err error + val reflect.Value +} + +func wrapStruct(val interface{}) *objectAny { + return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *objectAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectAny) MustBeValid() Any { + return any +} + +func (any *objectAny) Parse() *Iterator { + return nil +} + +func (any *objectAny) LastError() error { + return any.err +} + +func (any *objectAny) ToBool() bool { + return any.val.NumField() != 0 +} + +func (any *objectAny) ToInt() int { + return 0 +} + +func (any *objectAny) ToInt32() int32 { + return 0 +} + +func (any *objectAny) ToInt64() int64 { + return 0 +} + +func (any *objectAny) ToUint() uint { + return 0 +} + +func (any *objectAny) ToUint32() uint32 { + return 0 +} + +func (any *objectAny) ToUint64() uint64 { + return 0 +} + +func (any *objectAny) ToFloat32() float32 { + return 0 +} + +func (any *objectAny) ToFloat64() float64 { + return 0 +} + +func (any *objectAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *objectAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + field := any.val.FieldByName(firstPath) + if !field.IsValid() { + return newInvalidAny(path) + } + return Wrap(field.Interface()) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for i := 0; i < any.val.NumField(); i++ { + field := any.val.Field(i) + if field.CanInterface() { + mapped := Wrap(field.Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[any.val.Type().Field(i).Name] = mapped + } + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectAny) Keys() []string { + keys := make([]string, 0, any.val.NumField()) + for i := 0; i < any.val.NumField(); i++ { + keys = append(keys, any.val.Type().Field(i).Name) + } + return keys +} + +func (any *objectAny) Size() int { + return any.val.NumField() +} + +func (any *objectAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *objectAny) GetInterface() interface{} { + return any.val.Interface() +} + +type mapAny struct { + baseAny + err error + val reflect.Value +} + +func wrapMap(val interface{}) *mapAny { + return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *mapAny) ValueType() ValueType { + return ObjectValue +} + +func (any *mapAny) MustBeValid() Any { + return any +} + +func (any *mapAny) Parse() *Iterator { + return nil +} + +func (any *mapAny) LastError() error { + return any.err +} + +func (any *mapAny) ToBool() bool { + return true +} + +func (any *mapAny) ToInt() int { + return 0 +} + +func (any *mapAny) ToInt32() int32 { + return 0 +} + +func (any *mapAny) ToInt64() int64 { + return 0 +} + +func (any *mapAny) ToUint() uint { + return 0 +} + +func (any *mapAny) ToUint32() uint32 { + return 0 +} + +func (any *mapAny) ToUint64() uint64 { + return 0 +} + +func (any *mapAny) ToFloat32() float32 { + return 0 +} + +func (any *mapAny) ToFloat64() float64 { + return 0 +} + +func (any *mapAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *mapAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for _, key := range any.val.MapKeys() { + keyAsStr := key.String() + element := Wrap(any.val.MapIndex(key).Interface()) + mapped := element.Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[keyAsStr] = mapped + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + value := any.val.MapIndex(reflect.ValueOf(firstPath)) + if !value.IsValid() { + return newInvalidAny(path) + } + return Wrap(value.Interface()) + } +} + +func (any *mapAny) Keys() []string { + keys := make([]string, 0, any.val.Len()) + for _, key := range any.val.MapKeys() { + keys = append(keys, key.String()) + } + return keys +} + +func (any *mapAny) Size() int { + return any.val.Len() +} + +func (any *mapAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *mapAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go new file mode 100644 index 0000000..a4b93c7 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_str.go @@ -0,0 +1,166 @@ +package jsoniter + +import ( + "fmt" + "strconv" +) + +type stringAny struct { + baseAny + val string +} + +func (any *stringAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} +} + +func (any *stringAny) Parse() *Iterator { + return nil +} + +func (any *stringAny) ValueType() ValueType { + return StringValue +} + +func (any *stringAny) MustBeValid() Any { + return any +} + +func (any *stringAny) LastError() error { + return nil +} + +func (any *stringAny) ToBool() bool { + str := any.ToString() + if str == "0" { + return false + } + for _, c := range str { + switch c { + case ' ', '\n', '\r', '\t': + default: + return true + } + } + return false +} + +func (any *stringAny) ToInt() int { + return int(any.ToInt64()) + +} + +func (any *stringAny) ToInt32() int32 { + return int32(any.ToInt64()) +} + +func (any *stringAny) ToInt64() int64 { + if any.val == "" { + return 0 + } + + flag := 1 + startPos := 0 + endPos := 0 + if any.val[0] == '+' || any.val[0] == '-' { + startPos = 1 + } + + if any.val[0] == '-' { + flag = -1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64) + return int64(flag) * parsed +} + +func (any *stringAny) ToUint() uint { + return uint(any.ToUint64()) +} + +func (any *stringAny) ToUint32() uint32 { + return uint32(any.ToUint64()) +} + +func (any *stringAny) ToUint64() uint64 { + if any.val == "" { + return 0 + } + + startPos := 0 + endPos := 0 + + if any.val[0] == '-' { + return 0 + } + if any.val[0] == '+' { + startPos = 1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64) + return parsed +} + +func (any *stringAny) ToFloat32() float32 { + return float32(any.ToFloat64()) +} + +func (any *stringAny) ToFloat64() float64 { + if len(any.val) == 0 { + return 0 + } + + // first char invalid + if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') { + return 0 + } + + // extract valid num expression from string + // eg 123true => 123, -12.12xxa => -12.12 + endPos := 1 + for i := 1; i < len(any.val); i++ { + if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' { + endPos = i + 1 + continue + } + + // end position is the first char which is not digit + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + endPos = i + break + } + } + parsed, _ := strconv.ParseFloat(any.val[:endPos], 64) + return parsed +} + +func (any *stringAny) ToString() string { + return any.val +} + +func (any *stringAny) WriteTo(stream *Stream) { + stream.WriteString(any.val) +} + +func (any *stringAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_uint32.go b/vendor/github.com/json-iterator/go/any_uint32.go new file mode 100644 index 0000000..656bbd3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_uint32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint32Any struct { + baseAny + val uint32 +} + +func (any *uint32Any) LastError() error { + return nil +} + +func (any *uint32Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint32Any) MustBeValid() Any { + return any +} + +func (any *uint32Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint32Any) ToInt() int { + return int(any.val) +} + +func (any *uint32Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint32Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint32Any) ToUint32() uint32 { + return any.val +} + +func (any *uint32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *uint32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *uint32Any) WriteTo(stream *Stream) { + stream.WriteUint32(any.val) +} + +func (any *uint32Any) Parse() *Iterator { + return nil +} + +func (any *uint32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_uint64.go b/vendor/github.com/json-iterator/go/any_uint64.go new file mode 100644 index 0000000..7df2fce --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_uint64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint64Any struct { + baseAny + val uint64 +} + +func (any *uint64Any) LastError() error { + return nil +} + +func (any *uint64Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint64Any) MustBeValid() Any { + return any +} + +func (any *uint64Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint64Any) ToInt() int { + return int(any.val) +} + +func (any *uint64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint64Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint64Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *uint64Any) ToUint64() uint64 { + return any.val +} + +func (any *uint64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint64Any) ToString() string { + return strconv.FormatUint(any.val, 10) +} + +func (any *uint64Any) WriteTo(stream *Stream) { + stream.WriteUint64(any.val) +} + +func (any *uint64Any) Parse() *Iterator { + return nil +} + +func (any *uint64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/build.sh b/vendor/github.com/json-iterator/go/build.sh new file mode 100755 index 0000000..b45ef68 --- /dev/null +++ b/vendor/github.com/json-iterator/go/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +set -x + +if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then + mkdir -p /tmp/build-golang/src/github.com/json-iterator + ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go +fi +export GOPATH=/tmp/build-golang +go get -u github.com/golang/dep/cmd/dep +cd /tmp/build-golang/src/github.com/json-iterator/go +exec $GOPATH/bin/dep ensure -update diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go new file mode 100644 index 0000000..bd66947 --- /dev/null +++ b/vendor/github.com/json-iterator/go/config.go @@ -0,0 +1,368 @@ +package jsoniter + +import ( + "encoding/json" + "github.com/modern-go/concurrent" + "github.com/modern-go/reflect2" + "io" + "reflect" + "sync" + "unsafe" +) + +// Config customize how the API should behave. +// The API is created from Config by Froze. +type Config struct { + IndentionStep int + MarshalFloatWith6Digits bool + EscapeHTML bool + SortMapKeys bool + UseNumber bool + DisallowUnknownFields bool + TagKey string + OnlyTaggedField bool + ValidateJsonRawMessage bool + ObjectFieldMustBeSimpleString bool +} + +// API the public interface of this package. +// Primary Marshal and Unmarshal. +type API interface { + IteratorPool + StreamPool + MarshalToString(v interface{}) (string, error) + Marshal(v interface{}) ([]byte, error) + MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) + UnmarshalFromString(str string, v interface{}) error + Unmarshal(data []byte, v interface{}) error + Get(data []byte, path ...interface{}) Any + NewEncoder(writer io.Writer) *Encoder + NewDecoder(reader io.Reader) *Decoder + Valid(data []byte) bool + RegisterExtension(extension Extension) + DecoderOf(typ reflect2.Type) ValDecoder + EncoderOf(typ reflect2.Type) ValEncoder +} + +// ConfigDefault the default API +var ConfigDefault = Config{ + EscapeHTML: true, +}.Froze() + +// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior +var ConfigCompatibleWithStandardLibrary = Config{ + EscapeHTML: true, + SortMapKeys: true, + ValidateJsonRawMessage: true, +}.Froze() + +// ConfigFastest marshals float with only 6 digits precision +var ConfigFastest = Config{ + EscapeHTML: false, + MarshalFloatWith6Digits: true, // will lose precession + ObjectFieldMustBeSimpleString: true, // do not unescape object field +}.Froze() + +type frozenConfig struct { + configBeforeFrozen Config + sortMapKeys bool + indentionStep int + objectFieldMustBeSimpleString bool + onlyTaggedField bool + disallowUnknownFields bool + decoderCache *concurrent.Map + encoderCache *concurrent.Map + extensions []Extension + streamPool *sync.Pool + iteratorPool *sync.Pool +} + +func (cfg *frozenConfig) initCache() { + cfg.decoderCache = concurrent.NewMap() + cfg.encoderCache = concurrent.NewMap() +} + +func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) { + cfg.decoderCache.Store(cacheKey, decoder) +} + +func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) { + cfg.encoderCache.Store(cacheKey, encoder) +} + +func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder { + decoder, found := cfg.decoderCache.Load(cacheKey) + if found { + return decoder.(ValDecoder) + } + return nil +} + +func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { + encoder, found := cfg.encoderCache.Load(cacheKey) + if found { + return encoder.(ValEncoder) + } + return nil +} + +var cfgCache = concurrent.NewMap() + +func getFrozenConfigFromCache(cfg Config) *frozenConfig { + obj, found := cfgCache.Load(cfg) + if found { + return obj.(*frozenConfig) + } + return nil +} + +func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { + cfgCache.Store(cfg, frozenConfig) +} + +// Froze forge API from config +func (cfg Config) Froze() API { + api := &frozenConfig{ + sortMapKeys: cfg.SortMapKeys, + indentionStep: cfg.IndentionStep, + objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, + onlyTaggedField: cfg.OnlyTaggedField, + disallowUnknownFields: cfg.DisallowUnknownFields, + } + api.streamPool = &sync.Pool{ + New: func() interface{} { + return NewStream(api, nil, 512) + }, + } + api.iteratorPool = &sync.Pool{ + New: func() interface{} { + return NewIterator(api) + }, + } + api.initCache() + encoderExtension := EncoderExtension{} + decoderExtension := DecoderExtension{} + if cfg.MarshalFloatWith6Digits { + api.marshalFloatWith6Digits(encoderExtension) + } + if cfg.EscapeHTML { + api.escapeHTML(encoderExtension) + } + if cfg.UseNumber { + api.useNumber(decoderExtension) + } + if cfg.ValidateJsonRawMessage { + api.validateJsonRawMessage(encoderExtension) + } + if len(encoderExtension) > 0 { + api.extensions = append(api.extensions, encoderExtension) + } + if len(decoderExtension) > 0 { + api.extensions = append(api.extensions, decoderExtension) + } + api.configBeforeFrozen = cfg + return api +} + +func (cfg Config) frozeWithCacheReuse() *frozenConfig { + api := getFrozenConfigFromCache(cfg) + if api != nil { + return api + } + api = cfg.Froze().(*frozenConfig) + addFrozenConfigToCache(cfg, api) + return api +} + +func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { + encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { + rawMessage := *(*json.RawMessage)(ptr) + iter := cfg.BorrowIterator([]byte(rawMessage)) + iter.Read() + if iter.Error != nil { + stream.WriteRaw("null") + } else { + cfg.ReturnIterator(iter) + stream.WriteRaw(string(rawMessage)) + } + }, func(ptr unsafe.Pointer) bool { + return false + }} + extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder + extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder +} + +func (cfg *frozenConfig) useNumber(extension DecoderExtension) { + extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { + exitingValue := *((*interface{})(ptr)) + if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr { + iter.ReadVal(exitingValue) + return + } + if iter.WhatIsNext() == NumberValue { + *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) + } else { + *((*interface{})(ptr)) = iter.Read() + } + }} +} +func (cfg *frozenConfig) getTagKey() string { + tagKey := cfg.configBeforeFrozen.TagKey + if tagKey == "" { + return "json" + } + return tagKey +} + +func (cfg *frozenConfig) RegisterExtension(extension Extension) { + cfg.extensions = append(cfg.extensions, extension) +} + +type lossyFloat32Encoder struct { +} + +func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32Lossy(*((*float32)(ptr))) +} + +func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type lossyFloat64Encoder struct { +} + +func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64Lossy(*((*float64)(ptr))) +} + +func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +// EnableLossyFloatMarshalling keeps 10**(-6) precision +// for float variables for better performance. +func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) { + // for better performance + extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{} + extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{} +} + +type htmlEscapedStringEncoder struct { +} + +func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteStringWithHTMLEscaped(str) +} + +func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) { + encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{} +} + +func (cfg *frozenConfig) cleanDecoders() { + typeDecoders = map[string]ValDecoder{} + fieldDecoders = map[string]ValDecoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) cleanEncoders() { + typeEncoders = map[string]ValEncoder{} + fieldEncoders = map[string]ValEncoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return "", stream.Error + } + return string(stream.Buffer()), nil +} + +func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return nil, stream.Error + } + result := stream.Buffer() + copied := make([]byte, len(result)) + copy(copied, result) + return copied, nil +} + +func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + if prefix != "" { + panic("prefix is not supported") + } + for _, r := range indent { + if r != ' ' { + panic("indent can only be space") + } + } + newCfg := cfg.configBeforeFrozen + newCfg.IndentionStep = len(indent) + return newCfg.frozeWithCacheReuse().Marshal(v) +} + +func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { + data := []byte(str) + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.ReadVal(v) + c := iter.nextToken() + if c == 0 { + if iter.Error == io.EOF { + return nil + } + return iter.Error + } + iter.ReportError("Unmarshal", "there are bytes left after unmarshal") + return iter.Error +} + +func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + return locatePath(iter, path) +} + +func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.ReadVal(v) + c := iter.nextToken() + if c == 0 { + if iter.Error == io.EOF { + return nil + } + return iter.Error + } + iter.ReportError("Unmarshal", "there are bytes left after unmarshal") + return iter.Error +} + +func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { + stream := NewStream(cfg, writer, 512) + return &Encoder{stream} +} + +func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { + iter := Parse(cfg, reader, 512) + return &Decoder{iter} +} + +func (cfg *frozenConfig) Valid(data []byte) bool { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.Skip() + return iter.Error == nil +} diff --git a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md new file mode 100644 index 0000000..3095662 --- /dev/null +++ b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md @@ -0,0 +1,7 @@ +| json type \ dest type | bool | int | uint | float |string| +| --- | --- | --- | --- |--|--| +| number | positive => true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin| +| string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin| +| bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"| +| object | true | 0 | 0 |0|originnal json| +| array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json| \ No newline at end of file diff --git a/vendor/github.com/json-iterator/go/iter.go b/vendor/github.com/json-iterator/go/iter.go new file mode 100644 index 0000000..95ae54f --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter.go @@ -0,0 +1,322 @@ +package jsoniter + +import ( + "encoding/json" + "fmt" + "io" +) + +// ValueType the type for JSON element +type ValueType int + +const ( + // InvalidValue invalid JSON element + InvalidValue ValueType = iota + // StringValue JSON element "string" + StringValue + // NumberValue JSON element 100 or 0.10 + NumberValue + // NilValue JSON element null + NilValue + // BoolValue JSON element true or false + BoolValue + // ArrayValue JSON element [] + ArrayValue + // ObjectValue JSON element {} + ObjectValue +) + +var hexDigits []byte +var valueTypes []ValueType + +func init() { + hexDigits = make([]byte, 256) + for i := 0; i < len(hexDigits); i++ { + hexDigits[i] = 255 + } + for i := '0'; i <= '9'; i++ { + hexDigits[i] = byte(i - '0') + } + for i := 'a'; i <= 'f'; i++ { + hexDigits[i] = byte((i - 'a') + 10) + } + for i := 'A'; i <= 'F'; i++ { + hexDigits[i] = byte((i - 'A') + 10) + } + valueTypes = make([]ValueType, 256) + for i := 0; i < len(valueTypes); i++ { + valueTypes[i] = InvalidValue + } + valueTypes['"'] = StringValue + valueTypes['-'] = NumberValue + valueTypes['0'] = NumberValue + valueTypes['1'] = NumberValue + valueTypes['2'] = NumberValue + valueTypes['3'] = NumberValue + valueTypes['4'] = NumberValue + valueTypes['5'] = NumberValue + valueTypes['6'] = NumberValue + valueTypes['7'] = NumberValue + valueTypes['8'] = NumberValue + valueTypes['9'] = NumberValue + valueTypes['t'] = BoolValue + valueTypes['f'] = BoolValue + valueTypes['n'] = NilValue + valueTypes['['] = ArrayValue + valueTypes['{'] = ObjectValue +} + +// Iterator is a io.Reader like object, with JSON specific read functions. +// Error is not returned as return value, but stored as Error member on this iterator instance. +type Iterator struct { + cfg *frozenConfig + reader io.Reader + buf []byte + head int + tail int + captureStartedAt int + captured []byte + Error error + Attachment interface{} // open for customized decoder +} + +// NewIterator creates an empty Iterator instance +func NewIterator(cfg API) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: nil, + head: 0, + tail: 0, + } +} + +// Parse creates an Iterator instance from io.Reader +func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: reader, + buf: make([]byte, bufSize), + head: 0, + tail: 0, + } +} + +// ParseBytes creates an Iterator instance from byte array +func ParseBytes(cfg API, input []byte) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: input, + head: 0, + tail: len(input), + } +} + +// ParseString creates an Iterator instance from string +func ParseString(cfg API, input string) *Iterator { + return ParseBytes(cfg, []byte(input)) +} + +// Pool returns a pool can provide more iterator with same configuration +func (iter *Iterator) Pool() IteratorPool { + return iter.cfg +} + +// Reset reuse iterator instance by specifying another reader +func (iter *Iterator) Reset(reader io.Reader) *Iterator { + iter.reader = reader + iter.head = 0 + iter.tail = 0 + return iter +} + +// ResetBytes reuse iterator instance by specifying another byte array as input +func (iter *Iterator) ResetBytes(input []byte) *Iterator { + iter.reader = nil + iter.buf = input + iter.head = 0 + iter.tail = len(input) + return iter +} + +// WhatIsNext gets ValueType of relatively next json element +func (iter *Iterator) WhatIsNext() ValueType { + valueType := valueTypes[iter.nextToken()] + iter.unreadByte() + return valueType +} + +func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + return false + } + return true +} + +func (iter *Iterator) isObjectEnd() bool { + c := iter.nextToken() + if c == ',' { + return false + } + if c == '}' { + return true + } + iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c})) + return true +} + +func (iter *Iterator) nextToken() byte { + // a variation of skip whitespaces, returning the next non-whitespace token + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + 1 + return c + } + if !iter.loadMore() { + return 0 + } + } +} + +// ReportError record a error in iterator instance with current position. +func (iter *Iterator) ReportError(operation string, msg string) { + if iter.Error != nil { + if iter.Error != io.EOF { + return + } + } + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + peekEnd := iter.head + 10 + if peekEnd > iter.tail { + peekEnd = iter.tail + } + parsing := string(iter.buf[peekStart:peekEnd]) + contextStart := iter.head - 50 + if contextStart < 0 { + contextStart = 0 + } + contextEnd := iter.head + 50 + if contextEnd > iter.tail { + contextEnd = iter.tail + } + context := string(iter.buf[contextStart:contextEnd]) + iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", + operation, msg, iter.head-peekStart, parsing, context) +} + +// CurrentBuffer gets current buffer as string for debugging purpose +func (iter *Iterator) CurrentBuffer() string { + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head, + string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) +} + +func (iter *Iterator) readByte() (ret byte) { + if iter.head == iter.tail { + if iter.loadMore() { + ret = iter.buf[iter.head] + iter.head++ + return ret + } + return 0 + } + ret = iter.buf[iter.head] + iter.head++ + return ret +} + +func (iter *Iterator) loadMore() bool { + if iter.reader == nil { + if iter.Error == nil { + iter.head = iter.tail + iter.Error = io.EOF + } + return false + } + if iter.captured != nil { + iter.captured = append(iter.captured, + iter.buf[iter.captureStartedAt:iter.tail]...) + iter.captureStartedAt = 0 + } + for { + n, err := iter.reader.Read(iter.buf) + if n == 0 { + if err != nil { + if iter.Error == nil { + iter.Error = err + } + return false + } + } else { + iter.head = 0 + iter.tail = n + return true + } + } +} + +func (iter *Iterator) unreadByte() { + if iter.Error != nil { + return + } + iter.head-- + return +} + +// Read read the next JSON element as generic interface{}. +func (iter *Iterator) Read() interface{} { + valueType := iter.WhatIsNext() + switch valueType { + case StringValue: + return iter.ReadString() + case NumberValue: + if iter.cfg.configBeforeFrozen.UseNumber { + return json.Number(iter.readNumberAsString()) + } + return iter.ReadFloat64() + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + return nil + case BoolValue: + return iter.ReadBool() + case ArrayValue: + arr := []interface{}{} + iter.ReadArrayCB(func(iter *Iterator) bool { + var elem interface{} + iter.ReadVal(&elem) + arr = append(arr, elem) + return true + }) + return arr + case ObjectValue: + obj := map[string]interface{}{} + iter.ReadMapCB(func(Iter *Iterator, field string) bool { + var elem interface{} + iter.ReadVal(&elem) + obj[field] = elem + return true + }) + return obj + default: + iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) + return nil + } +} diff --git a/vendor/github.com/json-iterator/go/iter_array.go b/vendor/github.com/json-iterator/go/iter_array.go new file mode 100644 index 0000000..6188cb4 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_array.go @@ -0,0 +1,58 @@ +package jsoniter + +// ReadArray read array element, tells if the array has more element to read. +func (iter *Iterator) ReadArray() (ret bool) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return false // null + case '[': + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + return true + } + return false + case ']': + return false + case ',': + return true + default: + iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c})) + return + } +} + +// ReadArrayCB read array with callback +func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { + c := iter.nextToken() + if c == '[' { + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + if !callback(iter) { + return false + } + c = iter.nextToken() + for c == ',' { + if !callback(iter) { + return false + } + c = iter.nextToken() + } + if c != ']' { + iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) + return false + } + return true + } + return true + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) + return false +} diff --git a/vendor/github.com/json-iterator/go/iter_float.go b/vendor/github.com/json-iterator/go/iter_float.go new file mode 100644 index 0000000..4f883c0 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_float.go @@ -0,0 +1,347 @@ +package jsoniter + +import ( + "encoding/json" + "io" + "math/big" + "strconv" + "strings" + "unsafe" +) + +var floatDigits []int8 + +const invalidCharForNumber = int8(-1) +const endOfNumber = int8(-2) +const dotInNumber = int8(-3) + +func init() { + floatDigits = make([]int8, 256) + for i := 0; i < len(floatDigits); i++ { + floatDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + floatDigits[i] = i - int8('0') + } + floatDigits[','] = endOfNumber + floatDigits[']'] = endOfNumber + floatDigits['}'] = endOfNumber + floatDigits[' '] = endOfNumber + floatDigits['\t'] = endOfNumber + floatDigits['\n'] = endOfNumber + floatDigits['.'] = dotInNumber +} + +// ReadBigFloat read big.Float +func (iter *Iterator) ReadBigFloat() (ret *big.Float) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + prec := 64 + if len(str) > prec { + prec = len(str) + } + val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero) + if err != nil { + iter.Error = err + return nil + } + return val +} + +// ReadBigInt read big.Int +func (iter *Iterator) ReadBigInt() (ret *big.Int) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + ret = big.NewInt(0) + var success bool + ret, success = ret.SetString(str, 10) + if !success { + iter.ReportError("ReadBigInt", "invalid big int") + return nil + } + return ret +} + +//ReadFloat32 read float32 +func (iter *Iterator) ReadFloat32() (ret float32) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat32() + } + iter.unreadByte() + return iter.readPositiveFloat32() +} + +func (iter *Iterator) readPositiveFloat32() (ret float32) { + value := uint64(0) + c := byte(' ') + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c = iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.ReportError("readFloat32", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat32", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat32", "leading zero is invalid") + return + } + } + value = uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.head = i + return float32(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat32SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float32(float64(value) / float64(pow10[decimalPlaces])) + } + // too many decimal places + return iter.readFloat32SlowPath() + case invalidCharForNumber: + fallthrough + case dotInNumber: + return iter.readFloat32SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat32SlowPath() +} + +func (iter *Iterator) readNumberAsString() (ret string) { + strBuf := [16]byte{} + str := strBuf[0:0] +load_loop: + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + str = append(str, c) + continue + default: + iter.head = i + break load_loop + } + } + if !iter.loadMore() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + return + } + if len(str) == 0 { + iter.ReportError("readNumberAsString", "invalid number") + } + return *(*string)(unsafe.Pointer(&str)) +} + +func (iter *Iterator) readFloat32SlowPath() (ret float32) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat32SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 32) + if err != nil { + iter.Error = err + return + } + return float32(val) +} + +// ReadFloat64 read float64 +func (iter *Iterator) ReadFloat64() (ret float64) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat64() + } + iter.unreadByte() + return iter.readPositiveFloat64() +} + +func (iter *Iterator) readPositiveFloat64() (ret float64) { + value := uint64(0) + c := byte(' ') + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c = iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.ReportError("readFloat64", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat64", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat64", "leading zero is invalid") + return + } + } + value = uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.head = i + return float64(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat64SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float64(value) / float64(pow10[decimalPlaces]) + } + // too many decimal places + return iter.readFloat64SlowPath() + case invalidCharForNumber: + fallthrough + case dotInNumber: + return iter.readFloat64SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat64SlowPath() +} + +func (iter *Iterator) readFloat64SlowPath() (ret float64) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat64SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 64) + if err != nil { + iter.Error = err + return + } + return val +} + +func validateFloat(str string) string { + // strconv.ParseFloat is not validating `1.` or `1.e1` + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} + +// ReadNumber read json.Number +func (iter *Iterator) ReadNumber() (ret json.Number) { + return json.Number(iter.readNumberAsString()) +} diff --git a/vendor/github.com/json-iterator/go/iter_int.go b/vendor/github.com/json-iterator/go/iter_int.go new file mode 100644 index 0000000..2142320 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_int.go @@ -0,0 +1,345 @@ +package jsoniter + +import ( + "math" + "strconv" +) + +var intDigits []int8 + +const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 +const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 + +func init() { + intDigits = make([]int8, 256) + for i := 0; i < len(intDigits); i++ { + intDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + intDigits[i] = i - int8('0') + } +} + +// ReadUint read uint +func (iter *Iterator) ReadUint() uint { + if strconv.IntSize == 32 { + return uint(iter.ReadUint32()) + } + return uint(iter.ReadUint64()) +} + +// ReadInt read int +func (iter *Iterator) ReadInt() int { + if strconv.IntSize == 32 { + return int(iter.ReadInt32()) + } + return int(iter.ReadInt64()) +} + +// ReadInt8 read int8 +func (iter *Iterator) ReadInt8() (ret int8) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt8+1 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int8(val) + } + val := iter.readUint32(c) + if val > math.MaxInt8 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int8(val) +} + +// ReadUint8 read uint8 +func (iter *Iterator) ReadUint8() (ret uint8) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint8 { + iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint8(val) +} + +// ReadInt16 read int16 +func (iter *Iterator) ReadInt16() (ret int16) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt16+1 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int16(val) + } + val := iter.readUint32(c) + if val > math.MaxInt16 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int16(val) +} + +// ReadUint16 read uint16 +func (iter *Iterator) ReadUint16() (ret uint16) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint16 { + iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint16(val) +} + +// ReadInt32 read int32 +func (iter *Iterator) ReadInt32() (ret int32) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt32+1 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int32(val) + } + val := iter.readUint32(c) + if val > math.MaxInt32 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int32(val) +} + +// ReadUint32 read uint32 +func (iter *Iterator) ReadUint32() (ret uint32) { + return iter.readUint32(iter.nextToken()) +} + +func (iter *Iterator) readUint32(c byte) (ret uint32) { + ind := intDigits[c] + if ind == 0 { + iter.assertInteger() + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint32(ind) + if iter.tail-iter.head > 10 { + i := iter.head + ind2 := intDigits[iter.buf[i]] + if ind2 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + i++ + ind3 := intDigits[iter.buf[i]] + if ind3 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10 + uint32(ind2) + } + //iter.head = i + 1 + //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) + i++ + ind4 := intDigits[iter.buf[i]] + if ind4 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100 + uint32(ind2)*10 + uint32(ind3) + } + i++ + ind5 := intDigits[iter.buf[i]] + if ind5 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) + } + i++ + ind6 := intDigits[iter.buf[i]] + if ind6 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) + } + i++ + ind7 := intDigits[iter.buf[i]] + if ind7 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) + } + i++ + ind8 := intDigits[iter.buf[i]] + if ind8 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) + } + i++ + ind9 := intDigits[iter.buf[i]] + value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) + iter.head = i + if ind9 == invalidCharForNumber { + iter.assertInteger() + return value + } + } + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + if value > uint32SafeToMultiply10 { + value2 := (value << 3) + (value << 1) + uint32(ind) + if value2 < value { + iter.ReportError("readUint32", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint32(ind) + } + if !iter.loadMore() { + iter.assertInteger() + return value + } + } +} + +// ReadInt64 read int64 +func (iter *Iterator) ReadInt64() (ret int64) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint64(iter.readByte()) + if val > math.MaxInt64+1 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return -int64(val) + } + val := iter.readUint64(c) + if val > math.MaxInt64 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return int64(val) +} + +// ReadUint64 read uint64 +func (iter *Iterator) ReadUint64() uint64 { + return iter.readUint64(iter.nextToken()) +} + +func (iter *Iterator) readUint64(c byte) (ret uint64) { + ind := intDigits[c] + if ind == 0 { + iter.assertInteger() + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint64(ind) + if iter.tail-iter.head > 10 { + i := iter.head + ind2 := intDigits[iter.buf[i]] + if ind2 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + i++ + ind3 := intDigits[iter.buf[i]] + if ind3 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10 + uint64(ind2) + } + //iter.head = i + 1 + //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) + i++ + ind4 := intDigits[iter.buf[i]] + if ind4 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100 + uint64(ind2)*10 + uint64(ind3) + } + i++ + ind5 := intDigits[iter.buf[i]] + if ind5 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) + } + i++ + ind6 := intDigits[iter.buf[i]] + if ind6 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) + } + i++ + ind7 := intDigits[iter.buf[i]] + if ind7 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) + } + i++ + ind8 := intDigits[iter.buf[i]] + if ind8 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) + } + i++ + ind9 := intDigits[iter.buf[i]] + value = value*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) + iter.head = i + if ind9 == invalidCharForNumber { + iter.assertInteger() + return value + } + } + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + if value > uint64SafeToMultiple10 { + value2 := (value << 3) + (value << 1) + uint64(ind) + if value2 < value { + iter.ReportError("readUint64", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint64(ind) + } + if !iter.loadMore() { + iter.assertInteger() + return value + } + } +} + +func (iter *Iterator) assertInteger() { + if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' { + iter.ReportError("assertInteger", "can not decode float as int") + } +} diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go new file mode 100644 index 0000000..ebd3da8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_object.go @@ -0,0 +1,248 @@ +package jsoniter + +import ( + "fmt" + "unicode" +) + +// ReadObject read one field from object. +// If object ended, returns empty string. +// Otherwise, returns the field name. +func (iter *Iterator) ReadObject() (ret string) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return "" // null + case '{': + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + return field + } + if c == '}' { + return "" // end of object + } + iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) + return + case ',': + field := iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + return field + case '}': + return "" // end of object + default: + iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) + return + } +} + +// CaseInsensitive +func (iter *Iterator) readFieldHash() int64 { + hash := int64(0x811c9dc5) + c := iter.nextToken() + if c != '"' { + iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) + return 0 + } + for { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + b := iter.buf[i] + if b == '\\' { + iter.head = i + for _, b := range iter.readStringSlowPath() { + if 'A' <= b && b <= 'Z' { + b += 'a' - 'A' + } + hash ^= int64(b) + hash *= 0x1000193 + } + c = iter.nextToken() + if c != ':' { + iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) + return 0 + } + return hash + } + if b == '"' { + iter.head = i + 1 + c = iter.nextToken() + if c != ':' { + iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) + return 0 + } + return hash + } + if 'A' <= b && b <= 'Z' { + b += 'a' - 'A' + } + hash ^= int64(b) + hash *= 0x1000193 + } + if !iter.loadMore() { + iter.ReportError("readFieldHash", `incomplete field name`) + return 0 + } + } +} + +func calcHash(str string) int64 { + hash := int64(0x811c9dc5) + for _, b := range str { + hash ^= int64(unicode.ToLower(b)) + hash *= 0x1000193 + } + return int64(hash) +} + +// ReadObjectCB read object with callback, the key is ascii only and field name not copied +func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + var field string + if c == '{' { + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadObjectCB", `object not ended with }`) + return false + } + return true + } + if c == '}' { + return true + } + iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c})) + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +// ReadMapCB read map with callback, the key can be any string +func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return false + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return false + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadMapCB", `object not ended with }`) + return false + } + return true + } + if c == '}' { + return true + } + iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *Iterator) readObjectStart() bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '}' { + return false + } + iter.unreadByte() + return true + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return false + } + iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) + return false +} + +func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { + str := iter.ReadStringAsSlice() + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if iter.buf[iter.head] != ':' { + iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) + return + } + iter.head++ + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if ret == nil { + return str + } + return ret +} diff --git a/vendor/github.com/json-iterator/go/iter_skip.go b/vendor/github.com/json-iterator/go/iter_skip.go new file mode 100644 index 0000000..f58beb9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip.go @@ -0,0 +1,129 @@ +package jsoniter + +import "fmt" + +// ReadNil reads a json object as nil and +// returns whether it's a nil or not +func (iter *Iterator) ReadNil() (ret bool) { + c := iter.nextToken() + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') // null + return true + } + iter.unreadByte() + return false +} + +// ReadBool reads a json object as BoolValue +func (iter *Iterator) ReadBool() (ret bool) { + c := iter.nextToken() + if c == 't' { + iter.skipThreeBytes('r', 'u', 'e') + return true + } + if c == 'f' { + iter.skipFourBytes('a', 'l', 's', 'e') + return false + } + iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c})) + return +} + +// SkipAndReturnBytes skip next JSON element, and return its content as []byte. +// The []byte can be kept, it is a copy of data. +func (iter *Iterator) SkipAndReturnBytes() []byte { + iter.startCapture(iter.head) + iter.Skip() + return iter.stopCapture() +} + +type captureBuffer struct { + startedAt int + captured []byte +} + +func (iter *Iterator) startCapture(captureStartedAt int) { + if iter.captured != nil { + panic("already in capture mode") + } + iter.captureStartedAt = captureStartedAt + iter.captured = make([]byte, 0, 32) +} + +func (iter *Iterator) stopCapture() []byte { + if iter.captured == nil { + panic("not in capture mode") + } + captured := iter.captured + remaining := iter.buf[iter.captureStartedAt:iter.head] + iter.captureStartedAt = -1 + iter.captured = nil + if len(captured) == 0 { + copied := make([]byte, len(remaining)) + copy(copied, remaining) + return copied + } + captured = append(captured, remaining...) + return captured +} + +// Skip skips a json object and positions to relatively the next json object +func (iter *Iterator) Skip() { + c := iter.nextToken() + switch c { + case '"': + iter.skipString() + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + case '0': + iter.unreadByte() + iter.ReadFloat32() + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.skipNumber() + case '[': + iter.skipArray() + case '{': + iter.skipObject() + default: + iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) + return + } +} + +func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b4 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } +} + +func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } +} diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go new file mode 100644 index 0000000..8fcdc3b --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go @@ -0,0 +1,144 @@ +//+build jsoniter_sloppy + +package jsoniter + +// sloppy but faster implementation, do not validate the input json + +func (iter *Iterator) skipNumber() { + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\r', '\t', ',', '}', ']': + iter.head = i + return + } + } + if !iter.loadMore() { + return + } + } +} + +func (iter *Iterator) skipArray() { + level := 1 + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '[': // If open symbol, increase level + level++ + case ']': // If close symbol, increase level + level-- + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete array") + return + } + } +} + +func (iter *Iterator) skipObject() { + level := 1 + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '{': // If open symbol, increase level + level++ + case '}': // If close symbol, increase level + level-- + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete object") + return + } + } +} + +func (iter *Iterator) skipString() { + for { + end, escaped := iter.findStringEnd() + if end == -1 { + if !iter.loadMore() { + iter.ReportError("skipString", "incomplete string") + return + } + if escaped { + iter.head = 1 // skip the first char as last char read is \ + } + } else { + iter.head = end + return + } + } +} + +// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go +// Tries to find the end of string +// Support if string contains escaped quote symbols. +func (iter *Iterator) findStringEnd() (int, bool) { + escaped := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + if !escaped { + return i + 1, false + } + j := i - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return i + 1, true + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + } + } else if c == '\\' { + escaped = true + } + } + j := iter.tail - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return -1, false // do not end with \ + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + + } + return -1, true // end with \ +} diff --git a/vendor/github.com/json-iterator/go/iter_skip_strict.go b/vendor/github.com/json-iterator/go/iter_skip_strict.go new file mode 100644 index 0000000..f67bc2e --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip_strict.go @@ -0,0 +1,89 @@ +//+build !jsoniter_sloppy + +package jsoniter + +import "fmt" + +func (iter *Iterator) skipNumber() { + if !iter.trySkipNumber() { + iter.unreadByte() + iter.ReadFloat32() + } +} + +func (iter *Iterator) trySkipNumber() bool { + dotFound := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + case '.': + if dotFound { + iter.ReportError("validateNumber", `more than one dot found in number`) + return true // already failed + } + if i+1 == iter.tail { + return false + } + c = iter.buf[i+1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + iter.ReportError("validateNumber", `missing digit after dot`) + return true // already failed + } + dotFound = true + default: + switch c { + case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } + iter.head = i + return true // must be valid + } + return false // may be invalid + } + } + return false +} + +func (iter *Iterator) skipString() { + if !iter.trySkipString() { + iter.unreadByte() + iter.ReadString() + } +} + +func (iter *Iterator) trySkipString() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + iter.head = i + 1 + return true // valid + } else if c == '\\' { + return false + } else if c < ' ' { + iter.ReportError("trySkipString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return true // already failed + } + } + return false +} + +func (iter *Iterator) skipObject() { + iter.unreadByte() + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + return true + }) +} + +func (iter *Iterator) skipArray() { + iter.unreadByte() + iter.ReadArrayCB(func(iter *Iterator) bool { + iter.Skip() + return true + }) +} diff --git a/vendor/github.com/json-iterator/go/iter_str.go b/vendor/github.com/json-iterator/go/iter_str.go new file mode 100644 index 0000000..adc487e --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_str.go @@ -0,0 +1,215 @@ +package jsoniter + +import ( + "fmt" + "unicode/utf16" +) + +// ReadString read string from iterator +func (iter *Iterator) ReadString() (ret string) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + ret = string(iter.buf[iter.head:i]) + iter.head = i + 1 + return ret + } else if c == '\\' { + break + } else if c < ' ' { + iter.ReportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return + } + } + return iter.readStringSlowPath() + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return "" + } + iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) + return +} + +func (iter *Iterator) readStringSlowPath() (ret string) { + var str []byte + var c byte + for iter.Error == nil { + c = iter.readByte() + if c == '"' { + return string(str) + } + if c == '\\' { + c = iter.readByte() + str = iter.readEscapedChar(c, str) + } else { + str = append(str, c) + } + } + iter.ReportError("readStringSlowPath", "unexpected end of input") + return +} + +func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { + switch c { + case 'u': + r := iter.readU4() + if utf16.IsSurrogate(r) { + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != '\\' { + iter.unreadByte() + str = appendRune(str, r) + return str + } + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != 'u' { + str = appendRune(str, r) + return iter.readEscapedChar(c, str) + } + r2 := iter.readU4() + if iter.Error != nil { + return nil + } + combined := utf16.DecodeRune(r, r2) + if combined == '\uFFFD' { + str = appendRune(str, r) + str = appendRune(str, r2) + } else { + str = appendRune(str, combined) + } + } else { + str = appendRune(str, r) + } + case '"': + str = append(str, '"') + case '\\': + str = append(str, '\\') + case '/': + str = append(str, '/') + case 'b': + str = append(str, '\b') + case 'f': + str = append(str, '\f') + case 'n': + str = append(str, '\n') + case 'r': + str = append(str, '\r') + case 't': + str = append(str, '\t') + default: + iter.ReportError("readEscapedChar", + `invalid escape char after \`) + return nil + } + return str +} + +// ReadStringAsSlice read string from iterator without copying into string form. +// The []byte can not be kept, as it will change after next iterator call. +func (iter *Iterator) ReadStringAsSlice() (ret []byte) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + // for: field name, base64, number + if iter.buf[i] == '"' { + // fast path: reuse the underlying buffer + ret = iter.buf[iter.head:i] + iter.head = i + 1 + return ret + } + } + readLen := iter.tail - iter.head + copied := make([]byte, readLen, readLen*2) + copy(copied, iter.buf[iter.head:iter.tail]) + iter.head = iter.tail + for iter.Error == nil { + c := iter.readByte() + if c == '"' { + return copied + } + copied = append(copied, c) + } + return copied + } + iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) + return +} + +func (iter *Iterator) readU4() (ret rune) { + for i := 0; i < 4; i++ { + c := iter.readByte() + if iter.Error != nil { + return + } + if c >= '0' && c <= '9' { + ret = ret*16 + rune(c-'0') + } else if c >= 'a' && c <= 'f' { + ret = ret*16 + rune(c-'a'+10) + } else if c >= 'A' && c <= 'F' { + ret = ret*16 + rune(c-'A'+10) + } else { + iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) + return + } + } + return ret +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + + surrogateMin = 0xD800 + surrogateMax = 0xDFFF + + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. + runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" +) + +func appendRune(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p = append(p, byte(r)) + return p + case i <= rune2Max: + p = append(p, t2|byte(r>>6)) + p = append(p, tx|byte(r)&maskx) + return p + case i > maxRune, surrogateMin <= i && i <= surrogateMax: + r = runeError + fallthrough + case i <= rune3Max: + p = append(p, t3|byte(r>>12)) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + default: + p = append(p, t4|byte(r>>18)) + p = append(p, tx|byte(r>>12)&maskx) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + } +} diff --git a/vendor/github.com/json-iterator/go/jsoniter.go b/vendor/github.com/json-iterator/go/jsoniter.go new file mode 100644 index 0000000..c2934f9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/jsoniter.go @@ -0,0 +1,18 @@ +// Package jsoniter implements encoding and decoding of JSON as defined in +// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. +// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter +// and variable type declarations (if any). +// jsoniter interfaces gives 100% compatibility with code using standard lib. +// +// "JSON and Go" +// (https://golang.org/doc/articles/json_and_go.html) +// gives a description of how Marshal/Unmarshal operate +// between arbitrary or predefined json objects and bytes, +// and it applies to jsoniter.Marshal/Unmarshal as well. +// +// Besides, jsoniter.Iterator provides a different set of interfaces +// iterating given bytes/string/reader +// and yielding parsed elements one by one. +// This set of interfaces reads input as required and gives +// better performance. +package jsoniter diff --git a/vendor/github.com/json-iterator/go/pool.go b/vendor/github.com/json-iterator/go/pool.go new file mode 100644 index 0000000..7350626 --- /dev/null +++ b/vendor/github.com/json-iterator/go/pool.go @@ -0,0 +1,41 @@ +package jsoniter + +import ( + "io" +) + +// IteratorPool a thread safe pool of iterators with same configuration +type IteratorPool interface { + BorrowIterator(data []byte) *Iterator + ReturnIterator(iter *Iterator) +} + +// StreamPool a thread safe pool of streams with same configuration +type StreamPool interface { + BorrowStream(writer io.Writer) *Stream + ReturnStream(stream *Stream) +} + +func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { + stream := cfg.streamPool.Get().(*Stream) + stream.Reset(writer) + return stream +} + +func (cfg *frozenConfig) ReturnStream(stream *Stream) { + stream.Error = nil + stream.Attachment = nil + cfg.streamPool.Put(stream) +} + +func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator { + iter := cfg.iteratorPool.Get().(*Iterator) + iter.ResetBytes(data) + return iter +} + +func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { + iter.Error = nil + iter.Attachment = nil + cfg.iteratorPool.Put(iter) +} diff --git a/vendor/github.com/json-iterator/go/reflect.go b/vendor/github.com/json-iterator/go/reflect.go new file mode 100644 index 0000000..5c7d3a8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect.go @@ -0,0 +1,321 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "reflect" + "unsafe" +) + +// ValDecoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValDecoder with json.Decoder. +// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). +// +// Reflection on type to create decoders, which is then cached +// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions +// 1. create instance of new value, for example *int will need a int to be allocated +// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New +// 3. assignment to map, both key and value will be reflect.Value +// For a simple struct binding, it will be reflect.Value free and allocation free +type ValDecoder interface { + Decode(ptr unsafe.Pointer, iter *Iterator) +} + +// ValEncoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValEncoder with json.Encoder. +// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). +type ValEncoder interface { + IsEmpty(ptr unsafe.Pointer) bool + Encode(ptr unsafe.Pointer, stream *Stream) +} + +type checkIsEmpty interface { + IsEmpty(ptr unsafe.Pointer) bool +} + +type ctx struct { + *frozenConfig + prefix string + encoders map[reflect2.Type]ValEncoder + decoders map[reflect2.Type]ValDecoder +} + +func (b *ctx) append(prefix string) *ctx { + return &ctx{ + frozenConfig: b.frozenConfig, + prefix: b.prefix + " " + prefix, + encoders: b.encoders, + decoders: b.decoders, + } +} + +// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal +func (iter *Iterator) ReadVal(obj interface{}) { + cacheKey := reflect2.RTypeOf(obj) + decoder := iter.cfg.getDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + iter.ReportError("ReadVal", "can only unmarshal into pointer") + return + } + decoder = iter.cfg.DecoderOf(typ) + } + ptr := reflect2.PtrOf(obj) + if ptr == nil { + iter.ReportError("ReadVal", "can not read into nil pointer") + return + } + decoder.Decode(ptr, iter) +} + +// WriteVal copy the go interface into underlying JSON, same as json.Marshal +func (stream *Stream) WriteVal(val interface{}) { + if nil == val { + stream.WriteNil() + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := stream.cfg.getEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = stream.cfg.EncoderOf(typ) + } + encoder.Encode(reflect2.PtrOf(val), stream) +} + +func (cfg *frozenConfig) DecoderOf(typ reflect2.Type) ValDecoder { + cacheKey := typ.RType() + decoder := cfg.getDecoderFromCache(cacheKey) + if decoder != nil { + return decoder + } + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect2.Type]ValDecoder{}, + encoders: map[reflect2.Type]ValEncoder{}, + } + ptrType := typ.(*reflect2.UnsafePtrType) + decoder = decoderOfType(ctx, ptrType.Elem()) + cfg.addDecoderToCache(cacheKey, decoder) + return decoder +} + +func decoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := getTypeDecoderFromExtension(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfType(ctx, typ) + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + for _, extension := range ctx.extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + return decoder +} + +func createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := ctx.decoders[typ] + if decoder != nil { + return decoder + } + placeholder := &placeholderDecoder{} + ctx.decoders[typ] = placeholder + decoder = _createDecoderOfType(ctx, typ) + placeholder.decoder = decoder + return decoder +} + +func _createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := createDecoderOfJsonRawMessage(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfJsonNumber(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfMarshaler(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfAny(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfNative(ctx, typ) + if decoder != nil { + return decoder + } + switch typ.Kind() { + case reflect.Interface: + ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) + if isIFace { + return &ifaceDecoder{valType: ifaceType} + } + return &efaceDecoder{} + case reflect.Struct: + return decoderOfStruct(ctx, typ) + case reflect.Array: + return decoderOfArray(ctx, typ) + case reflect.Slice: + return decoderOfSlice(ctx, typ) + case reflect.Map: + return decoderOfMap(ctx, typ) + case reflect.Ptr: + return decoderOfOptional(ctx, typ) + default: + return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} + } +} + +func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder { + cacheKey := typ.RType() + encoder := cfg.getEncoderFromCache(cacheKey) + if encoder != nil { + return encoder + } + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect2.Type]ValDecoder{}, + encoders: map[reflect2.Type]ValEncoder{}, + } + encoder = encoderOfType(ctx, typ) + if typ.LikePtr() { + encoder = &onePtrEncoder{encoder} + } + cfg.addEncoderToCache(cacheKey, encoder) + return encoder +} + +type onePtrEncoder struct { + encoder ValEncoder +} + +func (encoder *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +func (encoder *onePtrEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := getTypeEncoderFromExtension(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfType(ctx, typ) + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + for _, extension := range ctx.extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + return encoder +} + +func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := ctx.encoders[typ] + if encoder != nil { + return encoder + } + placeholder := &placeholderEncoder{} + ctx.encoders[typ] = placeholder + encoder = _createEncoderOfType(ctx, typ) + placeholder.encoder = encoder + return encoder +} +func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := createEncoderOfJsonRawMessage(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfJsonNumber(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfMarshaler(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfAny(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return encoderOfStruct(ctx, typ) + case reflect.Array: + return encoderOfArray(ctx, typ) + case reflect.Slice: + return encoderOfSlice(ctx, typ) + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return encoderOfOptional(ctx, typ) + default: + return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} + } +} + +type lazyErrorDecoder struct { + err error +} + +func (decoder *lazyErrorDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.WhatIsNext() != NilValue { + if iter.Error == nil { + iter.Error = decoder.err + } + } else { + iter.Skip() + } +} + +type lazyErrorEncoder struct { + err error +} + +func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if ptr == nil { + stream.WriteNil() + } else if stream.Error == nil { + stream.Error = encoder.err + } +} + +func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type placeholderDecoder struct { + decoder ValDecoder +} + +func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.decoder.Decode(ptr, iter) +} + +type placeholderEncoder struct { + encoder ValEncoder +} + +func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(ptr, stream) +} + +func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(ptr) +} diff --git a/vendor/github.com/json-iterator/go/reflect_array.go b/vendor/github.com/json-iterator/go/reflect_array.go new file mode 100644 index 0000000..13a0b7b --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_array.go @@ -0,0 +1,104 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "unsafe" +) + +func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + decoder := decoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + return &arrayDecoder{arrayType, decoder} +} + +func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + if arrayType.Len() == 0 { + return emptyArrayEncoder{} + } + encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + return &arrayEncoder{arrayType, encoder} +} + +type emptyArrayEncoder struct{} + +func (encoder emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteEmptyArray() +} + +func (encoder emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return true +} + +type arrayEncoder struct { + arrayType *reflect2.UnsafeArrayType + elemEncoder ValEncoder +} + +func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(ptr) + encoder.elemEncoder.Encode(elemPtr, stream) + for i := 1; i < encoder.arrayType.Len(); i++ { + stream.WriteMore() + elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) + } +} + +func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type arrayDecoder struct { + arrayType *reflect2.UnsafeArrayType + elemDecoder ValDecoder +} + +func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) + } +} + +func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + arrayType := decoder.arrayType + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return + } + if c != '[' { + iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c})) + return + } + c = iter.nextToken() + if c == ']' { + return + } + iter.unreadByte() + elemPtr := arrayType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, iter) + length := 1 + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + if length >= arrayType.Len() { + iter.Skip() + continue + } + idx := length + length += 1 + elemPtr = arrayType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, iter) + } + if c != ']' { + iter.ReportError("decode array", "expect ], but found "+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_dynamic.go b/vendor/github.com/json-iterator/go/reflect_dynamic.go new file mode 100644 index 0000000..8b6bc8b --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_dynamic.go @@ -0,0 +1,70 @@ +package jsoniter + +import ( + "github.com/modern-go/reflect2" + "reflect" + "unsafe" +) + +type dynamicEncoder struct { + valType reflect2.Type +} + +func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + stream.WriteVal(obj) +} + +func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.valType.UnsafeIndirect(ptr) == nil +} + +type efaceDecoder struct { +} + +func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + pObj := (*interface{})(ptr) + obj := *pObj + if obj == nil { + *pObj = iter.Read() + return + } + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + *pObj = iter.Read() + return + } + ptrType := typ.(*reflect2.UnsafePtrType) + ptrElemType := ptrType.Elem() + if iter.WhatIsNext() == NilValue { + if ptrElemType.Kind() != reflect.Ptr { + iter.skipFourBytes('n', 'u', 'l', 'l') + *pObj = nil + return + } + } + if reflect2.IsNil(obj) { + obj := ptrElemType.New() + iter.ReadVal(obj) + *pObj = obj + return + } + iter.ReadVal(obj) +} + +type ifaceDecoder struct { + valType *reflect2.UnsafeIFaceType +} + +func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) + return + } + obj := decoder.valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + iter.ReportError("decode non empty interface", "can not unmarshal into nil") + return + } + iter.ReadVal(obj) +} diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go new file mode 100644 index 0000000..917bbe8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_extension.go @@ -0,0 +1,471 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "reflect" + "sort" + "strings" + "unicode" + "unsafe" +) + +var typeDecoders = map[string]ValDecoder{} +var fieldDecoders = map[string]ValDecoder{} +var typeEncoders = map[string]ValEncoder{} +var fieldEncoders = map[string]ValEncoder{} +var extensions = []Extension{} + +// StructDescriptor describe how should we encode/decode the struct +type StructDescriptor struct { + Type reflect2.Type + Fields []*Binding +} + +// GetField get one field from the descriptor by its name. +// Can not use map here to keep field orders. +func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { + for _, binding := range structDescriptor.Fields { + if binding.Field.Name() == fieldName { + return binding + } + } + return nil +} + +// Binding describe how should we encode/decode the struct field +type Binding struct { + levels []int + Field reflect2.StructField + FromNames []string + ToNames []string + Encoder ValEncoder + Decoder ValDecoder +} + +// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder. +// Can also rename fields by UpdateStructDescriptor. +type Extension interface { + UpdateStructDescriptor(structDescriptor *StructDescriptor) + CreateMapKeyDecoder(typ reflect2.Type) ValDecoder + CreateMapKeyEncoder(typ reflect2.Type) ValEncoder + CreateDecoder(typ reflect2.Type) ValDecoder + CreateEncoder(typ reflect2.Type) ValEncoder + DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder + DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder +} + +// DummyExtension embed this type get dummy implementation for all methods of Extension +type DummyExtension struct { +} + +// UpdateStructDescriptor No-op +func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateMapKeyDecoder No-op +func (extension *DummyExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension *DummyExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// CreateDecoder No-op +func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateEncoder No-op +func (extension *DummyExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension *DummyExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension *DummyExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type EncoderExtension map[reflect2.Type]ValEncoder + +// UpdateStructDescriptor No-op +func (extension EncoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateDecoder No-op +func (extension EncoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateEncoder get encoder from map +func (extension EncoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return extension[typ] +} + +// CreateMapKeyDecoder No-op +func (extension EncoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension EncoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension EncoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type DecoderExtension map[reflect2.Type]ValDecoder + +// UpdateStructDescriptor No-op +func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateMapKeyDecoder No-op +func (extension DecoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension DecoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// CreateDecoder get decoder from map +func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return extension[typ] +} + +// CreateEncoder No-op +func (extension DecoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension DecoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension DecoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type funcDecoder struct { + fun DecoderFunc +} + +func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.fun(ptr, iter) +} + +type funcEncoder struct { + fun EncoderFunc + isEmptyFunc func(ptr unsafe.Pointer) bool +} + +func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.fun(ptr, stream) +} + +func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { + if encoder.isEmptyFunc == nil { + return false + } + return encoder.isEmptyFunc(ptr) +} + +// DecoderFunc the function form of TypeDecoder +type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) + +// EncoderFunc the function form of TypeEncoder +type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) + +// RegisterTypeDecoderFunc register TypeDecoder for a type with function +func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { + typeDecoders[typ] = &funcDecoder{fun} +} + +// RegisterTypeDecoder register TypeDecoder for a typ +func RegisterTypeDecoder(typ string, decoder ValDecoder) { + typeDecoders[typ] = decoder +} + +// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function +func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) { + RegisterFieldDecoder(typ, field, &funcDecoder{fun}) +} + +// RegisterFieldDecoder register TypeDecoder for a struct field +func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) { + fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder +} + +// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function +func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc} +} + +// RegisterTypeEncoder register TypeEncoder for a type +func RegisterTypeEncoder(typ string, encoder ValEncoder) { + typeEncoders[typ] = encoder +} + +// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function +func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc}) +} + +// RegisterFieldEncoder register TypeEncoder for a struct field +func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { + fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder +} + +// RegisterExtension register extension +func RegisterExtension(extension Extension) { + extensions = append(extensions, extension) +} + +func getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := _getTypeDecoderFromExtension(ctx, typ) + if decoder != nil { + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + for _, extension := range ctx.extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + } + return decoder +} +func _getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { + for _, extension := range extensions { + decoder := extension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + } + for _, extension := range ctx.extensions { + decoder := extension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + } + typeName := typ.String() + decoder := typeDecoders[typeName] + if decoder != nil { + return decoder + } + if typ.Kind() == reflect.Ptr { + ptrType := typ.(*reflect2.UnsafePtrType) + decoder := typeDecoders[ptrType.Elem().String()] + if decoder != nil { + return &OptionalDecoder{ptrType.Elem(), decoder} + } + } + return nil +} + +func getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := _getTypeEncoderFromExtension(ctx, typ) + if encoder != nil { + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + for _, extension := range ctx.extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + } + return encoder +} + +func _getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { + for _, extension := range extensions { + encoder := extension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + } + for _, extension := range ctx.extensions { + encoder := extension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + } + typeName := typ.String() + encoder := typeEncoders[typeName] + if encoder != nil { + return encoder + } + if typ.Kind() == reflect.Ptr { + typePtr := typ.(*reflect2.UnsafePtrType) + encoder := typeEncoders[typePtr.Elem().String()] + if encoder != nil { + return &OptionalEncoder{encoder} + } + } + return nil +} + +func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { + structType := typ.(*reflect2.UnsafeStructType) + embeddedBindings := []*Binding{} + bindings := []*Binding{} + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + tag, hastag := field.Tag().Lookup(ctx.getTagKey()) + if ctx.onlyTaggedField && !hastag { + continue + } + tagParts := strings.Split(tag, ",") + if tag == "-" { + continue + } + if field.Anonymous() && (tag == "" || tagParts[0] == "") { + if field.Type().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, field.Type()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } else if field.Type().Kind() == reflect.Ptr { + ptrType := field.Type().(*reflect2.UnsafePtrType) + if ptrType.Elem().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, ptrType.Elem()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &dereferenceEncoder{binding.Encoder} + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } + } + } + fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) + fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name()) + decoder := fieldDecoders[fieldCacheKey] + if decoder == nil { + decoder = decoderOfType(ctx.append(field.Name()), field.Type()) + } + encoder := fieldEncoders[fieldCacheKey] + if encoder == nil { + encoder = encoderOfType(ctx.append(field.Name()), field.Type()) + } + binding := &Binding{ + Field: field, + FromNames: fieldNames, + ToNames: fieldNames, + Decoder: decoder, + Encoder: encoder, + } + binding.levels = []int{i} + bindings = append(bindings, binding) + } + return createStructDescriptor(ctx, typ, bindings, embeddedBindings) +} +func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + structDescriptor := &StructDescriptor{ + Type: typ, + Fields: bindings, + } + for _, extension := range extensions { + extension.UpdateStructDescriptor(structDescriptor) + } + for _, extension := range ctx.extensions { + extension.UpdateStructDescriptor(structDescriptor) + } + processTags(structDescriptor, ctx.frozenConfig) + // merge normal & embedded bindings & sort with original order + allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + sort.Sort(allBindings) + structDescriptor.Fields = allBindings + return structDescriptor +} + +type sortableBindings []*Binding + +func (bindings sortableBindings) Len() int { + return len(bindings) +} + +func (bindings sortableBindings) Less(i, j int) bool { + left := bindings[i].levels + right := bindings[j].levels + k := 0 + for { + if left[k] < right[k] { + return true + } else if left[k] > right[k] { + return false + } + k++ + } +} + +func (bindings sortableBindings) Swap(i, j int) { + bindings[i], bindings[j] = bindings[j], bindings[i] +} + +func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { + for _, binding := range structDescriptor.Fields { + shouldOmitEmpty := false + tagParts := strings.Split(binding.Field.Tag().Get(cfg.getTagKey()), ",") + for _, tagPart := range tagParts[1:] { + if tagPart == "omitempty" { + shouldOmitEmpty = true + } else if tagPart == "string" { + if binding.Field.Type().Kind() == reflect.String { + binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg} + binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} + } else { + binding.Decoder = &stringModeNumberDecoder{binding.Decoder} + binding.Encoder = &stringModeNumberEncoder{binding.Encoder} + } + } + } + binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + } +} + +func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { + // ignore? + if wholeTag == "-" { + return []string{} + } + // rename? + var fieldNames []string + if tagProvidedFieldName == "" { + fieldNames = []string{originalFieldName} + } else { + fieldNames = []string{tagProvidedFieldName} + } + // private? + isNotExported := unicode.IsLower(rune(originalFieldName[0])) + if isNotExported { + fieldNames = []string{} + } + return fieldNames +} diff --git a/vendor/github.com/json-iterator/go/reflect_json_number.go b/vendor/github.com/json-iterator/go/reflect_json_number.go new file mode 100644 index 0000000..98d45c1 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_json_number.go @@ -0,0 +1,112 @@ +package jsoniter + +import ( + "encoding/json" + "github.com/modern-go/reflect2" + "strconv" + "unsafe" +) + +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +func CastJsonNumber(val interface{}) (string, bool) { + switch typedVal := val.(type) { + case json.Number: + return string(typedVal), true + case Number: + return string(typedVal), true + } + return "", false +} + +var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem() +var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem() + +func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{} + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{} + } + return nil +} + +func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{} + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{} + } + return nil +} + +type jsonNumberCodec struct { +} + +func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + switch iter.WhatIsNext() { + case StringValue: + *((*json.Number)(ptr)) = json.Number(iter.ReadString()) + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + *((*json.Number)(ptr)) = "" + default: + *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) + } +} + +func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + number := *((*json.Number)(ptr)) + if len(number) == 0 { + stream.writeByte('0') + } else { + stream.WriteRaw(string(number)) + } +} + +func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.Number)(ptr))) == 0 +} + +type jsoniterNumberCodec struct { +} + +func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + switch iter.WhatIsNext() { + case StringValue: + *((*Number)(ptr)) = Number(iter.ReadString()) + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + *((*Number)(ptr)) = "" + default: + *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) + } +} + +func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + number := *((*Number)(ptr)) + if len(number) == 0 { + stream.writeByte('0') + } else { + stream.WriteRaw(string(number)) + } +} + +func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*Number)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go new file mode 100644 index 0000000..f261993 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go @@ -0,0 +1,60 @@ +package jsoniter + +import ( + "encoding/json" + "github.com/modern-go/reflect2" + "unsafe" +) + +var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem() +var jsoniterRawMessageType = reflect2.TypeOfPtr((*RawMessage)(nil)).Elem() + +func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{} + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{} + } + return nil +} + +func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{} + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{} + } + return nil +} + +type jsonRawMessageCodec struct { +} + +func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) +} + +func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.RawMessage)(ptr))) == 0 +} + +type jsoniterRawMessageCodec struct { +} + +func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*RawMessage)(ptr)))) +} + +func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*RawMessage)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go new file mode 100644 index 0000000..8812f08 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_map.go @@ -0,0 +1,318 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "sort" + "unsafe" +) + +func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { + mapType := typ.(*reflect2.UnsafeMapType) + keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) + elemDecoder := decoderOfType(ctx.append("[mapElem]"), mapType.Elem()) + return &mapDecoder{ + mapType: mapType, + keyType: mapType.Key(), + elemType: mapType.Elem(), + keyDecoder: keyDecoder, + elemDecoder: elemDecoder, + } +} + +func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { + mapType := typ.(*reflect2.UnsafeMapType) + if ctx.sortMapKeys { + return &sortKeysMapEncoder{ + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + } + } + return &mapEncoder{ + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + } +} + +func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { + for _, extension := range ctx.extensions { + decoder := extension.CreateMapKeyDecoder(typ) + if decoder != nil { + return decoder + } + } + switch typ.Kind() { + case reflect.String: + return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyDecoder{decoderOfType(ctx, typ)} + default: + ptrType := reflect2.PtrTo(typ) + if ptrType.Implements(textMarshalerType) { + return &referenceDecoder{ + &textUnmarshalerDecoder{ + valType: ptrType, + }, + } + } + if typ.Implements(textMarshalerType) { + return &textUnmarshalerDecoder{ + valType: typ, + } + } + return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { + for _, extension := range ctx.extensions { + encoder := extension.CreateMapKeyEncoder(typ) + if encoder != nil { + return encoder + } + } + switch typ.Kind() { + case reflect.String: + return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyEncoder{encoderOfType(ctx, typ)} + default: + if typ == textMarshalerType { + return &directTextMarshalerEncoder{ + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + if typ.Implements(textMarshalerType) { + return &textMarshalerEncoder{ + valType: typ, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + if typ.Kind() == reflect.Interface { + return &dynamicMapKeyEncoder{ctx, typ} + } + return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +type mapDecoder struct { + mapType *reflect2.UnsafeMapType + keyType reflect2.Type + elemType reflect2.Type + keyDecoder ValDecoder + elemDecoder ValDecoder +} + +func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + mapType := decoder.mapType + c := iter.nextToken() + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + *(*unsafe.Pointer)(ptr) = nil + mapType.UnsafeSet(ptr, mapType.UnsafeNew()) + return + } + if mapType.UnsafeIsNil(ptr) { + mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) + } + if c != '{' { + iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return + } + c = iter.nextToken() + if c == '}' { + return + } + if c != '"' { + iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) + return + } + iter.unreadByte() + key := decoder.keyType.UnsafeNew() + decoder.keyDecoder.Decode(key, iter) + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return + } + elem := decoder.elemType.UnsafeNew() + decoder.elemDecoder.Decode(elem, iter) + decoder.mapType.UnsafeSetIndex(ptr, key, elem) + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + key := decoder.keyType.UnsafeNew() + decoder.keyDecoder.Decode(key, iter) + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return + } + elem := decoder.elemType.UnsafeNew() + decoder.elemDecoder.Decode(elem, iter) + decoder.mapType.UnsafeSetIndex(ptr, key, elem) + } + if c != '}' { + iter.ReportError("ReadMapCB", `expect }, but found `+string([]byte{c})) + } +} + +type numericMapKeyDecoder struct { + decoder ValDecoder +} + +func (decoder *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + if c != '"' { + iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) + return + } + decoder.decoder.Decode(ptr, iter) + c = iter.nextToken() + if c != '"' { + iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) + return + } +} + +type numericMapKeyEncoder struct { + encoder ValEncoder +} + +func (encoder *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.encoder.Encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type dynamicMapKeyEncoder struct { + ctx *ctx + valType reflect2.Type +} + +func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) +} + +func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + obj := encoder.valType.UnsafeIndirect(ptr) + return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) +} + +type mapEncoder struct { + mapType *reflect2.UnsafeMapType + keyEncoder ValEncoder + elemEncoder ValEncoder +} + +func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteObjectStart() + iter := encoder.mapType.UnsafeIterate(ptr) + for i := 0; iter.HasNext(); i++ { + if i != 0 { + stream.WriteMore() + } + key, elem := iter.UnsafeNext() + encoder.keyEncoder.Encode(key, stream) + if stream.indention > 0 { + stream.writeTwoBytes(byte(':'), byte(' ')) + } else { + stream.writeByte(':') + } + encoder.elemEncoder.Encode(elem, stream) + } + stream.WriteObjectEnd() +} + +func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := encoder.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type sortKeysMapEncoder struct { + mapType *reflect2.UnsafeMapType + keyEncoder ValEncoder + elemEncoder ValEncoder +} + +func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *(*unsafe.Pointer)(ptr) == nil { + stream.WriteNil() + return + } + stream.WriteObjectStart() + mapIter := encoder.mapType.UnsafeIterate(ptr) + subStream := stream.cfg.BorrowStream(nil) + subIter := stream.cfg.BorrowIterator(nil) + keyValues := encodedKeyValues{} + for mapIter.HasNext() { + subStream.buf = make([]byte, 0, 64) + key, elem := mapIter.UnsafeNext() + encoder.keyEncoder.Encode(key, subStream) + if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { + stream.Error = subStream.Error + } + encodedKey := subStream.Buffer() + subIter.ResetBytes(encodedKey) + decodedKey := subIter.ReadString() + if stream.indention > 0 { + subStream.writeTwoBytes(byte(':'), byte(' ')) + } else { + subStream.writeByte(':') + } + encoder.elemEncoder.Encode(elem, subStream) + keyValues = append(keyValues, encodedKV{ + key: decodedKey, + keyValue: subStream.Buffer(), + }) + } + sort.Sort(keyValues) + for i, keyValue := range keyValues { + if i != 0 { + stream.WriteMore() + } + stream.Write(keyValue.keyValue) + } + stream.WriteObjectEnd() + stream.cfg.ReturnStream(subStream) + stream.cfg.ReturnIterator(subIter) +} + +func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := encoder.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type encodedKeyValues []encodedKV + +type encodedKV struct { + key string + keyValue []byte +} + +func (sv encodedKeyValues) Len() int { return len(sv) } +func (sv encodedKeyValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv encodedKeyValues) Less(i, j int) bool { return sv[i].key < sv[j].key } diff --git a/vendor/github.com/json-iterator/go/reflect_marshaler.go b/vendor/github.com/json-iterator/go/reflect_marshaler.go new file mode 100644 index 0000000..58ac959 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_marshaler.go @@ -0,0 +1,218 @@ +package jsoniter + +import ( + "encoding" + "encoding/json" + "github.com/modern-go/reflect2" + "unsafe" +) + +var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() +var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem() +var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem() +var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem() + +func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder { + ptrType := reflect2.PtrTo(typ) + if ptrType.Implements(unmarshalerType) { + return &referenceDecoder{ + &unmarshalerDecoder{ptrType}, + } + } + if ptrType.Implements(textUnmarshalerType) { + return &referenceDecoder{ + &textUnmarshalerDecoder{ptrType}, + } + } + return nil +} + +func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == marshalerType { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &directMarshalerEncoder{ + checkIsEmpty: checkIsEmpty, + } + return encoder + } + if typ.Implements(marshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &marshalerEncoder{ + valType: typ, + checkIsEmpty: checkIsEmpty, + } + return encoder + } + ptrType := reflect2.PtrTo(typ) + if ctx.prefix != "" && ptrType.Implements(marshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) + var encoder ValEncoder = &marshalerEncoder{ + valType: ptrType, + checkIsEmpty: checkIsEmpty, + } + return &referenceEncoder{encoder} + } + if typ == textMarshalerType { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &directTextMarshalerEncoder{ + checkIsEmpty: checkIsEmpty, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + return encoder + } + if typ.Implements(textMarshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &textMarshalerEncoder{ + valType: typ, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + checkIsEmpty: checkIsEmpty, + } + return encoder + } + // if prefix is empty, the type is the root type + if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) + var encoder ValEncoder = &textMarshalerEncoder{ + valType: ptrType, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + checkIsEmpty: checkIsEmpty, + } + return &referenceEncoder{encoder} + } + return nil +} + +type marshalerEncoder struct { + checkIsEmpty checkIsEmpty + valType reflect2.Type +} + +func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + if encoder.valType.IsNullable() && reflect2.IsNil(obj) { + stream.WriteNil() + return + } + marshaler := obj.(json.Marshaler) + bytes, err := marshaler.MarshalJSON() + if err != nil { + stream.Error = err + } else { + stream.Write(bytes) + } +} + +func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type directMarshalerEncoder struct { + checkIsEmpty checkIsEmpty +} + +func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + marshaler := *(*json.Marshaler)(ptr) + if marshaler == nil { + stream.WriteNil() + return + } + bytes, err := marshaler.MarshalJSON() + if err != nil { + stream.Error = err + } else { + stream.Write(bytes) + } +} + +func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type textMarshalerEncoder struct { + valType reflect2.Type + stringEncoder ValEncoder + checkIsEmpty checkIsEmpty +} + +func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + if encoder.valType.IsNullable() && reflect2.IsNil(obj) { + stream.WriteNil() + return + } + marshaler := (obj).(encoding.TextMarshaler) + bytes, err := marshaler.MarshalText() + if err != nil { + stream.Error = err + } else { + str := string(bytes) + encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) + } +} + +func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type directTextMarshalerEncoder struct { + stringEncoder ValEncoder + checkIsEmpty checkIsEmpty +} + +func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + marshaler := *(*encoding.TextMarshaler)(ptr) + if marshaler == nil { + stream.WriteNil() + return + } + bytes, err := marshaler.MarshalText() + if err != nil { + stream.Error = err + } else { + str := string(bytes) + encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) + } +} + +func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type unmarshalerDecoder struct { + valType reflect2.Type +} + +func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valType := decoder.valType + obj := valType.UnsafeIndirect(ptr) + unmarshaler := obj.(json.Unmarshaler) + iter.nextToken() + iter.unreadByte() // skip spaces + bytes := iter.SkipAndReturnBytes() + err := unmarshaler.UnmarshalJSON(bytes) + if err != nil { + iter.ReportError("unmarshalerDecoder", err.Error()) + } +} + +type textUnmarshalerDecoder struct { + valType reflect2.Type +} + +func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valType := decoder.valType + obj := valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + ptrType := valType.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elem := elemType.UnsafeNew() + ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem)) + obj = valType.UnsafeIndirect(ptr) + } + unmarshaler := (obj).(encoding.TextUnmarshaler) + str := iter.ReadString() + err := unmarshaler.UnmarshalText([]byte(str)) + if err != nil { + iter.ReportError("textUnmarshalerDecoder", err.Error()) + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_native.go b/vendor/github.com/json-iterator/go/reflect_native.go new file mode 100644 index 0000000..7f1e246 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_native.go @@ -0,0 +1,455 @@ +package jsoniter + +import ( + "encoding/base64" + "github.com/modern-go/reflect2" + "reflect" + "strconv" + "unsafe" +) + +const ptrSize = 32 << uintptr(^uintptr(0)>>63) + +func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { + sliceDecoder := decoderOfSlice(ctx, typ) + return &base64Codec{sliceDecoder: sliceDecoder} + } + typeName := typ.String() + kind := typ.Kind() + switch kind { + case reflect.String: + if typeName != "string" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { + sliceDecoder := decoderOfSlice(ctx, typ) + return &base64Codec{sliceDecoder: sliceDecoder} + } + typeName := typ.String() + switch typ.Kind() { + case reflect.String: + if typeName != "string" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +type stringCodec struct { +} + +func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*string)(ptr)) = iter.ReadString() +} + +func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteString(str) +} + +func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +type int8Codec struct { +} + +func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int8)(ptr)) = iter.ReadInt8() + } +} + +func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt8(*((*int8)(ptr))) +} + +func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int8)(ptr)) == 0 +} + +type int16Codec struct { +} + +func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int16)(ptr)) = iter.ReadInt16() + } +} + +func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt16(*((*int16)(ptr))) +} + +func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int16)(ptr)) == 0 +} + +type int32Codec struct { +} + +func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int32)(ptr)) = iter.ReadInt32() + } +} + +func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt32(*((*int32)(ptr))) +} + +func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int32)(ptr)) == 0 +} + +type int64Codec struct { +} + +func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int64)(ptr)) = iter.ReadInt64() + } +} + +func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt64(*((*int64)(ptr))) +} + +func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int64)(ptr)) == 0 +} + +type uint8Codec struct { +} + +func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint8)(ptr)) = iter.ReadUint8() + } +} + +func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint8(*((*uint8)(ptr))) +} + +func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint8)(ptr)) == 0 +} + +type uint16Codec struct { +} + +func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint16)(ptr)) = iter.ReadUint16() + } +} + +func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint16(*((*uint16)(ptr))) +} + +func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint16)(ptr)) == 0 +} + +type uint32Codec struct { +} + +func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint32)(ptr)) = iter.ReadUint32() + } +} + +func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint32(*((*uint32)(ptr))) +} + +func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint32)(ptr)) == 0 +} + +type uint64Codec struct { +} + +func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint64)(ptr)) = iter.ReadUint64() + } +} + +func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint64(*((*uint64)(ptr))) +} + +func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint64)(ptr)) == 0 +} + +type float32Codec struct { +} + +func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*float32)(ptr)) = iter.ReadFloat32() + } +} + +func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32(*((*float32)(ptr))) +} + +func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type float64Codec struct { +} + +func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*float64)(ptr)) = iter.ReadFloat64() + } +} + +func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64(*((*float64)(ptr))) +} + +func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +type boolCodec struct { +} + +func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*bool)(ptr)) = iter.ReadBool() + } +} + +func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteBool(*((*bool)(ptr))) +} + +func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { + return !(*((*bool)(ptr))) +} + +type base64Codec struct { + sliceType *reflect2.UnsafeSliceType + sliceDecoder ValDecoder +} + +func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + codec.sliceType.UnsafeSetNil(ptr) + return + } + switch iter.WhatIsNext() { + case StringValue: + encoding := base64.StdEncoding + src := iter.SkipAndReturnBytes() + src = src[1 : len(src)-1] + decodedLen := encoding.DecodedLen(len(src)) + dst := make([]byte, decodedLen) + len, err := encoding.Decode(dst, src) + if err != nil { + iter.ReportError("decode base64", err.Error()) + } else { + dst = dst[:len] + codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst)) + } + case ArrayValue: + codec.sliceDecoder.Decode(ptr, iter) + default: + iter.ReportError("base64Codec", "invalid input") + } +} + +func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + src := *((*[]byte)(ptr)) + if len(src) == 0 { + stream.WriteNil() + return + } + encoding := base64.StdEncoding + stream.writeByte('"') + size := encoding.EncodedLen(len(src)) + buf := make([]byte, size) + encoding.Encode(buf, src) + stream.buf = append(stream.buf, buf...) + stream.writeByte('"') +} + +func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*[]byte)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go new file mode 100644 index 0000000..43ec71d --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_optional.go @@ -0,0 +1,133 @@ +package jsoniter + +import ( + "github.com/modern-go/reflect2" + "reflect" + "unsafe" +) + +func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + decoder := decoderOfType(ctx, elemType) + if ctx.prefix == "" && elemType.Kind() == reflect.Ptr { + return &dereferenceDecoder{elemType, decoder} + } + return &OptionalDecoder{elemType, decoder} +} + +func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elemEncoder := encoderOfType(ctx, elemType) + encoder := &OptionalEncoder{elemEncoder} + return encoder +} + +type OptionalDecoder struct { + ValueType reflect2.Type + ValueDecoder ValDecoder +} + +func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + *((*unsafe.Pointer)(ptr)) = nil + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + newPtr := decoder.ValueType.UnsafeNew() + decoder.ValueDecoder.Decode(newPtr, iter) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + //reuse existing instance + decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } + } +} + +type dereferenceDecoder struct { + // only to deference a pointer + valueType reflect2.Type + valueDecoder ValDecoder +} + +func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + newPtr := decoder.valueType.UnsafeNew() + decoder.valueDecoder.Decode(newPtr, iter) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + //reuse existing instance + decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } +} + +type OptionalEncoder struct { + ValueEncoder ValEncoder +} + +func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*unsafe.Pointer)(ptr)) == nil +} + +type dereferenceEncoder struct { + ValueEncoder ValEncoder +} + +func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + dePtr := *((*unsafe.Pointer)(ptr)) + if dePtr == nil { + return true + } + return encoder.ValueEncoder.IsEmpty(dePtr) +} + +func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + deReferenced := *((*unsafe.Pointer)(ptr)) + if deReferenced == nil { + return true + } + isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := unsafe.Pointer(deReferenced) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type referenceEncoder struct { + encoder ValEncoder +} + +func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +type referenceDecoder struct { + decoder ValDecoder +} + +func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) +} diff --git a/vendor/github.com/json-iterator/go/reflect_slice.go b/vendor/github.com/json-iterator/go/reflect_slice.go new file mode 100644 index 0000000..9441d79 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_slice.go @@ -0,0 +1,99 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "unsafe" +) + +func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + return &sliceDecoder{sliceType, decoder} +} + +func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + return &sliceEncoder{sliceType, encoder} +} + +type sliceEncoder struct { + sliceType *reflect2.UnsafeSliceType + elemEncoder ValEncoder +} + +func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if encoder.sliceType.UnsafeIsNil(ptr) { + stream.WriteNil() + return + } + length := encoder.sliceType.UnsafeLengthOf(ptr) + if length == 0 { + stream.WriteEmptyArray() + return + } + stream.WriteArrayStart() + encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream) + for i := 1; i < length; i++ { + stream.WriteMore() + elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) + } +} + +func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.sliceType.UnsafeLengthOf(ptr) == 0 +} + +type sliceDecoder struct { + sliceType *reflect2.UnsafeSliceType + elemDecoder ValDecoder +} + +func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) + } +} + +func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + sliceType := decoder.sliceType + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + sliceType.UnsafeSetNil(ptr) + return + } + if c != '[' { + iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c})) + return + } + c = iter.nextToken() + if c == ']' { + sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) + return + } + iter.unreadByte() + sliceType.UnsafeGrow(ptr, 1) + elemPtr := sliceType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, iter) + length := 1 + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + idx := length + length += 1 + sliceType.UnsafeGrow(ptr, length) + elemPtr = sliceType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, iter) + } + if c != ']' { + iter.ReportError("decode slice", "expect ], but found "+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go new file mode 100644 index 0000000..e718722 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go @@ -0,0 +1,1034 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "strings" + "unsafe" +) + +func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { + bindings := map[string]*Binding{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, fromName := range binding.FromNames { + old := bindings[fromName] + if old == nil { + bindings[fromName] = binding + continue + } + ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding) + if ignoreOld { + delete(bindings, fromName) + } + if !ignoreNew { + bindings[fromName] = binding + } + } + } + fields := map[string]*structFieldDecoder{} + for k, binding := range bindings { + fields[k] = binding.Decoder.(*structFieldDecoder) + } + return createStructDecoder(ctx, typ, fields) +} + +func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder { + if ctx.disallowUnknownFields { + return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} + } + knownHash := map[int64]struct{}{ + 0: {}, + } + switch len(fields) { + case 0: + return &skipObjectDecoder{typ} + case 1: + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder} + } + case 2: + var fieldHash1 int64 + var fieldHash2 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldHash1 == 0 { + fieldHash1 = fieldHash + fieldDecoder1 = fieldDecoder + } else { + fieldHash2 = fieldHash + fieldDecoder2 = fieldDecoder + } + } + return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2} + case 3: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } + } + return &threeFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3} + case 4: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } + } + return &fourFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4} + case 5: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } + } + return &fiveFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5} + case 6: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } + } + return &sixFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6} + case 7: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } + } + return &sevenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7} + case 8: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } + } + return &eightFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8} + case 9: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldName9 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } + } + return &nineFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8, + fieldName9, fieldDecoder9} + case 10: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldName9 int64 + var fieldName10 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + var fieldDecoder10 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else if fieldName9 == 0 { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } else { + fieldName10 = fieldHash + fieldDecoder10 = fieldDecoder + } + } + return &tenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8, + fieldName9, fieldDecoder9, + fieldName10, fieldDecoder10} + } + return &generalStructDecoder{typ, fields, false} +} + +type generalStructDecoder struct { + typ reflect2.Type + fields map[string]*structFieldDecoder + disallowUnknownFields bool +} + +func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + decoder.decodeOneField(ptr, iter) + for iter.nextToken() == ',' { + decoder.decodeOneField(ptr, iter) + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) { + var field string + var fieldDecoder *structFieldDecoder + if iter.cfg.objectFieldMustBeSimpleString { + fieldBytes := iter.ReadStringAsSlice() + field = *(*string)(unsafe.Pointer(&fieldBytes)) + fieldDecoder = decoder.fields[field] + if fieldDecoder == nil { + fieldDecoder = decoder.fields[strings.ToLower(field)] + } + } else { + field = iter.ReadString() + fieldDecoder = decoder.fields[field] + if fieldDecoder == nil { + fieldDecoder = decoder.fields[strings.ToLower(field)] + } + } + if fieldDecoder == nil { + msg := "found unknown field: " + field + if decoder.disallowUnknownFields { + iter.ReportError("ReadObject", msg) + } + c := iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + iter.Skip() + return + } + c := iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + fieldDecoder.Decode(ptr, iter) +} + +type skipObjectDecoder struct { + typ reflect2.Type +} + +func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valueType := iter.WhatIsNext() + if valueType != ObjectValue && valueType != NilValue { + iter.ReportError("skipObjectDecoder", "expect object or null") + return + } + iter.Skip() +} + +type oneFieldStructDecoder struct { + typ reflect2.Type + fieldHash int64 + fieldDecoder *structFieldDecoder +} + +func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + if iter.readFieldHash() == decoder.fieldHash { + decoder.fieldDecoder.Decode(ptr, iter) + } else { + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type twoFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder +} + +func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type threeFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder +} + +func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type fourFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder +} + +func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type fiveFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder +} + +func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type sixFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder +} + +func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type sevenFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder +} + +func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type eightFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder +} + +func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type nineFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder + fieldHash9 int64 + fieldDecoder9 *structFieldDecoder +} + +func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type tenFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder + fieldHash9 int64 + fieldDecoder9 *structFieldDecoder + fieldHash10 int64 + fieldDecoder10 *structFieldDecoder +} + +func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + case decoder.fieldHash10: + decoder.fieldDecoder10.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } +} + +type structFieldDecoder struct { + field reflect2.StructField + fieldDecoder ValDecoder +} + +func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + fieldPtr := decoder.field.UnsafeGet(ptr) + decoder.fieldDecoder.Decode(fieldPtr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error()) + } +} + +type stringModeStringDecoder struct { + elemDecoder ValDecoder + cfg *frozenConfig +} + +func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.elemDecoder.Decode(ptr, iter) + str := *((*string)(ptr)) + tempIter := decoder.cfg.BorrowIterator([]byte(str)) + defer decoder.cfg.ReturnIterator(tempIter) + *((*string)(ptr)) = tempIter.ReadString() +} + +type stringModeNumberDecoder struct { + elemDecoder ValDecoder +} + +func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) + return + } + decoder.elemDecoder.Decode(ptr, iter) + if iter.Error != nil { + return + } + c = iter.readByte() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go new file mode 100644 index 0000000..d0759cf --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go @@ -0,0 +1,210 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "unsafe" +) + +func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { + type bindingTo struct { + binding *Binding + toName string + ignored bool + } + orderedBindings := []*bindingTo{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, toName := range binding.ToNames { + new := &bindingTo{ + binding: binding, + toName: toName, + } + for _, old := range orderedBindings { + if old.toName != toName { + continue + } + old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) + } + orderedBindings = append(orderedBindings, new) + } + } + if len(orderedBindings) == 0 { + return &emptyStructEncoder{} + } + finalOrderedFields := []structFieldTo{} + for _, bindingTo := range orderedBindings { + if !bindingTo.ignored { + finalOrderedFields = append(finalOrderedFields, structFieldTo{ + encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + toName: bindingTo.toName, + }) + } + } + return &structEncoder{typ, finalOrderedFields} +} + +func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { + encoder := createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return &structEncoder{typ: typ} + case reflect.Array: + return &arrayEncoder{} + case reflect.Slice: + return &sliceEncoder{} + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return &OptionalEncoder{} + default: + return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)} + } +} + +func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { + newTagged := new.Field.Tag().Get(cfg.getTagKey()) != "" + oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" + if newTagged { + if oldTagged { + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } else { + return true, false + } + } else { + if oldTagged { + return true, false + } + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } +} + +type structFieldEncoder struct { + field reflect2.StructField + fieldEncoder ValEncoder + omitempty bool +} + +func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + fieldPtr := encoder.field.UnsafeGet(ptr) + encoder.fieldEncoder.Encode(fieldPtr, stream) + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) + } +} + +func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := encoder.field.UnsafeGet(ptr) + return encoder.fieldEncoder.IsEmpty(fieldPtr) +} + +func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := encoder.field.UnsafeGet(ptr) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type IsEmbeddedPtrNil interface { + IsEmbeddedPtrNil(ptr unsafe.Pointer) bool +} + +type structEncoder struct { + typ reflect2.Type + fields []structFieldTo +} + +type structFieldTo struct { + encoder *structFieldEncoder + toName string +} + +func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteObjectStart() + isNotFirst := false + for _, field := range encoder.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if field.encoder.IsEmbeddedPtrNil(ptr) { + continue + } + if isNotFirst { + stream.WriteMore() + } + stream.WriteObjectField(field.toName) + field.encoder.Encode(ptr, stream) + isNotFirst = true + } + stream.WriteObjectEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) + } +} + +func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type emptyStructEncoder struct { +} + +func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type stringModeNumberEncoder struct { + elemEncoder ValEncoder +} + +func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.elemEncoder.Encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} + +type stringModeStringEncoder struct { + elemEncoder ValEncoder + cfg *frozenConfig +} + +func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + tempStream := encoder.cfg.BorrowStream(nil) + defer encoder.cfg.ReturnStream(tempStream) + encoder.elemEncoder.Encode(ptr, tempStream) + stream.WriteString(string(tempStream.Buffer())) +} + +func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go new file mode 100644 index 0000000..17662fd --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream.go @@ -0,0 +1,211 @@ +package jsoniter + +import ( + "io" +) + +// stream is a io.Writer like object, with JSON specific write functions. +// Error is not returned as return value, but stored as Error member on this stream instance. +type Stream struct { + cfg *frozenConfig + out io.Writer + buf []byte + Error error + indention int + Attachment interface{} // open for customized encoder +} + +// NewStream create new stream instance. +// cfg can be jsoniter.ConfigDefault. +// out can be nil if write to internal buffer. +// bufSize is the initial size for the internal buffer in bytes. +func NewStream(cfg API, out io.Writer, bufSize int) *Stream { + return &Stream{ + cfg: cfg.(*frozenConfig), + out: out, + buf: make([]byte, 0, bufSize), + Error: nil, + indention: 0, + } +} + +// Pool returns a pool can provide more stream with same configuration +func (stream *Stream) Pool() StreamPool { + return stream.cfg +} + +// Reset reuse this stream instance by assign a new writer +func (stream *Stream) Reset(out io.Writer) { + stream.out = out + stream.buf = stream.buf[:0] +} + +// Available returns how many bytes are unused in the buffer. +func (stream *Stream) Available() int { + return cap(stream.buf) - len(stream.buf) +} + +// Buffered returns the number of bytes that have been written into the current buffer. +func (stream *Stream) Buffered() int { + return len(stream.buf) +} + +// Buffer if writer is nil, use this method to take the result +func (stream *Stream) Buffer() []byte { + return stream.buf +} + +// SetBuffer allows to append to the internal buffer directly +func (stream *Stream) SetBuffer(buf []byte) { + stream.buf = buf +} + +// Write writes the contents of p into the buffer. +// It returns the number of bytes written. +// If nn < len(p), it also returns an error explaining +// why the write is short. +func (stream *Stream) Write(p []byte) (nn int, err error) { + stream.buf = append(stream.buf, p...) + if stream.out != nil { + nn, err = stream.out.Write(stream.buf) + stream.buf = stream.buf[nn:] + return + } + return len(p), nil +} + +// WriteByte writes a single byte. +func (stream *Stream) writeByte(c byte) { + stream.buf = append(stream.buf, c) +} + +func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { + stream.buf = append(stream.buf, c1, c2) +} + +func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { + stream.buf = append(stream.buf, c1, c2, c3) +} + +func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { + stream.buf = append(stream.buf, c1, c2, c3, c4) +} + +func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { + stream.buf = append(stream.buf, c1, c2, c3, c4, c5) +} + +// Flush writes any buffered data to the underlying io.Writer. +func (stream *Stream) Flush() error { + if stream.out == nil { + return nil + } + if stream.Error != nil { + return stream.Error + } + n, err := stream.out.Write(stream.buf) + if err != nil { + if stream.Error == nil { + stream.Error = err + } + return err + } + stream.buf = stream.buf[n:] + return nil +} + +// WriteRaw write string out without quotes, just like []byte +func (stream *Stream) WriteRaw(s string) { + stream.buf = append(stream.buf, s...) +} + +// WriteNil write null to stream +func (stream *Stream) WriteNil() { + stream.writeFourBytes('n', 'u', 'l', 'l') +} + +// WriteTrue write true to stream +func (stream *Stream) WriteTrue() { + stream.writeFourBytes('t', 'r', 'u', 'e') +} + +// WriteFalse write false to stream +func (stream *Stream) WriteFalse() { + stream.writeFiveBytes('f', 'a', 'l', 's', 'e') +} + +// WriteBool write true or false into stream +func (stream *Stream) WriteBool(val bool) { + if val { + stream.WriteTrue() + } else { + stream.WriteFalse() + } +} + +// WriteObjectStart write { with possible indention +func (stream *Stream) WriteObjectStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('{') + stream.writeIndention(0) +} + +// WriteObjectField write "field": with possible indention +func (stream *Stream) WriteObjectField(field string) { + stream.WriteString(field) + if stream.indention > 0 { + stream.writeTwoBytes(':', ' ') + } else { + stream.writeByte(':') + } +} + +// WriteObjectEnd write } with possible indention +func (stream *Stream) WriteObjectEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte('}') +} + +// WriteEmptyObject write {} +func (stream *Stream) WriteEmptyObject() { + stream.writeByte('{') + stream.writeByte('}') +} + +// WriteMore write , with possible indention +func (stream *Stream) WriteMore() { + stream.writeByte(',') + stream.writeIndention(0) + stream.Flush() +} + +// WriteArrayStart write [ with possible indention +func (stream *Stream) WriteArrayStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('[') + stream.writeIndention(0) +} + +// WriteEmptyArray write [] +func (stream *Stream) WriteEmptyArray() { + stream.writeTwoBytes('[', ']') +} + +// WriteArrayEnd write ] with possible indention +func (stream *Stream) WriteArrayEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte(']') +} + +func (stream *Stream) writeIndention(delta int) { + if stream.indention == 0 { + return + } + stream.writeByte('\n') + toWrite := stream.indention - delta + for i := 0; i < toWrite; i++ { + stream.buf = append(stream.buf, ' ') + } +} diff --git a/vendor/github.com/json-iterator/go/stream_float.go b/vendor/github.com/json-iterator/go/stream_float.go new file mode 100644 index 0000000..f318d2c --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_float.go @@ -0,0 +1,94 @@ +package jsoniter + +import ( + "math" + "strconv" +) + +var pow10 []uint64 + +func init() { + pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} +} + +// WriteFloat32 write float32 to stream +func (stream *Stream) WriteFloat32(val float32) { + abs := math.Abs(float64(val)) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32) +} + +// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat32Lossy(val float32) { + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat32(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val)*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[len(stream.buf)-1] == '0' { + stream.buf = stream.buf[:len(stream.buf)-1] + } +} + +// WriteFloat64 write float64 to stream +func (stream *Stream) WriteFloat64(val float64) { + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64) +} + +// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat64Lossy(val float64) { + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat64(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(val*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[len(stream.buf)-1] == '0' { + stream.buf = stream.buf[:len(stream.buf)-1] + } +} diff --git a/vendor/github.com/json-iterator/go/stream_int.go b/vendor/github.com/json-iterator/go/stream_int.go new file mode 100644 index 0000000..d1059ee --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_int.go @@ -0,0 +1,190 @@ +package jsoniter + +var digits []uint32 + +func init() { + digits = make([]uint32, 1000) + for i := uint32(0); i < 1000; i++ { + digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' + if i < 10 { + digits[i] += 2 << 24 + } else if i < 100 { + digits[i] += 1 << 24 + } + } +} + +func writeFirstBuf(space []byte, v uint32) []byte { + start := v >> 24 + if start == 0 { + space = append(space, byte(v>>16), byte(v>>8)) + } else if start == 1 { + space = append(space, byte(v>>8)) + } + space = append(space, byte(v)) + return space +} + +func writeBuf(buf []byte, v uint32) []byte { + return append(buf, byte(v>>16), byte(v>>8), byte(v)) +} + +// WriteUint8 write uint8 to stream +func (stream *Stream) WriteUint8(val uint8) { + stream.buf = writeFirstBuf(stream.buf, digits[val]) +} + +// WriteInt8 write int8 to stream +func (stream *Stream) WriteInt8(nval int8) { + var val uint8 + if nval < 0 { + val = uint8(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint8(nval) + } + stream.buf = writeFirstBuf(stream.buf, digits[val]) +} + +// WriteUint16 write uint16 to stream +func (stream *Stream) WriteUint16(val uint16) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return +} + +// WriteInt16 write int16 to stream +func (stream *Stream) WriteInt16(nval int16) { + var val uint16 + if nval < 0 { + val = uint16(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint16(nval) + } + stream.WriteUint16(val) +} + +// WriteUint32 write uint32 to stream +func (stream *Stream) WriteUint32(val uint32) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q2]) + } else { + r3 := q2 - q3*1000 + stream.buf = append(stream.buf, byte(q3+'0')) + stream.buf = writeBuf(stream.buf, digits[r3]) + } + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) +} + +// WriteInt32 write int32 to stream +func (stream *Stream) WriteInt32(nval int32) { + var val uint32 + if nval < 0 { + val = uint32(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint32(nval) + } + stream.WriteUint32(val) +} + +// WriteUint64 write uint64 to stream +func (stream *Stream) WriteUint64(val uint64) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q2]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q3]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q4]) + stream.buf = writeBuf(stream.buf, digits[r4]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q5]) + } else { + stream.buf = writeFirstBuf(stream.buf, digits[q6]) + r6 := q5 - q6*1000 + stream.buf = writeBuf(stream.buf, digits[r6]) + } + stream.buf = writeBuf(stream.buf, digits[r5]) + stream.buf = writeBuf(stream.buf, digits[r4]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) +} + +// WriteInt64 write int64 to stream +func (stream *Stream) WriteInt64(nval int64) { + var val uint64 + if nval < 0 { + val = uint64(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint64(nval) + } + stream.WriteUint64(val) +} + +// WriteInt write int to stream +func (stream *Stream) WriteInt(val int) { + stream.WriteInt64(int64(val)) +} + +// WriteUint write uint to stream +func (stream *Stream) WriteUint(val uint) { + stream.WriteUint64(uint64(val)) +} diff --git a/vendor/github.com/json-iterator/go/stream_str.go b/vendor/github.com/json-iterator/go/stream_str.go new file mode 100644 index 0000000..54c2ba0 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_str.go @@ -0,0 +1,372 @@ +package jsoniter + +import ( + "unicode/utf8" +) + +// htmlSafeSet holds the value true if the ASCII character with the given +// array position can be safely represented inside a JSON string, embedded +// inside of HTML